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
1=== modified file 'VERSION'
2--- VERSION 2011-11-17 22:53:42 +0000
3+++ VERSION 2011-11-18 07:40:33 +0000
4@@ -1,1 +1,3 @@
5-r2906 (2011-11-17 22:53:41)
6\ No newline at end of file
7+<<<<<<< TREE
8+r2906 (2011-11-17 22:53:41)=======
9+r2928 (2011-11-17 09:42:19)>>>>>>> MERGE-SOURCE
10
11=== added file 'clean_la.cmd'
12--- clean_la.cmd 1970-01-01 00:00:00 +0000
13+++ clean_la.cmd 2011-11-18 07:40:33 +0000
14@@ -0,0 +1,11 @@
15+@echo off
16+rem CHOICE Do you want to delete and reinitialise the Sahana Eden Database
17+rem if ERRORLEVEL N goto end
18+
19+rd /Q /S compiled
20+
21+del databases\*.* /Q
22+del errors\*.* /Q
23+del sessions\*.* /Q
24+python ..\..\web2py.py -S la -M -R applications\la\static\scripts\tools\noop.py
25+PAUSE
26\ No newline at end of file
27
28=== modified file 'controllers/admin.py'
29--- controllers/admin.py 2011-10-16 02:20:28 +0000
30+++ controllers/admin.py 2011-11-18 07:40:33 +0000
31@@ -73,6 +73,37 @@
32
33
34 # -----------------------------------------------------------------------------
35+def register_onaccept(form):
36+ """
37+ LA-specific:
38+ Ensure manually-created users get added to 'Staff' role &
39+ have an HRM record created.
40+ """
41+ # Usual Registration Tasks
42+ # (PR record, Authenticated Role, Contacts)
43+ person = auth.s3_register(form)
44+
45+ # LA-specific
46+ # Add to 'Staff' role
47+ table = db.auth_group
48+ STAFF = db(table.uuid == "STAFF").select(table.id,
49+ limitby=(0, 1)).first().id
50+ table = db.pr_person
51+ person_uuid = db(table.id == person).select(table.uuid,
52+ limitby=(0, 1)).first().uuid
53+ table = db.auth_user
54+ query = (table.person_uuid == person_uuid)
55+ user = db(query).select(table.id,
56+ limitby=(0, 1)).first().id
57+ table = db.auth_membership
58+ table.insert(user_id = user,
59+ group_id = STAFF)
60+
61+ # Create an HRM record so that the user appears in human_resource_id() lookups
62+ table = db.hrm_human_resource
63+ table.insert(person_id=person)
64+
65+# -----------------------------------------------------------------------------
66 @auth.s3_requires_membership(1)
67 def user():
68 """ RESTful CRUD controller """
69@@ -84,7 +115,10 @@
70 s3mgr.configure(tablename,
71 main="first_name",
72 # Add users to Person Registry & 'Authenticated' role:
73- create_onaccept = auth.s3_register)
74+ create_onaccept = register_onaccept)
75+
76+ # Staff don't need a Mobile Phone
77+ deployment_settings.auth.registration_requests_mobile_phone = False
78
79 def disable_user(r):
80 if not r.id:
81@@ -116,7 +150,7 @@
82 table = auth.settings.table_user
83 query = (table.id == r.id)
84 db(query).update(registration_key = "")
85-
86+
87 session.confirmation = T("User Account has been Approved")
88 redirect(URL(args=[]))
89
90@@ -751,6 +785,20 @@
91 return response.stream(portable_app)
92
93 # =============================================================================
94+# LA Code
95+# =============================================================================
96+@auth.s3_requires_membership(1)
97+def rostermail():
98+ """
99+ Email Addresses for the Volunteer Roster to be sent to
100+ """
101+
102+ return s3_rest_controller("vol", resourcename)
103+
104+
105+
106+
107+# =============================================================================
108 # Deprecated Code below here
109 # =============================================================================
110 @auth.s3_requires_membership(1)
111
112=== modified file 'controllers/default.py'
113--- controllers/default.py 2011-11-14 23:42:57 +0000
114+++ controllers/default.py 2011-11-18 07:40:33 +0000
115@@ -25,6 +25,7 @@
116
117 return response.download(request, db)
118
119+<<<<<<< TREE
120 # =============================================================================
121 def register_validation(form):
122 """ Validate the fields in registration form """
123@@ -105,293 +106,17 @@
124 T("This setting can only be controlled by the Administrator.")))
125
126 # =============================================================================
127+=======
128+# -----------------------------------------------------------------------------
129+>>>>>>> MERGE-SOURCE
130 def index():
131 """ Main Home Page """
132
133 title = deployment_settings.get_system_name()
134 response.title = title
135
136- if deployment_settings.has_module("cr"):
137- s3mgr.load("cr_shelter")
138- SHELTERS = s3.crud_strings["cr_shelter"].subtitle_list
139- else:
140- SHELTERS = ""
141-
142- # Menu Boxes
143- menu_btns = [#div, label, app, function
144- ["facility", SHELTERS, "cr", "shelter"],
145- ["facility", T("Warehouses"), "inv", "warehouse"],
146- ["facility", T("Hospitals"), "hms", "hospital"],
147- ["facility", T("Offices"), "org", "office"],
148- ["sit", T("Incidents"), "irs", "ireport"],
149- ["sit", T("Assessments"), "assess", "assess"],
150- ["sit", T("Assets"), "asset", "asset"],
151- ["sit", T("Inventory Items"), "inv", "inv_item"],
152- ["dec", T("Gap Map"), "project", "gap_map"],
153- ["dec", T("Gap Report"), "project", "gap_report"],
154- ["dec", T("Requests"), "req", "req"],
155- ["res", T("Projects"), "project", "project"],
156- ["res", T("Activities"), "project", "assess"],
157- ["res", T("Commitments"), "req", "commit"],
158- ["res", T("Sent Shipments"), "inv", "send"],
159- ["res", T("Received Shipments"), "inv", "recv"],
160- ]
161-
162- # Change to (Mitigation)/Preparedness/Response/Recovery?
163- menu_divs = {"facility": DIV( H3(T("Facilities")),
164- _id = "facility_box", _class = "menu_box"),
165- "sit": DIV( H3(T("Situation")),
166- _id = "menu_div_sit", _class = "menu_div"),
167- "dec": DIV( H3(T("Decision")),
168- _id = "menu_div_dec", _class = "menu_div"),
169- "res": DIV( H3(T("Response")),
170- _id = "menu_div_res", _class = "menu_div"),
171- }
172-
173- for div, label, app, function in menu_btns:
174- if deployment_settings.has_module(app):
175- # @ToDo: Also check permissions (e.g. for anonymous users)
176- menu_divs[div].append(A( DIV(label,
177- _class = "menu-btn-r"),
178- _class = "menu-btn-l",
179- _href = URL(app,function)
180- )
181- )
182-
183- div_arrow = DIV(IMG(_src = "/%s/static/img/arrow_blue_right.png" % \
184- request.application),
185- _class = "div_arrow")
186- sit_dec_res_box = DIV(menu_divs["sit"],
187- div_arrow,
188- menu_divs["dec"],
189- div_arrow,
190- menu_divs["res"],
191- _id = "sit_dec_res_box",
192- _class = "menu_box fleft swidth"
193- #div_additional,
194- )
195- facility_box = menu_divs["facility"]
196- facility_box.append( A( IMG(_src = "/%s/static/img/map_icon_128.png" % \
197- request.application),
198- _href = URL(c="gis", f="index"),
199- _title = T("Map")
200- )
201- )
202-
203- datatable_ajax_source = ""
204- # Check logged in AND permissions
205- if AUTHENTICATED in session.s3.roles and \
206- auth.s3_has_permission("read", db.org_organisation):
207- org_items = organisation()
208- datatable_ajax_source = "/%s/default/organisation.aaData" % \
209- request.application
210- response.s3.actions = None
211- response.view = "default/index.html"
212- auth.permission.controller = "org"
213- auth.permission.function = "site"
214- permitted_facilities = auth.permission.permitted_facilities(redirect_on_error=False)
215- manage_facility_box = ""
216- if permitted_facilities:
217- facility_list = s3_represent_facilities(db, permitted_facilities,
218- link=False)
219- facility_opts = [OPTION(opt[1], _value = opt[0])
220- for opt in facility_list]
221- if facility_list:
222- manage_facility_box = DIV(H3(T("Manage Your Facilities")),
223- SELECT(_id = "manage_facility_select",
224- _style = "max-width:400px;",
225- *facility_opts
226- ),
227- A(T("Go"),
228- _href = URL(c="default", f="site",
229- args=[facility_list[0][0]]),
230- #_disabled = "disabled",
231- _id = "manage_facility_btn",
232- _class = "action-btn"
233- ),
234- _id = "manage_facility_box",
235- _class = "menu_box fleft")
236- response.s3.jquery_ready.append( """
237-$('#manage_facility_select').change(function() {
238- $('#manage_facility_btn').attr('href', S3.Ap.concat('/default/site/', $('#manage_facility_select').val()));
239-})""" )
240- else:
241- manage_facility_box = DIV()
242-
243- org_box = DIV( H3(T("Organizations")),
244- A(T("Add Organization"),
245- _href = URL(c="org", f="organisation",
246- args=["create"]),
247- _id = "add-btn",
248- _class = "action-btn",
249- _style = "margin-right: 10px;"),
250- org_items["items"],
251- _id = "org_box",
252- _class = "menu_box fleft"
253- )
254- else:
255- manage_facility_box = ""
256- org_box = ""
257-
258- # @ToDo: Replace this with an easily-customisable section on the homepage
259- #settings = db(db.s3_setting.id == 1).select(limitby=(0, 1)).first()
260- #if settings:
261- # admin_name = settings.admin_name
262- # admin_email = settings.admin_email
263- # admin_tel = settings.admin_tel
264- #else:
265- # # db empty and prepopulate is false
266- # admin_name = T("Sahana Administrator").xml(),
267- # admin_email = "support@Not Set",
268- # admin_tel = T("Not Set").xml(),
269-
270- # Login/Registration forms
271- self_registration = deployment_settings.get_security_self_registration()
272- registered = False
273- login_form = None
274- login_div = None
275- register_form = None
276- register_div = None
277- if AUTHENTICATED not in session.s3.roles:
278- # This user isn't yet logged-in
279- if request.cookies.has_key("registered"):
280- # This browser has logged-in before
281- registered = True
282-
283- # Provide a login box on front page
284- request.args = ["login"]
285- auth.messages.submit_button = T("Login")
286- login_form = auth()
287- login_div = DIV(H3(T("Login")),
288- P(XML("%s <b>%s</b> %s" % (T("Registered users can"),
289- T("login"),
290- T("to access the system")))))
291-
292- if self_registration:
293- # Provide a Registration box on front page
294- request.args = ["register"]
295- if deployment_settings.get_terms_of_service():
296- auth.messages.submit_button = T("I accept. Create my account.")
297- else:
298- auth.messages.submit_button = T("Register")
299- register_form = auth()
300- register_div = DIV(H3(T("Register")),
301- P(XML("%s <b>%s</b>" % (T("If you would like to help, then please"),
302- T("sign-up now")))))
303-
304- # Add client-side validation
305- s3_register_validation()
306-
307- if session.s3.debug:
308- response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
309- else:
310- response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
311- if request.env.request_method == "POST":
312- post_script = """// Unhide register form
313- $('#register_form').removeClass('hide');
314- // Hide login form
315- $('#login_form').addClass('hide');"""
316- else:
317- post_script = ""
318- register_script = """
319- // Change register/login links to avoid page reload, make back button work.
320- $('#register-btn').attr('href', '#register');
321- $('#login-btn').attr('href', '#login');
322- %s
323- // Redirect Register Button to unhide
324- $('#register-btn').click(function() {
325- // Unhide register form
326- $('#register_form').removeClass('hide');
327- // Hide login form
328- $('#login_form').addClass('hide');
329- });
330-
331- // Redirect Login Button to unhide
332- $('#login-btn').click(function() {
333- // Hide register form
334- $('#register_form').addClass('hide');
335- // Unhide login form
336- $('#login_form').removeClass('hide');
337- });""" % post_script
338- response.s3.jquery_ready.append(register_script)
339-
340- if deployment_settings.frontpage.rss:
341- response.s3.external_stylesheets.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.css" )
342- response.s3.scripts.append( "http://www.google.com/jsapi?key=notsupplied-wizard" )
343- response.s3.scripts.append( "http://www.google.com/uds/solutions/dynamicfeed/gfdynamicfeedcontrol.js" )
344- counter = 0
345- feeds = ""
346- for feed in deployment_settings.frontpage.rss:
347- counter += 1
348- feeds = "".join((feeds,
349- "{title: '%s',\n" % feed["title"],
350- "url: '%s'}" % feed["url"]))
351- # Don't add a trailing comma for old IEs
352- if counter != len(deployment_settings.frontpage.rss):
353- feeds += ",\n"
354- feed_control = "".join(("""
355-function LoadDynamicFeedControl() {
356- var feeds = [
357- """, feeds, """
358- ];
359- var options = {
360- // milliseconds before feed is reloaded (5 minutes)
361- feedCycleTime : 300000,
362- numResults : 5,
363- stacked : true,
364- horizontal : false,
365- title : '""", str(T("News")), """'
366- };
367- new GFdynamicFeedControl(feeds, 'feed-control', options);
368-}
369-// Load the feeds API and set the onload callback.
370-google.load('feeds', '1');
371-google.setOnLoadCallback(LoadDynamicFeedControl);"""))
372- response.s3.js_global.append( feed_control )
373-
374- return dict(title = title,
375-
376- sit_dec_res_box = sit_dec_res_box,
377- facility_box = facility_box,
378- manage_facility_box = manage_facility_box,
379- org_box = org_box,
380-
381- r = None, # Required for dataTable to work
382- datatable_ajax_source = datatable_ajax_source,
383- #admin_name=admin_name,
384- #admin_email=admin_email,
385- #admin_tel=admin_tel,
386- self_registration=self_registration,
387- registered=registered,
388- login_form=login_form,
389- login_div=login_div,
390- register_form=register_form,
391- register_div=register_div
392- )
393-
394-# -----------------------------------------------------------------------------
395-def organisation():
396- """
397- Function to handle pagination for the org list on the homepage
398- """
399-
400- table = db.org_organisation
401- table.id.label = T("Organization")
402- table.id.represent = organisation_represent
403-
404- response.s3.dataTable_sPaginationType = "two_button"
405- response.s3.dataTable_sDom = "rtip" #"frtip" - filter broken
406- response.s3.dataTable_iDisplayLength = 25
407-
408- s3mgr.configure("org_organisation",
409- listadd = False,
410- addbtn = True,
411- super_entity = db.pr_pentity,
412- linkto = "/%s/org/organisation/%s" % (request.application,
413- "%s"),
414- list_fields = ["id",])
415-
416- return s3_rest_controller("org", "organisation")
417+ return dict(title = title)
418+
419 # -----------------------------------------------------------------------------
420 def site():
421 """
422@@ -410,7 +135,7 @@
423 args = [id]))
424 else:
425 raise HTTP(404)
426-
427+
428 # -----------------------------------------------------------------------------
429 def message():
430 #if "verify_email_sent" in request.args:
431@@ -447,12 +172,13 @@
432 _table_user = auth.settings.table_user
433 if request.args and request.args(0) == "profile":
434 #_table_user.organisation.writable = False
435- _table_user.utc_offset.readable = True
436- _table_user.utc_offset.writable = True
437+ #_table_user.utc_offset.readable = True
438+ #_table_user.utc_offset.writable = True
439+ pass
440
441 login_form = register_form = None
442 if request.args and request.args(0) == "login":
443- auth.messages.submit_button = T("Login")
444+ auth.messages.submit_button = T("Sign In")
445 form = auth()
446 login_form = form
447 if s3.crud.submit_style:
448@@ -577,10 +303,25 @@
449 xlwt_version=xlwt_version
450 )
451
452+# =============================================================================
453+# LA Custom Views
454+# =============================================================================
455+def why():
456+ """ Custom View """
457+ response.title = T("Why?")
458+ return dict()
459+
460+# -----------------------------------------------------------------------------
461+def contact():
462+ """ Custom View """
463+ response.title = T("Contact us")
464+ return dict()
465+
466 # -----------------------------------------------------------------------------
467 def help():
468 """ Custom View """
469 response.title = T("Help")
470+<<<<<<< TREE
471 return dict()
472
473 # -----------------------------------------------------------------------------
474@@ -623,5 +364,641 @@
475 response.title = T("Contact us")
476 return dict()
477
478+=======
479+ entries = []
480+ question = T("How do I register as a volunteer?")
481+ reply = T("Follow these steps, to register:")
482+ list = []
483+ 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"),
484+ apply = "<strong>%s</strong>" % T("'APPLY'")))
485+ 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'")))
486+ entry = (question, reply, list)
487+ entries.append(entry)
488+ question = T("How do I update my Profile, Skills and Emergency Details?")
489+ reply = T("After you are signed-in, please follow these steps to edit your profile: ")
490+ list = []
491+ list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>" % T("VOLUNTEER")))
492+ list.append(T("On the left menu, click %(profile)s .") % dict(profile="<strong>%s</strong>" % T("'My Profile'")))
493+ list.append(T("On this page, you can update your profile."))
494+ 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")))
495+ list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>" % T("Save")))
496+ list.append(T("On the left menu, click %(skills)s.") % dict(skills="<strong>%s</strong>" % T("Skills")))
497+ list.append(T("Click the %s sign next to the skill(s) that best describes how you can support the City.") % "<strong>'+'</strong>")
498+ 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)."))
499+ 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")))
500+ list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
501+ list.append(T("You may also update your Emergency Contacts information by clicking on 'Emergency Contacts' located on the left menu."))
502+ list.append(T("Then click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
503+ entry = (question, reply, list)
504+ entries.append(entry)
505+ question = T("How do I apply for a Volunteer Request after I have registered with Give2LA?")
506+ 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'"))
507+ list = []
508+ list.append(T("Enter your E-Mail and Password information."))
509+ list.append(T("Review the 'List of Requests for Volunteers'."))
510+ list.append(T("To select a Volunteer Task, click on %(apply)s.") % dict(apply="<strong>%s</strong>") % T("'APPLY'"))
511+ list.append(T("Review the 'Volunteer Assignment Details'. Enter your Emergency Contact information."))
512+ list.append(T("Download the Give2LA Volunteer Registration Forms, complete the forms, and take them with you to your Volunteer Assignment."))
513+ list.append(T("Then click %(commit)s.") % dict(commit="<strong>%s</strong>") % T("Commit"))
514+ list.append(T("Review the Volunteer Application details."))
515+ 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'")))
516+ entry = (question, reply, list)
517+ entries.append(entry)
518+ question = T("Can I provide feedback or evaluation for an assignment after volunteering?")
519+ reply = T("Yes. After you have signed-in, follow these steps:")
520+ list = []
521+ list.append(T("On the top menu, click %(volunteer)s.") % dict(volunteer="<strong>%s</strong>") % T("VOLUNTEER"))
522+ list.append(T("On the left menu, click %(assignments)s.") % dict(assignments="<strong>%s</strong>") % T("'My Assignments'"))
523+ list.append(T("Click on the 'Details' button of the Volunteer Task you have completed."))
524+ list.append(T("Scroll down to the bottom of the screen to get to 'Evaluation of Event'."))
525+ list.append(T("Enter the evaluation details; and click %(save)s") % dict(save="<strong>%s</strong>") % T("Save"))
526+ entry = (question, reply, list)
527+ entries.append(entry)
528+ question = T("I would like to register my corporation for donations, what is the process?")
529+ reply = T("Follow these steps, to register")
530+ list = []
531+ 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'")))
532+ 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'")))
533+ entry = (question, reply, list)
534+ entries.append(entry)
535+
536+ return dict(entries=entries)
537+
538+# -----------------------------------------------------------------------------
539+def faq():
540+ """ Custom View """
541+ donateLink = A(T("Donate Page"), _href=URL(c="don", f="index"))
542+
543+ response.title = T("Frequently Asked Questions")
544+ entries = []
545+ question = T("Is there a minimum age limit to volunteer?")
546+ reply = T("Yes, you have to be at least 18 years of age to Volunteer.")
547+ entry = (question, reply)
548+ entries.append(entry)
549+ question = T("What is the Privacy policy of Give2LA?")
550+ reply = T("Please refer to the %(privacy)s") % dict(privacy=A(T("Privacy Policy"),
551+ _href=URL(c="default", f="disclaimer")))
552+ entry = (question, reply)
553+ entries.append(entry)
554+ question = T("Can I bring a friend to volunteer?")
555+ reply = T("Yes, but your friend must also %(register)s and apply to the same Volunteer Assignment.") % dict(register=A(T("Register"),
556+ _href=URL(c="vol", f="register")))
557+ entry = (question, reply)
558+ entries.append(entry)
559+ question = T("Will I get any food or reimbursements for expenses while volunteering?")
560+ reply = T("No, unless it is otherwise stated on the Volunteer Assignment.")
561+ entry = (question, reply)
562+ entries.append(entry)
563+ question = T("Can I donate cash to support the City of Los Angeles?")
564+ 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)
565+ entry = (question, reply)
566+ entries.append(entry)
567+ question = T("What is the process for donating in-kind Items?")
568+ 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)
569+ entry = (question, reply)
570+ entries.append(entry)
571+ question = T("Do I have to be a U.S. citizen or legal U.S. resident to volunteer?")
572+ reply = T("Yes. You must be a U.S. citizen, legal U.S. resident, or have gained legal entry into the United States.")
573+ entry = (question, reply)
574+ entries.append(entry)
575+ question = T("Do I have to live in the City of Los Angeles to volunteer?")
576+ reply = T("No, anyone may register to support the City of Los Angeles' volunteer efforts.")
577+ entry = (question, reply)
578+ entries.append(entry)
579+ question = T("Is my donation tax deductible?")
580+ 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.")
581+ entry = (question, reply)
582+ entries.append(entry)
583+
584+ return dict(entries=entries)
585+
586+# -----------------------------------------------------------------------------
587+def sitemap():
588+ """ Custom View """
589+ response.title = T("Site Map")
590+ return dict()
591+
592+# -----------------------------------------------------------------------------
593+def disclaimer():
594+ """ Custom View """
595+ response.title = T("Disclaimer")
596+ return dict()
597+
598+# -----------------------------------------------------------------------------
599+def register():
600+ """
601+ Registration for Organisations
602+ - custom form
603+ """
604+
605+ # Which type of organisation are we registering?
606+ don = False
607+ vol = False
608+ if "type" in request.vars:
609+ if request.vars.type == "don":
610+ don = True
611+ elif request.vars.type == "vol":
612+ vol = True
613+ auth.settings.registration_requires_approval = True
614+
615+ auth.messages.submit_button = T("I accept. Create my account.")
616+ request.args = ["register"]
617+ _table_user.language.default = T.accepted_language
618+ _table_user.language.readable = False
619+ _table_user.language.writable = False
620+ form = auth()
621+ form.attributes["_id"] = "regform"
622+ # Custom class for Submit Button
623+ form[0][-1][0][0]["_class"] = "accept-button"
624+
625+ # Cancel button
626+ form[0][-1][0].append(BR())
627+ #form[0][-1][1].append(INPUT(_type="reset", _value=T("Cancel")))
628+ form[0][-1][0].append(INPUT(_type="button",
629+ _value=T("Cancel"),
630+ _class="wide-grey-button",
631+ _onClick="javascript: history.go(-1)"))
632+
633+ formstyle = s3.crud.formstyle
634+
635+ # Organisation
636+ if form.errors.organisation:
637+ organisation_error = DIV(form.errors.organisation,
638+ _id="organisation__error",
639+ _class="error",
640+ _style="display: block;")
641+ else:
642+ organisation_error = ""
643+ if don:
644+ label = T("Corporation/Organization Name")
645+ else:
646+ label = T("Organization Name")
647+ row = formstyle(id = "organisation",
648+ label = LABEL("%s:" % label,
649+ SPAN(" *", _class="req")),
650+ widget = DIV(INPUT(_name="organisation",
651+ _id="organisation",
652+ _class="string"),
653+ organisation_error),
654+ comment = "")
655+ form[0].insert(0, row)
656+
657+ # Industry Sector
658+ if vol:
659+ hidden = True
660+ widget = INPUT(_name="sector_id",
661+ _id="sector_id",
662+ _class="string")
663+ else:
664+ from gluon.sqlhtml import OptionsWidget
665+ hidden = False
666+ widget = OptionsWidget.widget(db.org_organisation.sector_id,
667+ value="")
668+ # dropdown
669+ row = formstyle(id = "sector_id",
670+ label = LABEL("%s:" % T("Industry Sector")),
671+ widget = widget,
672+ comment = "",
673+ hidden = hidden)
674+ form[0].insert(1, row)
675+ # freetext box for not listed
676+ row = formstyle(id = "sector_other",
677+ label = LABEL("%s:" % T("Other Sector not listed")),
678+ widget = INPUT(_name="sector_other",
679+ _id="sector_other",
680+ _class="string"),
681+ comment = "",
682+ hidden = hidden)
683+ form[0].insert(2, row)
684+
685+
686+ # Primary Contact Person section
687+ row = TR(TD(LABEL(T("Primary Contact")),
688+ _colspan="3",
689+ _class="subheading"))
690+ form[0][2].append(row)
691+ row = formstyle(id = "middle_name",
692+ label = LABEL("%s:" % T("Middle Name")),
693+ widget = INPUT(_name="middle_name",
694+ _id="middle_name",
695+ _class="string"),
696+ comment = "")
697+ form[0][4].append(row)
698+
699+ row = formstyle(id = "secondary_email",
700+ label = LABEL("%s:" % T("Secondary Email")),
701+ widget = INPUT(_name="secondary_email",
702+ _id="secondary_email",
703+ _class="string"),
704+ comment = "")
705+ form[0][12].append(row)
706+
707+ # What are you offering?
708+ if don or vol:
709+ hidden = True
710+ else:
711+ hidden = False
712+ row = formstyle(id = "offer",
713+ hidden = hidden,
714+ label = LABEL("%s:" % T("We can offer"),
715+ SPAN(" *", _class="req")),
716+ widget = (T("Items"),
717+ INPUT(_type="checkbox",
718+ _value="on",
719+ value="on" if don else "",
720+ _name="has_items",
721+ _id="has_items",
722+ _class="boolean"),
723+ T("Volunteers"),
724+ INPUT(_type="checkbox",
725+ _value="on",
726+ value="on" if vol else "",
727+ _name="vols",
728+ _id="vols",
729+ _class="boolean"),
730+ ),
731+ comment = "")
732+ form[0][12].append(row)
733+
734+ # Phone
735+ mobile_phone_widget = INPUT(_name="mobile_phone",
736+ _id="",
737+ _class="string")
738+ if form.errors.mobile_phone:
739+ mobile_phone_error = DIV(form.errors.mobile_phone,
740+ _id="mobile_phone__error",
741+ _class="error",
742+ _style="display: block;")
743+ # Can't wrap widget in a DIV for client-side validation, so only do so
744+ # when server-side validation happens
745+ mobile_phone_widget = DIV(mobile_phone_widget,
746+ mobile_phone_error)
747+
748+ if form.errors.work_phone:
749+ work_phone_error = DIV(form.errors.work_phone,
750+ _id="work_phone__error",
751+ _class="error",
752+ _style="display: block;")
753+ else:
754+ work_phone_error = ""
755+ row = formstyle(id = "phone",
756+ label = LABEL("%s:" % T("Work Phone")),
757+ widget = DIV(INPUT(_name="work_phone",
758+ _id="",
759+ _class="string"),
760+ work_phone_error),
761+ comment = "")
762+ form[0][12].append(row)
763+ row = formstyle(id = "phone",
764+ label = LABEL("%s:" % current.deployment_settings.get_ui_label_mobile_phone(),
765+ SPAN(" *", _class="req")),
766+ widget = mobile_phone_widget,
767+ comment = "")
768+ form[0][12].append(row)
769+
770+ # Address
771+ row = TR(TD(LABEL(T("Corporation/Organization Address")),
772+ _colspan="3",
773+ _class="subheading"))
774+ form[0][12].append(row)
775+ if form.errors.address1:
776+ address1_error = DIV(form.errors.address1,
777+ _id="address1__error",
778+ _class="error",
779+ _style="display: block;")
780+ else:
781+ address1_error = ""
782+ row = formstyle(id = "address1",
783+ label = LABEL("%s:" % T("Address 1"),
784+ SPAN(" *", _class="req")
785+ ),
786+ widget = (INPUT(_name="address1",
787+ _id="address1",
788+ _class="string"),
789+ address1_error),
790+ comment = "")
791+ form[0][12].append(row)
792+ row = formstyle(id = "address2",
793+ label = LABEL("%s:" % T("Address 2")),
794+ widget = INPUT(_name="address2",
795+ _id="address2",
796+ _class="string"),
797+ comment = "")
798+ form[0][12].append(row)
799+ row = formstyle(id = "city",
800+ label = LABEL("%s:" % T("City"),
801+ SPAN(" *", _class="req")),
802+ widget = INPUT(_name="city",
803+ _id = "city",
804+ _class = "string"),
805+ comment = "")
806+ form[0][12].append(row)
807+ states = S3LocationDropdownWidget(level="L1",
808+ default="California",
809+ empty=False)
810+ widget = states(db.pr_address.location_id, None)
811+ row = formstyle(id = "state",
812+ label = LABEL("%s:" % T("State"),
813+ SPAN(" *", _class="req")),
814+ widget = widget,
815+ comment = "")
816+ form[0][12].append(row)
817+ if form.errors.zip:
818+ zip_error = DIV(form.errors.zip,
819+ _id="zip__error",
820+ _class="error",
821+ _style="display: block;")
822+ else:
823+ zip_error = ""
824+ row = formstyle(id = "zip",
825+ label = LABEL("%s:" % T("Zip"),
826+ SPAN(" *", _class="req")
827+ ),
828+ widget = ( INPUT(_name="zip",
829+ _id="zip",
830+ _class="string"),
831+ zip_error
832+ ),
833+ comment = "")
834+ form[0][12].append(row)
835+
836+
837+ #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"),
838+ # _id="terms_of_service__label"),
839+ # _class="w2p_fl"),
840+ # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(),
841+ # _onfocus="this.rows=10",
842+ # _readonly="readonly",
843+ # _style="width:100%;text-align:",
844+ # _cols="80", _rows="10"),
845+ # _id="terms_of_service"),
846+ # _class="w2p_fw",
847+ # _colspan="2"),
848+ # _id="terms_of_service__row"))
849+
850+ # Add client-side validation
851+ # simplified copy of s3_register_validation()
852+ script = "".join(( """
853+var required = '""", str(T("This field is required.")), """';
854+$('#regform').validate({
855+ errorClass: 'req',
856+ rules: {
857+ first_name: {
858+ required: true
859+ },
860+ last_name: {
861+ required: true
862+ },
863+ email: {
864+ required: true,
865+ email: true
866+ },
867+ organisation: {
868+ required: true
869+ },
870+ mobile_phone: {
871+ required: true
872+ },
873+ address1: {
874+ required: true
875+ },
876+ city: {
877+ required: true
878+ },
879+ zip: {
880+ required: true
881+ },
882+ password: {
883+ required: true
884+ },
885+ password_two: {
886+ required: true,
887+ equalTo: '.password:first'
888+ }
889+ },
890+ messages: {
891+ first_name: '""", str(T("Enter your firstname")), """',
892+ last_name: required,
893+ email: {
894+ required: '""", str(T("Please enter a valid email address")), """',
895+ minlength: '""", str(T("Please enter a valid email address")), """'
896+ },
897+ mobile_phone: required,
898+ address1: required,
899+ city: required,
900+ zip: required,
901+ password: {
902+ required: '""", str(T("Provide a password")), """'
903+ },
904+ password_two: {
905+ required: '""", str(T("Repeat your password")), """',
906+ equalTo: '""", str(T("Enter the same password as above")), """'
907+ }
908+ },
909+ errorPlacement: function(error, element) {
910+ error.appendTo( element.parent().next() );
911+ },
912+ submitHandler: function(form) {
913+ form.submit();
914+ }
915+});""" ))
916+ response.s3.jquery_ready.append( script )
917+
918+ if session.s3.debug:
919+ response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
920+ response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir )
921+ else:
922+ response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
923+ response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir )
924+
925+ response.s3.jquery_ready.append("$('.password:first').pstrength();\n")
926+ response.s3.js_global.append("".join((
927+ "S3.i18n.password_chars = '%s';\n" % T("The minimum number of characters is "),
928+ "S3.i18n.very_weak = '%s';\n" % T("Very Weak"),
929+ "S3.i18n.weak = '%s';\n" % T("Weak"),
930+ "S3.i18n.medium = '%s';\n" % T("Medium"),
931+ "S3.i18n.strong = '%s';\n" % T("Strong"),
932+ "S3.i18n.very_strong = '%s';\n" % T("Very Strong"),
933+ "S3.i18n.too_short = '%s';\n" % T("Too Short"),
934+ "S3.i18n.unsafe_password = '%s';\n" % T("Unsafe Password Word!"),
935+ )))
936+
937+ response.title = T("Register")
938+ response.s3.has_required = True
939+
940+ return dict(form=form)
941+
942+# -----------------------------------------------------------------------------
943+def register_validation(form):
944+ """ Validate the custom fields in registration form """
945+ # Name
946+ if "organisation" in request.post_vars and request.post_vars.organisation:
947+ # Check not in use
948+ table = db.org_organisation
949+ query = (table.name == request.post_vars.organisation)
950+ name = db(query).select(table.id, limitby=(0, 1)).first()
951+ if name:
952+ form.errors.organisation = T("Organisation Name is already in use")
953+ else:
954+ form.errors.organisation = T("Organisation Name is required")
955+ # Phone
956+ if "work_phone" in request.post_vars and request.post_vars.work_phone:
957+ regex = re.compile(single_phone_number_pattern)
958+ if not regex.match(request.post_vars.work_phone):
959+ form.errors.work_phone = T("Invalid phone number")
960+ if "mobile_phone" in request.post_vars and request.post_vars.mobile_phone:
961+ regex = re.compile(single_phone_number_pattern)
962+ if not regex.match(request.post_vars.mobile_phone):
963+ form.errors.mobile_phone = T("Invalid phone number")
964+ else:
965+ form.errors.mobile_phone = T("Phone number is required")
966+ # Address
967+ if not request.post_vars.address1:
968+ form.errors.address1 = T("Address is required")
969+ if not request.post_vars.city:
970+ form.errors.city = T("City is required")
971+ if not request.post_vars.zip:
972+ form.errors.zip = T("Zip is required")
973+
974+ return
975+
976+# -----------------------------------------------------------------------------
977+def register_onaccept(form):
978+ # Usual Registration Tasks
979+ # (PR record, Authenticated Role, Contacts)
980+ person = auth.s3_register(form)
981+
982+ # LA-specific
983+ ptable = db.pr_person
984+ query = (ptable.id == person)
985+
986+ db(query).update(middle_name=request.post_vars.middle_name)
987+
988+ pe = db(query).select(ptable.pe_id,
989+ limitby=(0, 1)).first().pe_id
990+
991+ # Organisation
992+ organisation = request.post_vars.organisation
993+ if "vols" in request.post_vars and request.post_vars.vols == "on":
994+ has_vols = True
995+ else:
996+ has_vols = False
997+ if "has_items" in request.post_vars and request.post_vars.has_items == "on":
998+ has_items = True
999+ else:
1000+ has_items = False
1001+
1002+ # Phone
1003+ table = db.pr_contact
1004+ work_phone = request.post_vars.work_phone
1005+ mobile_phone = request.post_vars.mobile_phone
1006+ if mobile_phone:
1007+ # Don't auto-subscribe to SMS (priority 10)
1008+ table.insert(pe_id = pe,
1009+ contact_method = "SMS",
1010+ value = mobile_phone,
1011+ priority=10)
1012+ if work_phone:
1013+ table.insert(pe_id = pe,
1014+ contact_method = "WORK_PHONE",
1015+ value = work_phone)
1016+
1017+ # Address
1018+ address1 = request.post_vars.address1
1019+ address2 = request.post_vars.address2
1020+ #if address2:
1021+ # address = "%s\n%s" % (address1,
1022+ # address2)
1023+ #else:
1024+ # address = address1
1025+ city = request.post_vars.city
1026+ state = request.post_vars.location_id
1027+ zip = request.post_vars.zip
1028+ if request.post_vars.sector_other:
1029+ sector_other = "Sector: %s" % request.post_vars.sector_other
1030+ else:
1031+ sector_other = ""
1032+ otable = db.org_organisation
1033+ org = otable.insert(name = organisation,
1034+ has_vols = has_vols,
1035+ has_items = has_items,
1036+ #phone=phone,
1037+ address=address1,
1038+ address_2=address2,
1039+ L3=city,
1040+ L1=state,
1041+ postcode=zip,
1042+ sector_id=request.post_vars.sector_id,
1043+ comments=sector_other)
1044+ record = Storage(id=org)
1045+ s3mgr.model.update_super(otable, record)
1046+ auth.s3_set_record_owner(otable, org)
1047+ # For OrgDons which don't require approval
1048+ if auth.user:
1049+ # Update the session
1050+ auth.user.organisation_id = org
1051+ user_id = auth.user.id
1052+ else:
1053+ user_id = form.vars.id
1054+
1055+ # Create HRM
1056+ table = db.hrm_human_resource
1057+ hrm = table.insert(person_id = person,
1058+ organisation_id = org,
1059+ focal_point = True,
1060+ owned_by_user = user_id)
1061+ record = Storage(id=hrm)
1062+ s3mgr.model.update_super(table, record)
1063+ auth.s3_set_record_owner(table, hrm)
1064+
1065+ # Set the Roles
1066+ person = db(query).select(ptable.uuid,
1067+ limitby=(0, 1)).first()
1068+ if not person:
1069+ # Error
1070+ return
1071+ utable = db[auth.settings.table_user]
1072+ query = (utable.person_uuid == person.uuid)
1073+ db(query).update(organisation_id = org)
1074+ user = db(query).select(utable.id,
1075+ limitby=(0, 1)).first()
1076+ if not user:
1077+ # Error
1078+ return
1079+ mtable = db[auth.settings.table_membership]
1080+ gtable = db[auth.settings.table_group]
1081+ _org = db(otable.id == org).select(otable.owned_by_organisation,
1082+ limitby=(0, 1)).first()
1083+ if _org:
1084+ mtable.insert(user_id = user.id,
1085+ group_id = _org.owned_by_organisation)
1086+
1087+ if has_vols:
1088+ OrgVol = db(gtable.uuid == ORG_VOL).select(gtable.id,
1089+ limitby=(0, 1)).first()
1090+ if OrgVol:
1091+ mtable.insert(user_id = user.id,
1092+ group_id = OrgVol.id)
1093+ # Go to the Contacts page so that a secondary contact can be added
1094+ # Flag that we've come from registration for subsequent workflow
1095+ #redirect(URL(c="vol", f="organisation", args=[org, "human_resource"],
1096+ # vars={"register":1}))
1097+
1098+ if has_items:
1099+ OrgDon = db(gtable.uuid == ORG_DON).select(gtable.id,
1100+ limitby=(0, 1)).first()
1101+ if OrgDon:
1102+ mtable.insert(user_id = user.id,
1103+ group_id = OrgDon.id)
1104+ # Go to the Contacts page so that a secondary contact can be added
1105+ # Flag that we've come from registration for subsequent workflow
1106+ redirect(URL(c="don", f="organisation", args=[org, "human_resource"],
1107+ vars={"register":1}))
1108+
1109+# -----------------------------------------------------------------------------
1110+#auth.settings.registration_requires_approval = True
1111+auth.settings.register_onvalidation = register_validation
1112+auth.settings.register_onaccept = register_onaccept
1113+>>>>>>> MERGE-SOURCE
1114
1115 # END =========================================================================
1116
1117=== added file 'controllers/don.py'
1118--- controllers/don.py 1970-01-01 00:00:00 +0000
1119+++ controllers/don.py 2011-11-18 07:40:33 +0000
1120@@ -0,0 +1,1041 @@
1121+# -*- coding: utf-8 -*-
1122+
1123+"""
1124+ Donations (LA Specific)
1125+
1126+ @author: Michael Howden (michael@sahanafoundation.org)
1127+ @date-created: 2011-08-02
1128+"""
1129+
1130+
1131+module = request.controller
1132+resourcename = request.function
1133+
1134+if not deployment_settings.has_module(module):
1135+ raise HTTP(404, body="Module disabled: %s" % module)
1136+
1137+# Options Menu (available in all Functions)
1138+shn_menu(module)
1139+
1140+# Load Models
1141+s3mgr.load("don_collect")
1142+# -----------------------------------------------------------------------------
1143+def index():
1144+ """ Custom View """
1145+ if s3_has_role(STAFF) or s3_has_role(BOC):
1146+ redirect(URL(f="req"))
1147+ else:
1148+ response.menu_options = []
1149+ if session.s3.debug:
1150+ response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir )
1151+ else:
1152+ response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir )
1153+
1154+ response.title = T("Donate")
1155+ response.s3.jquery_ready.append("""
1156+ $(".donate-popup").css("display", "none");
1157+ $(".organizations-list li a").hoverIntent(donateFadeIn, donateFadeOut);
1158+ """)
1159+ response.s3.js_global.append("""
1160+ function donateFadeIn(){$(this).next(".donate-popup").fadeIn();}
1161+ function donateFadeOut(){$(this).next(".donate-popup").fadeOut();}
1162+ """)
1163+
1164+ # Get Donation Drives List
1165+ table = db.don_collect
1166+ query = ( ( table.end_datetime > request.utcnow ) &
1167+ ( table.deleted == False )
1168+ )
1169+ rows = db(query).select( table.start_datetime,
1170+ table.end_datetime,
1171+ table.site_id,
1172+ orderby = table.start_datetime
1173+ )
1174+ if rows:
1175+ list = []
1176+ offset = IS_UTC_OFFSET.get_offset_value(session.s3.utc_offset)
1177+ for row in rows:
1178+ if offset:
1179+ start_datetime = row.start_datetime + datetime.timedelta(seconds=offset)
1180+ end_datetime = row.end_datetime + datetime.timedelta(seconds=offset)
1181+
1182+ start_date = start_datetime.strftime("%b %d")
1183+ start_time = start_datetime.strftime("%I:%M %p")
1184+ end_date = end_datetime.strftime("%b %d")
1185+ end_time = end_datetime.strftime("%I:%M %p")
1186+
1187+ site = shn_site_represent(row.site_id, address = True)
1188+
1189+ if start_date == end_date:
1190+ list.append( LI( SPAN( start_date, _class = "date"),
1191+ " %s - %s" % (start_time, end_time),
1192+ site,
1193+ BR()
1194+ )
1195+ )
1196+ else:
1197+ list.append( LI( SPAN( start_date, _class = "date" ),
1198+ " %s - " % start_time,
1199+ SPAN( end_date, _class = "date" ),
1200+ " %s" % end_time,
1201+ site,
1202+ BR()
1203+ )
1204+ )
1205+ donation_drives = TAG[""](*list)
1206+ else:
1207+ donation_drives = P(T("No Donation Drives Scheduled. Please check back later"))
1208+
1209+ return dict(donation_drives = donation_drives)
1210+
1211+# -----------------------------------------------------------------------------
1212+def don_organisation_represent(id):
1213+ if isinstance(id, Row):
1214+ # Do not repeat the lookup if already done by IS_ONE_OF or RHeader
1215+ org = id
1216+ else:
1217+ table = db.org_organisation
1218+ query = (table.id == id)
1219+ org = db(query).select(table.name,
1220+ limitby = (0, 1)).first()
1221+ if org:
1222+ return A(org.name,
1223+ _href = URL(c="don", f="organisation", args = [id]))
1224+ else:
1225+ return NONE
1226+
1227+# -----------------------------------------------------------------------------
1228+def match():
1229+ # Get Req Resource Details
1230+ tablename, req_id = request.vars.viewing.split(".")
1231+
1232+ # create fake resource for rheader
1233+ s3mgr.load("req_req")
1234+ req = db(db.req_req.id == req_id).select(limitby = (0, 1)).first()
1235+ r = Storage()
1236+ r.record = req
1237+ r.representation = "html"
1238+ r.name = "don"
1239+ r.function = "match"
1240+ r.vars = request.vars
1241+ rheader = req_rheader(r)
1242+
1243+ # Get Item Filter
1244+ req_item = db(db.req_req_item.req_id == req_id).select(db.req_req_item.item_id,
1245+ limitby = [0,1]
1246+ ).first()
1247+ if req_item:
1248+ item_id = req_item.item_id
1249+ else:
1250+ item_id = None
1251+ response.s3.filter = (db.don_don_item.item_id == item_id)
1252+
1253+ # Configure don_don_item list
1254+ db.don_don_item.organisation_id.represent = don_organisation_represent
1255+ s3mgr.configure("don_don_item",
1256+ insertable = False,
1257+ list_fields = ["id",
1258+ "organisation_id",
1259+ "item_id",
1260+ "quantity",
1261+ "type",
1262+ "comments"]
1263+ )
1264+ response.s3.actions = [dict(url = URL(c="don", f="req",
1265+ args = [req_id, "commit"],
1266+ vars = dict(don_item_id = "[id]")
1267+ ),
1268+ _class = "action-btn",
1269+ label = str(T("Select")),
1270+ )
1271+ ]
1272+
1273+ output = don_item()
1274+
1275+ # Customize form
1276+ output["rheader"] = rheader
1277+ output["title"] = T("Request for Donations Details")
1278+ output["subtitle"] = T("Matching Resources in Virtual Donation Inventory")
1279+
1280+ return output
1281+# -----------------------------------------------------------------------------
1282+def req_summary(r):
1283+ rtable = db.req_req
1284+ itable = db.req_req_item
1285+ ctable = db.req_commit
1286+ req = r.record
1287+ item = req.req_req_item.select().first() or Storage()
1288+ commit = req.req_commit.select().first() or Storage()
1289+
1290+ item_str = response.s3.concat_item_pack_quantity( item.item,
1291+ item.item_pack,
1292+ item.quantity)
1293+
1294+ summary = TABLE( TR( TH( rtable.status.label ),
1295+ rtable.status.represent(req.status),
1296+ TH( ctable.status.label ),
1297+ ctable.status.represent(commit.status),
1298+ ),
1299+ #TR( TH( rtable.event_id.label ),
1300+ # rtable.event_id.represent(req.event_id),
1301+ # TH( rtable.incident_id.label ),
1302+ # rtable.incident_id.represent(req.incident_id),
1303+ # ),
1304+ TR( TH( rtable.request_number.label ),
1305+ req.request_number,
1306+ TH( rtable.priority.label ),
1307+ rtable.priority.represent( req.priority ),
1308+ ),
1309+ TR( TH( rtable.date_required.label ),
1310+ req.date_required,
1311+ TH( rtable.site_id.label ),
1312+ rtable.site_id.represent( req.site_id ),
1313+ ),
1314+ TR( TH( itable.item.label ),
1315+ item_str,
1316+ TH( itable.item_id.label ),
1317+ itable.item_id.represent( item.item_id ),
1318+ ),
1319+ TR( #TH( rtable.purpose.label ),
1320+ #req.purpose,
1321+ TH( itable.specs.label ),
1322+ item.specs,
1323+ ),
1324+ )
1325+ return summary
1326+# -----------------------------------------------------------------------------
1327+def req_form(r):
1328+ form_btns = DIV( BUTTON(T("Request for Donation Form"),
1329+ _class = "accept-button",
1330+ _onClick = "javascript: window.location='%s'" % \
1331+ URL(c = request.controller,
1332+ f = "req_print",
1333+ args = r.id
1334+ )
1335+ ),
1336+ # Also in controllers/vol.py - DRY
1337+ A( IMG( _src = "/%s/static/img/get_adobe_reader.png" % request.application,
1338+ _title = "%s - %s" % (T("Get Adobe Reader"),
1339+ T("This link will open a new browser window.")),
1340+ _alt = T("Get Adobe Reader"),
1341+ _width = 158,
1342+ _height = 39,
1343+ _style = "float:right;"),
1344+ _href="http://www.adobe.com/products/acrobat/readstep2.html",
1345+ _target="_blank"),
1346+ )
1347+
1348+ ftable = db.req_fulfill
1349+ query = (ftable.req_id == r.id)
1350+ frecord = db(query).select(limitby=(0, 1)).first()
1351+ if frecord and frecord.datetime_fulfill != None:
1352+ form_btns.append( BUTTON (T("Donation Certificate"),
1353+ _class = "accept-button",
1354+ _onClick = "javascript: window.location='%s'" % \
1355+ URL(c = request.controller,
1356+ f = "req_print",
1357+ args = [r.id, True]
1358+ )
1359+ ))
1360+ return form_btns
1361+# -----------------------------------------------------------------------------
1362+def req_rheader(r):
1363+ """
1364+ Resource Header for Requests for Donations
1365+ - Staff View
1366+ """
1367+ record = r.record
1368+ if r.representation == "html" and record:
1369+ tabs = [(T("Details"), None)]
1370+ req_item_tab_label = T("Resource")
1371+ tabs.append((req_item_tab_label, "req_item"))
1372+ tabs.append((T("Find Match"), "match/"))
1373+ if deployment_settings.get_req_use_commit():
1374+ tabs.append((T("Donation"), "commit"))
1375+ tabs.append(( T("Received"), "fulfill"))
1376+ tabs.append(( T("Surplus"), "surplus_item"))
1377+ if deployment_settings.has_module("doc"):
1378+ tabs.append((T("Documents"), "document"))
1379+
1380+ rheader_tabs = s3_rheader_tabs(r, tabs)
1381+
1382+ site_id = request.vars.site_id
1383+ if site_id:
1384+ site_name = shn_site_represent(site_id, show_link = False)
1385+ commit_btn = TAG[""](
1386+ A( T("Commit from %s") % site_name,
1387+ _href = URL(c = "req",
1388+ f = "commit_req",
1389+ args = [r.id],
1390+ vars = dict(site_id = site_id)
1391+ ),
1392+ _class = "action-btn"
1393+ ),
1394+ A( T("Send from %s") % site_name,
1395+ _href = URL(c = "req",
1396+ f = "send_req",
1397+ args = [r.id],
1398+ vars = dict(site_id = site_id)
1399+ ),
1400+ _class = "action-btn"
1401+ )
1402+ )
1403+ #else:
1404+ # commit_btn = A( T("Commit"),
1405+ # _href = URL(c = "req",
1406+ # f = "commit",
1407+ # args = ["create"],
1408+ # vars = dict(req_id = r.id)
1409+ # ),
1410+ # _class = "action-btn"
1411+ # )
1412+ response.s3.rfooter = commit_btn
1413+
1414+ rheader = DIV( req_summary(r),
1415+ req_form(r)
1416+ )
1417+
1418+ rheader.append(rheader_tabs)
1419+
1420+ return rheader
1421+ #else:
1422+ # No Record means that we are either a Create or List Create
1423+ # Inject the helptext script
1424+ # Removed because causes an error if validation fails twice
1425+ # return response.s3.req_helptext_script
1426+ return None
1427+# -----------------------------------------------------------------------------
1428+def req():
1429+ """
1430+ /don/req
1431+ """
1432+ s3mgr.load("req_req")
1433+ req_table = db.req_req
1434+
1435+ req_type = 1
1436+ req_table.type.default = req_type
1437+ query = (db.req_req.type == req_type)
1438+ if response.s3.filter:
1439+ response.s3.filter = response.s3.filter & query
1440+ else:
1441+ response.s3.filter = query
1442+ # -------------------------------------------------------------------------------------------
1443+ s3mgr.configure("req_req",
1444+ list_fields = ["id",
1445+ #"priority",
1446+ "status",
1447+ (T("BOC Status"), "req_commit_status"),
1448+ "created_on",
1449+ "date_required",
1450+ (T("Resource"), "item"),
1451+ "site_id",
1452+ ],
1453+ orderby = ["created_on"])
1454+
1455+ s3mgr.load("req_req")
1456+
1457+ # -------------------------------------------------------------------------------------------
1458+ ADD_ITEM_REQUEST = T("Make a Request for Donations")
1459+ LIST_ITEM_REQUEST = T("List Requests for Donations")
1460+ s3.crud_strings["req_req"] = Storage(
1461+ title_create = ADD_ITEM_REQUEST,
1462+ title_display = T("Request for Donations Details"),
1463+ title_list = LIST_ITEM_REQUEST,
1464+ title_update = T("Edit Request for Donations"),
1465+ title_search = T("Search Requests for Donations"),
1466+ subtitle_create = ADD_ITEM_REQUEST,
1467+ subtitle_list = T("Requests for Donations"),
1468+ label_list_button = LIST_ITEM_REQUEST,
1469+ label_create_button = ADD_ITEM_REQUEST,
1470+ label_delete_button = T("Delete Request for Donations"),
1471+ msg_record_created = T("Request for Donations Added"),
1472+ msg_record_modified = T("Request for Donations Updated"),
1473+ msg_record_deleted = T("Request for Donations Canceled"),
1474+ msg_list_empty = T("No Requests for Donations")
1475+ )
1476+
1477+ # Request for Donation labels
1478+ req_table.purpose.label = T("What the Resources will be used for")
1479+ req_table.site_id.label =T("Deliver To Facility")
1480+ req_table.request_for_id.label = T("Deliver To Person")
1481+ req_table.created_on.label = T("Pushed to BOC")
1482+
1483+ if "document" in request.args:
1484+ s3mgr.load("doc_document")
1485+
1486+ def prep(r):
1487+ # Remove type from list_fields
1488+ list_fields = s3mgr.model.get_config("req_req",
1489+ "list_fields")
1490+ try:
1491+ list_fields.remove("type")
1492+ except:
1493+ # It has already been removed.
1494+ # This can happen if the req controller is called
1495+ # for a second time, such as when printing reports
1496+ # see vol.print_assignment()
1497+ pass
1498+ s3mgr.configure(tablename, list_fields=list_fields)
1499+
1500+
1501+ if r.interactive:
1502+ # Set Fields and Labels
1503+ req_table.type.readable = False
1504+ req_table.type.writable = False
1505+
1506+
1507+ if r.method != "create" and False: # @ToDo: Remove "and False" - this has been added for training to allow records to be edit
1508+ # Disable Edit for fields where WebEOC is Master
1509+ req_table.event_id.writable = False
1510+ req_table.incident_id.writable = False
1511+ req_table.request_number.writable = False
1512+ req_table.priority.writable = False
1513+ req_table.site_id.writable = False
1514+ req_table.request_for_id.writable = False
1515+ req_table.date_required.writable = False
1516+ req_table.date_required_until.writable = False
1517+ req_table.purpose.writable = False
1518+ req_table.date.writable = False
1519+ req_table.requester_id.writable = False
1520+ req_table.approved_by_id.writable = False
1521+ req_table.comments.writable = False
1522+ req_table.cancel.writable = False
1523+
1524+ if r.record and r.record.req_req_item.count():#r.component and r.component.name == "req_item":
1525+ # Is this component being updated (not created)
1526+ req_item_table = db.req_req_item
1527+ #req_item_table.item.writable = False
1528+ req_item_table.item_pack_id.writable = False
1529+ req_item_table.quantity.writable = False
1530+
1531+ elif r.record and r.record.req_req_skill.count():#r.component and r.component.name == "req_skill":
1532+ # Is this component being updated (not created)
1533+ req_skill_table = db.req_req_skill
1534+ req_skill_table.skill_id.writable = False
1535+ req_skill_table.quantity.writable = False
1536+
1537+ #req_table.recv_by_id.label = T("Delivered To")
1538+
1539+ # Update Donated By from selection on Match tab
1540+ don_item_id = request.vars.don_item_id
1541+ if r.component and r.component.name == "commit" and don_item_id:
1542+ request.vars.pop("don_item_id")
1543+ don_item = db(db.don_don_item.id == don_item_id
1544+ ).select(db.don_don_item.organisation_id,
1545+ limitby=[0,1]).first()
1546+ if don_item:
1547+ db.req_commit.donated_by_id.default = don_item.organisation_id
1548+ db(db.req_commit.req_id == r.id).update(donated_by_id = don_item.organisation_id)
1549+ if r.component and r.component.name == "req_item":
1550+ s3mgr.s3.crud.submit_button = T("Save&Find Match")
1551+ match_url = URL(c="don", f = "match",
1552+ vars = dict(viewing="req_req.%s" % r.id)
1553+ )
1554+ s3mgr.configure("req_req_item",
1555+ update_next = match_url,
1556+ create_next = match_url
1557+ )
1558+
1559+ if r.method != "update" and r.method != "read":
1560+ if not r.component:
1561+ # Hide fields which don't make sense in a Create form
1562+ # - includes one embedded in list_create
1563+ # - list_fields over-rides, so still visible within list itself
1564+ response.s3.req_create_form_mods()
1565+
1566+ # Get the default Facility for this user
1567+ # @ToDo: Use site_id in User Profile (like current organisation_id)
1568+ if deployment_settings.has_module("hrm"):
1569+ query = (db.hrm_human_resource.person_id == s3_logged_in_person())
1570+ site = db(query).select(db.org_site.id,
1571+ limitby=(0, 1)).first()
1572+ if site:
1573+ r.table.site_id.default = site.id
1574+
1575+ elif r.component.name == "document":
1576+ s3.crud.submit_button = T("Add")
1577+ table = r.component.table
1578+ # @ToDo: Fix for Link Table
1579+ #table.date.default = r.record.date
1580+ #if r.record.site_id:
1581+ # stable = db.org_site
1582+ # query = (stable.id == r.record.site_id)
1583+ # site = db(query).select(stable.location_id,
1584+ # stable.organisation_id,
1585+ # limitby=(0, 1)).first()
1586+ # if site:
1587+ # table.location_id.default = site.location_id
1588+ # table.organisation_id.default = site.organisation_id
1589+
1590+ elif r.component.name == "req_item":
1591+ table = r.component.table
1592+ table.site_id.writable = table.site_id.readable = False
1593+ response.s3.req_hide_quantities(table)
1594+
1595+ if r.component:
1596+ if r.component.name == "document" or \
1597+ r.component.name == "req_item" or \
1598+ r.component.name == "req_skill":
1599+ # Limit site_id to facilities the user has permissions for
1600+ # @ToDo: Non-Item requests shouldn't be bound to a Facility?
1601+ auth.permission.permitted_facilities(table=r.table,
1602+ error_msg=T("You do not have permission for any facility to make a request."))
1603+ else:
1604+ # Limit site_id to facilities the user has permissions for
1605+ # @ToDo: Non-Item requests shouldn't be bound to a Facility?
1606+ auth.permission.permitted_facilities(table=r.table,
1607+ error_msg=T("You do not have permission for any facility to make a request."))
1608+
1609+ return True
1610+ response.s3.prep = prep
1611+
1612+ # Post-process
1613+ def postp(r, output):
1614+ if r.interactive:
1615+ s3_action_buttons(r)
1616+ if r.component and r.component.name == "req_item":
1617+ req_item_don_item_btn = dict(url = URL(c = "req",
1618+ f = "req_item_don_item",
1619+ args = ["[id]"]
1620+ ),
1621+ _class = "action-btn",
1622+ label = str(T("Find")), # Change to Fulfil? Match?
1623+ )
1624+ response.s3.actions.append(req_item_don_item_btn)
1625+ return output
1626+
1627+ response.s3.postp = postp
1628+
1629+ output = s3_rest_controller("req", "req", rheader=req_rheader)
1630+ return output
1631+# -----------------------------------------------------------------------------
1632+def req_print():
1633+ """ Print Donation Request Form """
1634+ s3mgr.load("req_req")
1635+ r = s3base.S3Request(s3mgr,
1636+ prefix="req",
1637+ name="req",
1638+ extension="pdf",
1639+ args = request.args[0])
1640+ if len(request.args) > 1:
1641+ s3mgr.configure("req_req",
1642+ callback = response.s3.donationCertificate,
1643+ formname = T("Donation Certificate"),
1644+ header = response.s3.donCertBorder,
1645+ footer = lambda x, y: None,
1646+ )
1647+ else:
1648+ s3mgr.configure("req_req",
1649+ callback = response.s3.donationRequest,
1650+ formname = T("Request for Donations"),
1651+ footer = response.s3.donationFooter
1652+ )
1653+ return r()
1654+
1655+# -----------------------------------------------------------------------------
1656+
1657+def loan():
1658+ """ Loans REST Controller """
1659+
1660+ s3mgr.load("req_commit")
1661+ ctable = db.req_commit
1662+
1663+ # Filter for Loans
1664+ response.s3.filter = (ctable.status == 9 )
1665+ s3mgr.configure("req_commit",
1666+ list_fields = ["donated_by_id",
1667+ "specs",
1668+ # Site virtual Field?
1669+ "datetime_return",
1670+ ],
1671+ orderby = ["datetime_return"])
1672+ output = s3_rest_controller("req", "commit")
1673+ if isinstance(output, dict):
1674+ output["title"] = T("Donations on Loan Report")
1675+ output["subtitle"] = T("Donations on Loan")
1676+ response.s3.actions = [dict(url = URL(c = "don",
1677+ f = "req",
1678+ args = ["commit","[id]"],
1679+ ),
1680+ _class = "action-btn",
1681+ label = str(T("Open")),
1682+ ),
1683+ ]
1684+ return output
1685+
1686+# -----------------------------------------------------------------------------
1687+s3mgr.configure("don_don_item",
1688+ list_fields = ["id",
1689+ "organisation_id",
1690+ "item_category_id",
1691+ "item_id",
1692+ "pack_value",
1693+ "quantity",
1694+ ]
1695+ )
1696+
1697+ADD_ITEM = T("Add Donation Resource")
1698+LIST_ITEMS = T("List Donation Resources")
1699+s3.crud_strings["don_don_item"] = Storage(
1700+ title_create = ADD_ITEM,
1701+ title_display = T("Donation Resource Details"),
1702+ title_list = LIST_ITEMS,
1703+ title_update = T("Edit Donation Resource"),
1704+ title_search = T("Search Donation Resources"),
1705+ subtitle_create = ADD_ITEM,
1706+ subtitle_list = T("Donation Resources"),
1707+ label_list_button = LIST_ITEMS,
1708+ label_create_button = ADD_ITEM,
1709+ label_delete_button = T("Remove Donation Resource"),
1710+ msg_record_created = T("Donation Resource Added"),
1711+ msg_record_modified = T("Donation Resource updated"),
1712+ msg_record_deleted = T("Donation Resource removed"),
1713+ msg_list_empty = T("No Donation Resources for this Corporation"))
1714+
1715+ADD_GOODS = T("In the event of a declared disaster we MAY be able to donate the following Goods:")
1716+LIST_GOODS = T("List Donation Goods")
1717+s3.crud_strings["don_good"] = Storage(
1718+ title_create = ADD_GOODS,
1719+ title_display = T("Donation Good Details"),
1720+ title_list = LIST_GOODS,
1721+ title_update = T("Edit Donation Goods"),
1722+ title_search = T("Search Donation Goods"),
1723+ subtitle_create = ADD_GOODS,
1724+ subtitle_list = T("Donate Goods"),
1725+ label_list_button = LIST_GOODS,
1726+ label_create_button = ADD_GOODS,
1727+ label_delete_button = T("Remove Donation Goods"),
1728+ msg_record_created = T("Donation Goods Added"),
1729+ msg_record_modified = T("Donation Goods updated"),
1730+ msg_record_deleted = T("Donation Goods removed"),
1731+ msg_list_empty = T("No Donation Goods for this Corporation"))
1732+
1733+ADD_SERVICE = T("In the event of a declared disaster we MAY be able to donate the following Services:")
1734+LIST_SERVICES = T("List Donation Services")
1735+s3.crud_strings["don_service"] = Storage(
1736+ title_create = ADD_SERVICE,
1737+ title_display = T("Donation Service Details"),
1738+ title_list = LIST_SERVICES,
1739+ title_update = T("Edit Donation Service"),
1740+ title_search = T("Search Donation Services"),
1741+ subtitle_create = ADD_SERVICE,
1742+ subtitle_list = T("Donate Services"),
1743+ label_list_button = LIST_SERVICES,
1744+ label_create_button = ADD_SERVICE,
1745+ label_delete_button = T("Remove Donation Service"),
1746+ msg_record_created = T("Donation Service Added"),
1747+ msg_record_modified = T("Donation Service updated"),
1748+ msg_record_deleted = T("Donation Service removed"),
1749+ msg_list_empty = T("No Donation Services for this Corporation"))
1750+
1751+ADD_FACILITY = T("In the event of a declared disaster we MAY be able to donate the following Facilities:")
1752+LIST_FACILITYS = T("List Donation Facilities")
1753+s3.crud_strings["don_facility"] = Storage(
1754+ title_create = ADD_FACILITY,
1755+ title_display = T("Donation Facility Details"),
1756+ title_list = LIST_FACILITYS,
1757+ title_update = T("Edit Donation Facility"),
1758+ title_search = T("Search Donation Facilities"),
1759+ subtitle_create = ADD_FACILITY,
1760+ subtitle_list = T("Donate Facilities"),
1761+ label_list_button = LIST_FACILITYS,
1762+ label_create_button = ADD_FACILITY,
1763+ label_delete_button = T("Remove Donation Facility"),
1764+ msg_record_created = T("Donation Facility Added"),
1765+ msg_record_modified = T("Donation Facility updated"),
1766+ msg_record_deleted = T("Donation Facility removed"),
1767+ msg_list_empty = T("No Donation Facilities for this Corporation"))
1768+
1769+# -----------------------------------------------------------------------------
1770+def don_item_filter(don_item_add_filter_func):
1771+ """
1772+ Filter donated 'items' by category
1773+ Services = category 'SERVICES'
1774+ Facilities = category 'FACILITY'
1775+ Goods = everything else
1776+ """
1777+ itable = db.don_don_item
1778+ ctable = db.supply_item_category
1779+
1780+ query = (ctable.code == "FACILITY")
1781+ facility_cat_id = db(query).select(ctable.id,
1782+ limitby = (0, 1),
1783+ cache = gis.cache).first().id
1784+ query = (ctable.code == "SERVICES")
1785+ service_cat_id = db(query).select(ctable.id,
1786+ limitby = (0, 1),
1787+ cache = gis.cache).first().id
1788+
1789+ itable.organisation_id.widget = None # Implement SearchACWidget for Organisations
1790+ itable.organisation_id.requires = IS_NULL_OR(IS_ONE_OF(db, "org_organisation.id",
1791+ organisation_represent,
1792+ orderby="org_organisation.name",
1793+ sort=True,
1794+ filterby = "has_items",
1795+ filter_opts = [True])
1796+ )
1797+ itable.item_id.widget = None
1798+
1799+ if not s3_has_role(STAFF):
1800+ # Only Staff can add Categories
1801+ itable.item_category_id.comment = ""
1802+ # Only Staff can add Item Types
1803+ # @ToDo: Allow adding Items to 'OTHER' category
1804+ itable.item_id.comment = ""
1805+ # Only Staff can add Item Units
1806+ # @ToDo: Should Units for Services/Facilities be hardcoded/hidden?
1807+ # (always day/ea)
1808+ comment = DIV(_class="tooltip",
1809+ _title="%s|%s" % (T("Resource Units"),
1810+ T("The way in which an item is normally distributed")))
1811+ script = SCRIPT(
1812+"""
1813+S3FilterFieldChange({
1814+ 'FilterField': 'item_id',
1815+ 'Field': 'item_pack_id',
1816+ 'FieldResource':'item_pack',
1817+ 'FieldPrefix': 'supply',
1818+ 'msgNoRecords': S3.i18n.no_packs,
1819+ 'fncPrep': fncPrepItem,
1820+ 'fncRepresent': fncRepresentItem
1821+});""")
1822+ itable.item_pack_id.comment = TAG[""](comment, script)
1823+
1824+ item_type = request.vars.item
1825+ if item_type == "goods":
1826+ s3.crud_strings["don_don_item"] = s3.crud_strings["don_good"]
1827+
1828+ itable.lead_time.readable = True
1829+ itable.lead_time.writable = True
1830+ itable.type.readable = True
1831+ itable.type.writable = True
1832+ itable.item_category_id.requires = IS_NULL_OR(IS_ONE_OF(db,
1833+ "supply_item_category.id",
1834+ "%(name)s",
1835+ not_filterby = "id",
1836+ not_filter_opts = [facility_cat_id, service_cat_id],
1837+ sort=True))
1838+ response.s3.jquery_ready = [
1839+"""
1840+$(document).ready(function() {
1841+ S3FilterFieldChange({
1842+ 'FilterField': 'item_category_id',
1843+ 'Field': 'item_id',
1844+ 'FieldResource':'item',
1845+ 'FieldPrefix': 'supply',
1846+ //'url': S3.Ap.concat('/req/req_item_packs/'),
1847+ //'msgNoRecords': S3.i18n.no_packs,
1848+ //'fncPrep': fncPrepItem,
1849+ //'fncRepresent': fncRepresentItem
1850+ });
1851+});
1852+"""
1853+]
1854+ query = (itable.item_category_id != facility_cat_id) & \
1855+ (itable.item_category_id != service_cat_id)
1856+ don_item_add_filter_func( query )
1857+ elif item_type in ["services", "facilities"]:
1858+ if item_type == "services":
1859+ s3.crud_strings["don_don_item"] = s3.crud_strings["don_service"]
1860+
1861+ item_category_filter = service_cat_id
1862+ itable.item_id.label = T("Service Type")
1863+ if s3_has_role(STAFF):
1864+ itable.item_id.comment = DIV(A(T("Add Service Type"),
1865+ _class="colorbox",
1866+ _href=URL(c="supply", f="item",
1867+ args="create",
1868+ vars=dict(format="popup")),
1869+ _target="top",
1870+ _title=T("Add Service Type")))
1871+ itable.quantity.label = T("Duration of Donated Services")
1872+ itable.item_pack_id.label = T("Unit of Time")
1873+ itable.item_pack_id.readable = True
1874+ itable.item_pack_id.writable = True
1875+ itable.pack_value.label = T("Estimated Value ($) per Unit of Time")
1876+
1877+ elif item_type == "facilities":
1878+ s3.crud_strings["don_don_item"] = s3.crud_strings["don_facility"]
1879+
1880+ item_category_filter = facility_cat_id
1881+ itable.item_id.label = T("Facility Type")
1882+ if s3_has_role(STAFF):
1883+ itable.item_id.comment = DIV(A(T("Add Facility Type"),
1884+ _class="colorbox",
1885+ _href=URL(c="supply", f="item",
1886+ args="create",
1887+ vars=dict(format="popup")),
1888+ _target="top",
1889+ _title=T("Add Facility Type")))
1890+ itable.specs.label = T("Specifications (Square Feet, Building Type, Stories, Services)")
1891+
1892+ itable.item_category_id.readable = itable.item_category_id.writable = False
1893+ itable.item_category_id.default = item_category_filter
1894+
1895+ itable.item_id.requires = IS_ONE_OF(db, "supply_item.id",
1896+ lambda id: response.s3.item_represent(id,
1897+ show_um = False,
1898+ show_link = False),
1899+ filterby = "item_category_id",
1900+ filter_opts = [item_category_filter],
1901+ sort=True)
1902+
1903+ query = (itable.item_category_id == item_category_filter)
1904+ don_item_add_filter_func( query )
1905+# -----------------------------------------------------------------------------
1906+def organisation():
1907+ """
1908+ /org/organisation/ corporation
1909+ """
1910+
1911+ otable = db.org_organisation
1912+
1913+ otable.acronym.readable = False
1914+ otable.acronym.writable = False
1915+ otable.sector_id.readable = True
1916+ otable.sector_id.writable = True
1917+ org_has_items_field = otable.has_items
1918+ org_has_items_field.default = True
1919+ response.s3.filter = (org_has_items_field == True)
1920+
1921+ if not s3_has_role(STAFF):
1922+ # Tweak the breadcrumb
1923+ breadcrumbs[2] = (T("Organization Profile"), False,
1924+ URL(c=request.controller,
1925+ f=request.function,
1926+ args=request.args))
1927+
1928+ def corporation_rheader(r, tabs = []):
1929+ """ Corporation rheader """
1930+
1931+ if r.representation == "html":
1932+
1933+ if r.record is None:
1934+ # List or Create form: rheader makes no sense here
1935+ return None
1936+
1937+ tabs = [(T("Basic Details"), None),
1938+ (T("Contacts"), "human_resource"),
1939+ (T("Donate Goods"), "don_item", dict(item="goods")),
1940+ (T("Donate Services "), "don_item", dict(item="services")),
1941+ (T("Donate Facilities "), "don_item", dict(item="facilities")),
1942+ ]
1943+ if "register" not in request.vars:
1944+ tabs.append( (T("Donations"), "commit") )
1945+ rheader_tabs = s3_rheader_tabs(r, tabs)
1946+
1947+ organisation = r.record
1948+ if organisation.sector_id:
1949+ _sectors = org_sector_represent(organisation.sector_id)
1950+ else:
1951+ _sectors = None
1952+
1953+ if deployment_settings.get_ui_cluster():
1954+ sector_label = T("Cluster(s)")
1955+ else:
1956+ sector_label = T("Sector(s)")
1957+
1958+ rheader = DIV(TABLE(
1959+ TR(
1960+ TH("%s: " % T("Corporation")),
1961+ organisation.name,
1962+ TH("%s: " % sector_label),
1963+ _sectors
1964+ )),
1965+ rheader_tabs
1966+ )
1967+ return rheader
1968+ return None
1969+
1970+ ADD_CORPORATION = T("Add Corporation / Organization")
1971+ LIST_CORPORATIONS = T("List Corporations & Organizations")
1972+ s3.crud_strings["org_organisation"] = Storage(
1973+ title_create = ADD_CORPORATION,
1974+ title_display = T("Corporation / Organization Details"),
1975+ title_list = LIST_CORPORATIONS,
1976+ title_update = T("Edit Corporation / Organization"),
1977+ title_search = T("Search Corporations & Organizations"),
1978+ subtitle_create = T("Add New Corporation / Organization"),
1979+ subtitle_list = T("Corporations & Organizations"),
1980+ label_list_button = LIST_CORPORATIONS,
1981+ label_create_button = ADD_CORPORATION,
1982+ label_delete_button = T("Delete Corporation / Organization"),
1983+ msg_record_created = T("Corporation / Organization added"),
1984+ msg_record_modified = T("Corporation / Organization updated"),
1985+ msg_record_deleted = T("Corporation / Organization deleted"),
1986+ msg_list_empty = T("No Corporations & Organizations currently registered"))
1987+
1988+ def prep(r):
1989+ don_item_filter(lambda query:
1990+ r.resource.add_component_filter("don_item", query))
1991+ if r.component:
1992+ if r.component.name == "don_item":
1993+ itable = db.don_don_item
1994+ itable.currency.readable = False
1995+ elif r.component.name == "human_resource":
1996+ hrtable = db.hrm_human_resource
1997+ hrtable.type.writable = hrtable.type.readable = False
1998+ hrtable.status.writable = hrtable.status.readable = False
1999+ hrtable.focal_point.writable = hrtable.focal_point.readable = False
2000+ response.s3.jquery_ready.append("$('#hrm_human_resource_person_id__row1').hide();")
2001+
2002+ s3.crud_strings["hrm_human_resource"] = Storage(
2003+ title_create = T("Add Contact"),
2004+ title_display = T("Contact Details"),
2005+ title_list = T("Contacts"),
2006+ title_update = T("Edit Contact"),
2007+ title_search = T("Search Contacts"),
2008+ subtitle_create = T("Additional Contacts (optional)"),
2009+ subtitle_list = T("Contacts"),
2010+ label_list_button = T("List Contacts"),
2011+ label_create_button = T("Add Contacts"),
2012+ label_delete_button = T("Delete Contact"),
2013+ msg_record_created = T("Contact added"),
2014+ msg_record_modified = T("Contact updated"),
2015+ msg_record_deleted = T("Contact deleted"),
2016+ msg_no_match = T("No Contacts Found"),
2017+ msg_list_empty = T("Currently there are no Contact registered"))
2018+
2019+ # Donation Organization Regisration Workflow
2020+ if "register" in request.vars:
2021+ # Only force the open on 1st run
2022+ response.s3.show_listadd = True
2023+ s3mgr.configure("hrm_human_resource",
2024+ create_next = URL(c="don", f="organisation",
2025+ args = [r.record.id, "don_item"],
2026+ vars = dict(item="goods"))
2027+ )
2028+
2029+ # Add req to Corporations as Donations
2030+ s3mgr.configure("req_commit",
2031+ insertable = False,
2032+ editable = False,
2033+ deletable = False,
2034+ )
2035+
2036+ s3mgr.configure( "org_organisation",
2037+ list_fields = ["id",
2038+ "name",
2039+ #"type",
2040+ "sector_id",
2041+ #"country",
2042+ #"website"
2043+ ])
2044+
2045+ # req CRUD strings
2046+ REQ = T("Donation")
2047+ #ADD_REQ = T("Add Donation")
2048+ LIST_REQ = T("List Donations")
2049+ s3.crud_strings["req_req"] = Storage(
2050+ #title_create = ADD_REQ,
2051+ title_display = T("Donation Details"),
2052+ title_list = LIST_REQ,
2053+ #title_update = T("Edit Donation"),
2054+ title_search = T("Search Donations"),
2055+ #subtitle_create = ADD_REQ,
2056+ subtitle_list = T("Donations"),
2057+ label_list_button = LIST_REQ,
2058+ #label_create_button = ADD_REQ,
2059+ #label_delete_button = T("Remove Donations"),
2060+ #msg_record_created = T("Donation Added"),
2061+ #msg_record_modified = T("Donation updated"),
2062+ #msg_record_deleted = T("Donation removed"),
2063+ msg_list_empty = T("No Donations from this Corporation"))
2064+
2065+ if not s3_has_role(STAFF):
2066+ response.s3.donate_cash_link =True
2067+
2068+ return organisation_controller(organisation_rheader = corporation_rheader,
2069+ org_prep = prep)
2070+
2071+# -----------------------------------------------------------------------------
2072+def don_item():
2073+ """ REST Controller """
2074+
2075+ def don_item_add_filter_func(query):
2076+ response.s3.filter = query
2077+ don_item_filter(don_item_add_filter_func)
2078+
2079+ # Tweak the breadcrumb
2080+ type = request.get_vars.item
2081+ if type == "goods":
2082+ label = T("Goods")
2083+ elif type == "services":
2084+ label = T("Services")
2085+ elif type == "facilities":
2086+ label = T("Facilities")
2087+ else:
2088+ # Error!
2089+ label = ""
2090+ breadcrumbs[2] = (label, False,
2091+ URL(c=request.controller,
2092+ f=request.function,
2093+ vars=request.vars))
2094+
2095+ def postp(r, output):
2096+ # maintain the ?items= type
2097+ if "type" in request.vars:
2098+ response.s3.actions = [
2099+ dict(label=str(UPDATE),
2100+ _class="action-btn",
2101+ url=URL(args = ["[id]"] + ["update"],
2102+ vars=request.vars)),
2103+ ]
2104+ return output
2105+ response.s3.postp = postp
2106+
2107+ output = s3_rest_controller(module, "don_item")
2108+ return output
2109+
2110+# -----------------------------------------------------------------------------
2111+def collect():
2112+ """ REST Controller """
2113+ def prep(r):
2114+ s3mgr.configure("don_collect",
2115+ list_fields = ["id",
2116+ "start_datetime",
2117+ "end_datetime",
2118+ "site_id",
2119+ "organisation_id",
2120+ ])
2121+ return True
2122+
2123+ response.s3.prep = prep
2124+ output = s3_rest_controller(module, resourcename)
2125+ return output
2126+
2127+# -----------------------------------------------------------------------------
2128+def distribute():
2129+ """ REST Controller """
2130+ output = s3_rest_controller(module, resourcename)
2131+ return output
2132+
2133+# -----------------------------------------------------------------------------
2134+def profile():
2135+ """ Organisation Profile """
2136+ return organisation_profile()
2137+
2138+# -----------------------------------------------------------------------------
2139+################################################################################
2140+### Hook to call get the donation certificate
2141+################################################################################
2142+#def certprint():
2143+# """ Print Cert TEST """
2144+# s3mgr.load("don_distribute")
2145+# r = s3base.S3Request(s3mgr,
2146+# prefix="don",
2147+# name="distribute",
2148+# extension="pdf")
2149+# s3mgr.configure("don_distribute",
2150+# callback = response.s3.donationCertificate,
2151+# formname = "Donation Certificate",
2152+# header = response.s3.donCertBorder,
2153+# footer = lambda x, y: None,
2154+# )
2155+# return r()
2156+################################################################################
2157+###
2158+################################################################################
2159+
2160+
2161+# END =========================================================================
2162\ No newline at end of file
2163
2164=== modified file 'controllers/event.py'
2165--- controllers/event.py 2011-10-13 16:40:31 +0000
2166+++ controllers/event.py 2011-11-18 07:40:33 +0000
2167@@ -32,6 +32,16 @@
2168 redirect(URL(f="event", args="create"))
2169
2170 # =============================================================================
2171+# Incidents
2172+# =============================================================================
2173+def incident():
2174+ """ RESTful CRUD controller """
2175+
2176+ tablename = "event_incident"
2177+ s3mgr.load(tablename)
2178+ return s3_rest_controller(module, resourcename)
2179+
2180+# =============================================================================
2181 # Events
2182 # =============================================================================
2183 def event():
2184@@ -184,7 +194,7 @@
2185 tabs.append((T("Map Configuration"), "config"))
2186
2187 rheader = lambda r, tabs=tabs: event_rheader(r, tabs)
2188- output = s3_rest_controller("event", resourcename,
2189+ output = s3_rest_controller(module, resourcename,
2190 rheader=rheader)
2191 return output
2192
2193
2194=== modified file 'controllers/gis.py'
2195--- controllers/gis.py 2011-11-12 23:58:22 +0000
2196+++ controllers/gis.py 2011-11-18 07:40:33 +0000
2197@@ -98,7 +98,7 @@
2198 catalogue_toolbar = False
2199
2200 # @ToDo: Make these configurable
2201- search = True
2202+ search = False
2203 googleEarth = True
2204 googleStreetview = True
2205 catalogue_layers = True
2206@@ -127,7 +127,8 @@
2207 search=search,
2208 catalogue_layers=catalogue_layers,
2209 mouse_position = mouse_position,
2210- print_tool = print_tool
2211+ print_tool = print_tool,
2212+ collapsed = True
2213 )
2214
2215 return map
2216
2217=== modified file 'controllers/hrm.py'
2218--- controllers/hrm.py 2011-11-17 14:39:04 +0000
2219+++ controllers/hrm.py 2011-11-18 07:40:33 +0000
2220@@ -1033,4 +1033,228 @@
2221 redirect_vars = {fieldname: id},
2222 title_name = title)
2223
2224+# =============================================================================
2225+# Adding a human resource inline
2226+# =============================================================================
2227+
2228+def create_inline():
2229+
2230+ # arguments ?
2231+ formstyle = s3_formstyle
2232+ field_name = field.name
2233+
2234+ # Set up fields
2235+ pr_person = db.pr_person
2236+ hrm_human_resource = db.hrm_human_resource
2237+
2238+ fields = [
2239+ pr_person.first_name,
2240+ pr_person.middle_name,
2241+ pr_person.last_name,
2242+
2243+ hrm_human_resource.job_title,
2244+ ]
2245+
2246+ emailRequired = (
2247+ request.controller == "hrm" and
2248+ deployment_settings.get_hrm_email_required()
2249+ )
2250+
2251+ if emailRequired:
2252+ email_validator = IS_EMAIL()
2253+ else:
2254+ email_validator = IS_NULL_OR(IS_EMAIL())
2255+
2256+ email_field_name = "email_address"
2257+ mobile_phone_field_name = "mobile_phone"
2258+ fields.extend([
2259+ Field(
2260+ "organisation_id",
2261+ notnull=True,
2262+ requires = hrm_human_resource.organisation_id.requires,
2263+ label = hrm_human_resource.organisation_id.label,
2264+ represent = hrm_human_resource.organisation_id.represent,
2265+ ),
2266+ Field(
2267+ email_field_name,
2268+ notnull=emailRequired,
2269+ requires=email_validator,
2270+ label=T("Email Address")
2271+ ),
2272+ Field(
2273+ mobile_phone_field_name,
2274+ label=T("Mobile Phone Number")
2275+ )
2276+ ])
2277+
2278+ labels, required = s3_mark_required(fields)
2279+ if required:
2280+ response.s3.has_required = True
2281+
2282+ form = SQLFORM.factory(table_name="hrm_human_resource",
2283+ labels=labels,
2284+ formstyle=formstyle,
2285+ separator = "",
2286+ *fields)
2287+
2288+ # JavaScript
2289+ def add_script(script_name):
2290+ response.s3.scripts.append(
2291+ "%s/%s" % (response.s3.script_dir, script_name)
2292+ )
2293+
2294+ result = dict(
2295+ form = TAG[""](
2296+ # to stop some browsers appying a default table style to unstyled tables
2297+ XML("""<style type="text/css">table { font-size:inherit; }</style>"""),
2298+ form
2299+ ),
2300+ created_object_id = None,
2301+ created_object_representation = "",
2302+ errors = form.errors
2303+ )
2304+
2305+ accepted = form.accepts(request.vars)#, session):
2306+
2307+ # more validation, don't let other validation errors upset this,
2308+ # as the user wants to see all errors in one go
2309+ pr_contact = db.pr_contact
2310+ pr_person = db.pr_person
2311+ def var(name):
2312+ return request.vars.get(name, None)
2313+
2314+ def check_request_var_matches_value_if_given(var_name, value):
2315+ if var(var_name):
2316+ if var(var_name) != value:
2317+ if not form.errors.has_key(var_name):
2318+ form.errors[var_name] = (
2319+ T("There is a existing record, but the %(property)s is different. "
2320+ "(Clearing this field allows use of the existing record)")
2321+ ) % dict(
2322+ property = var_name.replace("_", " ")
2323+ )
2324+
2325+ def existing(*query):
2326+ return db(*query).select().first()
2327+
2328+ existing_mobile_phone_contact = None
2329+ existing_person = None
2330+ existing_human_resource = None
2331+
2332+ # look for a person with the same email address
2333+ email_address = var(email_field_name)
2334+ if email_address:
2335+ existing_email_contact = existing(
2336+ (pr_contact.contact_method == "EMAIL") &
2337+ (pr_contact.value == email_address)
2338+ )
2339+ if existing_email_contact is not None:
2340+ # check every other contact detail matches, otherwise complain
2341+
2342+ # mobile phone
2343+ existing_mobile_phone_contact = existing(
2344+ (pr_contact.contact_method == "MOBILE PHONE") &
2345+ (pr_contact.pe_id == existing_email_contact.pe_id)
2346+ )
2347+ if existing_mobile_phone_contact is not None:
2348+ check_request_var_matches_value_if_given(
2349+ "mobile_phone",
2350+ existing_mobile_phone_contact.value
2351+ )
2352+
2353+ # person details
2354+ existing_person = existing(
2355+ pr_person.pe_id == existing_email_contact.pe_id
2356+ )
2357+ if existing_person is not None:
2358+ check_request_var_matches_value_if_given(
2359+ "first_name",
2360+ existing_person.first_name
2361+ )
2362+ check_request_var_matches_value_if_given(
2363+ "middle_name",
2364+ existing_person.middle_name
2365+ )
2366+ check_request_var_matches_value_if_given(
2367+ "last_name",
2368+ existing_person.last_name
2369+ )
2370+
2371+ # human resource
2372+ existing_human_resource = existing(
2373+ hrm_human_resource.person_id == existing_person.id
2374+ )
2375+ if existing_human_resource is not None:
2376+ check_request_var_matches_value_if_given(
2377+ "job_title",
2378+ existing_human_resource.job_title
2379+ )
2380+ check_request_var_matches_value_if_given(
2381+ "organisation_id",
2382+ existing_human_resource.organisation_id
2383+ )
2384+
2385+ if accepted: # create objects as necessary
2386+ # an email address is assumed to uniquely identify a person
2387+ # however, there is no guarantee that a person has an email address
2388+ if existing_email_contact is None:
2389+ # there is no pr_pentity
2390+ pe_id = db.pr_pentity.insert(
2391+ ).pe_id
2392+
2393+ db.pr_contact.insert(
2394+ pe_id = pe_id,
2395+ contact_method = "EMAIL",
2396+ value = email_address,
2397+ )
2398+ else:
2399+ contact_id = existing_email_contact.id
2400+ pe_id = existing_email_contact.pe_id
2401+
2402+ assert pe_id is not None
2403+
2404+ if existing_mobile_phone_contact is None:
2405+ if var(mobile_phone_field_name):
2406+ db.pr_contact.insert(
2407+ pe_id = pe_id,
2408+ contact_method = "MOBILE PHONE",
2409+ value = var(mobile_phone_field_name)
2410+ )
2411+
2412+ if existing_person is None:
2413+ person_id = db.pr_person.insert(
2414+ pe_id = pe_id,
2415+ first_name = var("first_name"),
2416+ middle_name = var("middle_name"),
2417+ last_name = var("last_name")
2418+ )
2419+ else:
2420+ person_id = existing_person.id
2421+
2422+ if form.errors:
2423+ response.flash = "form is invalid"
2424+ else:
2425+ if existing_human_resource:
2426+ result.update(
2427+ created_object_id = existing_human_resource.id,
2428+ created_object_representation = hrm_human_resource_represent(existing_human_resource)
2429+ )
2430+ # nothing needs adding?
2431+ else:
2432+ created_human_resource = db.hrm_human_resource.insert(
2433+ person_id = person_id,
2434+ job_title = var("job_title"),
2435+ organisation_id = var("organisation_id")
2436+ )
2437+ db.commit()
2438+ result.update(
2439+ created_object_id = created_human_resource.id,
2440+ created_object_representation = hrm_human_resource_represent(created_human_resource)
2441+ )
2442+ response.flash = T("form accepted")
2443+
2444+ result["vars"] = form.vars
2445+ response.view="inner_form.html"
2446+ return result
2447+
2448 # END =========================================================================
2449
2450=== added file 'controllers/master.py'
2451--- controllers/master.py 1970-01-01 00:00:00 +0000
2452+++ controllers/master.py 2011-11-18 07:40:33 +0000
2453@@ -0,0 +1,22 @@
2454+# -*- coding: utf-8 -*-
2455+
2456+"""
2457+ Master Data - Controllers
2458+
2459+ @author: Fran
2460+"""
2461+
2462+module = request.controller
2463+
2464+if module not in deployment_settings.modules:
2465+ raise HTTP(404, body="Module disabled: %s" % module)
2466+
2467+# Options Menu (available in all Functions' Views)
2468+shn_menu(module)
2469+
2470+def index():
2471+ "Module's Home Page"
2472+
2473+ module_name = deployment_settings.modules[module].name_nice
2474+ response.title = module_name
2475+ return dict(module_name=module_name)
2476
2477=== modified file 'controllers/org.py'
2478--- controllers/org.py 2011-10-28 22:01:42 +0000
2479+++ controllers/org.py 2011-11-18 07:40:33 +0000
2480@@ -159,4 +159,127 @@
2481
2482 return output
2483
2484+
2485+# =============================================================================
2486+def add_site_inline():
2487+ """ Form to be pulled in by AJAX by the S3AddObjectWidget """
2488+ formstyle = s3_formstyle
2489+ field_name = field.name
2490+
2491+ # Set up fields
2492+ org_office = db.org_office
2493+
2494+ field_names = [
2495+ "type",
2496+ "name",
2497+ "address",
2498+ "address_2",
2499+ "L3",
2500+ "L1",
2501+ "postcode",
2502+ "phone1",
2503+ ]
2504+ fields = []
2505+ for field_name in field_names:
2506+ fields.append(getattr(org_office, field_name))
2507+
2508+ labels, required = s3_mark_required(fields)
2509+ if required:
2510+ response.s3.has_required = True
2511+
2512+ form = SQLFORM.factory(table_name="org_office",
2513+ labels=labels,
2514+ formstyle=formstyle,
2515+ separator = "",
2516+ *fields)
2517+
2518+ # change submit button text
2519+ submit_line = form[0][-1][0]
2520+ submit_button = submit_line[0]
2521+ submit_button.attributes["_value"] = T("Save")
2522+
2523+ # add cancel and reset buttons
2524+ submit_line.append(
2525+ INPUT(_type="button", _value=T("Cancel"), _onclick="close_iframe()")
2526+ )
2527+ submit_line.append(
2528+ INPUT(_type="reset", _value=T("Clear"))
2529+ )
2530+
2531+ # JavaScript
2532+ def add_script(script_name):
2533+ response.s3.scripts.append(
2534+ "%s/%s" % (response.s3.script_dir, script_name)
2535+ )
2536+
2537+ result = dict(
2538+ form = TAG[""](
2539+ # to stop some browsers appying a default table style to unstyled tables
2540+ XML("""<style type="text/css">table { font-size:inherit; }</style>"""),
2541+ form
2542+ ),
2543+ created_object_id = None,
2544+ created_object_representation = "",
2545+ errors = form.errors
2546+ )
2547+
2548+ accepted = form.accepts(request.vars)#, session):
2549+ # more validation, don't let other validation errors upset this,
2550+ # as the user wants to see all errors in one go
2551+ def var(name):
2552+ return request.vars.get(name, None)
2553+ def check_request_var_matches_value_if_given(var_name, value):
2554+ if var(var_name):
2555+ if var(var_name) != value:
2556+ if not form.errors.has_key(var_name):
2557+ form.errors[var_name] = (
2558+ T("There is a existing record, but the %(property)s is different. "
2559+ "(Clearing this field allows use of the existing record)")
2560+ ) % dict(
2561+ property = var_name.replace("_", " ")
2562+ )
2563+ def existing(*query):
2564+ return db(*query).select().first()
2565+ # look for an office with the same name
2566+ name = var("name")
2567+ if name:
2568+ existing_office = existing(
2569+ org_office.name == name
2570+ )
2571+ if existing_office is not None:
2572+ for field_name in field_names:
2573+ check_request_var_matches_value_if_given(
2574+ field_name,
2575+ getattr(existing_office, field_name)
2576+ )
2577+ else:
2578+ existing_office = None
2579+ if accepted:
2580+ # create objects as necessary
2581+ if form.errors:
2582+ response.flash = "form is invalid"
2583+ else:
2584+ if existing_office is not None:
2585+ result.update(
2586+ created_object_id = existing_office.id,
2587+ created_object_representation = existing_office.name
2588+ )
2589+ # nothing needs adding?
2590+ else:
2591+ created_office = db.org_office.insert(
2592+ **dict(
2593+ (field_name, var(field_name)) for field_name in field_names
2594+ )
2595+ )
2596+ db.commit()
2597+ result.update(
2598+ created_object_id = created_office.id,
2599+ created_object_representation = created_office.name
2600+ )
2601+ response.flash = T("form accepted")
2602+
2603+ result["vars"] = form.vars
2604+ response.view="inner_form.html"
2605+ return result
2606+
2607 # END =========================================================================
2608
2609=== modified file 'controllers/project.py'
2610--- controllers/project.py 2011-11-04 10:52:23 +0000
2611+++ controllers/project.py 2011-11-18 07:40:33 +0000
2612@@ -16,7 +16,6 @@
2613
2614 # =============================================================================
2615 def index():
2616-
2617 """ Module's Home Page """
2618
2619 module_name = deployment_settings.modules[module].name_nice
2620@@ -30,21 +29,18 @@
2621
2622 # =============================================================================
2623 def need():
2624-
2625 """ RESTful CRUD controller """
2626
2627 return s3_rest_controller(module, resourcename)
2628
2629 # -----------------------------------------------------------------------------
2630 def need_type():
2631-
2632 """ RESTful CRUD controller """
2633
2634 return s3_rest_controller(module, resourcename)
2635
2636 # =============================================================================
2637 def project():
2638-
2639 """ RESTful CRUD controller """
2640
2641 tablename = "%s_%s" % (module, resourcename)
2642@@ -117,9 +113,9 @@
2643 rheader = site_rheader)
2644 # =============================================================================
2645 def activity():
2646-
2647 """ RESTful CRUD controller """
2648
2649+<<<<<<< TREE
2650 tablename = "%s_%s" % (module, resourcename)
2651 table = db[tablename]
2652
2653@@ -172,10 +168,13 @@
2654 )
2655 return rheader
2656 return None
2657+=======
2658+ # Defined in the Model for use from Multiple Controllers for unified menus
2659+ return response.s3.project_activity_controller()
2660+>>>>>>> MERGE-SOURCE
2661
2662 # =============================================================================
2663 def task():
2664-
2665 """ RESTful CRUD controller """
2666
2667 # Pre-process
2668@@ -257,7 +256,6 @@
2669
2670 # =============================================================================
2671 def gap_report():
2672-
2673 """ Provide a Report on Gaps between Activities & Needs Assessments """
2674
2675 # Get all assess_summary
2676
2677=== modified file 'controllers/req.py'
2678--- controllers/req.py 2011-11-07 19:55:13 +0000
2679+++ controllers/req.py 2011-11-18 07:40:33 +0000
2680@@ -37,9 +37,13 @@
2681 - custom View
2682 """
2683
2684- module_name = deployment_settings.modules[module].name_nice
2685- response.title = module_name
2686- return dict(module_name=module_name)
2687+ if s3_has_role("ADMIN"):
2688+ module_name = deployment_settings.modules[module].name_nice
2689+ response.title = module_name
2690+ return dict(module_name=module_name)
2691+
2692+ else:
2693+ redirect(URL(f="req_skill"))
2694
2695 # -----------------------------------------------------------------------------
2696 def is_affiliated():
2697@@ -68,10 +72,13 @@
2698
2699 # -----------------------------------------------------------------------------
2700 def req():
2701- """ REST Controller """
2702-
2703- # Defined in the Model for use from Multiple Controllers for unified menus
2704- return response.s3.req_controller()
2705+ """ REST Controller for non-interactive ONLY"""
2706+
2707+ if "rcomponents" not in request.get_vars:
2708+ request.get_vars.update(rcomponents="pr_contact")
2709+
2710+ response.s3.prep = lambda r: not r.interactive
2711+ return s3_rest_controller("req", "req")
2712
2713 # =============================================================================
2714 def req_item():
2715@@ -135,10 +142,10 @@
2716
2717 output["title"] = T("Request Item from Available Inventory")
2718 output["req_btn"] = A( T("Return to Request"),
2719- _href = URL( c = "req",
2720- f = "req",
2721- args = [req_item.req_id, "req_item"]
2722- ),
2723+ _href = URL(c = "req",
2724+ f = "req",
2725+ args = [req_item.req_id, "req_item"]
2726+ ),
2727 _class = "action-btn"
2728 )
2729
2730@@ -301,8 +308,13 @@
2731 if r.representation == "html":
2732 record = r.record
2733 if record and r.name == "commit":
2734+<<<<<<< TREE
2735 tabs = [(T("Edit Details"), None)]
2736
2737+=======
2738+ tabs = [(T("Details"), None)]
2739+
2740+>>>>>>> MERGE-SOURCE
2741 if record.type == 1:
2742 tabs.append((T("Items"), "commit_item"))
2743
2744
2745=== modified file 'controllers/supply.py'
2746--- controllers/supply.py 2011-10-29 12:26:52 +0000
2747+++ controllers/supply.py 2011-11-18 07:40:33 +0000
2748@@ -87,10 +87,25 @@
2749 # =============================================================================
2750 def item():
2751 """ RESTful CRUD controller """
2752+ itable = db.supply_item
2753+ if "item_category_id" in request.vars:
2754+ itable.item_category_id.default = request.vars.item_category_id
2755+ itable.item_category_id.writable = False
2756
2757+ # LA: Hide Extra Item Fields
2758+ itable.code.readable = itable.code.writable = False
2759+ itable.brand_id.readable = itable.brand_id.writable = False
2760+ itable.model.readable = itable.model.writable = False
2761+ itable.year.readable = itable.year.writable = False
2762+ itable.weight.readable = itable.weight.writable = False
2763+ itable.length.readable = itable.length.writable = False
2764+ itable.width.readable = itable.width.writable = False
2765+ itable.height.readable = itable.height.writable = False
2766+ itable.volume.readable = itable.volume.writable = False
2767+
2768 # Sort Alphabetically for the AJAX-pulled dropdown
2769 s3mgr.configure("supply_item",
2770- orderby=db.supply_item.name)
2771+ orderby=itable.name)
2772
2773 # Defined in the Model for use from Multiple Controllers for unified menus
2774 return response.s3.supply_item_controller()
2775
2776=== modified file 'controllers/vol.py' (properties changed: +x to -x)
2777--- controllers/vol.py 2011-10-13 16:40:31 +0000
2778+++ controllers/vol.py 2011-11-18 07:40:33 +0000
2779@@ -2,8 +2,6 @@
2780
2781 """
2782 Volunteer Module
2783- - A 'My Sahana' view of an individual Volunteer's Data, Tasks, etc
2784- (Ability for Anonymous users to sign-up as a Volunteer?)
2785 """
2786
2787 module = request.controller
2788@@ -19,8 +17,11 @@
2789 def index():
2790 """ Module's Home Page """
2791
2792- # Default to the Personal profile
2793- return person()
2794+ if s3_has_role(STAFF):
2795+ response.view = "vol/index.html"
2796+ return dict()
2797+ else:
2798+ redirect(URL(c="vol", f="req_skill"))
2799
2800 # -----------------------------------------------------------------------------
2801 # People
2802@@ -28,150 +29,41 @@
2803 def person():
2804 """
2805 Person Controller
2806- - allows a person to view/update the details held about them
2807+ - List of Volunteers
2808 """
2809
2810+ module = "pr"
2811 resourcename = "person"
2812+ tablename = "pr_person"
2813+ table = db[tablename]
2814+
2815+ response.s3.filter = (table.volunteer == True)
2816
2817 # Load Model
2818 s3mgr.load("pr_address")
2819- s3mgr.load("hrm_skill")
2820-
2821- s3.crud.submit_button = T("Next")
2822-
2823- s3mgr.model.add_component("hrm_certification",
2824- pr_person="person_id")
2825-
2826- s3mgr.model.add_component("hrm_competency",
2827- pr_person="person_id")
2828-
2829- s3mgr.model.add_component("hrm_credential",
2830- pr_person="person_id")
2831-
2832- s3mgr.model.add_component("hrm_training",
2833- pr_person="person_id")
2834-
2835- s3mgr.model.add_component("hrm_experience",
2836- pr_person="person_id")
2837-
2838- # Q: Are volunteers assigned to a specific organisation outside of a specific Event?
2839- # Yes, some are: CERT
2840- s3mgr.model.add_component("hrm_human_resource",
2841- pr_person="person_id")
2842-
2843- # Configure human resource table
2844- # - for Positions
2845- tablename = "hrm_human_resource"
2846- table = db[tablename]
2847- table.type.readable = True
2848- table.type.writable = False
2849- table.location_id.writable = False # Populated from pr_address
2850- table.location_id.readable = False
2851- s3mgr.configure(tablename,
2852- list_fields=["id",
2853- "organisation_id",
2854- "job_title",
2855- "status"])
2856-
2857- # Configure person table
2858- # - hide fields
2859- tablename = "pr_person"
2860- table = db[tablename]
2861- table.pe_label.readable = False
2862- table.pe_label.writable = False
2863- table.missing.readable = False
2864- table.missing.writable = False
2865- table.age_group.readable = False
2866- table.age_group.writable = False
2867- s3mgr.configure(tablename,
2868- # Wizard: Move to next Tab after Save
2869- update_next = URL(args=["[id]", "address"]),
2870- deletable=False)
2871-
2872- # Configure for personal mode
2873- s3.crud_strings[tablename].update(
2874- title_display = T("Personal Profile"),
2875- title_update = T("Personal Profile"))
2876- # People can view their own HR data, but not edit it
2877- db.hrm_human_resource.organisation_id.readable = True
2878- s3mgr.configure("hrm_human_resource",
2879- insertable = False,
2880- editable = False,
2881- deletable = False)
2882- s3mgr.configure("hrm_certification",
2883- insertable = True,
2884- editable = True,
2885- deletable = True)
2886- s3mgr.configure("hrm_credential",
2887- insertable = False,
2888- editable = False,
2889- deletable = False)
2890- s3mgr.configure("hrm_competency",
2891- insertable = True, # Can add unconfirmed
2892- editable = False,
2893- deletable = False)
2894- s3mgr.configure("hrm_training", # Can add but not provide grade
2895- insertable = True,
2896- editable = False,
2897- deletable = False)
2898- s3mgr.configure("hrm_experience",
2899- insertable = False,
2900- editable = False,
2901- deletable = False)
2902- s3mgr.configure("pr_group_membership",
2903- insertable = False,
2904- editable = False,
2905- deletable = False)
2906- tabs = [(T("Person Details"), None),
2907- (T("Addresses"), "address"),
2908- (T("Certificates"), "certification"),
2909- (T("Contact Information"), "contact"),
2910- #(T("Skills"), "competency"),
2911- #(T("Credentials"), "credential"),
2912- #(T("Trainings"), "training"),
2913- #(T("Mission Record"), "experience"),
2914- #(T("Positions"), "human_resource"),
2915- #(T("Teams"), "group_membership")
2916- ]
2917-
2918- # Prepare CRUD
2919- def prep(r):
2920- if r.interactive:
2921- resource = r.resource
2922- r.resource.build_query(id=s3_logged_in_person())
2923- if resource.count() == 1:
2924- resource.load()
2925- r.record = resource.records().first()
2926- if r.record:
2927- r.id = r.record.id
2928- if r.component:
2929- if r.component.name == "address":
2930- s3mgr.configure("pr_address",
2931- create_next = URL(args=[str(r.id), "certification"]))
2932- elif r.component.name == "certification":
2933- r.component.table.certificate_id.comment = None
2934- r.component.table.organisation_id.readable = False
2935- s3mgr.configure("hrm_certification",
2936- create_next = URL(args=[str(r.id), "contact"]))
2937- #elif r.component.name == "contact":
2938- # s3mgr.configure("pr_contact",
2939- # create_next = URL(# args=[str(r.id), ""]))
2940-
2941- return True
2942- else:
2943- # This controller is only for interactive use
2944- redirect(URL(f='default', c="index"))
2945- response.s3.prep = prep
2946-
2947- rheader = lambda r, tabs=tabs: vol_rheader(r, tabs)
2948-
2949- output = s3_rest_controller("pr", resourcename,
2950- native=False,
2951- rheader=rheader)
2952+ s3mgr.load("vol_skill")
2953+
2954+ s3mgr.model.add_component("vol_skill",
2955+ pr_person="person_id")
2956+
2957+ s3mgr.configure("vol_skill",
2958+ deletable = False)
2959+
2960+ tabs = [ (T("Basic Details"), None),
2961+ (T("Skills"), "skill"),
2962+ (T("Organizational Affiliations"), "organisation"),
2963+ (T("Address"), "address"),
2964+ (T("Contact Details"), "contact"),
2965+ ]
2966+
2967+ rheader = lambda r: vol_pr_rheader(r, tabs=tabs)
2968+
2969+ output = s3_rest_controller(module, resourcename, rheader=rheader)
2970+
2971 return output
2972
2973 # -----------------------------------------------------------------------------
2974-def vol_rheader(r, tabs=[]):
2975+def vol_pr_rheader(r, tabs=[]):
2976 """ Resource headers for component views """
2977
2978 rheader = None
2979@@ -190,46 +82,2367 @@
2980 TH(""),
2981 ""),
2982
2983- TR(TH("%s: " % T("Date of Birth")),
2984- "%s" % (s3_date_represent(person.date_of_birth) or T("unknown")),
2985- TH(""),
2986- ""),
2987-
2988 ), rheader_tabs)
2989
2990 return rheader
2991
2992-# -----------------------------------------------------------------------------
2993-# Tasks
2994-# -----------------------------------------------------------------------------
2995-def task():
2996-
2997- """ Allow a volunteer to View the details of their own tasks """
2998-
2999- tablename = "project_task"
3000- s3mgr.load(tablename)
3001- table = db[tablename]
3002-
3003- my_person_id = s3_logged_in_person()
3004-
3005- if not my_person_id:
3006- session.error = T("No person record found for current user.")
3007- redirect(URL(f="index"))
3008-
3009- table.person_id.default = my_person_id
3010-
3011- response.s3.filter = (table.person_id == my_person_id)
3012-
3013- s3.crud_strings[tablename].title_list = T("My Tasks")
3014- s3.crud_strings[tablename].subtitle_list = T("Task List")
3015- s3.crud_strings[tablename].msg_list_empty = T("No tasks currently assigned")
3016-
3017- s3mgr.configure(tablename,
3018- insertable = False,
3019- editable = False,
3020- deletable = False)
3021-
3022- return s3_rest_controller("project", "task")
3023+# =============================================================================
3024+def organisation():
3025+ """
3026+ Org Controller for OrgAdmins
3027+ """
3028+
3029+ table = db.org_organisation
3030+
3031+ table.acronym.readable = False
3032+ table.acronym.writable = False
3033+ org_has_vols_field = table.has_vols
3034+ org_has_vols_field.default = True
3035+ response.s3.filter = (org_has_vols_field == True)
3036+
3037+ if "register" in request.vars:
3038+ response.s3.show_listadd = True
3039+ output = organisation_controller(organisation_rheader = organisation_rheader)
3040+
3041+ if isinstance(output, dict):
3042+ output["title"] = T("Edit Organization Profile")
3043+ return output
3044+
3045+# -----------------------------------------------------------------------------
3046+def organisation_rheader(r, tabs = []):
3047+ """ Organisation rheader """
3048+
3049+ if r.representation == "html":
3050+
3051+ if r.record is None:
3052+ # List or Create form: rheader makes no sense here
3053+ return None
3054+
3055+ tabs = [(T("Basic Details"), None),
3056+ (T("Contacts"), "human_resource"),
3057+ #(T("Activities"), "activity")
3058+ ]
3059+ rheader_tabs = s3_rheader_tabs(r, tabs)
3060+
3061+ organisation = r.record
3062+
3063+ rheader = DIV(TABLE(
3064+ TR(
3065+ TH("%s: " % T("Organization")),
3066+ organisation.name,
3067+ ),
3068+ ),
3069+ rheader_tabs
3070+ )
3071+ return rheader
3072+ return None
3073+
3074+# =============================================================================
3075+def vol_sidebar():
3076+ """ Sidebar for people who aren't logged-in """
3077+
3078+ request.args = ["login"]
3079+ loginform = auth()
3080+ loginform.attributes["_id"] = "loginform"
3081+ request.args = []
3082+
3083+ if not response.menu_left:
3084+ response.menu_left = DIV()
3085+
3086+ if not auth.is_logged_in():
3087+ response.menu_left.append(
3088+ DIV(
3089+ P(T("Already registered?"),
3090+ BR(),
3091+ "%s:" % T("Sign in here")),
3092+ #loginform,
3093+ FORM(
3094+ LABEL(T("Email"), _for="email"),
3095+ INPUT(_type="text", _name="email", _title=T("Email")),
3096+ LABEL(T("Password"), _for="password"),
3097+ INPUT(_type="password", _name="password", _title=T("Password")),
3098+ A(SPAN(T("Sign In")),
3099+ _href="#",
3100+ _onclick="$('#sign-in-menu form').submit();",
3101+ _class="sign-in-button"),
3102+ loginform.custom.end,
3103+ _action="", _enctype="multipart/form-data", _method="post"),
3104+ _id="sign-in-menu",
3105+ _class="sub-menu"))
3106+ response.menu_left.append(
3107+ DIV(
3108+ P("%s:" % T("Other Volunteering Opportunities"), _class="osm-title"),
3109+ UL(
3110+ LI(
3111+ A(
3112+ DIV("American Red Cross", _class="link-name"),
3113+ DIV(
3114+ H3("redcrossla.org"),
3115+ IMG(_src="/%s/static/img/la/logo_arc.png" % request.application, _width="87", _height="29", _alt="American Red Cross Logo"),
3116+ 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.")),
3117+ _class="other-popup"),
3118+ _href="http://redcrossla.org", _target="_blank",
3119+ _title="American Red Cross - %s" % T("Link will open to new Window"))
3120+ ),
3121+ LI(
3122+ A(
3123+ DIV("CERT", _class="link-name"),
3124+ DIV(
3125+ H3("www.cert-la.com"),
3126+ IMG(_src="/%s/static/img/la/logo_cert.png" % request.application, _width="101", _height="100", _alt="CERT Logo"),
3127+ 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.")),
3128+ _class="other-popup"),
3129+ _href="http://www.cert-la.com", _target="_blank",
3130+ _title="CERT - %s" % T("Link will open to new Window"))
3131+ ),
3132+ LI(
3133+ A(
3134+ DIV("LA County Disaster Healthcare Volunteers", _class="link-name"),
3135+ DIV(
3136+ H3("www.lacountydhv.org"),
3137+ IMG(_src="/%s/static/img/la/logo_dhv.png" % request.application, _width="88", _height="30", _alt="Disaster Healthcare Volunteers"),
3138+ 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.")),
3139+ _class="other-popup"),
3140+ _href="http://www.lacountydhv.org", _target="_blank",
3141+ _title="Disaster Healthcare Volunteers - %s" % T("Link will open to new Window"))
3142+ ),
3143+ LI(
3144+ A(
3145+ DIV("L.A. Works", _class="link-name"),
3146+ DIV(
3147+ H3("www.laworks.com"),
3148+ IMG(_src="/%s/static/img/la/laworks.png" % request.application, _width="47", _height="40", _alt="L.A. Works Logo"),
3149+ 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.")),
3150+ _class="other-popup"),
3151+ _href="http://www.laworks.com", _target="_blank",
3152+ _title="L.A. Works - %s" % T("Link will open to new Window"))
3153+ ),
3154+ LI(
3155+ A(
3156+ DIV("Public Health Emergency Volunteer Network", _class="link-name"),
3157+ DIV(
3158+ H3("publichealth.lacounty.gov"),
3159+ IMG(_src="/%s/static/img/la/logo_phev.png" % request.application, _width="121", _height="30", _alt="Public Health Emergency Volunteer (PHEV) Network"),
3160+ 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.")),
3161+ _class="other-popup"),
3162+ _href="http://publichealth.lacounty.gov/eprp/volview.htm", _target="_blank",
3163+ _title="Public Health Emergency Volunteer (PHEV) Network - %s" % T("Link will open to new Window"))
3164+ ),
3165+ LI(
3166+ A(
3167+ DIV("VCLA", _class="link-name"),
3168+ DIV(
3169+ H3("www.vcla.net"),
3170+ IMG(_src="/%s/static/img/la/vcla.png" % request.application, _width="40", _height="40", _alt="VCLA Logo"),
3171+ 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.")),
3172+ _class="other-popup"),
3173+ _href="http://www.vcla.net", _target="_blank",
3174+ _title="VCLA - %s" % T("Link will open to new Window"))
3175+ )
3176+ ),
3177+ _class="other-sub-menu")
3178+ )
3179+ if session.s3.debug:
3180+ response.s3.scripts.append( "%s/jquery.hoverIntent.js" % s3_script_dir )
3181+ else:
3182+ response.s3.scripts.append( "%s/jquery.hoverIntent.minified.js" % s3_script_dir )
3183+
3184+ response.s3.jquery_ready.append("""
3185+$('.other-popup').css('display', 'none');
3186+$('.tooltip .message').css('display', 'none');
3187+$('.other-sub-menu li a').hoverIntent(menuFadeIn, menuFadeOut);
3188+$('.tooltip a').hoverIntent(tooltipFadeIn, tooltipFadeOut);""")
3189+ response.s3.js_global.append("""
3190+// For Popup Panels for the Other Menu
3191+function menuFadeIn(){$(this).children('.other-popup').fadeIn();}
3192+function menuFadeOut(){$(this).children('.other-popup').fadeOut();}
3193+// For Tooltop Panels for the Other Menu
3194+function tooltipFadeIn(){$(this).next('.message').fadeIn();}
3195+function tooltipFadeOut(){$(this).next('.message').fadeOut();}""")
3196+
3197+# -----------------------------------------------------------------------------
3198+def register():
3199+ """ Custom Registration Form """
3200+
3201+ auth.messages.submit_button = T("I accept. Create my account.")
3202+ request.args = ["register"]
3203+ db[auth.settings.table_user].language.default = T.accepted_language
3204+ # @ToDo: Make use to the SQLFORM.createform function instead of inserting fields?
3205+ form = auth()
3206+ form.attributes["_id"] = "regform"
3207+ # Custom class for Submit Button
3208+ form[0][-1][0][0]["_class"] = "accept-button"
3209+
3210+ # Cancel button
3211+ form[0][-1][0].append(BR())
3212+ #form[0][-1][0].append(INPUT(_type="reset", _value=T("Cancel")))
3213+ form[0][-1][0].append(INPUT(_type="button",
3214+ _value=T("Cancel"),
3215+ _class="wide-grey-button",
3216+ _onClick="javascript: history.go(-1)"))
3217+
3218+ formstyle = s3.crud.formstyle
3219+
3220+ # Medical note
3221+ row = formstyle(id = "",
3222+ label = "",
3223+ widget = DIV("%s:" % T("If you are a Medical or Health Professional and wish to volunteer in a professional capacity, please register at"),
3224+ BR(),
3225+ A("LA County Disaster Healthcare Volunteers",
3226+ _href="http://www.lacountydhv.org",
3227+ _target="_blank"),
3228+ BR(),
3229+ BR(),
3230+ "%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"),
3231+ BR(),
3232+ A("LA County Department of Public Health Emergency Preparedness and Response Program",
3233+ _href="http://publichealth.lacounty.gov/eprp/volview.htm",
3234+ _target="_blank"),
3235+ _style="width: 400px;",
3236+ ),
3237+ comment = "")
3238+ form[0].insert(0, row)
3239+
3240+ # Middle Name
3241+ row = formstyle(id = "middle_name",
3242+ label = LABEL("%s:" % T("Middle Name"),
3243+ _for="middle_name"),
3244+ widget = INPUT(_name="middle_name",
3245+ _id="middle_name",
3246+ _class="string"),
3247+ comment = "")
3248+ form[0][2].append(row)
3249+
3250+ # Phone
3251+ phone_opts = {
3252+ "SMS": current.deployment_settings.get_ui_label_mobile_phone(),
3253+ "HOME_PHONE": T("Home phone"),
3254+ "WORK_PHONE": T("Work phone")
3255+ }
3256+ if form.errors.phone:
3257+ phone_error = DIV(form.errors.phone,
3258+ _id="phone__error",
3259+ _class="error",
3260+ _style="display: block;")
3261+ else:
3262+ phone_error = ""
3263+ phone_widget = (INPUT(_name="phone",
3264+ _id="",
3265+ _class="string"),
3266+ SELECT(OPTION(current.deployment_settings.get_ui_label_mobile_phone(), _value="SMS"),
3267+ OPTION(T("Home phone"), _value="HOME_PHONE"),
3268+ OPTION(T("Work phone"), _value="WORK_PHONE"),
3269+ requires=IS_IN_SET(phone_opts),
3270+ value="SMS",
3271+ _name="phone_type",
3272+ _alt="Phone Type",
3273+ _id="phone_type"),
3274+ phone_error
3275+ )
3276+ phone_help = DIV(_class="tooltip",
3277+ _title="%s|%s" % (T("Phone"),
3278+ 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.")))
3279+ row = formstyle(id = "phone",
3280+ label = LABEL("%s:" % T("Phone"),
3281+ SPAN(" *", _class="req"),
3282+ _for="phone"),
3283+ widget = phone_widget,
3284+ comment = phone_help)
3285+ form[0][11].append(row)
3286+
3287+ # Address
3288+ if form.errors.address1:
3289+ address1_error = DIV(form.errors.address1,
3290+ _id="address1__error",
3291+ _class="error",
3292+ _style="display: block;")
3293+ else:
3294+ address1_error = ""
3295+ row = formstyle(id = "address1",
3296+ label = LABEL("%s:" % T("Address 1"),
3297+ SPAN(" *", _class="req"),
3298+ _for="address1"),
3299+ widget = (INPUT(_name="address1",
3300+ _id="address1",
3301+ _class="string"),
3302+ address1_error),
3303+ comment = "")
3304+ form[0][11].append(row)
3305+ row = formstyle(id = "address2",
3306+ label = LABEL("%s:" % T("Address 2"),
3307+ _for="address2"),
3308+ widget = INPUT(_name="address2",
3309+ _id="address2",
3310+ _class="string"),
3311+ comment = "")
3312+ form[0][11].append(row)
3313+ row = formstyle(id = "city",
3314+ label = LABEL("%s:" % T("City"),
3315+ SPAN(" *", _class="req"),
3316+ _for="city"),
3317+ widget = INPUT(_name="city",
3318+ _id = "city",
3319+ _class = "string"),
3320+ comment = "")
3321+ form[0][11].append(row)
3322+ states = S3LocationDropdownWidget(level="L1",
3323+ default="California",
3324+ empty=False)
3325+ widget = states(db.pr_address.location_id, None)
3326+ row = formstyle(id = "state",
3327+ label = LABEL("%s:" % T("State"),
3328+ SPAN(" *", _class="req"),
3329+ _for="location_id"),
3330+ widget = widget,
3331+ comment = "")
3332+ form[0][11].append(row)
3333+ if form.errors.zip:
3334+ zip_error = DIV(form.errors.zip,
3335+ _id="zip__error",
3336+ _class="error",
3337+ _style="display: block;")
3338+ else:
3339+ zip_error = ""
3340+ row = formstyle(id = "zip",
3341+ label = LABEL("%s:" % T("Zip"),
3342+ SPAN(" *", _class="req"),
3343+ _for="zip"
3344+ ),
3345+ widget = ( INPUT(_name="zip",
3346+ _id="zip",
3347+ _class="string"),
3348+ zip_error
3349+ ),
3350+ comment = "")
3351+ form[0][11].append(row)
3352+
3353+
3354+ #form[0][-2].append(TR(TD(LABEL(T("Terms of Service:"),
3355+ # _id="terms_of_service__label"),
3356+ # _class="w2p_fl"),
3357+ # TD(LABEL(TEXTAREA(deployment_settings.get_terms_of_service(),
3358+ # _onfocus="this.rows=10",
3359+ # _readonly="readonly",
3360+ # _style="width:100%;text-align:",
3361+ # _cols="80", _rows="10"),
3362+ # _id="terms_of_service"),
3363+ # _class="w2p_fw",
3364+ # _colspan="2"),
3365+ # _id="terms_of_service__row"))
3366+
3367+ # Eighteen
3368+ if form.errors.eighteen:
3369+ eighteen_error = DIV(form.errors.eighteen,
3370+ _id="eighteen__error",
3371+ _class="error",
3372+ _style="display: block;")
3373+ else:
3374+ eighteen_error = ""
3375+ label = LABEL(#"%s:" % T("I am 18 or over"),
3376+ T("I am 18 or over"),
3377+ SPAN(" *", _class="req"),
3378+ _for="eighteen",
3379+ _style="display: inline;",
3380+ _id="eighteen__label")
3381+ widget = INPUT(_type="checkbox",
3382+ _value="on",
3383+ _name="eighteen",
3384+ _id="eighteen",
3385+ _class="boolean")
3386+ #row = formstyle(id = "eighteen",
3387+ # label = label,
3388+ # widget = (widget,
3389+ # eighteen_error),
3390+ # comment = "")
3391+ row = TR(TD(widget, label, eighteen_error),
3392+ TD(),
3393+ _id="eighteen")
3394+ form[0][-2].append(row)
3395+
3396+ # US Citizen
3397+ if form.errors.citizen:
3398+ citizen_error = DIV(form.errors.citizen,
3399+ _id="citizen__error",
3400+ _class="error",
3401+ _style="display: block;")
3402+ else:
3403+ citizen_error = ""
3404+ label = LABEL(#"%s:" % T("I am a U.S. Citizen"),
3405+ T("I am a U.S. Citizen"),
3406+ SPAN(" *", _class="req"),
3407+ _for="citizen",
3408+ _style="display: inline;",
3409+ _id="citizen__label")
3410+ widget = INPUT(_type="checkbox",
3411+ _value="on",
3412+ _name="citizen",
3413+ _id="citizen",
3414+ _class="boolean")
3415+ #row = formstyle(id = "citizen",
3416+ # label = label,
3417+ # widget = (widget,
3418+ # citizen_error),
3419+ # comment = "")
3420+ row = TR(TD(widget, label, citizen_error),
3421+ TD(),
3422+ _id="citizen")
3423+ form[0][-2].append(row)
3424+
3425+ # Privacy Policy
3426+ row = formstyle(id = "",
3427+ label = "",
3428+ widget = DIV(XML(T("By clicking on 'I accept' below you are agreeing to the %(privacy_policy)s.") % \
3429+ dict(privacy_policy = A(T("Privacy Policy"),
3430+ _href = URL(c="default",
3431+ f="disclaimer#privacy"),
3432+ _target = "_blank"
3433+ )
3434+ )
3435+ ),
3436+ _style="width: 300px;",
3437+ ),
3438+ comment = "")
3439+ form[0][-2].append(row)
3440+
3441+ # Add client-side validation
3442+ # simplified copy of s3_register_validation()
3443+ script = "".join(( """
3444+var required = '""", str(T("This field is required.")), """';
3445+$('#regform').validate({
3446+ errorClass: 'req',
3447+ rules: {
3448+ first_name: {
3449+ required: true
3450+ },
3451+ last_name: {
3452+ required: true
3453+ },
3454+ phone: {
3455+ required: true
3456+ },
3457+ email: {
3458+ required: true,
3459+ email: true
3460+ },
3461+ address1: {
3462+ required: true
3463+ },
3464+ city: {
3465+ required: true
3466+ },
3467+ zip: {
3468+ required: true
3469+ },
3470+ password: {
3471+ required: true
3472+ },
3473+ password_two: {
3474+ required: true,
3475+ equalTo: '.password:first'
3476+ },
3477+ eighteen: {
3478+ required: true
3479+ },
3480+ citizen: {
3481+ required: true
3482+ }
3483+ },
3484+ messages: {
3485+ first_name: '""", str(T("Enter your firstname")), """',
3486+ last_name: required,
3487+ phone: required,
3488+ email: {
3489+ required: '""", str(T("Please enter a valid email address")), """',
3490+ minlength: '""", str(T("Please enter a valid email address")), """'
3491+ },
3492+ address1: required,
3493+ city: required,
3494+ zip: required,
3495+ password: {
3496+ required: '""", str(T("Provide a password")), """'
3497+ },
3498+ password_two: {
3499+ required: '""", str(T("Repeat your password")), """',
3500+ equalTo: '""", str(T("Enter the same password as above")), """'
3501+ },
3502+ 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.")), """',
3503+ 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.")), """',
3504+ },
3505+ errorPlacement: function(error, element) {
3506+ error.appendTo( element.parent().next() );
3507+ },
3508+ submitHandler: function(form) {
3509+ form.submit();
3510+ }
3511+});""" ))
3512+ response.s3.jquery_ready.append( script )
3513+
3514+ if session.s3.debug:
3515+ response.s3.scripts.append( "%s/jquery.validate.js" % s3_script_dir )
3516+ response.s3.scripts.append( "%s/jquery.pstrength.1.3.js" % s3_script_dir )
3517+ else:
3518+ response.s3.scripts.append( "%s/jquery.validate.min.js" % s3_script_dir )
3519+ response.s3.scripts.append( "%s/jquery.pstrength.1.3.min.js" % s3_script_dir )
3520+
3521+ response.s3.jquery_ready.append("$('.password:first').pstrength();\n")
3522+ response.s3.js_global.append("".join((
3523+ "S3.i18n.password_chars = '%s';\n" % T("The minimum number of characters is "),
3524+ "S3.i18n.very_weak = '%s';\n" % T("Very Weak"),
3525+ "S3.i18n.weak = '%s';\n" % T("Weak"),
3526+ "S3.i18n.medium = '%s';\n" % T("Medium"),
3527+ "S3.i18n.strong = '%s';\n" % T("Strong"),
3528+ "S3.i18n.very_strong = '%s';\n" % T("Very Strong"),
3529+ "S3.i18n.too_short = '%s';\n" % T("Too Short"),
3530+ "S3.i18n.unsafe_password = '%s';\n" % T("Unsafe Password Word!"),
3531+ )))
3532+
3533+ # Add sidebar for login box & other volunteering opportunities
3534+ vol_sidebar()
3535+
3536+ response.s3.donate_cash_link = True
3537+
3538+ response.title = T("Register")
3539+ response.s3.has_required = True
3540+
3541+ return dict(form=form)
3542+
3543+# -----------------------------------------------------------------------------
3544+def register_validation(form):
3545+ """ Validate the custom fields in registration form """
3546+ # Terms of Service
3547+ if "eighteen" not in request.post_vars or request.post_vars.eighteen != "on":
3548+ 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.")
3549+ if "citizen" not in request.post_vars or request.post_vars.citizen != "on":
3550+ 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.")
3551+ # Phone
3552+ if "phone" in request.post_vars and request.post_vars.phone:
3553+ regex = re.compile(single_phone_number_pattern)
3554+ if not regex.match(request.post_vars.phone):
3555+ form.errors.phone = T("Invalid phone number")
3556+ else:
3557+ form.errors.phone = T("Phone number is required")
3558+ # Address
3559+ if not request.post_vars.address1:
3560+ form.errors.address1 = T("Address is required")
3561+ if not request.post_vars.city:
3562+ form.errors.city = T("City is required")
3563+ if not request.post_vars.zip:
3564+ form.errors.zip = T("Zip is required")
3565+
3566+ return
3567+
3568+# -----------------------------------------------------------------------------
3569+def register_onaccept(form):
3570+ # Usual Registration Tasks
3571+ # (PR record, Authenticated Role, Contacts)
3572+ person = auth.s3_register(form)
3573+
3574+ # LA-specific
3575+ table = db.pr_person
3576+ query = (table.id == person)
3577+
3578+ db(query).update(volunteer=True,
3579+ middle_name=request.post_vars.middle_name)
3580+
3581+ pe = db(query).select(table.pe_id,
3582+ limitby=(0, 1)).first().pe_id
3583+
3584+ # Phone
3585+ table = db.pr_contact
3586+ phone = request.post_vars.phone
3587+ phone_type = request.post_vars.phone_type
3588+ # Don't auto-subscribe to SMS (priority 10)
3589+ table.insert(pe_id = pe,
3590+ contact_method = phone_type,
3591+ value = phone,
3592+ priority=10)
3593+
3594+ # Address
3595+ table = db.gis_location
3596+ address1 = request.post_vars.address1
3597+ address2 = request.post_vars.address2
3598+ if address2:
3599+ address = "%s\n%s" % (address1,
3600+ address2)
3601+ else:
3602+ address = address1
3603+ city = request.post_vars.city
3604+ location = request.post_vars.location_id
3605+ state = db(table.id == location).select(table.id,
3606+ table.name,
3607+ cache=gis.cache,
3608+ limitby=(0, 1)).first()
3609+ if state:
3610+ statename = state.name
3611+ else:
3612+ # Duff data - not USA
3613+ statename = "unknown"
3614+ zip = request.post_vars.zip
3615+ county = ""
3616+ if city:
3617+ query = (table.name == city) & \
3618+ (table.level == "L3") & \
3619+ (table.path.like("%%/%s/%%" % state))
3620+ _city = db(query).select(table.id,
3621+ table.parent,
3622+ limitby=(0, 1)).first()
3623+ if _city:
3624+ if _city.parent != state:
3625+ query = (table.id == _city.parent)
3626+ county = db(query).select(table.name,
3627+ limitby=(0, 1)).first().name
3628+ elif state:
3629+ _city = table.insert(name=city, level="L3", parent=state.id)
3630+ gis.update_location_tree(_city, state.id)
3631+ else:
3632+ usa = db(table.code == "US").select(table.id,
3633+ limitby=(0, 1)).first().id
3634+ _city = table.insert(name=city, level="L3", parent=usa)
3635+ gis.update_location_tree(_city, usa)
3636+ else:
3637+ _city = None
3638+ location = table.insert(addr_street=address, addr_postcode=zip, parent=_city)
3639+ gis.update_location_tree(location, _city)
3640+ s3mgr.load("pr_address")
3641+ table = db.pr_address
3642+ table.insert(pe_id = pe,
3643+ location_id = location,
3644+ address=address,
3645+ postcode=zip,
3646+ L3=city,
3647+ L2=county,
3648+ L1=statename,
3649+ L0="United States")
3650+
3651+# -----------------------------------------------------------------------------
3652+auth.settings.register_onvalidation = register_validation
3653+auth.settings.register_onaccept = register_onaccept
3654+auth.settings.register_next = URL(c="vol", f="skill", args=["create"])
3655+
3656+# Organisation widget for use in Registration Screen
3657+# NB User Profile is only editable by Admin - using User Management
3658+org_widget = IS_ONE_OF(db, "org_organisation.id",
3659+ organisation_represent,
3660+ orderby="org_organisation.name",
3661+ sort=True)
3662+if deployment_settings.get_auth_registration_organisation_mandatory():
3663+ _table_user.organisation_id.requires = org_widget
3664+else:
3665+ _table_user.organisation_id.requires = IS_NULL_OR(org_widget)
3666+
3667+# =============================================================================
3668+def profile():
3669+ """ Custom Profile Screen """
3670+
3671+ if not auth.is_logged_in():
3672+ redirect(URL(f="user", args="login"))
3673+ elif s3_has_role(ORG_VOL):
3674+ #return organisation_profile()
3675+ redirect(URL(f="organisation", args=[auth.user.organisation_id]))
3676+
3677+ # Only show admin-set fields if there is data
3678+ table = db.auth_user
3679+ if not auth.user.organisation_id:
3680+ # Not relevant to Volunteers
3681+ table.organisation_id.readable = False
3682+ if not auth.user.site_id:
3683+ # Only relevant to Field Staff
3684+ table.site_id.readable = False
3685+
3686+ # Validate the custom fields
3687+ auth.settings.profile_onvalidation = profile_validation
3688+
3689+ # Process the custom fields
3690+ auth.settings.profile_onaccept = profile_onaccept
3691+
3692+ auth.messages.profile_save_button = "Save"
3693+
3694+ request.args = ["profile"]
3695+ form = auth()
3696+
3697+ # Custom class for Submit Button
3698+ form[0][-1][1][0]["_class"] = "submit-button"
3699+
3700+ # Lookup the Person
3701+ id = auth.s3_logged_in_person()
3702+ table = db.pr_person
3703+ person = db(table.id == id).select(table.pe_id,
3704+ table.middle_name,
3705+ table.volunteer,
3706+ limitby=(0, 1)).first()
3707+
3708+ row = TR(TD(LABEL("%s:" % table.middle_name.label, _for="middle_name")),
3709+ TD(INPUT(_name="middle_name",
3710+ _id="middle_name",
3711+ _class="string",
3712+ _value=person.middle_name)))
3713+ form[0][0].append(row)
3714+
3715+ # Lookup the Contacts
3716+ table = db.pr_contact
3717+ query = (table.pe_id == person.pe_id) & \
3718+ (table.deleted == False)
3719+ contacts = db(query).select(table.contact_method,
3720+ table.value,
3721+ table.priority)
3722+ cell = ""
3723+ home = ""
3724+ work = ""
3725+ sms_enabled = False
3726+ email_enabled = True
3727+ for contact in contacts:
3728+ if contact.contact_method == "SMS":
3729+ cell = contact.value
3730+ if contact.priority == 10:
3731+ sms_enabled = False
3732+ else:
3733+ sms_enabled = True
3734+ elif contact.contact_method == "EMAIL":
3735+ if contact.priority == 10:
3736+ email_enabled = False
3737+ else:
3738+ email_enabled = True
3739+ elif contact.contact_method == "HOME_PHONE":
3740+ home = contact.value
3741+ elif contact.contact_method == "WORK_PHONE":
3742+ work = contact.value
3743+
3744+ # Cell phone
3745+ if form.errors.mobile:
3746+ cell_error = DIV(form.errors.mobile,
3747+ _id="mobile__error",
3748+ _class="error",
3749+ _style="display: block;")
3750+ else:
3751+ cell_error = ""
3752+ row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["SMS"], _for="mobile")),
3753+ TD(INPUT(_name="mobile",
3754+ _id="mobile",
3755+ _class="string",
3756+ _value=cell),
3757+ cell_error))
3758+ form[0][2].append(row)
3759+ # @ToDo: JS validation
3760+
3761+ if person.volunteer:
3762+ # Home phone
3763+ if form.errors.home_phone:
3764+ home_phone_error = DIV(form.errors.home_phone,
3765+ _id="home_phone__error",
3766+ _class="error",
3767+ _style="display: block;")
3768+ else:
3769+ home_phone_error = ""
3770+ row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["HOME_PHONE"], _for="home_phone")),
3771+ TD(INPUT(_name="home_phone",
3772+ _id="home_phone",
3773+ _class="string",
3774+ _value=home),
3775+ home_phone_error))
3776+ form[0][2].append(row)
3777+ # @ToDo: JS validation
3778+
3779+ # Work phone
3780+ if form.errors.work_phone:
3781+ work_phone_error = DIV(form.errors.work_phone,
3782+ _id="work_phone__error",
3783+ _class="error",
3784+ _style="display: block;")
3785+ else:
3786+ work_phone_error = ""
3787+ row = TR(TD(LABEL("%s:" % msg.CONTACT_OPTS["WORK_PHONE"], _for="work_phone")),
3788+ TD(INPUT(_name="work_phone",
3789+ _id="work_phone",
3790+ _class="string",
3791+ _value=work),
3792+ work_phone_error))
3793+ form[0][2].append(row)
3794+ # @ToDo: JS validation
3795+
3796+ # Lookup the Address
3797+ table = db.pr_address
3798+ query = (table.pe_id == person.pe_id) & \
3799+ (table.deleted == False)
3800+ address = db(query).select(table.location_id,
3801+ limitby=(0, 1)).first()
3802+ address1 = ""
3803+ address2 = ""
3804+ city = ""
3805+ state = ""
3806+ zip = ""
3807+ if address:
3808+ table = db.gis_location
3809+ query = (table.id == address.location_id)
3810+ location = db(query).select(table.id,
3811+ table.path,
3812+ table.parent,
3813+ table.addr_street,
3814+ table.addr_postcode,
3815+ limitby=(0, 1)).first()
3816+ if location:
3817+ try:
3818+ address1, address2 = location.addr_street.split("\n", 1)
3819+ except ValueError:
3820+ address1 = location.addr_street
3821+ zip = location.addr_postcode
3822+ results = gis.get_parent_per_level(None, location.id, location)
3823+ try:
3824+ city = results["L3"].name
3825+ #except KeyError, AttributeError:
3826+ except:
3827+ pass
3828+ try:
3829+ state = results["L1"].name
3830+ #except KeyError, AttributeError:
3831+ except:
3832+ pass
3833+
3834+ if form.errors.address1:
3835+ address1_error = DIV(form.errors.address1,
3836+ _id="address1__error",
3837+ _class="error",
3838+ _style="display: block;")
3839+ else:
3840+ address1_error = ""
3841+ row = TR(TD(LABEL("%s: " % T("Address 1"),
3842+ SPAN("*", _class="req"),
3843+ _for="address1")),
3844+ TD(INPUT(_name="address1",
3845+ _id="address1",
3846+ _class="string",
3847+ _value=address1),
3848+ address1_error))
3849+ form[0][2].append(row)
3850+ row = TR(TD(LABEL("%s:" % T("Address 2"), _for="address2")),
3851+ TD(INPUT(_name="address2",
3852+ _id="address2",
3853+ _class="string",
3854+ _value=address2)))
3855+ form[0][2].append(row)
3856+ row = TR(TD(LABEL("%s: " % T("City"),
3857+ SPAN("*", _class="req"),
3858+ _for="city")),
3859+ TD(INPUT(_name="city",
3860+ _id="city",
3861+ _class="string",
3862+ _value=city)))
3863+ form[0][2].append(row)
3864+ states = S3LocationDropdownWidget(level="L1",
3865+ default=state or "California",
3866+ empty=False)
3867+ widget = states(db.pr_address.location_id, None)
3868+ row = TR(TD(LABEL("%s:" % T("State"),
3869+ SPAN("*", _class="req"),
3870+ _for="location_id")),
3871+ TD(widget))
3872+ form[0][2].append(row)
3873+ if form.errors.zip:
3874+ zip_error = DIV(form.errors.zip,
3875+ _id="zip__error",
3876+ _class="error",
3877+ _style="display: block;")
3878+ else:
3879+ zip_error = ""
3880+ row = TR(TD(LABEL("%s:" % T("Zip"),
3881+ SPAN("*", _class="req"),
3882+ _for="zip")),
3883+ TD(INPUT(_name="zip",
3884+ _id="zip",
3885+ _class="string",
3886+ _value=zip),
3887+ zip_error))
3888+ form[0][2].append(row)
3889+
3890+ # Notifications
3891+ div = DIV(TR(TD(LABEL("%s:" % T("Notifications"))),
3892+ TD()
3893+ ),
3894+ TR(TD(T("Receive Notifications via Email?")),
3895+ TD(INPUT(_type="checkbox",
3896+ _value="on",
3897+ value="on" if email_enabled else "",
3898+ _name="sub_email",
3899+ _id="sub_email",
3900+ _alt=T("Receive Notifications via Email?"),
3901+ _class="boolean"))
3902+ ),
3903+ TR(TD(T("Receive Notifications via SMS?")),
3904+ TD(INPUT(_type="checkbox",
3905+ _value="on",
3906+ value="on" if sms_enabled else "",
3907+ _name="sub_sms",
3908+ _id="sub_sms",
3909+ _alt=T("Receive Notifications via SMS?"),
3910+ _class="boolean")),
3911+ TD(DIV(_class="tooltip",
3912+ _title="%s|%s" % (T("Receive Notifications via SMS"),
3913+ T("Note that this may incur costs from your carrier."))))
3914+ )
3915+ )
3916+ form[0][-2].append(div)
3917+
3918+ # Affiliated Orgs
3919+ s3mgr.load("vol_organisation")
3920+ table = db.vol_organisation
3921+ orgs = db(table.pe_id == person.pe_id).select(table.organisations_id,
3922+ limitby=(0, 1)).first()
3923+ if orgs:
3924+ orgs = orgs.organisations_id
3925+ table = db.org_organisation
3926+ if orgs:
3927+ _orgs = db(table.id.belongs(orgs)).select(table.name)
3928+ else:
3929+ _orgs = []
3930+ orgs = []
3931+ for org in _orgs:
3932+ orgs.append(org.name)
3933+ else:
3934+ orgs = []
3935+
3936+ div = DIV(TR(TD(),
3937+ TD(B(T("Affiliation with other volunteer organizations")))),
3938+ TR(TD(T("Are you affiliated with other volunteer organizations?"),
3939+ " (", DIV(T("Check all that apply"),
3940+ _style="display: inline;",
3941+ _class="red"),
3942+ ")",
3943+ _colspan=2)),
3944+ TR(TD("American Red Cross"),
3945+ TD(INPUT(_type="checkbox",
3946+ _value="on",
3947+ value="on" if "American Red Cross of Greater Los Angeles" in orgs else "",
3948+ _name="arc",
3949+ _id="arc",
3950+ _alt=T("American Red Cross"),
3951+ _class="boolean"))),
3952+ TR(TD("CERT"),
3953+ TD(INPUT(_type="checkbox",
3954+ _value="on",
3955+ value="on" if "CERT Los Angeles" in orgs else "",
3956+ _name="cert",
3957+ _id="cert",
3958+ _alt=T("CERT"),
3959+ _class="boolean"))),
3960+ TR(TD("Disaster Healthcare Volunteers"),
3961+ TD(INPUT(_type="checkbox",
3962+ _value="on",
3963+ value="on" if "Disaster Healthcare Volunteers" in orgs else "",
3964+ _name="dhv",
3965+ _id="dhv",
3966+ _alt=T("Disaster Healthcare Volunteers"),
3967+ _class="boolean"))),
3968+ TR(TD("L.A. Works"),
3969+ TD(INPUT(_type="checkbox",
3970+ _value="on",
3971+ value="on" if "LA Works" in orgs else "",
3972+ _name="laworks",
3973+ _id="laworks",
3974+ _alt=T("L.A. Works"),
3975+ _class="boolean"))),
3976+ TR(TD("Volunteer Center of Los Angeles"),
3977+ TD(INPUT(_type="checkbox",
3978+ _value="on",
3979+ value="on" if "Volunteer Center of Los Angeles" in orgs else "",
3980+ _name="vcla",
3981+ _id="vcla",
3982+ _alt=T("Volunteer Center of Los Angeles"),
3983+ _class="boolean"))),
3984+ )
3985+ form[0][-2].append(div)
3986+
3987+ # Skills
3988+ # - separate screen
3989+
3990+ response.title = T("Profile")
3991+ response.s3.has_required = True
3992+
3993+ return dict(form=form)
3994+
3995+# -----------------------------------------------------------------------------
3996+def profile_validation(form):
3997+ """ Validate the custom fields in profile form """
3998+
3999+ if s3_has_role(STAFF):
4000+ volunteer = False
4001+ else:
4002+ volunteer = True
4003+
4004+ # Mobile Phone
4005+ if "mobile" in request.post_vars and request.post_vars.mobile:
4006+ regex = re.compile(single_phone_number_pattern)
4007+ if not regex.match(request.post_vars.mobile):
4008+ form.errors.mobile = T("Invalid phone number")
4009+ elif "sub_sms" in request.post_vars and request.post_vars.sub_sms == "on":
4010+ form.errors.mobile = T("Cell phone number is required for SMS notifications")
4011+ # Home Phone
4012+ if "home_phone" in request.post_vars and request.post_vars.home_phone:
4013+ regex = re.compile(single_phone_number_pattern)
4014+ if not regex.match(request.post_vars.home_phone):
4015+ form.errors.home_phone = T("Invalid phone number")
4016+ # Work Phone
4017+ if "work_phone" in request.post_vars and request.post_vars.work_phone:
4018+ regex = re.compile(single_phone_number_pattern)
4019+ if not regex.match(request.post_vars.work_phone):
4020+ form.errors.work_phone = T("Invalid phone number")
4021+ # Address
4022+ if volunteer and not request.post_vars.address1:
4023+ form.errors.address1 = T("Address is required")
4024+ if volunteer and not request.post_vars.zip:
4025+ form.errors.zip = T("Zip is required")
4026+
4027+ return
4028+
4029+# -----------------------------------------------------------------------------
4030+def profile_onaccept(form):
4031+ """ Process the custom fields """
4032+
4033+ if s3_has_role(STAFF):
4034+ volunteer = False
4035+ else:
4036+ volunteer = True
4037+
4038+ table = db.pr_person
4039+ query = (table.id == auth.s3_logged_in_person())
4040+ db(query).update(middle_name=request.post_vars.middle_name)
4041+ pe = db(query).select(table.pe_id,
4042+ limitby=(0, 1)).first().pe_id
4043+
4044+ if volunteer:
4045+ # Contacts / Notifications
4046+ if "sub_email" in request.post_vars and \
4047+ request.post_vars.sub_email == "on":
4048+ email_enabled = True
4049+ else:
4050+ email_enabled = False
4051+ if "sub_sms" in request.post_vars and \
4052+ request.post_vars.sub_sms == "on":
4053+ sms_enabled = True
4054+ else:
4055+ sms_enabled = False
4056+ home_phone = request.post_vars.home_phone
4057+ work_phone = request.post_vars.work_phone
4058+ email = request.post_vars.email
4059+ cell = request.post_vars.mobile
4060+ table = db.pr_contact
4061+ if email:
4062+ utable = db.auth_user
4063+ query = (utable.id == auth.user.id)
4064+ _email = db(query).select(utable.email,
4065+ limitby=(0, 1)).first().email
4066+ if not _email == email:
4067+ # Email has changed
4068+ # Check that the new email doesn't clash
4069+ query2 = (utable.email == email)
4070+ test = db(query2).select(utable.id,
4071+ limitby=(0, 1)).first()
4072+ if not test:
4073+ # update auth_user
4074+ db(query).update(email=email)
4075+ # update pr_contact
4076+ query = (table.value == _email)
4077+ if volunteer:
4078+ priority = 1 if email_enabled else 10
4079+ db(query).update(value=email, priority=priority)
4080+ else:
4081+ db(query).update(value=email)
4082+ else:
4083+ # Existing .requires validation prevents the user from reusing
4084+ # an existing email
4085+ pass
4086+ elif volunteer:
4087+ # Just update the notifications
4088+ query = (table.value == email)
4089+ priority = 1 if email_enabled else 10
4090+ db(query).update(priority=priority)
4091+
4092+ _cell = ""
4093+ _home_phone = ""
4094+ _work_phone = ""
4095+ query = (table.pe_id == pe) & \
4096+ (table.deleted == False)
4097+ contacts = db(query).select(table.contact_method,
4098+ table.value)
4099+ for contact in contacts:
4100+ if contact.contact_method == "SMS":
4101+ _cell = contact.value
4102+ elif contact.contact_method == "HOME_PHONE":
4103+ _home_phone = contact.value
4104+ elif contact.contact_method == "WORK_PHONE":
4105+ _work_phone = contact.value
4106+ table = db.pr_contact
4107+ base_query = (table.pe_id == pe)
4108+ if volunteer:
4109+ priority = 1 if sms_enabled else 10
4110+ if _cell:
4111+ # Update existing record
4112+ query = base_query & (table.value == _cell)
4113+ db(query).update(value=cell, priority=priority)
4114+ elif cell:
4115+ # Insert new record
4116+ table.insert(pe_id=pe, contact_method="SMS", value=cell,
4117+ priority=priority)
4118+ if _home_phone:
4119+ # Update existing record
4120+ query = base_query & (table.value == _home_phone)
4121+ db(query).update(value=home_phone)
4122+ elif home_phone:
4123+ # Insert new record
4124+ table.insert(pe_id=pe, contact_method="HOME_PHONE",
4125+ value=home_phone)
4126+
4127+ if _work_phone:
4128+ # Update existing record
4129+ query = base_query & (table.value == _work_phone)
4130+ db(query).update(value=work_phone)
4131+ elif work_phone:
4132+ # Insert new record
4133+ table.insert(pe_id=pe, contact_method="WORK_PHONE",
4134+ value=work_phone)
4135+
4136+ # Address
4137+ address1 = request.post_vars.address1
4138+ address2 = request.post_vars.address2
4139+ if address2:
4140+ address = "%s\n%s" % (address1, address2)
4141+ else:
4142+ address = address1
4143+ zip = request.post_vars.zip
4144+ city = request.post_vars.city
4145+ state = request.post_vars.location_id
4146+ table = db.gis_location
4147+ statename = db(table.id == state).select(table.name,
4148+ cache=gis.cache,
4149+ limitby=(0, 1)).first().name
4150+ county = ""
4151+ if city:
4152+ query = (table.name == city) & \
4153+ (table.level == "L3") & \
4154+ (table.path.like("%%/%s/%%" % state))
4155+ _city = db(query).select(table.id,
4156+ table.parent,
4157+ limitby=(0, 1)).first()
4158+ if _city:
4159+ if _city.parent != state:
4160+ query = (table.id == _city.parent)
4161+ county = db(query).select(table.name,
4162+ limitby=(0, 1)).first().name
4163+ else:
4164+ _city = table.insert(name=city, level="L3", parent=state)
4165+ gis.update_location_tree(_city, state)
4166+ else:
4167+ _city = None
4168+ table = db.pr_address
4169+ query = (table.pe_id == pe) & \
4170+ (table.deleted == False)
4171+ test = db(query).select(table.location_id,
4172+ limitby=(0, 1)).first()
4173+ if test:
4174+ db(query).update(address=address,
4175+ postcode=zip,
4176+ L3=city,
4177+ L2=county,
4178+ L1=statename,
4179+ L0="United States")
4180+ table = db.gis_location
4181+ location = test.location_id
4182+ query = (table.id == location)
4183+ db(query).update(addr_street=address,
4184+ addr_postcode=zip,
4185+ parent=_city)
4186+ gis.update_location_tree(location, _city)
4187+
4188+ # Affiliated Organisations
4189+ # Also in models/vol.py
4190+ vol_orgs = ["American Red Cross of Greater Los Angeles",
4191+ "CERT Los Angeles",
4192+ "Disaster Healthcare Volunteers",
4193+ "LA Works",
4194+ "Volunteer Center of Los Angeles"]
4195+ table = db.org_organisation
4196+ query = (table.name.belongs(vol_orgs))
4197+ orgs = db(query).select(table.id,
4198+ table.name,
4199+ cache=(cache.ram, 60))
4200+ for org in orgs:
4201+ if org.name == "American Red Cross of Greater Los Angeles":
4202+ ARC = org.id
4203+ elif org.name == "CERT Los Angeles":
4204+ CERT = org.id
4205+ elif org.name == "Disaster Healthcare Volunteers":
4206+ DHV = org.id
4207+ elif org.name == "LA Works":
4208+ LAW = org.id
4209+ elif org.name == "Volunteer Center of Los Angeles":
4210+ VCLA = org.id
4211+ orgs = []
4212+ if "arc" in request.post_vars and request.post_vars.arc == "on":
4213+ orgs.append(ARC)
4214+ if "cert" in request.post_vars and request.post_vars.cert == "on":
4215+ orgs.append(CERT)
4216+ if "dhv" in request.post_vars and request.post_vars.dhv == "on":
4217+ orgs.append(DHV)
4218+ if "laworks" in request.post_vars and \
4219+ request.post_vars.laworks == "on":
4220+ orgs.append(LAW)
4221+ if "vcla" in request.post_vars and request.post_vars.vcla == "on":
4222+ orgs.append(VCLA)
4223+ s3mgr.load("vol_organisation")
4224+ table = db.vol_organisation
4225+ query = (table.pe_id == pe)
4226+ test = db(query).select(table.id,
4227+ limitby=(0, 1)).first()
4228+ if test:
4229+ db(query).update(organisations_id = orgs)
4230+ else:
4231+ table.insert(pe_id = pe,
4232+ organisations_id = orgs,
4233+ owned_by_user = auth.user.id)
4234+
4235+ else:
4236+ # Not a volunteer: EOC staff
4237+ if _cell:
4238+ # Update existing record
4239+ query = base_query & (table.value == _cell)
4240+ db(query).update(value=cell)
4241+ elif cell:
4242+ # Insert new record
4243+ table.insert(pe_id=pe, contact_method="SMS", value=cell)
4244+
4245+# -----------------------------------------------------------------------------
4246+# Skills
4247+# -----------------------------------------------------------------------------
4248+def skill():
4249+ """
4250+ Collect a Volunteer's Skills
4251+ """
4252+
4253+ tablename = "vol_skill"
4254+ s3mgr.load(tablename)
4255+ table = db[tablename]
4256+
4257+ person = auth.s3_logged_in_person()
4258+ table.person_id.default = person
4259+ table.person_id.writable = table.person_id.readable = False
4260+
4261+ s3mgr.configure(tablename,
4262+ # Workflow: Prompt for creating Emergency Contacts after adding Skills
4263+ create_next = URL(f="contact", args=["my"]),
4264+ update_next = URL(f="skill", args=["my"]),
4265+ deletable = False,
4266+ listadd = False)
4267+
4268+ # Parse the request
4269+ if "my" in request.args:
4270+ query = (table.person_id == person)
4271+ record = db(query).select(table.id,
4272+ limitby=(0, 1),
4273+ cache = gis.cache).first()
4274+ if record:
4275+ r = s3mgr.parse_request(args=[str(record.id)])
4276+ else:
4277+ r = s3mgr.parse_request(args=["create"])
4278+ else:
4279+ r = s3mgr.parse_request()
4280+
4281+ # Execute the request
4282+ output = r()
4283+
4284+ response.title = T("My Skills")
4285+ return output
4286+
4287+# -----------------------------------------------------------------------------
4288+# Contacts
4289+# -----------------------------------------------------------------------------
4290+def contact():
4291+ """
4292+ Emergency Contacts for the volunteer
4293+ """
4294+
4295+ tablename = "vol_contact"
4296+ s3mgr.load(tablename)
4297+ table = db[tablename]
4298+
4299+ person = auth.s3_logged_in_person()
4300+ table.person_id.default = person
4301+ table.person_id.writable = table.person_id.readable = False
4302+
4303+ s3mgr.configure(tablename,
4304+ create_next = URL(f="req_skill"),
4305+ update_next = URL(f="contact", args=["my"]),
4306+ deletable = False,
4307+ listadd = False)
4308+
4309+ # Parse the request
4310+ if "my" in request.args:
4311+ query = (table.person_id == person)
4312+ record = db(query).select(table.id,
4313+ limitby=(0, 1)).first()
4314+ if record:
4315+ r = s3mgr.parse_request(args=[str(record.id)])
4316+ else:
4317+ r = s3mgr.parse_request(args=["create"])
4318+ else:
4319+ r = s3mgr.parse_request()
4320+
4321+ # Execute the request
4322+ output = r()
4323+
4324+ response.title = T("Emergency Contact")
4325+ return output
4326+
4327+# -----------------------------------------------------------------------------
4328+# Assignments
4329+# - My Assignments menu
4330+# -----------------------------------------------------------------------------
4331+def assignment():
4332+
4333+ """ Allow a Volunteer/Org to View the details of their own assignments """
4334+
4335+ tablename = "vol_assignment"
4336+ s3mgr.load(tablename)
4337+ table = db[tablename]
4338+
4339+ if auth.user.organisation_id:
4340+ response.s3.filter = (table.organisation_id == auth.user.organisation_id)
4341+ # Control List View
4342+ table.person_id.readable = False
4343+ table.number.readable = True
4344+ table.number.label = T("Number of Volunteers Committed")
4345+ else:
4346+ my_person_id = s3_logged_in_person()
4347+ # Control List View
4348+ table.person_id.readable = False
4349+
4350+ if not my_person_id:
4351+ session.error = T("No person record found for current user.")
4352+ redirect(URL(f="index"))
4353+
4354+ response.s3.filter = (table.person_id == my_person_id)
4355+
4356+ # Filter for current/past assignments
4357+ sel = ((table.checkout == None) |
4358+ (table.checkout >= request.utcnow) |
4359+ (table.task_evaluation == None))
4360+ s3.crud_strings[tablename].update(
4361+ subtitle_list = T("Current Assignments"))
4362+ if "show" in request.get_vars:
4363+ show = request.get_vars["show"]
4364+ if show == "past":
4365+ sel = ((table.checkout < request.utcnow) &
4366+ (table.task_evaluation != None))
4367+ s3.crud_strings[tablename].update(
4368+ subtitle_list = T("Past Assignments"),
4369+ msg_no_match = T("No past assignments"))
4370+ response.s3.filter &= sel
4371+
4372+ # Post-process
4373+ def postp(r, output):
4374+ if r.interactive:
4375+ response.s3.actions = [dict(
4376+ url = URL(c = "vol",
4377+ f = "req",
4378+ args = ["assignment", "[id]"]),
4379+ _class = "action-btn",
4380+ label = str(T("Details"))
4381+ )]
4382+ if "show" in request.get_vars and request.get_vars["show"] == "past":
4383+ response.s3.actions += [dict(
4384+ url = URL(c=request.controller,
4385+ f="req",
4386+ args=["assignment",
4387+ "[id]",
4388+ "print"]),
4389+ _class = "action-btn",
4390+ label = str(T("Certificate"))
4391+ )]
4392+
4393+ return output
4394+ response.s3.postp = postp
4395+
4396+ output = s3_rest_controller("vol", "assignment")
4397+ return output
4398+
4399+# -----------------------------------------------------------------------------
4400+# Requests
4401+# -----------------------------------------------------------------------------
4402+def vol_req_rheader(r):
4403+ """
4404+ Resource Header for Requests
4405+ - Volunteer view
4406+ - inc Volunteer Roster
4407+ """
4408+
4409+ if r.representation == "html":
4410+ if r.name == "req":
4411+ record = r.record
4412+ if record:
4413+ if s3_has_role(STAFF):
4414+ # Show Tabs on Roster
4415+ tabs = [(T("Details"), None)]
4416+ if record.type == 3 and deployment_settings.has_module("hrm"):
4417+ tabs.append((T("Requested Volunteers"), "req_skill"))
4418+ if deployment_settings.has_module("doc"):
4419+ tabs.append((T("Documents"), "document"))
4420+ #if deployment_settings.get_req_use_commit():
4421+ # tabs.append((T("Commitments"), "commit"))
4422+ tabs.append((T("Roster"), "assignment"))
4423+ try:
4424+ # Remove the default_type from URLs as set within respective controller
4425+ r.vars.pop("default_type")
4426+ except KeyError:
4427+ pass
4428+ rheader_tabs = s3_rheader_tabs(r, tabs)
4429+ elif not r.component:
4430+ # Volunteers should only ever access Requests via the Components
4431+ return
4432+
4433+ table = db.req_req_skill
4434+ query = (table.req_id == record.id)
4435+ srecord = db(query).select(table.skill_id,
4436+ table.quantity,
4437+ table.quantity_commit,
4438+ limitby=(0, 1)).first()
4439+ if srecord:
4440+ skills = response.s3.hrm_multi_skill_represent(srecord.skill_id)
4441+ requested = srecord.quantity
4442+ required = srecord.quantity - srecord.quantity_commit
4443+ else:
4444+ skills = requested = required = ""
4445+
4446+ address = shn_site_represent(record.site_id, address=True)
4447+ #table = db.org_office
4448+ #query = (table.id == record.site_id)
4449+ #srecord = db(query).select(table.name,
4450+ # table.address,
4451+ # table.postcode,
4452+ # table.L3,
4453+ # table.L1,
4454+ # limitby=(0, 1)).first()
4455+ #if srecord:
4456+ # location = T("%(site)s in %(location)s") % dict(site = srecord.name,
4457+ # location = record.location)
4458+ # ltable = db.gis_location
4459+ # query = (ltable.name == srecord.L1)
4460+ # state = db(query).select(ltable.code,
4461+ # limitby=(0, 1),
4462+ # cache=gis.cache).first()
4463+ # if state:
4464+ # statecode = state.code
4465+ # else:
4466+ # # Not valid US data (e.g. prepopulate)
4467+ # statecode = None
4468+ # address = "%s, %s %s %s" % (srecord.address,
4469+ # srecord.L3,
4470+ # statecode,
4471+ # srecord.postcode)
4472+ #else:
4473+ # location = address = ""
4474+
4475+ table = db.hrm_human_resource
4476+ query = (table.id == record.request_for_id)
4477+ person = db(query).select(table.person_id,
4478+ limitby=(0, 1)).first()
4479+ phone = email = report_to = ""
4480+ if person:
4481+ report_to = person_represent(person.person_id)
4482+
4483+ ptable = db.pr_person
4484+ ctable = db.pr_contact
4485+ query = (ptable.id == person.person_id) & \
4486+ (ctable.pe_id == ptable.pe_id)
4487+ contacts = db(query).select(ctable.contact_method,
4488+ ctable.value)
4489+ for contact in contacts:
4490+ if contact.contact_method == "SMS":
4491+ phone = contact.value
4492+ elif contact.contact_method == "EMAIL":
4493+ email = contact.value
4494+
4495+ if s3_has_role(STAFF):
4496+ subtitle = T("Request Details")
4497+ buttons = DIV(
4498+ BUTTON(T("PRINT ROSTER"),
4499+ _class="wide-grey-button",
4500+ _onClick="javascript: window.location='%s'" % \
4501+ URL(c=request.controller,
4502+ f="req",
4503+ args=[record.id,
4504+ "assignment",
4505+ "print"])),
4506+ BUTTON(T("CANCEL REQUEST"),
4507+ _class="wide-grey-button",
4508+ _onClick="javascript: window.location='%s'" % \
4509+ URL(c=request.controller,
4510+ f="req",
4511+ args=[record.id,
4512+ "cancel"]))
4513+ )
4514+ textbox = ""
4515+ else:
4516+ subtitle = T("Volunteer Assignment Details")
4517+ buttons = ""
4518+ if r.component.name == "application":
4519+ 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."))
4520+ else:
4521+ give2la_forms = A( T("Give2LA Registration Forms"),
4522+ _href = URL(c="static",
4523+ f="Volunteer_Ethics_and_Conduct.pdf"),
4524+ _target="_blank"
4525+ )
4526+ 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.")),
4527+ 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.") %
4528+ dict(give2la_forms = give2la_forms) )),
4529+ P(T("Please let us know in advance if you cannot report for your Volunteer Assignment by calling the Point of Contact listed above.")),
4530+ )
4531+
4532+ if record.date_required:
4533+ time_req = s3_time_represent(record.date_required,
4534+ utc=True)
4535+ else:
4536+ time_req = ""
4537+ if record.date_required_until:
4538+ time_until = s3_time_represent(record.date_required_until,
4539+ utc=True)
4540+ else:
4541+ time_until = ""
4542+
4543+ class DL(DIV):
4544+ tag = 'dl'
4545+
4546+ class DT(DIV):
4547+ tag = 'dt'
4548+
4549+ class DD(DIV):
4550+ tag = 'dd'
4551+
4552+ rheader = DIV(
4553+ textbox,
4554+ H2(subtitle, _class="paper-strip"),
4555+ buttons,
4556+ DIV(
4557+ TABLE(
4558+ TR(
4559+ TH(T("Request Number")),
4560+ TH(T("Task")),
4561+ TH(T("Date+Time")),
4562+ TH(T("Required Skills")),
4563+ TH(T("Request Priority")),
4564+ TH(T("Location")),
4565+ TH(T("Number of Volunteers"),BR(),DIV("(", T("Still Required"), "/", T("Total Requested"), ")")), # (assigned/required)
4566+ _class="odd"
4567+ ),
4568+ TR(
4569+ TD(record.request_number),
4570+ TD(record.purpose),
4571+ TD(B(s3_date_represent_utc(record.date_required)),
4572+ BR(),
4573+ "%s - %s" % (time_req,
4574+ time_until),
4575+ ),
4576+ TD(skills),
4577+ TD(response.s3.req_priority_represent(record.priority) ),
4578+ TD(record.location or ""),
4579+ TD(B(required),
4580+ " / %s" % requested,
4581+ _class="red"),
4582+ _class="even"
4583+ ),
4584+ _class="datatable display"
4585+ ),
4586+ _id="table-container"
4587+ ),
4588+ DL(
4589+ DT(T("Point of Contact")),
4590+ DD(report_to,
4591+ BR(),
4592+ "%s: %s" % (T("Phone"),
4593+ phone),
4594+ BR(),
4595+ "%s: %s" % (T("Email"),
4596+ email),
4597+ ),
4598+ DT(T("Volunteering Location")),
4599+ DD(#location,
4600+ #BR(),
4601+ address),
4602+ DT(T("Comments")),
4603+ DD(record.comments),
4604+ _class="assignment-details"
4605+ ),
4606+ )
4607+ if r.component and r.component.name == "assignment":
4608+ if s3_has_role(STAFF):
4609+ # Volunteer Roster
4610+ response.s3.rfooter = DIV(
4611+ BUTTON(T("CHECK-IN ALL"),
4612+ _class="wide-grey-button",
4613+ _onClick="javascript: window.location='%s'" % \
4614+ URL(c=request.controller,
4615+ f="req",
4616+ args=[record.id,
4617+ "assignment",
4618+ "checkin"])),
4619+ BUTTON(T("CHECK-OUT ALL"),
4620+ _class="wide-grey-button",
4621+ _onClick="javascript: window.location='%s'" % \
4622+ URL(c=request.controller,
4623+ f="req",
4624+ args=[record.id,
4625+ "assignment",
4626+ "checkout"]))
4627+ )
4628+ else:
4629+ # Volunteer Assignment
4630+ assignment = r.component_id
4631+ table = db.vol_assignment
4632+ query = table.id == r.component_id
4633+ record = db(query).select(limitby=(0, 1)).first()
4634+ if not record:
4635+ # Probably a Volunteer trying to use a URL for STAFF
4636+ session.error = auth.permission.INSUFFICIENT_PRIVILEGES
4637+ redirect(URL(c="vol", f="req_skill"))
4638+ req_id = record.req_id
4639+ if record.checkout != None and record.task_evaluation != None:
4640+ printBtn = T("PRINT CERTIFICATE")
4641+ else:
4642+ printBtn = T("PRINT VOLUNTEER ASSIGNMENT FORM")
4643+ if record.checkin:
4644+ cancelBtn = ""
4645+ else:
4646+ # Only show the Cancel button if Volunteer not yet checked-in
4647+ cancelBtn = BUTTON(T("CANCEL ASSIGNMENT"),
4648+ _class="wide-grey-button",
4649+ _onClick="javascript: window.location='%s'" % \
4650+ URL(c=request.controller,
4651+ f="req",
4652+ args=[record.req_id,
4653+ "assignment",
4654+ assignment,
4655+ "delete"]))
4656+
4657+ rheader.append(
4658+ DIV(
4659+ A(SPAN(printBtn),
4660+ _class="big-red-arrow",
4661+ _onClick="javascript: window.location='%s'" % \
4662+ URL(c=request.controller,
4663+ f="req",
4664+ args=["assignment",
4665+ assignment,
4666+ "print"])),
4667+ # Also in controllers/don.py - DRY
4668+ A(IMG(_src="/%s/static/img/get_adobe_reader.png" % request.application,
4669+ _title="%s - %s" % (T("Get Adobe Reader"),
4670+ T("This link will open a new browser window.")),
4671+ _alt=T("Get Adobe Reader"),
4672+ _width=158,
4673+ _height=39,
4674+ _style="float:right;"),
4675+ _href="http://www.adobe.com/products/acrobat/readstep2.html",
4676+ _target="_blank"),
4677+ BR(),
4678+ cancelBtn
4679+ )
4680+ )
4681+ if s3_has_role(STAFF):
4682+ rheader.append(rheader_tabs)
4683+
4684+ return rheader
4685+ return None
4686+
4687+# -----------------------------------------------------------------------------
4688+def req():
4689+ """ REST Controller """
4690+
4691+ s3mgr.load("req_req")
4692+ default_type = 3
4693+ request.vars["default_type"] = 3
4694+
4695+ if "skill_id" in request.get_vars:
4696+ # Look up the Request from the Skill component
4697+ # (since that is what is available to us within the dataTables row)
4698+ table = db.req_req_skill
4699+ query = (table.id == request.vars.skill_id)
4700+ req = db(query).select(table.req_id,
4701+ limitby=(0, 1)).first()
4702+ if not req:
4703+ session.error = T("Invalid Request!")
4704+ redirect(URL(f="req_skill", args=[], vars={}))
4705+ # @ToDo: A nicer way to do this (without a 2nd request)
4706+ # simply amending request.args doesn't work
4707+ # Need to rewrite to not use prep/postp but rather process r() directly
4708+ redirect(URL(args = [req.req_id, "application", "create"],
4709+ vars={}))
4710+
4711+ if "document" in request.args:
4712+ s3mgr.load("doc_document")
4713+
4714+ req_table = db.req_req
4715+ s3mgr.configure(req_table,
4716+ orderby=~req_table.priority)
4717+
4718+ type_field = req_table.type
4719+ type_field.default = int(default_type)
4720+ type_field.writable = False
4721+
4722+ if s3_has_role(STAFF):
4723+ if "assignment" in request.args or \
4724+ "checkin" in request.args or \
4725+ "checkout" in request.args:
4726+ s3mgr.load("vol_assignment")
4727+
4728+ elif s3_has_role(ORG_VOL):
4729+ s3mgr.load("vol_application")
4730+ # Volunteer Orgs can see Public Requests & those published for them
4731+ org = auth.user.organisation_id
4732+ response.s3.filter = (req_table.public == True) | \
4733+ (req_table.organisations_id.belongs((org,)))
4734+ s3mgr.configure(req_table,
4735+ editable=False), # We need the Controller/Table ACL to be editable to be able to add components
4736+ if "application" in request.args:
4737+ s3.crud.submit_button = T("COMMIT")
4738+ table = db.vol_application
4739+ table.organisation_id.default = org
4740+ table.organisation_id.readable = table.organisation_id.writable = False
4741+ table.number.readable = table.number.writable = True
4742+ table.person_id.readable = table.person_id.writable = False
4743+ field = table.team_leader_id
4744+ field.readable = field.writable = True
4745+ field.requires = IS_NOT_EMPTY()
4746+ #table.person_id.label = T("Team Leader")
4747+ #table.person_id.comment = None
4748+ #table.person_id.widget = S3AddPersonWidget(
4749+ # #select_existing=False
4750+ # )
4751+ #table.person_id.requires = IS_ADD_PERSON_WIDGET()
4752+ #field = table.team_leader
4753+ #field.readable = field.writable = True
4754+ #field.requires = IS_NOT_EMPTY()
4755+ #field = table.team_leader_contact
4756+ #field.readable = field.writable = True
4757+ #field.requires = IS_NOT_EMPTY()
4758+ table.emergency_contact_name.readable = table.emergency_contact_name.writable = False
4759+ table.emergency_contact_name.requires = []
4760+ table.emergency_contact_relationship.readable = table.emergency_contact_relationship.writable = False
4761+ table.emergency_contact_relationship.requires = []
4762+ table.emergency_contact_phone.readable = table.emergency_contact_phone.writable = False
4763+ table.emergency_contact_phone.requires = []
4764+ s3.crud_strings["vol_application"].subtitle_create = ""
4765+
4766+ elif "assignment" in request.args:
4767+ table = db.vol_assignment
4768+ table.organisation_id.default = org
4769+ table.organisation_id.readable = table.organisation_id.writable = False
4770+ table.person_id.readable = table.person_id.writable = False
4771+ # Make the component multiple=False
4772+ s3mgr.model.add_component("vol_assignment",
4773+ req_req=dict(joinby="req_id",
4774+ multiple=False))
4775+ else:
4776+ s3mgr.load("vol_application")
4777+ # Volunteers can only see Public Requests
4778+ response.s3.filter = (req_table.public == True)
4779+ s3mgr.configure(req_table,
4780+ editable=False), # We need the Controller/Table ACL to be editable to be able to add components
4781+ person = s3_logged_in_person()
4782+ if "application" in request.args:
4783+ # Check for required Skills
4784+ table = db.req_req_skill
4785+ query = (table.req_id == request.args[0])
4786+ req = db(query).select(table.skill_id,
4787+ limitby=(0, 1)).first()
4788+ if req and req.skill_id:
4789+ # Read the applicant's skills
4790+ table = db.vol_skill
4791+ query = (table.person_id == auth.s3_logged_in_person())
4792+ skillset = db(query).select(table.skill_id,
4793+ limitby=(0, 1)).first()
4794+ gap = False
4795+ if not skillset:
4796+ gap = True
4797+ else:
4798+ for skill in req.skill_id:
4799+ if not skill in skillset.skill_id:
4800+ gap = True
4801+ break
4802+ if gap:
4803+ 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.")
4804+
4805+ s3.crud.submit_button = T("COMMIT")
4806+ table = db.vol_application
4807+ table.person_id.default = person
4808+ table.person_id.readable = table.person_id.writable = False
4809+ s3.crud_strings["vol_application"].subtitle_create = ""
4810+ # Read in current Emergency Contacts
4811+ ctable = db.vol_contact
4812+ query = (ctable.person_id == person)
4813+ contacts = db(query).select(limitby=(0, 1)).first()
4814+ if contacts:
4815+ table.emergency_contact_name.default = contacts.emergency_contact_name
4816+ table.emergency_contact_relationship.default = contacts.emergency_contact_relationship
4817+ table.emergency_contact_phone.default = contacts.emergency_contact_phone
4818+
4819+ elif "assignment" in request.args:
4820+ table = db.vol_assignment
4821+ table.person_id.default = person
4822+ table.person_id.readable = table.person_id.writable = False
4823+ # Make the component multiple=False
4824+ # @ToDo: Currently multiple=False will just return the .first() record even if inaccessible!
4825+ # That would be fixed by a filter, however then UI would break.
4826+ s3mgr.model.add_component("vol_assignment",
4827+ req_req=dict(joinby="req_id",
4828+ multiple=False))
4829+
4830+ def prep(r):
4831+ db.req_req.status.readable = db.req_req.status.writable = False
4832+
4833+ # Remove type from list_fields
4834+ list_fields = s3mgr.model.get_config("req_req",
4835+ "list_fields")
4836+ try:
4837+ list_fields.remove("type")
4838+ except:
4839+ # It has already been removed.
4840+ # This can happen if the req controller is called
4841+ # for a second time, such as when printing reports
4842+ # see vol.print_assignment()
4843+ pass
4844+ s3mgr.configure(tablename, list_fields=list_fields)
4845+
4846+ # @ToDo: MH - type is always 3
4847+ type = ( r.record and r.record.type ) or \
4848+ ( request.vars and request.vars.default_type )
4849+ if type:
4850+ type = int(type)
4851+ req_table.type.default = int(type)
4852+
4853+ # Filter the query based on type
4854+ if response.s3.filter:
4855+ response.s3.filter = response.s3.filter & \
4856+ (db.req_req.type == type)
4857+ else:
4858+ response.s3.filter = (db.req_req.type == type)
4859+
4860+ #if type == 3:
4861+ s3mgr.configure("req_req",
4862+ list_fields = ["id",
4863+ "priority",
4864+ "event_id",
4865+ "purpose",
4866+ "site_id",
4867+ "date_required",
4868+ ])
4869+
4870+ if r.interactive:
4871+ # Set Fields and Labels depending on type
4872+ # @ToDo: MH - type is always 3
4873+ if type:
4874+ # This prevents the type from being edited AFTER it is set
4875+ req_table.type.readable = False
4876+ req_table.type.writable = False
4877+
4878+ # @ToDo: MH - refer to crud strings here - rather than in deployment_settings
4879+ crud_strings = deployment_settings.get_req_req_crud_strings(type)
4880+ if crud_strings:
4881+ s3.crud_strings["req_req"] = crud_strings
4882+
4883+ if "application" in request.args:
4884+ s3.crud_strings["req_req"].title_display = T("Volunteer Application")
4885+ elif "assignment" in request.args:
4886+ if s3_has_role(STAFF) and not r.component_id:
4887+ s3.crud_strings["req_req"].title_display = T("Volunteer Roster")
4888+ else:
4889+ s3.crud_strings["req_req"].title_display = T("Volunteer Assignment")
4890+ atable = db.vol_assignment
4891+ # @ToDo: Hide if vol hasn't yet checked-out or if time not > time_until
4892+ #atable.task_evaluation.readable = False
4893+
4894+
4895+ if r.method != "create" and False: # @ToDo: Remove "and False" - this has been added for training to allow records to be edit
4896+ # Disable Edit for fields where WebEOC is Master
4897+ req_table.event_id.writable = False
4898+ req_table.incident_id.writable = False
4899+ #req_table.incident_id.writable = True
4900+ req_table.request_number.writable = False
4901+ req_table.priority.writable = False
4902+ req_table.site_id.writable = False
4903+ req_table.request_for_id.writable = False
4904+ req_table.date_required.writable = False
4905+ req_table.date_required_until.writable = False
4906+ req_table.purpose.writable = False
4907+ req_table.date.writable = False
4908+ req_table.requester_id.writable = False
4909+ req_table.approved_by_id.writable = False
4910+ req_table.comments.writable = False
4911+ req_table.cancel.writable = False
4912+
4913+ if r.record and r.record.req_req_skill.count():#r.component and r.component.name == "req_skill":
4914+ # Is this component being updated (not created)
4915+ req_skill_table = db.req_req_skill
4916+ req_skill_table.skill_id.writable = False
4917+ req_skill_table.quantity.writable = False
4918+
4919+ # @ToDo: apply these changes via JS for the create form where type is editable
4920+ #if type == 3: # Person
4921+ req_table.date_required.requires = req_table.date_required.requires.other
4922+ req_table.date_required_until.requires = req_table.date_required_until.requires.other
4923+ req_table.location.readable = True
4924+ req_table.public.readable = True
4925+ req_table.organisations_id.readable = True
4926+ req_table.emailed.readable = True
4927+
4928+ if r.method == "create" or True: # @ToDo: Remove "or True" - this has been added for training to allow records to be edit
4929+ # Only enable Edit for fields where Sahana (not WebEOC) is Master
4930+ req_table.location.writable = True
4931+ req_table.public.writable = True
4932+ req_table.organisations_id.writable = True
4933+
4934+ req_table.purpose.label = T("Task Details")
4935+ req_table.site_id.label = T("Report To Facility")
4936+ req_table.request_for_id.label = T("Point of Contact")
4937+
4938+ if r.method != "update" and r.method != "read":
4939+ if not r.component:
4940+ # Hide fields which don't make sense in a Create form
4941+ # - includes one embedded in list_create
4942+ # - list_fields over-rides, so still visible within list itself
4943+ response.s3.req_create_form_mods()
4944+
4945+ # Get the default Facility for this user
4946+ # @ToDo: Use site_id in User Profile (like current organisation_id)
4947+ if deployment_settings.has_module("hrm"):
4948+ query = (db.hrm_human_resource.person_id == s3_logged_in_person())
4949+ site = db(query).select(db.org_site.id,
4950+ limitby=(0, 1)).first()
4951+ if site:
4952+ r.table.site_id.default = site.id
4953+
4954+ elif r.component.name == "document":
4955+ s3.crud.submit_button = T("Add")
4956+ table = r.component.table
4957+ # @ToDo: Fix for Link Table
4958+ #table.date.default = r.record.date
4959+ #if r.record.site_id:
4960+ # stable = db.org_site
4961+ # query = (stable.id == r.record.site_id)
4962+ # site = db(query).select(stable.location_id,
4963+ # stable.organisation_id,
4964+ # limitby=(0, 1)).first()
4965+ # if site:
4966+ # table.location_id.default = site.location_id
4967+ # table.organisation_id.default = site.organisation_id
4968+
4969+ elif r.component.name == "req_skill":
4970+ #req_hide_quantities(r.component.table)
4971+ table = r.component.table
4972+ table.quantity_commit.writable = table.quantity_commit.readable = False
4973+ table.quantity_fulfil.writable = table.quantity_fulfil.readable = False
4974+
4975+ if r.component:
4976+ if r.component.name == "document" or \
4977+ r.component.name == "req_skill":
4978+ # Limit site_id to facilities the user has permissions for
4979+ # @ToDo: Non-Item requests shouldn't be bound to a Facility?
4980+ auth.permission.permitted_facilities(table=r.table,
4981+ error_msg=T("You do not have permission for any facility to make a request."))
4982+
4983+ elif r.component.name == "assignment":
4984+ table = db.vol_assignment
4985+ # Tweak the breadcrumb
4986+ if r.component.count() > 1:
4987+ label = T("Roster")
4988+ else:
4989+ label = T("Assignment")
4990+ breadcrumbs[2] = (label, False,
4991+ URL(c=request.controller,
4992+ f=request.function,
4993+ args=request.args))
4994+ if s3_has_role(STAFF):
4995+ table.report_to_id.default = r.record.request_for_id
4996+ else:
4997+ # Volunteer can evaluate task if vol has checked-in and (checked-out or time > time_until)
4998+ query = (table.id == r.component_id)
4999+ assign = db(query).select(table.checkin,
5000+ table.checkout,
The diff has been truncated for viewing.