Merge lp:~graeme-acm/sahana-eden/LA into lp:sahana-eden
- LA
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Fran Boon | Pending | ||
Review via email: mp+70544@code.launchpad.net |
Commit message
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)
- 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
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, |