forked from sahana/eden
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreq.py
1628 lines (1442 loc) · 67.5 KB
/
req.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""
Request Management
"""
module = request.controller
resourcename = request.function
if not settings.has_module(module):
raise HTTP(404, body="Module disabled: %s" % module)
# -----------------------------------------------------------------------------
def index():
""" Module's Home Page """
return s3db.cms_index(module, alt_function="index_alt")
# -----------------------------------------------------------------------------
def index_alt():
"""
Module homepage for non-Admin users when no CMS content found
"""
# Just redirect to the list of Requests
redirect(URL(f="req"))
# -----------------------------------------------------------------------------
def is_affiliated():
"""
Check if User is affiliated to an Organisation
@ToDo: Move this elsewhere
"""
if not auth.is_logged_in():
return False
elif s3_has_role(ADMIN):
return True
else:
table = auth.settings.table_user
auth_user = db(table.id == auth.user.id).select(table.organisation_id,
limitby=(0, 1)
).first()
if auth_user and auth_user.organisation_id:
return True
else:
return False
# =============================================================================
def create():
""" Redirect to req/create """
redirect(URL(f="req", args="create"))
# -----------------------------------------------------------------------------
def marker_fn(record):
"""
Function to decide which Marker to use for Requests Map
@ToDo: Use Symbology
"""
# Base Icon based on Type
type = record.type
if type in (1, 8):
# Items
marker = "asset"
elif type == 3:
# People
marker = "staff"
#elif type == 6:
# # Food
# marker = "food"
else:
marker = "request"
# Colour code by priority
priority = record.priority
if priority == 3:
# High
marker = "%s_red" % marker
elif priority == 2:
# Medium
marker = "%s_yellow" % marker
#elif priority == 1:
# # Low
# marker = "%s_yellow" % marker
mtable = db.gis_marker
marker = db(mtable.name == marker).select(mtable.image,
mtable.height,
mtable.width,
cache=s3db.cache,
limitby=(0, 1)).first()
return marker
# -----------------------------------------------------------------------------
def req():
"""
REST Controller for Request Instances
"""
s3.filter = (s3db.req_req.is_template == False)
output = req_controller()
return output
# -----------------------------------------------------------------------------
def req_template():
"""
REST Controller for Request Templates
"""
# Hide fields which aren't relevant to templates
# @ToDo: Need to get this done later after being opened by Types?
table = s3db.req_req
field = table.is_template
field.default = True
field.readable = field.writable = False
s3.filter = (field == True)
if "req_item" in request.args:
# List fields for req_item
table = s3db.req_req_item
list_fields = ["id",
"item_id",
"item_pack_id",
"quantity",
"comments",
]
s3db.configure("req_req_item",
list_fields=list_fields)
elif "req_skill" in request.args:
# List fields for req_skill
table = s3db.req_req_skill
list_fields = ["id",
"skill_id",
"quantity",
"comments",
]
s3db.configure("req_req_skill",
list_fields=list_fields)
else:
# Main Req
fields = ["req_ref",
"date",
"date_required",
"date_required_until",
"date_recv",
"recv_by_id",
"cancel",
"commit_status",
"transit_status",
"fulfil_status",
]
for fieldname in fields:
field = table[fieldname]
field.readable = field.writable = False
table.purpose.label = T("Details")
list_fields = ["id",
"site_id"
]
if len(settings.get_req_req_type()) > 1:
list_fields.append("type")
list_fields.append("priority")
list_fields.append("purpose")
list_fields.append("comments")
s3db.configure("req_req",
list_fields=list_fields)
# CRUD strings
ADD_REQUEST = T("Add Request Template")
s3.crud_strings["req_req"] = Storage(
label_create = ADD_REQUEST,
title_display = T("Request Template Details"),
title_list = T("Request Templates"),
title_update = T("Edit Request Template"),
label_list_button = T("List Request Templates"),
label_delete_button = T("Delete Request Template"),
msg_record_created = T("Request Template Added"),
msg_record_modified = T("Request Template Updated"),
msg_record_deleted = T("Request Template Deleted"),
msg_list_empty = T("No Request Templates"))
output = req_controller()
return output
# -----------------------------------------------------------------------------
def req_controller():
""" REST Controller """
def prep(r):
table = r.table
s3.req_prep(r)
#if len(settings.get_req_req_type()) == 1:
# # Remove type from list_fields
# list_fields = s3db.get_config("req_req", "list_fields")
# try:
# list_fields.remove("type")
# except:
# # It has already been removed.
# # This can happen if the req controller is called
# # for a second time, such as when printing reports
# pass
# s3db.configure("req_req", list_fields=list_fields)
type = (r.record and r.record.type) or \
(request.vars.type and int(request.vars.type))
if r.interactive:
# Set the req_item site_id (Requested From), called from action buttons on req/req_item_inv_item/x page
if "req_item_id" in request.vars and "inv_item_id" in request.vars:
iitable = s3db.inv_inv_item
inv_item = db(iitable.id == request.vars.inv_item_id).select(iitable.site_id,
iitable.item_id,
limitby=(0, 1)
).first()
site_id = inv_item.site_id
item_id = inv_item.item_id
# @ToDo: Check Permissions & Avoid DB updates in GETs
db(s3db.req_req_item.id == request.vars.req_item_id).update(site_id = site_id)
response.confirmation = T("%(item)s requested from %(site)s") % \
{"item": s3db.supply_ItemRepresent()(item_id),
"site": s3db.org_SiteRepresent()(site_id)
}
elif "req.site_id" in r.get_vars:
# Called from 'Make new request' button on [siteinstance]/req page
table.site_id.default = get_vars.get("req.site_id")
table.site_id.writable = False
if r.http == "POST":
del r.get_vars["req.site_id"]
table.requester_id.represent = requester_represent
# Set Fields and Labels depending on type
if type:
table.type.default = type
# This prevents the type from being edited AFTER it is set
table.type.readable = table.type.writable = False
crud_strings = settings.get_req_req_crud_strings(type)
if crud_strings:
s3.crud_strings["req_req"] = crud_strings
elif type == 1:
s3.crud_strings["req_req"].label_create = T("Make Supplies Request")
elif type == 3:
s3.crud_strings["req_req"].label_create = T("Make People Request")
# Filter the query based on type
if s3.filter:
s3.filter = s3.filter & \
(table.type == type)
else:
s3.filter = (table.type == type)
# These changes are applied via JS in create forms where type is editable
if type == 1: # Item
table.date_recv.readable = table.date_recv.writable = True
if settings.get_req_items_ask_purpose():
table.purpose.label = T("What the Items will be used for")
table.site_id.label = T("Deliver To")
table.request_for_id.label = T("Deliver To")
table.requester_id.label = T("Site Contact")
table.recv_by_id.label = T("Delivered To")
elif type == 3: # Person
table.date_required_until.readable = table.date_required_until.writable = True
table.purpose.label = T("Task Details")
table.purpose.comment = DIV(_class="tooltip",
_title="%s|%s" % (T("Task Details"),
T("Include any special requirements such as equipment which they need to bring.")))
table.site_id.label = T("Report To")
table.requester_id.label = T("Volunteer Contact")
table.request_for_id.label = T("Report To")
table.recv_by_id.label = T("Reported To")
if r.component:
if r.component.name == "document":
s3.crud.submit_button = T("Add")
#table = r.component.table
# @ToDo: Fix for Link Table
#table.date.default = r.record.date
#if r.record.site_id:
# stable = db.org_site
# query = (stable.id == r.record.site_id)
# site = db(query).select(stable.location_id,
# stable.organisation_id,
# limitby=(0, 1)).first()
# if site:
# table.location_id.default = site.location_id
# table.organisation_id.default = site.organisation_id
elif r.component.name == "req_item":
ctable = r.component.table
ctable.site_id.writable = ctable.site_id.readable = False
s3.req_hide_quantities(ctable)
elif r.component.name == "req_skill":
s3.req_hide_quantities(r.component.table)
elif r.component.alias == "job":
s3task.configure_tasktable_crud(
function="req_add_from_template",
args = [r.id],
vars = dict(user_id = auth.user is not None and auth.user.id or 0),
period = 86400, # seconds, so 1 day
)
db.scheduler_task.timeout.writable = False
else:
if r.id:
table.is_template.readable = table.is_template.writable = False
method = r.method
if method not in ("map", "read", "search", "update"):
# Hide fields which don't make sense in a Create form
# - includes one embedded in list_create
# - list_fields over-rides, so still visible within list itself
s3.req_create_form_mods()
if type and settings.get_req_inline_forms():
# Inline Forms
s3.req_inline_form(type, method)
# Get the default Facility for this user
#if settings.has_module("hrm"):
# hrtable = s3db.hrm_human_resource
# query = (hrtable.person_id == s3_logged_in_person())
# site = db(query).select(hrtable.site_id,
# limitby=(0, 1)).first()
# if site:
# r.table.site_id.default = site.site_id
# Use site_id in User Profile
if auth.is_logged_in():
if not table.site_id.default:
table.site_id.default = auth.user.site_id
elif method == "map":
# Tell the client to request per-feature markers
s3db.configure("req_req", marker_fn=marker_fn)
elif method == "update":
if settings.get_req_inline_forms():
# Inline Forms
s3.req_inline_form(type, method)
s3.scripts.append("/%s/static/scripts/S3/s3.req_update.js" % appname)
# Prevent Items from being added to closed or cancelled requests
if r.record and (r.record.closed or r.record.cancel):
s3db.configure("req_req_item",
insertable = False)
elif r.representation == "plain":
# Map Popups
pass
elif r.representation == "geojson":
# Load these models now as they'll be needed when we encode
mtable = s3db.gis_marker
s3db.configure("req_req", marker_fn=marker_fn)
if r.component and r.component.name == "commit":
table = r.component.table
record = r.record
stable = s3db.org_site
commit_status = record.commit_status
# Commits belonging to this request
rsites = []
query = (table.deleted == False)&(table.req_id == record.id)
req_sites = db(query).select(table.site_id)
for req_site in req_sites:
rsites += [req_site.site_id]
# All the sites
commit_sites = db((stable.deleted == False)).select(stable.id,
stable.code)
# Sites which have not committed to this request yet
site_opts = {}
for site in commit_sites:
if (site.id not in site_opts) and (site.id not in rsites):
site_opts[site.id] = site.code
table.site_id.requires = IS_IN_SET(site_opts)
if (commit_status == 2) and settings.get_req_restrict_on_complete():
# Restrict from committing to completed requests
listadd = False
else:
# Allow commitments to be added when doing so as a component
listadd = True
s3db.configure(table,
# Don't want filter_widgets in the component view
filter_widgets = None,
listadd = listadd,
)
if type == 1: # Items
# Limit site_id to facilities the user has permissions for
auth.permitted_facilities(table=r.table,
error_msg=T("You do not have permission for any facility to make a commitment."))
if r.interactive:
# Dropdown not Autocomplete
itable = s3db.req_commit_item
itable.req_item_id.widget = None
req_id = r.id
s3db.req_commit_item.req_item_id.requires = \
IS_ONE_OF(db,
"req_req_item.id",
s3db.req_item_represent,
orderby = "req_req_item.id",
filterby = "req_id",
filter_opts = [req_id],
sort=True
)
s3.jquery_ready.append('''
S3OptionsFilter({
'triggerName':'req_item_id',
'targetName':'item_pack_id',
'lookupPrefix':'req',
'lookupResource':'req_item_packs',
'lookupKey':'req_item_id',
'lookupField':'id',
'msgNoRecords':i18n.no_packs,
'fncPrep':S3.supply.fncPrepItem,
'fncRepresent':S3.supply.fncRepresentItem
})''')
# Custom Form
s3forms = s3base.s3forms
crud_form = s3forms.S3SQLCustomForm(
"site_id",
"date",
"date_available",
"committer_id",
s3forms.S3SQLInlineComponent(
"commit_item",
label = T("Items"),
fields = ["req_item_id",
"item_pack_id",
"quantity",
"comments"
]
),
"comments",
)
s3db.configure("req_commit",
crud_form = crud_form)
# Redirect to the Items tab after creation
#s3db.configure(table,
# create_next = URL(c="req", f="commit",
# args=["[id]", "commit_item"]),
# update_next = URL(c="req", f="commit",
# args=["[id]", "commit_item"]))
elif type == 3: # People
# Limit site_id to orgs the user has permissions for
# @ToDo: Make this customisable between Site/Org
# @ToDo: is_affiliated()
auth.permitted_facilities(table=r.table,
error_msg=T("You do not have permission for any facility to make a commitment."))
# Limit organisation_id to organisations the user has permissions for
#auth.permitted_organisations(table=r.table, redirect_on_error=False)
if r.interactive:
#table.organisation_id.readable = True
#table.organisation_id.writable = True
# Custom Form
s3forms = s3base.s3forms
crud_form = s3forms.S3SQLCustomForm(
"site_id",
"date",
"date_available",
"committer_id",
s3forms.S3SQLInlineComponent(
"commit_skill",
label = T("Skills"),
fields = ["quantity",
"skill_id",
"comments"
]
),
"comments",
)
s3db.configure("req_commit",
crud_form = crud_form)
# Redirect to the Skills tab after creation
#s3db.configure(table,
# create_next = URL(c="req", f="commit",
# args=["[id]", "commit_skill"]),
# update_next = URL(c="req", f="commit",
# args=["[id]", "commit_skill"]))
else:
# Non-Item commits can have an Organisation
# Check if user is affiliated to an Organisation
if is_affiliated():
# Limit organisation_id to organisations the user has permissions for
auth.permitted_organisations(table=r.table,
redirect_on_error=False)
table.organisation_id.readable = table.organisation_id.writable = True
else:
# Unaffiliated people can't commit on behalf of others
field = r.component.table.committer_id
field.writable = False
field.comment = None
# Non-Item commits shouldn't have a From Inventory
# @ToDo: Assets do? (Well, a 'From Site')
table.site_id.readable = table.site_id.writable = False
#if r.interactive and r.record.type == 3: # People
# # Redirect to the Persons tab after creation
# s3db.configure(table,
# create_next = URL(c="req", f="commit",
# args=["[id]", "commit_person"]),
# update_next = URL(c="req", f="commit",
# args=["[id]", "commit_person"])
# )
else:
# Limit site_id to facilities the user has permissions for
# @ToDo: Non-Item requests shouldn't be bound to a Facility?
auth.permitted_facilities(table=r.table,
error_msg=T("You do not have permission for any facility to make a request."))
return True
s3.prep = prep
# Post-process
def postp(r, output):
if r.interactive and r.method != "import":
if not r.component:
s3_action_buttons(r)
#s3_action_buttons(r, copyable=True)
# if "buttons" in output:
# buttons = output["buttons"]
# if "delete_btn" in buttons:
# delete_btn = buttons["delete_btn"]
# delete_btn = DIV(delete_btn,
# A(T("Copy Request"),
# _href=URL(args=[r.id, "copy"],
##vars={"type":r.record.type}
# ),
# _class="action-btn"))
# output["buttons"]["delete_btn"] = delete_btn
if settings.get_req_use_commit():
# This is appropriate to all
s3.actions.append(
dict(url = URL(c="req", f="req",
args=["[id]", "commit_all"]),
_class = "action-btn commit-btn",
label = str(T("Commit"))
)
)
s3.jquery_ready.append(
'''S3.confirmClick('.commit-btn','%s')''' % T("Do you want to commit to this request?"))
# This is only appropriate for item requests
#query = (r.table.type == 1)
#rows = db(query).select(r.table.id)
#restrict = [str(row.id) for row in rows]
#s3.actions.append(
# dict(url = URL(c="req", f="req",
# args=["[id]", "req_item"]),
# _class = "action-btn",
# label = str(T("View Items")),
# restrict = restrict
# )
# )
# This is only appropriate for people requests
#query = (r.table.type == 3)
#rows = db(query).select(r.table.id)
#restrict = [str(row.id) for row in rows]
#s3.actions.append(
# dict(url = URL(c="req", f="req",
# args=["[id]", "req_skill"]),
# _class = "action-btn",
# label = str(T("View Skills")),
# restrict = restrict
# )
# )
s3.actions.append(
dict(url = URL(c="req", f="req",
args=["[id]", "copy_all"]),
_class = "action-btn send-btn copy_all",
label = str(T("Copy"))
)
)
s3.actions.append(
dict(url = URL(c="req", f="req",
args=["[id]", "commit_all", "send"]),
_class = "action-btn send-btn dispatch",
label = str(T("Send"))
)
)
s3.jquery_ready.append(
'''S3.confirmClick('.send-btn','%s')''' % T("Are you sure you want to commit to this request and send a shipment?"))
else:
s3_action_buttons(r)
if r.component.name == "req_item" and settings.get_req_prompt_match():
req_item_inv_item_btn = dict(url = URL(c = "req",
f = "req_item_inv_item",
args = ["[id]"]
),
_class = "action-btn",
label = str(T("Request from Facility")),
)
s3.actions.append(req_item_inv_item_btn)
if r.component.name == "commit":
if "form" in output:
id = r.record.id
ctable = s3db.req_commit
query = (ctable.deleted == False) & \
(ctable.req_id == id)
exists = current.db(query).select(ctable.id, limitby=(0, 1))
if not exists:
s3.rfooter = A(T("Commit All"),
_href=URL(args=[id, "commit_all"]),
_class="action-btn",
_id="commit-btn",
)
s3.jquery_ready.append('''
S3.confirmClick('#commit-btn','%s')''' % T("Do you want to commit to this request?"))
else:
s3.actions.append(
dict(url = URL(c="req", f="send_commit",
args = ["[id]"]),
_class = "action-btn send-btn",
label = str(T("Prepare Shipment"))
)
)
s3.jquery_ready.append(
'''S3.confirmClick('.send-btn','%s')''' % T("Are you sure you want to send this shipment?"))
if r.component.alias == "job":
s3.actions = [
dict(label=str(T("Open")),
_class="action-btn",
url=URL(c="req", f="req_template",
args=[str(r.id), "job", "[id]"])),
dict(label=str(T("Reset")),
_class="action-btn",
url=URL(c="req", f="req_template",
args=[str(r.id), "job", "[id]", "reset"])),
dict(label=str(T("Run Now")),
_class="action-btn",
url=URL(c="req", f="req_template",
args=[str(r.id), "job", "[id]", "run"])),
]
return output
s3.postp = postp
return s3_rest_controller("req", "req", rheader = s3db.req_rheader)
# =============================================================================
def requester_represent(id, show_link=True):
"""
Represent a Requester as Name + Tel#
"""
if not id:
return current.messages["NONE"]
htable = s3db.hrm_human_resource
ptable = s3db.pr_person
ctable = s3db.pr_contact
query = (htable.person_id == ptable.id) & \
(ptable.id == id)
left = ctable.on((ctable.pe_id == ptable.pe_id) & \
(ctable.contact_method == "SMS"))
row = db(query).select(htable.type,
ptable.first_name,
ptable.middle_name,
ptable.last_name,
ctable.value,
left=left,
limitby=(0, 1)).first()
try:
hr = row["hrm_human_resource"]
except:
return current.messages.UNKNOWN_OPT
repr = s3_fullname(row.pr_person)
if row.pr_contact.value:
repr = "%s %s" % (repr, row.pr_contact.value)
if show_link:
if hr.type == 1:
controller = "hrm"
else:
controller = "vol"
request.extension = "html"
return A(repr,
_href = URL(c = controller,
f = "person",
args = [id, "contacts"]
)
)
return repr
# =============================================================================
def req_item():
"""
REST Controller
@ToDo: Filter out fulfilled Items?
"""
# Filter out Template Items
if request.function != "fema":
s3.filter = (FS("req_id$is_template") == False)
def prep(r):
if r.interactive or r.representation == "aadata":
list_fields = s3db.get_config("req_req_item", "list_fields")
list_fields.insert(1, "req_id$site_id")
list_fields.insert(1, "req_id$site_id$location_id$L4")
list_fields.insert(1, "req_id$site_id$location_id$L3")
s3db.configure("req_req_item",
insertable = False,
list_fields = list_fields,
)
s3.crud_strings["req_req_item"].title_list = T("Requested Items")
if r.method != None and r.method != "update" and r.method != "read":
# Hide fields which don't make sense in a Create form
# - includes one embedded in list_create
# - list_fields over-rides, so still visible within list itself
s3db.req_hide_quantities(r.table)
return True
s3.prep = prep
output = s3_rest_controller("req", "req_item")
if settings.get_req_prompt_match():
req_item_inv_item_btn = dict(url = URL(c="req", f="req_item_inv_item",
args=["[id]"]),
_class = "action-btn",
label = str(T("Request from Facility")),
)
if s3.actions:
s3.actions += [req_item_inv_item_btn]
else:
s3.actions = [req_item_inv_item_btn]
return output
# -----------------------------------------------------------------------------
def req_item_packs():
"""
Called by S3OptionsFilter to provide the pack options for an Item
"""
req_item_id = None
args = request.args
if len(args) == 1 and args[0].isdigit():
req_item_id = args[0]
else:
for v in request.vars:
if "." in v and v.split(".", 1)[1] == "req_item_id":
req_item_id = request.vars[v]
break
table = s3db.supply_item_pack
ritable = s3db.req_req_item
query = (ritable.id == req_item_id) & \
(ritable.item_id == table.item_id)
response.headers["Content-Type"] = "application/json"
return db(query).select(table.id,
table.name,
table.quantity).json()
# -----------------------------------------------------------------------------
def req_item_inv_item():
"""
Shows the inventory items which match a requested item
@ToDo: Make this page a component of req_item
"""
req_item_id = request.args[0]
request.args = [] #
ritable = s3db.req_req_item
req_item = ritable[req_item_id]
rtable = s3db.req_req
req = rtable[req_item.req_id]
output = {}
output["title"] = T("Request Stock from Available Warehouse")
output["req_btn"] = A(T("Return to Request"),
_href = URL(c="req", f="req",
args=[req_item.req_id, "req_item"]),
_class = "action-btn"
)
output["req_item"] = TABLE(TR(TH( "%s: " % T("Requested By") ),
rtable.site_id.represent(req.site_id),
TH( "%s: " % T("Item")),
ritable.item_id.represent(req_item.item_id),
),
TR(TH( "%s: " % T("Requester") ),
rtable.requester_id.represent(req.requester_id),
TH( "%s: " % T("Quantity")),
req_item.quantity,
),
TR(TH( "%s: " % T("Date Requested") ),
rtable.date.represent(req.date),
TH( T("Quantity Committed")),
req_item.quantity_commit,
),
TR(TH( "%s: " % T("Date Required") ),
rtable.date_required.represent(req.date_required),
TH( "%s: " % T("Quantity in Transit")),
req_item.quantity_transit,
),
TR(TH( "%s: " % T("Priority") ),
rtable.priority.represent(req.priority),
TH( "%s: " % T("Quantity Fulfilled")),
req_item.quantity_fulfil,
)
)
s3.no_sspag = True # pagination won't work with 2 datatables on one page @todo: test
itable = s3db.inv_inv_item
# Get list of matching inventory items
s3.filter = (itable.item_id == req_item.item_id)
# Tweak CRUD String for this context
s3.crud_strings["inv_inv_item"].msg_list_empty = T("No Inventories currently have this item in stock")
inv_items = s3_rest_controller("inv", "inv_item")
output["items"] = inv_items["items"]
if settings.get_supply_use_alt_name():
# Get list of alternative inventory items
atable = s3db.supply_item_alt
query = (atable.item_id == req_item.item_id ) & \
(atable.deleted == False )
alt_item_rows = db(query).select(atable.alt_item_id)
alt_item_ids = [alt_item_row.alt_item_id for alt_item_row in alt_item_rows]
if alt_item_ids:
s3.filter = (itable.item_id.belongs(alt_item_ids))
inv_items_alt = s3_rest_controller("inv", "inv_item")
output["items_alt"] = inv_items_alt["items"]
else:
output["items_alt"] = T("No Inventories currently have suitable alternative items in stock")
response.view = "req/req_item_inv_item.html"
s3.actions = [dict(url = URL(c = request.controller,
f = "req",
args = [req_item.req_id, "req_item"],
vars = dict(req_item_id = req_item_id,
inv_item_id = "[id]")
),
_class = "action-btn",
label = str(T("Request From")),
)]
return output
# =============================================================================
def req_skill():
"""
REST Controller
@ToDo: Filter out fulfilled Skills?
"""
# Filter out Template Items
s3.filter = (FS("req_id$is_template") == False)
def prep(r):
if r.interactive or r.representation == "aadata":
list_fields = s3db.get_config("req_req_skill", "list_fields")
list_fields.insert(1, "req_id$site_id")
list_fields.insert(1, "req_id$site_id$location_id$L4")
list_fields.insert(1, "req_id$site_id$location_id$L3")
s3db.configure("req_req_skill",
insertable=False,
list_fields = list_fields,
)
if r.method != "update" and r.method != "read":
# Hide fields which don't make sense in a Create form
# - includes one embedded in list_create
# - list_fields over-rides, so still visible within list itself
s3db.req_hide_quantities(r.table)
return True
s3.prep = prep
# Post-process
def postp(r, output):
if r.interactive:
s3.actions = [
dict(url = URL(c="req", f="req",
args=["req_skill", "[id]"]),
_class = "action-btn",
label = str(READ)
)
]
return output
s3.postp = postp
return s3_rest_controller("req", "req_skill")
# =============================================================================
def summary_option():
""" REST Controller """
return s3_rest_controller()
# =============================================================================
def commit():
""" REST Controller """
# Check if user is affiliated to an Organisation
if not is_affiliated():
tablename = "req_commit_person"
table = s3db[tablename]
# Unaffiliated people can't commit on behalf of others
table.person_id.writable = False
# & can only make single-person commitments
# (This should have happened in the main commitment)
s3db.configure(tablename,
insertable=False)
def prep(r):
if r.interactive:
# Commitments created through UI should be done via components
table = r.table
if r.record:
s3.crud.submit_button = T("Save Changes")
if r.record.type == 1: # Items
# Limit site_id to facilities the user has permissions for
auth.permitted_facilities(table=table,
error_msg=T("You do not have permission for any facility to make a commitment.") )
table.site_id.comment = A(T("Set as default Site"),
_id="req_commit_site_id_link",
_target="_blank",
_href=URL(c="default",
f="user",
args=["profile"]))
jappend = s3.jquery_ready.append
jappend('''
$('#req_commit_site_id_link').click(function(){
var site_id=$('#req_commit_site_id').val()
if(site_id){
var url = $('#req_commit_site_id_link').attr('href')
var exists=url.indexOf('?')
if(exists=='-1'){
$('#req_commit_site_id_link').attr('href',url+'?site_id='+site_id)
}
}
return true
})''')
# Dropdown not Autocomplete
itable = s3db.req_commit_item
itable.req_item_id.widget = None
jappend('''
S3OptionsFilter({
'triggerName':'req_item_id',
'targetName':'item_pack_id',
'lookupPrefix':'req',
'lookupResource':'req_item_packs',
'lookupKey':'req_item_id',
'lookupField':'id',
'msgNoRecords':i18n.no_packs,
'fncPrep':S3.supply.fncPrepItem,
'fncRepresent':S3.supply.fncRepresentItem
})''')
# Custom Form
s3forms = s3base.s3forms
crud_form = s3forms.S3SQLCustomForm(
"site_id",
"date",
"date_available",
"committer_id",
s3forms.S3SQLInlineComponent(
"commit_item",
label = T("Items"),
fields = ["req_item_id",
"item_pack_id",
"quantity",
"comments"
]
),
"comments",
)