text: # -*- 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
      s3_redirect_default(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
      """
  
      # 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)
  
      settings.req.prompt_match = False
  
      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
          s3.crud_strings["req_req"] = Storage(
              label_create = T("Create Request Template"),
              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(template = True)
      return output
  
  # -----------------------------------------------------------------------------
  def req_controller(template = False):
      """ 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 \
                 (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
                  item_id = inv_item.item_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()(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 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
                  r.resource.add_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")
                  # Keep consistency, don't change
                  #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
                      s3db.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 == "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)
  
                  elif method == "map":
                      # Tell the client to request per-feature markers
                      s3db.configure("req_req", marker_fn=marker_fn)
  
              if r.record:
                  # @ToDo: Prevent deletion of Requests which have had items sent
                  if r.record.closed or r.record.cancel:
                      # Prevent Items from being added to closed or cancelled requests
                      s3db.configure("req_req_item",
                                     insertable = False,
                                     )
  
          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 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.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)
              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
                      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 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
                      # 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 not template and settings.get_req_use_commit():
                      # This is appropriate to both Items and People
                      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
                  #        )
                  #    )
                  if settings.get_req_copyable():
                      s3.actions.append(
                          dict(url = URL(c="req", f="req",
                                         args=["[id]", "copy_all"]),
                               _class = "action-btn copy_all",
                               label = s3_unicode(T("Copy")).encode("utf8")
                              )
                          )
                      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)
                  if not template:
                      if settings.get_req_use_commit():
                          s3.actions.append(
                                  dict(url=URL(c="req", f="req",
                                               args=["[id]", "commit_all", "send"]),
                                       _class="action-btn send-btn dispatch",
                                       label=s3_unicode(T("Send")).encode("utf8")
                                       )
                                  )
                          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:
                          s3.actions.append(
                                       # Better to force users to go through the Check process
                                  dict(#url=URL(c="req", f="send_req",
                                       #        args=["[id]"],
                                       #        vars=dict(site_id=auth.user.site_id)
                                       #        ),
                                       url=URL(c="req", f="req",
                                               args=["[id]", "check"],
                                               vars={"site_id": auth.user.site_id}
                                               ),
                                       _class="action-btn send-btn dispatch",
                                       #label=s3_unicode(T("Send")).encode("utf8")
                                       label=s3_unicode(T("Check")).encode("utf8"),
                                       )
                                  )
                          confirm = T("Are you sure you want to send a shipment for this request?")
                          s3.jquery_ready.append('''S3.confirmClick('.send-btn','%s')''' % confirm)
  
              else:
                  s3_action_buttons(r)
                  if r.component.name == "req_item" and \
                     settings.get_req_prompt_match():
                      s3.actions.append(
                              dict(url = URL(c = "req",
                                             f = "req_item_inv_item",
                                             args = ["[id]"]
                                             ),
                                   _class = "action-btn",
                                   label = s3_unicode(T("Request from Facility")).encode("utf8"),
                                   )
                          )
                  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 = s3_unicode(T("Prepare Shipment")).encode("utf8")
                                                )
                                         )
                              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#
  
          @ToDo: Migrate to S3Represent
      """
  
      if not id:
          return current.messages["NONE"]
  
      if settings.has_module("hrm"):
          has_hrm = True
      else:
          has_hrm = False
  
      ptable = s3db.pr_person
      ctable = s3db.pr_contact
  
      query = (ptable.id == id)
      left = ctable.on((ctable.pe_id == ptable.pe_id) & \
                       (ctable.contact_method == "SMS"))
      fields = [ptable.first_name,
                ptable.middle_name,
                ptable.last_name,
                ctable.value,
                ]
      if has_hrm:
          htable = s3db.hrm_human_resource
          left = [left, htable.on(htable.person_id == ptable.id)]
          fields.append(htable.type)
      row = db(query).select(*fields,
                             left=left,
                             limitby=(0, 1)).first()
  
      repr = s3_fullname(row.pr_person)
      contact = row["pr_contact.value"]
      if contact:
          repr = "%s %s" % (repr, contact)
      if show_link:
          hr_type = row.get("hrm_human_resource.type")
          if hr_type:
              if hr_type == 1:
                  controller = "hrm"
              else:
                  controller = "vol"
          else:
              controller = "pr"
          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")
              levels = gis.get_relevant_hierarchy_levels()
              levels.reverse()
              for level in levels:
                  lfield = "req_id$site_id$location_id$%s" % level
                  list_fields.insert(1, lfield)
              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.append(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")
              # @ToDo: Do this based on active gis_config/gis_hierarchy
              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
                      s3db.req_commit_item.req_item_id.widget = None
  
                      # Options updater for inline items
                      if not r.component:
                          jappend('''
  $.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)
  
                  elif r.record.type == 3: # People
                      # Limit site_id to sites 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."))
                      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"]))
                      # Limit organisation_id to organisations the user has permissions for
                      #auth.permitted_organisations(table=r.table, redirect_on_error=False)
                      #table.organisation_id.readable = True
                      #table.organisation_id.writable = True
                      # Custom Form
                      s3forms = s3base.s3forms
                      crud_form = s3forms.S3SQLCustomForm(
                              #"organisation_id",
                              "site_id",
                              "date",
                              "date_available",
                              "committer_id",
                              s3forms.S3SQLInlineComponent(
                                  "commit_skill",
                                  label = T("People"),
                                  fields = ["quantity",
                                            "skill_id",
                                            "comments"
                                            ]
                              ),
                              "comments",
                          )
                      s3db.configure("req_commit", crud_form=crud_form)
  
                  else:
                      # Commits to Other requests can have an Organisation
                      # Limit organisation_id to organisations the user has permissions for
                      auth.permitted_organisations(table=r.table, redirect_on_error=False)
                      table.organisation_id.readable = True
                      table.organisation_id.writable = True
                      # Non-Item commits shouldn't have a From Inventory
                      # @ToDo: Assets do?
                      table.site_id.readable = False
                      table.site_id.writable = False
  
          if r.component:
              if r.component_name == "commit_item":
                  # Limit commit items to items from the request
                  s3db.req_commit_item.req_item_id.requires = \
                      IS_ONE_OF(db, "req_req_item.id",
                                s3db.req_item_represent,
                                filterby = "req_id",
                                filter_opts = [r.record.req_id],
                                orderby = "req_req_item.id",
                                sort = True,
                                )
              #elif r.component_name == "person":
              #    # Limit commit skills to skills from the request
              #    db.req_commit_skill.req_skill_id.requires = \
              #        IS_ONE_OF(db, "req_req_skill.id",
              #                  s3db.req_skill_represent,
              #                  filterby = "req_id",
              #                  filter_opts = [r.record.req_id],
              #                  orderby = "req_req_skill.id",
              #                  sort = True,
              #                  )
          return True
      s3.prep = prep
  
      def postp(r, output):
          if r.interactive and r.method != "import":
              if not r.component:
                  table = r.table
                  record = r.record
                  s3_action_buttons(r)
                  s3.actions.append(
                          dict(url = URL(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?"))
  
          return output
      s3.postp = postp
  
      return s3_rest_controller(rheader = commit_rheader)
  
  # -----------------------------------------------------------------------------
  def commit_rheader(r):
      """ Resource Header for Commitments """
  
      if r.representation == "html":
          record = r.record
          if record and r.name == "commit":
  
              s3_date_represent = s3base.S3DateTime.date_represent
  
              tabs = [(T("Edit Details"), None)]
              type = record.type and int(record.type)
  
              table = r.table
              if type == 1:
                  tabs.append((T("Items"), "commit_item"))
  
                  #req_record = db.req_req[record.req_id]
                  #req_date = req_record.date
                  rheader = DIV(TABLE(TR(TH("%s: " % table.req_id.label),
                                         table.req_id.represent(record.req_id),
                                         ),
                                      TR(TH("%s: " % T("Committing Warehouse")),
                                         s3db.org_site_represent(record.site_id),
                                         TH("%s: " % T("Commit Date")),
                                         s3_date_represent(record.date),
                                         ),
                                      TR(TH("%s: " % table.comments.label),
                                         TD(record.comments or "", _colspan=3)
                                         ),
                                      ),
                                  )
                  prepare_btn = A(T("Prepare Shipment"),
                                  _href = URL(f = "send_commit",
                                              args = [record.id]
                                              ),
                                  _id = "send_commit",
                                  _class = "action-btn"
                                  )
  
                  s3.rfooter = TAG[""](prepare_btn)
  
  #                send_btn = A( T("Send Commitment as Shipment"),
  #                              _href = URL(f = "send_commit",
  #                                          args = [record.id]
  #                                          ),
  #                              _id = "send_commit",
  #                              _class = "action-btn"
  #                              )
  #
  #                send_btn_confirm = SCRIPT("S3.confirmClick('#send_commit', '%s')" %
  #                                          T("Do you want to send these Committed items?") )
  #                s3.rfooter = TAG[""](send_btn,send_btn_confirm)
                  #rheader.append(send_btn)
                  #rheader.append(send_btn_confirm)
  
              elif type == 3:
                  #tabs.append((T("People"), "commit_person"))
                  tabs.append((T("People"), "commit_skill"))
  
                  #req_record = db.req_req[record.req_id]
                  #req_date = req_record.date
                  organisation_represent = s3db.org_organisation_represent
                  rheader = DIV(TABLE(TR(TH("%s: " % table.req_id.label),
                                         table.req_id.represent(record.req_id),
                                         ),
                                      TR(TH("%s: " % T("Committing Organization")),
                                         organisation_represent(record.organisation_id),
                                         TH("%s: " % T("Commit Date")),
                                         s3_date_represent(record.date),
                                         ),
                                      TR(TH("%s: " % table.comments.label),
                                         TD(record.comments, _colspan=3)
                                         ),
                                      ),
                                  )
              else:
                  # Other (& Assets/Shelter)
                  rheader = DIV(TABLE(TR(TH("%s: " % table.req_id.label),
                                         table.req_id.represent(record.req_id),
                                         ),
                                      TR(TH("%s: " % T("Committing Person")),
                                         table.committer_id.represent(record.committer_id),
                                         TH("%s: " % T("Commit Date")),
                                         s3_date_represent(record.date),
                                         ),
                                      TR(TH("%s: " % table.comments.label),
                                         TD(record.comments or "", _colspan=3)
                                         ),
                                      ),
                                )
  
              rheader_tabs = s3_rheader_tabs(r,
                                             tabs)
              rheader.append(rheader_tabs)
  
              return rheader
      return None
  
  # =============================================================================
  def send():
      """ RESTful CRUD controller """
  
      s3db.configure("inv_send",
                     listadd = False,
                     )
  
      return s3db.inv_send_controller()
  
  # ==============================================================================
  def send_commit():
      """
          Send a Shipment containing all items in a Commitment
      """
  
      return s3db.req_send_commit()
  
  # -----------------------------------------------------------------------------
  def send_process():
      """ Process a Shipment """
  
      return s3db.inv_send_process()
  
  # =============================================================================
  def commit_item():
      """ REST Controller """
  
      return s3_rest_controller()
  
  # =============================================================================
  def commit_req():
      """
          Function to commit items for a Request
          - i.e. copy data from a req into a commitment
          arg: req_id
          vars: site_id
      """
  
      req_id = request.args[0]
      site_id = request.vars.get("site_id")
  
      table = s3db.req_req
      r_req = db(table.id == req_id).select(table.type,
                                            limitby=(0, 1)).first()
  
      # User must have permissions over facility which is sending
      (prefix, resourcename, id) = s3db.get_instance(s3db.org_site, site_id)
      if not site_id or not auth.s3_has_permission("update",
                                                   "%s_%s" % (prefix,
                                                              resourcename),
                                                   record_id=id):
          session.error = T("You do not have permission to make this commitment.")
          redirect(URL(c="req", f="req",
                       args=[req_id]))
  
      # Create a new commit record
      commit_id = s3db.req_commit.insert(date = request.utcnow,
                                         req_id = req_id,
                                         site_id = site_id,
                                         type = r_req.type
                                         )
  
      # Only select items which are in the warehouse
      ritable = s3db.req_req_item
      iitable = s3db.inv_inv_item
      query = (ritable.req_id == req_id) & \
              (ritable.quantity_fulfil < ritable.quantity) & \
              (iitable.site_id == site_id) & \
              (ritable.item_id == iitable.item_id) & \
              (ritable.deleted == False)  & \
              (iitable.deleted == False)
      req_items = db(query).select(ritable.id,
                                   ritable.quantity,
                                   ritable.item_pack_id,
                                   iitable.item_id,
                                   iitable.quantity,
                                   iitable.item_pack_id)
  
      citable = s3db.req_commit_item
      for req_item in req_items:
          req_pack_quantity = req_item.req_req_item.pack_quantity()
          req_item_quantity = req_item.req_req_item.quantity * req_pack_quantity
  
          inv_item_quantity = req_item.inv_inv_item.quantity * \
                              req_item.inv_inv_item.pack_quantity()
  
          if inv_item_quantity > req_item_quantity:
              commit_item_quantity = req_item_quantity
          else:
              commit_item_quantity = inv_item_quantity
          commit_item_quantity = commit_item_quantity / req_pack_quantity
  
          if commit_item_quantity:
              req_item_id = req_item.req_req_item.id
              commit_item_id = citable.insert(commit_id = commit_id,
                                              req_item_id = req_item_id,
                                              item_pack_id = req_item.req_req_item.item_pack_id,
                                              quantity = commit_item_quantity
                                              )
  
              # Update the req_item.commit_quantity & req.commit_status
              s3base.s3_store_last_record_id("req_commit_item", commit_item_id)
              form = Storage()
              form.vars = Storage(
                      req_item_id = req_item_id
                  )
              s3db.req_commit_item_onaccept(form)
  
      # Redirect to commit
      redirect(URL(c="req", f="commit",
                   args=[commit_id, "commit_item"]))
  
  # =============================================================================
  def send_req():
      """
          Function to send items for a Request.
          - i.e. copy data from a req into a send
          arg: req_id
          vars: site_id
      """
  
      req_id = request.args[0]
      site_id = request.vars.get("site_id", None)
      table = s3db.req_req
      r_req = db(table.id == req_id).select(table.req_ref,
                                            table.requester_id,
                                            table.site_id,
                                            limitby=(0, 1)).first()
  
      # User must have permissions over facility which is sending
      (prefix, resourcename, id) = s3db.get_instance(db.org_site, site_id)
      if not site_id or not auth.s3_has_permission("update",
                                                   "%s_%s" % (prefix,
                                                              resourcename),
                                                   record_id=id):
          session.error = T("You do not have permission to send this shipment.")
          redirect(URL(c="req", f="req",
                       args = [req_id]))
  
      ritable = s3db.req_req_item
      iitable = s3db.inv_inv_item
      sendtable = s3db.inv_send
      tracktable = s3db.inv_track_item
      siptable = s3db.supply_item_pack
  
      # Get the items for this request that have not been fulfilled or in transit
      sip_id_field = siptable.id
      sip_quantity_field = siptable.quantity
      query = (ritable.req_id == req_id) & \
              (ritable.quantity_transit < ritable.quantity) & \
              (ritable.deleted == False) & \
              (ritable.item_pack_id == sip_id_field)
      req_items = db(query).select(ritable.id,
                                   ritable.quantity,
                                   ritable.quantity_transit,
                                   ritable.quantity_fulfil,
                                   ritable.item_id,
                                   sip_quantity_field
                                   )
  
      if not req_items:
          # Can't use site_name as gluon/languages.py def translate has a str() which can give a Unicode error
          #site_name = s3db.org_site_represent(site_id, show_link=False)
          session.warning = \
              T("This request has no items outstanding!")
  
          # Redirect to view the list of items in the Request
          redirect(URL(c="req", f="req",
                       args=[req_id, "req_item"])
                   )
  
      # Create a new send record
      code = s3db.supply_get_shipping_code("WB",
                                           site_id,
                                           s3db.inv_send.send_ref
                                           )
      send_id = sendtable.insert(send_ref = code,
                                 req_ref = r_req.req_ref,
                                 sender_id = auth.s3_logged_in_person(),
                                 site_id = site_id,
                                 date = request.utcnow,
                                 recipient_id = r_req.requester_id,
                                 to_site_id = r_req.site_id,
                                 status = s3db.inv_ship_status["IN_PROCESS"],
                                 )
  
      # Loop through each request item and find matches in the site inventory
      # - don't match items which are expired or in bad condition
      IN_PROCESS = s3db.inv_tracking_status["IN_PROCESS"]
      insert = tracktable.insert
      inv_remove = s3db.inv_remove
      ii_item_id_field = iitable.item_id
      ii_quantity_field = iitable.quantity
      ii_expiry_field = iitable.expiry_date
      ii_purchase_field = iitable.purchase_date
      iifields = [iitable.id,
                  ii_item_id_field,
                  ii_quantity_field,
                  iitable.item_pack_id,
                  iitable.pack_value,
                  iitable.currency,
                  ii_expiry_field,
                  ii_purchase_field,
                  iitable.bin,
                  iitable.owner_org_id,
                  iitable.supply_org_id,
                  sip_quantity_field,
                  iitable.item_source_no,
                  ]
      bquery = (ii_quantity_field > 0) & \
               (iitable.site_id == site_id) & \
               (iitable.deleted == False) & \
               (iitable.item_pack_id == sip_id_field) & \
               ((iitable.expiry_date >= request.now) | ((iitable.expiry_date == None))) & \
               (iitable.status == 0)
      orderby = ii_expiry_field | ii_purchase_field
  
      no_match = True
  
      for ritem in req_items:
          rim = ritem.req_req_item
          rim_id = rim.id
          query = bquery & \
                  (ii_item_id_field == rim.item_id)
          inv_items = db(query).select(*iifields,
                                       orderby=orderby)
  
          if len(inv_items) == 0:
              continue
          no_match = False
          one_match = len(inv_items) == 1
          # Get the Quantity Needed
          quantity_shipped = max(rim.quantity_transit, rim.quantity_fulfil)
          quantity_needed = (rim.quantity - quantity_shipped) * ritem.supply_item_pack.quantity
          # Insert the track item records
          # If there is more than one item match then we select the stock with the oldest expiry date first
          # then the oldest purchase date first
          # then a complete batch, if-possible
          iids = []
          append = iids.append
          for item in inv_items:
              if not quantity_needed:
                  break
              iitem = item.inv_inv_item
              if one_match:
                  # Remove this total from the warehouse stock
                  send_item_quantity = inv_remove(iitem, quantity_needed)
                  quantity_needed -= send_item_quantity
                  append(iitem.id)
              else:
                  quantity_available = iitem.quantity * item.supply_item_pack.quantity
                  if iitem.expiry_date:
                      # We take first from the oldest expiry date
                      send_item_quantity = min(quantity_needed, quantity_available)
                      # Remove this total from the warehouse stock
                      send_item_quantity = inv_remove(iitem, send_item_quantity)
                      quantity_needed -= send_item_quantity
                      append(iitem.id)
                  elif iitem.purchase_date:
                      # We take first from the oldest purchase date for non-expiring stock
                      send_item_quantity = min(quantity_needed, quantity_available)
                      # Remove this total from the warehouse stock
                      send_item_quantity = inv_remove(iitem, send_item_quantity)
                      quantity_needed -= send_item_quantity
                      append(iitem.id)
                  elif quantity_needed <= quantity_available:
                      # Assign a complete batch together if possible
                      # Remove this total from the warehouse stock
                      send_item_quantity = inv_remove(iitem, quantity_needed)
                      quantity_needed = 0
                      append(iitem.id)
                  else:
                      # Try again on the second loop, if-necessary
                      continue
  
              insert(send_id = send_id,
                     send_inv_item_id = iitem.id,
                     item_id = iitem.item_id,
                     req_item_id = rim_id,
                     item_pack_id = iitem.item_pack_id,
                     quantity = send_item_quantity,
                     recv_quantity = send_item_quantity,
                     status = IN_PROCESS,
                     pack_value = iitem.pack_value,
                     currency = iitem.currency,
                     bin = iitem.bin,
                     expiry_date = iitem.expiry_date,
                     owner_org_id = iitem.owner_org_id,
                     supply_org_id = iitem.supply_org_id,
                     item_source_no = iitem.item_source_no,
                     #comments = comment,
                     )
          # 2nd pass
          for item in inv_items:
              if not quantity_needed:
                  break
              iitem = item.inv_inv_item
              if iitem.id in iids:
                  continue
              # We have no way to know which stock we should take 1st so show all with quantity 0 & let the user decide
              send_item_quantity = 0
              insert(send_id = send_id,
                     send_inv_item_id = iitem.id,
                     item_id = iitem.item_id,
                     req_item_id = rim_id,
                     item_pack_id = iitem.item_pack_id,
                     quantity = send_item_quantity,
                     status = IN_PROCESS,
                     pack_value = iitem.pack_value,
                     currency = iitem.currency,
                     bin = iitem.bin,
                     expiry_date = iitem.expiry_date,
                     owner_org_id = iitem.owner_org_id,
                     supply_org_id = iitem.supply_org_id,
                     item_source_no = iitem.item_source_no,
                     #comments = comment,
                     )
  
      if no_match:
          # Can't use %(site_name)s as gluon/languages.py def translate has a str() which can give a Unicode error
          #site_name = s3db.org_site_represent(site_id, show_link=False)
          session.warning = \
              T("This site has no items exactly matching this request. There may still be other items in stock which can fulfill this request!")
  
      # Redirect to view the list of items in the Send
      redirect(URL(c="inv", f="send",
                   args=[send_id, "track_item"])
               )
  
  # =============================================================================
  def commit_item_json():
      """
         @ToDo: docstring to explain where this is used
      """
  
      ctable = s3db.req_commit
      itable = s3db.req_commit_item
      stable = s3db.org_site
      #ctable.date.represent = lambda dt: dt[:10]
      query = (itable.req_item_id == request.args[0]) & \
              (ctable.id == itable.commit_id) & \
              (ctable.site_id == stable.id) & \
              (itable.deleted == False)
      records = db(query).select(ctable.id,
                                 ctable.date,
                                 stable.name,
                                 itable.quantity,
                                 orderby = db.req_commit.date)
  
      json_str = '''[%s,%s''' % (json.dumps(dict(id = str(T("Committed")),
                                                 quantity = "#")),
                                 records.json()[1:])
  
      response.headers["Content-Type"] = "application/json"
      return json_str
  
  # =============================================================================
  def fema():
      """
          Custom Report to list all open requests for items that FEMA can supply
  
          @ToDo: Filter to just Sites that FEMA support
      """
  
      ritable = s3db.req_req_item
      rtable = db.req_req
      itable = db.supply_item
      ictable = db.supply_item_category
      citable = db.supply_catalog_item
      query = (ictable.name == "FEMA") & \
              (citable.item_category_id == ictable.id) & \
              (citable.item_id == itable.id) & \
              (itable.deleted != True)
      fema_items = db(query).select(itable.id)
      fema_item_ids = [item.id for item in fema_items]
  
      REQ_STATUS_COMPLETE = 2
      s3.filter = (rtable.deleted != True) & \
                  (rtable.is_template == False) & \
                  (rtable.commit_status != REQ_STATUS_COMPLETE) & \
                  (rtable.transit_status != REQ_STATUS_COMPLETE) & \
                  (rtable.fulfil_status != REQ_STATUS_COMPLETE) & \
                  (ritable.req_id == rtable.id) & \
                  (ritable.quantity > ritable.quantity_commit) & \
                  (ritable.quantity > ritable.quantity_transit) & \
                  (ritable.quantity > ritable.quantity_fulfil) & \
                  (ritable.deleted != True) & \
                  (ritable.item_id.belongs(fema_item_ids))
  
      # Filter Widgets
      filter_widgets = [
          s3base.S3OptionsFilter("req_id$site_id",
                                 label = T("Facility"),
                                 #cols = 3,
                                 ),
      ]
      s3db.configure("req_req_item", filter_widgets = filter_widgets)
  
      return req_item()
  
  # -----------------------------------------------------------------------------
  def organisation_needs():
      """
          RESTful CRUD Controller for Organisation Needs
      """
  
      def prep(r):
          if r.interactive:
              if r.method == "create":
                  # Filter from a Profile page?
                  # If so, then default the fields we know
                  organisation_id = get_vars.get("~.(organisation)", None)
                  if organisation_id:
                      field = s3db.req_organisation_needs.organisation_id
                      field.default = organisation_id
                      field.readable = False
                      field.writable = False
              elif r.method == "update":
                  # Don't allow changing the org in an existing needs record.
                  field = s3db.req_organisation_needs.organisation_id
                  field.writable = False
                  field.comment = None
          return True
      s3.prep = prep
  
      return s3_rest_controller()
  
  # -----------------------------------------------------------------------------
  def site_needs():
      """
          RESTful CRUD Controller for Site Needs
      """
  
      def prep(r):
          if r.interactive and r.method == "create":
              # Filter from a Profile page?
              # If so, then default the fields we know
              site_id = get_vars.get("~.(site)", None)
              if site_id:
                  field = s3db.req_site_needs.site_id
                  field.default = site_id
                  field.readable = False
                  field.writable = False
  
          return True
      s3.prep = prep
  
      return s3_rest_controller()
  
  # END =========================================================================
  