def req_controller(template = False):
    """ REST Controller """

    REQ_STATUS_PARTIAL  = 1
    REQ_STATUS_COMPLETE = 2

    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)

        req_type = (r.record and r.record.type) or \
                   (get_vars.type and int(get_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 get_vars and "inv_item_id" in get_vars:
                iitable = s3db.inv_inv_item
                inv_item = db(iitable.id == get_vars.inv_item_id).select(iitable.site_id,
                                                                         iitable.item_id,
                                                                         limitby=(0, 1)
                                                                         ).first()
                site_id = inv_item.site_id
                # @ToDo: Check Permissions & Avoid DB updates in GETs
                db(s3db.req_req_item.id == get_vars.req_item_id).update(site_id = site_id)
                response.confirmation = T("%(item)s requested from %(site)s") % \
                    {"item": s3db.supply_ItemRepresent()(inv_item.item_id),
                     "site": s3db.org_SiteRepresent()(site_id)
                     }
            elif "req.site_id" in 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 req_type:
                table.type.default = req_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(req_type)
                if crud_strings:
                    s3.crud_strings["req_req"] = crud_strings
                elif req_type == 1:
                    s3.crud_strings["req_req"].label_create = T("Make Supplies Request")
                elif req_type == 3:
                    s3.crud_strings["req_req"].label_create = T("Make People Request")

                # Filter the query based on type
                r.resource.add_filter(table.type == req_type)

            # These changes are applied via JS in create forms where type is editable
            if req_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")
                # Keep consistency, don't change
                #table.requester_id.label = T("Site Contact")
                table.recv_by_id.label = T("Delivered To")

            elif req_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

                keyvalue = settings.get_ui_auto_keyvalue()
                if keyvalue:
                    # What Keys do we have?
                    kvtable = s3db.req_req_tag
                    keys = db(kvtable.deleted == False).select(kvtable.tag,
                                                               distinct=True)
                    if keys:
                        tablename = "req_req"
                        crud_fields = [f for f in table.fields if table[f].readable]
                        cappend = crud_fields.append
                        add_component = s3db.add_components
                        list_fields = s3db.get_config(tablename,
                                                      "list_fields")
                        lappend = list_fields.append
                        for key in keys:
                            tag = key.tag
                            label = T(tag.title())
                            cappend(S3SQLInlineComponent("tag",
                                                         label = label,
                                                         name = tag,
                                                         multiple = False,
                                                         fields = [("", "value")],
                                                         filterby = dict(field = "tag",
                                                                         options = tag,
                                                                         )
                                                         ))
                            add_component(tablename,
                                          org_organisation_tag = {"name": tag,
                                                                  "joinby": "req_id",
                                                                  "filterby": "tag",
                                                                  "filterfor": (tag,),
                                                                  },
                                          )
                            lappend((label, "%s.value" % tag))
                        crud_form = S3SQLCustomForm(*crud_fields)
                        s3db.configure(tablename,
                                       crud_form = crud_form,
                                       )

                method = r.method
                if method in (None, "create"):
                    # 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_create_form_mods()

                    if req_type and settings.get_req_inline_forms():
                        # Inline Forms
                        s3db.req_inline_form(req_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() and not table.site_id.default:
                        table.site_id.default = auth.user.site_id

                elif method == "update":
                    if settings.get_req_inline_forms():
                        # Inline Forms
                        s3db.req_inline_form(req_type, method)
                    s3.scripts.append("/%s/static/scripts/S3/s3.req_update.js" % appname)

                elif method == "map":
                    # Tell the client to request per-feature markers
                    s3db.configure("req_req",
                                   marker_fn = marker_fn,
                                   )

        elif r.representation == "plain":
            # Map Popups
            pass

        elif r.representation == "geojson":
            req_ref_represent = table.req_ref.represent
            table.req_ref.represent = lambda v, show_link=False, pdf=False: \
                req_ref_represent(v, show_link)
            # 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:
            if r.component.name == "req_item":
                record = r.record
                if record: # Check as options.s3json checks the component without a record
                    # Prevent Adding/Deleting Items from Requests which are complete, closed or cancelled
                    # @ToDo: deployment_setting to determine which exact rule to apply?
                    if record.fulfil_status == REQ_STATUS_COMPLETE or \
                       record.transit_status == REQ_STATUS_COMPLETE or \
                       record.req_status == REQ_STATUS_COMPLETE or \
                       record.fulfil_status == REQ_STATUS_PARTIAL or \
                       record.transit_status == REQ_STATUS_PARTIAL or \
                       record.req_status == REQ_STATUS_PARTIAL or \
                       record.closed or \
                       record.cancel:
                        s3db.configure("req_req_item",
                                       deletable = False,
                                       insertable = False,
                                       )

            elif r.component.name == "commit":
                table = r.component.table
                record = r.record
                record_id = record.id
                stable = s3db.org_site
                rtype = record.type

                if (rtype == 3) and settings.get_req_commit_people():
                    # Don't allow people commits to happen in this view
                    insertable = False
                else:
                    commit_status = record.commit_status
                    if (commit_status == 2) and settings.get_req_restrict_on_complete():
                        # Restrict from committing to completed requests
                        insertable = False
                    else:
                        # Allow commitments to be added when doing so as a component
                        insertable = True

                # 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.append(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)

                s3db.configure(table,
                               # Don't want filter_widgets in the component view
                               filter_widgets = None,
                               insertable = insertable,
                               )

                if req_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
                        itable.req_item_id.requires = \
                                        IS_ONE_OF(db, "req_req_item.id",
                                                  s3db.req_item_represent,
                                                  filterby = "req_id",
                                                  filter_opts = [r.id],
                                                  orderby = "req_req_item.id",
                                                  sort = True,
                                                  )
                        s3.jquery_ready.append('''
$.filterOptionsS3({
 'trigger':{'alias':'commit_item','name':'req_item_id'},
 'target':{'alias':'commit_item','name':'item_pack_id'},
 'scope':'row',
 '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 req_type == 3: # People
                    # Limit site_id to orgs the user has permissions for
                    # @ToDo: Make this customisable between Site/Org
                    # @ToDo: is_affiliated() once Org is possible
                    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
                        # Limit commit skills to skills from the request
                        skills_filter(record_id)

                        # 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:
            # Not r.component
            # 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."))
            if r.id:
                # Prevent Deleting Requests which are complete or closed
                record = r.record
                if record.fulfil_status == REQ_STATUS_COMPLETE or \
                   record.transit_status == REQ_STATUS_COMPLETE or \
                   record.req_status == REQ_STATUS_COMPLETE or \
                   record.fulfil_status == REQ_STATUS_PARTIAL or \
                   record.transit_status == REQ_STATUS_PARTIAL or \
                   record.req_status == REQ_STATUS_PARTIAL or \
                   record.closed:
                    s3db.configure("req_req",
                                   deletable = False,
                                   )

        return True
    s3.prep = prep

    # Post-process
    def postp(r, output):

        if r.interactive:
            if r.method is None:
                # Customise Action Buttons
                if r.component:
                    s3_action_buttons(r, deletable=s3db.get_config(r.component.tablename, "deletable"))
                    if r.component.name == "req_item" and \
                       settings.get_req_prompt_match():
                        s3.actions.append(
                                dict(label = s3_unicode(T("Request from Facility")).encode("utf8"),
                                     url = URL(c = "req",
                                               f = "req_item_inv_item",
                                               args = ["[id]"]
                                               ),
                                     _class = "action-btn",
                                     )
                            )

                    elif r.component.name == "commit":
                        if output in "form":
                            # User has Write access
                            req_id = r.record.id
                            ctable = s3db.req_commit
                            query = (ctable.deleted == False) & \
                                    (ctable.req_id == req_id)
                            exists = current.db(query).select(ctable.id,
                                                              limitby=(0, 1))
                            if not exists:
                                s3.rfooter = A(T("Commit All"),
                                               _href=URL(args=[req_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?"))
                            elif r.record.type == 1:
                                # Items
                                s3.actions.append(
                                              dict(label = s3_unicode(T("Prepare Shipment")).encode("utf8"),
                                                   url = URL(c="req", f="send_commit",
                                                             args = ["[id]"]),
                                                   _class = "action-btn send-btn",
                                                   )
                                           )
                                s3.jquery_ready.append(
'''S3.confirmClick('.send-btn','%s')''' % T("Are you sure you want to send this shipment?"))

                    elif r.component.alias == "job":
                        record_id = r.id
                        s3.actions = [
                            dict(label = s3_unicode(T("Open")).encode("utf8"),
                                 url = URL(c="req", f="req_template",
                                           args=[record_id, "job", "[id]"]),
                                 ),
                            dict(label = s3_unicode(T("Reset")).encode("utf8"),
                                 url = URL(c="req", f="req_template",
                                           args=[record_id, "job", "[id]", "reset"]),
                                 _class = "action-btn",
                                 ),
                            dict(label = s3_unicode(T("Run Now")).encode("utf8"),
                                 url = URL(c="req", f="req_template",
                                           args=[record_id, "job", "[id]", "run"]),
                                 _class = "action-btn",
                                 ),
                            ]

                else:
                    # No Component
                    if r.http == "POST":
                        # Create form
                        # @ToDo: DRY
                        if not settings.get_req_inline_forms():
                            form_vars = output["form"].vars
                            type = form_vars.type
                            if type == "1":
                                # Stock: Open Tab for Items
                                r.next = URL(args=[form_vars.id, "req_item"])
                            elif type == "3":
                                # People: Open tab for Skills
                                r.next = URL(args=[form_vars.id, "req_skill"])
                    else:
                        s3_action_buttons(r, deletable =False)
                        # Add delete button for those records which are not completed
                        # @ToDo: Handle icons
                        table = r.table
                        query = (table.fulfil_status != REQ_STATUS_COMPLETE) & \
                                (table.transit_status != REQ_STATUS_COMPLETE) & \
                                (table.req_status != REQ_STATUS_COMPLETE) & \
                                (table.fulfil_status != REQ_STATUS_PARTIAL) & \
                                (table.transit_status != REQ_STATUS_PARTIAL) & \
                                (table.req_status != REQ_STATUS_PARTIAL)
                        rows = db(query).select(table.id)
                        restrict = [str(row.id) for row in rows]
                        s3.actions.append(
                            dict(label = s3_unicode(s3.crud_labels.DELETE).encode("utf8"),
                                 url = URL(c="req", f="req",
                                           args=["[id]", "delete"]),
                                 _class="delete-btn",
                                 restrict = restrict,
                                 )
                            )
                        if not template and settings.get_req_use_commit():
                            # This is appropriate to both Items and People
                            s3.actions.append(
                                dict(label = s3_unicode(T("Commit")).encode("utf8"),
                                     url = URL(c="req", f="req",
                                               args=["[id]", "commit_all"]),
                                     _class = "action-btn commit-btn",
                                     )
                                )
                            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 = (table.type == 1)
                        #rows = db(query).select(table.id)
                        #restrict = [str(row.id) for row in rows]
                        #s3.actions.append(
                        #    dict(label = s3_unicode(T("View Items")).encode("utf8"),
                        #         url = URL(c="req", f="req",
                        #                   args=["[id]", "req_item"]),
                        #         _class = "action-btn",
                        #         restrict = restrict,
                        #         )
                        #    )
                        # This is only appropriate for people requests
                        #query = (table.type == 3)
                        #rows = db(query).select(table.id)
                        #restrict = [str(row.id) for row in rows]
                        #s3.actions.append(
                        #    dict(label = s3_unicode(T("View Skills")).encode("utf8"),
                        #         url = URL(c="req", f="req",
                        #                   args=["[id]", "req_skill"]),
                        #         _class = "action-btn",
                        #         restrict = restrict,
                        #         )
                        #    )
                        if settings.get_req_copyable():
                            s3.actions.append(
                                dict(label = s3_unicode(T("Copy")).encode("utf8"),
                                     url = URL(c="req", f="req",
                                               args=["[id]", "copy_all"]),
                                     _class = "action-btn copy_all",
                                     )
                                )
                            confirm = T("Are you sure you want to create a new request as a copy of this one?")
                            s3.jquery_ready.append('''S3.confirmClick('.copy_all','%s')''' % confirm)
                        req_types = settings.get_req_req_type()
                        if not template:
                            if "Stock" in req_types:
                                if len(req_types) != 1 and (get_vars.type != "1"):
                                    # Restrict these Action Buttons to just those which are Items Requests
                                    table = r.table
                                    query = (table.deleted == False) & \
                                            (table.type == 1)
                                    rows = db(query).select(table.id)
                                    restrict = [str(row.id) for row in rows]
                                else:
                                    # All Requests are Items requests so no need to restrict
                                    restrict = None
                                if settings.get_req_use_commit():
                                    action = dict(label = s3_unicode(T("Send")).encode("utf8"),
                                                  url = URL(c="req", f="req",
                                                            args=["[id]", "commit_all", "send"]),
                                                  _class = "action-btn send-btn dispatch",
                                                  )
                                    if restrict is not None:
                                        action["restrict"] = restrict
                                    s3.actions.append(action)
                                    confirm = T("Are you sure you want to commit to this request and send a shipment?")
                                    s3.jquery_ready.append('''S3.confirmClick('.send-btn','%s')''' % confirm)
                                elif auth.user and auth.user.site_id:
                                    action = dict(# Better to force users to go through the Check process
                                                  #label = s3_unicode(T("Send")).encode("utf8"),
                                                  #url = URL(c="req", f="send_req",
                                                  #          args=["[id]"],
                                                  #          vars=dict(site_id=auth.user.site_id)
                                                  #          ),
                                                  label = s3_unicode(T("Check")).encode("utf8"),
                                                  url = URL(c="req", f="req",
                                                            args=["[id]", "check"],
                                                            ),
                                                  _class = "action-btn send-btn dispatch",
                                                  )
                                    if restrict is not None:
                                        action["restrict"] = restrict
                                    s3.actions.append(action)
                                    confirm = T("Are you sure you want to send a shipment for this request?")
                                    s3.jquery_ready.append('''S3.confirmClick('.send-btn','%s')''' % confirm)
                            if "People" in req_types and settings.get_req_commit_people():
                                if len(req_types) != 1 and (get_vars.type != "3"):
                                    # Restrict these Action Buttons to just those which are Skills Requests
                                    table = r.table
                                    query = (table.deleted == False) & \
                                            (table.type == 3)
                                    rows = db(query).select(table.id)
                                    restrict = [str(row.id) for row in rows]
                                else:
                                    # All Requests are Skills requests so no need to restrict
                                    restrict = None
                                if auth.user and auth.user.organisation_id:
                                    action = dict(label = s3_unicode(T("Check")).encode("utf8"),
                                                  url = URL(c="req", f="req",
                                                            args=["[id]", "check"],
                                                            ),
                                                  _class = "action-btn",
                                                  )
                                    if restrict is not None:
                                        action["restrict"] = restrict
                                    s3.actions.append(action)

            elif r.method == "create" and r.http == "POST":
                # Create form
                # @ToDo: DRY
                if not settings.get_req_inline_forms():
                    form_vars = output["form"].vars
                    req_type = form_vars.type
                    if req_type == "1":
                        # Stock: Open Tab for Items
                        r.next = URL(args=[form_vars.id, "req_item"])
                    elif req_type == "3":
                        # People: Open tab for Skills
                        r.next = URL(args=[form_vars.id, "req_skill"])

        return output
    s3.postp = postp

    return s3_rest_controller("req", "req",
                              rheader = s3db.req_rheader,
                              )

# =============================================================================
dataset/ETHPy150Open sahana/eden/controllers/req.py/req_controller/swapped operands of `in`