Exemple #1
0
    def _groups():
        """
            Committees/Mechanisms/Forums & Networks
            - Filtered subset of Organisations
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3db = current.s3db
        table = s3db.org_organisation
        table.address = Field.Lazy(s3db.org_organisation_address)

        s3request = s3_request("org", "organisation", extension="aadata")
        #(S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(["Committees/Mechanism/Forum",
                                                                 "Network"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id",
            "name",
            "acronym",
            (T("Type"), "organisation_type_id"),
            "year",
            (T("Address"), "address"),
            (T("Notes"), "comments"),
        ]
        return (s3request, field_list)
Exemple #2
0
    def _groups():
        """
            Committees/Mechanisms/Forums & Networks
            - Filtered subset of Organisations
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3db = current.s3db
        table = s3db.org_organisation
        table.virtualfields.append(s3db.org_organisation_address_virtual_field())

        s3request = s3_request("org", "organisation", extension="aadata")
        #(S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(["Committees/Mechanism/Forum",
                                                                 "Network"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id",
            "name",
            "acronym",
            (T("Type"), "organisation_type_id"),
            "year",
            (T("Address"), "address"),
            (T("Notes"), "comments"),
        ]
        return (s3request, field_list)
Exemple #3
0
def parameter():
    """
        REST controller for budget parameters
        - should always be 1 & only 1 record
    """

    s3db.configure(
        "budget_parameter",
        deletable=False,
    )

    table = s3db.budget_parameter
    record = db().select(table.id, limitby=(0, 1)).first()
    if not record:
        record_id = table.insert()
    else:
        record_id = record.id

    def postp(r, output):
        if isinstance(output, dict) and "buttons" in output:
            output["buttons"].pop("list_btn", None)
        return output

    s3.postp = postp

    from s3 import s3_request
    r = s3_request(args=[str(record_id)])
    return r()
Exemple #4
0
    def __call__(self):

        auth = current.auth
        if not auth.s3_logged_in():
            auth.permission.fail()

        # Use custom method
        current.s3db.set_method(
            "pr",
            "person",
            method="dashboard",
            action=PersonalDashboard,
        )

        # Call for currently logged-in person
        r = s3_request(
            "pr",
            "person",
            args=[
                str(auth.s3_logged_in_person()),
                "dashboard.%s" % auth.permission.format,
            ],
            r=current.request,
        )

        return r()
Exemple #5
0
def config():
    """ Synchronization Settings Controller """

    # Get the record ID of the first and only record
    table = s3db.sync_config
    record = db().select(table.id,
                         limitby = (0, 1)
                         ).first()
    if not record:
        record_id = table.insert()
    else:
        record_id = record.id

    def postp(r, output):
        if isinstance(output, dict) and "buttons" in output:
            output["buttons"].pop("list_btn", None)
        return output
    s3.postp = postp

    # Can't do anything else than update here
    from s3 import s3_request
    r = s3_request(args = [str(record_id), "update"],
                   extension = "html",
                   )
    return r()
Exemple #6
0
    def _regional():
        """
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3request = s3_request("org", "organisation", extension="aadata")
        # (S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(["Regional Organisation",
                                                                 "Regional Office",
                                                                 "Regional Center"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id",
            "name",
            "acronym",
            (T("Type"), "organisation_type_id"),
            "website",
            "region",
            "year",
            (T("Notes"), "comments")
        ]
        return (s3request, field_list)
Exemple #7
0
    def _regional():
        """
            Regional Organisations
            - Filtered subset of Organisations
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3request = s3_request("org", "organisation", extension="aadata")
        # (S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(["Regional Organisation",
                                                                 "Regional Office",
                                                                 "Regional Center"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id",
            "name",
            "acronym",
            (T("Type"), "organisation_type_id"),
            "website",
            "region",
            "year",
            (T("Notes"), "comments"),
        ]
        return (s3request, field_list)
Exemple #8
0
def forms():
    """ Controller to download form list and individual forms """

    from s3 import S3XForms

    if request.env.request_method != "GET":
        raise HTTP(405, current.ERROR.BAD_METHOD)

    args = request.args
    if len(args):
        # Individual form
        tablename = args[0]
        if "." in tablename:
            tablename, extension = tablename.split(".", 1)
        else:
            extension = "xhtml"
        try:
            prefix, name = tablename.split("_", 1)
        except ValueError:
            # Invalid tablename
            raise HTTP(404, current.error.BAD_RESOURCE)
        method = ["xform.%s" % extension]
        if len(args) > 1:
            method.insert(0, args[1])
        from s3 import s3_request
        r = s3_request(prefix, name,
                       args = method,
                       extension = None,
                       )
        r.set_handler("xform", S3XForms)
        output = r()
    else:
        # Form list
        xforms = S3XForms.formlist()
        if not xforms:
            raise HTTP(404, current.T("No XForms configured on this server"))

        formlist = TAG.forms()
        for url, title in xforms:
            formlist.append(TAG.form(title, _url=url))

        response.headers["Content-Type"] = "text/xml"
        response.view = "xforms/formlist.xml"
        output = {"formlist": formlist}

    return output
Exemple #9
0
    def _groups():
        """
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3request = s3_request("org", "organisation", extension="aadata")
        #(S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(
            ["Committees/Mechanism/Forum", "Network"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id", "name", "acronym", (T("Type"), "organisation_type_id"),
            "year", "address", (T("Notes"), "comments")
        ]
        return (s3request, field_list)
Exemple #10
0
def adjust_pools(rules):

    # Override auth (disables all permission checks)
    current.auth.override = True

    db = current.db
    s3db = current.s3db

    # Customise Resources (doesn't happen automatically when running from CLI)
    from s3 import s3_request
    r = s3_request("pr", "person")
    r.customise_resource("pr_person")
    r.customise_resource("pr_group_membership")

    # Get all volunteer records
    htable = s3db.hrm_human_resource
    query = (htable.type == 2) & (htable.deleted == False)
    rows = db(query).select(htable.person_id)

    if rows:
        info("Checking %s volunteer records" % len(rows))

        updated = 0
        for row in rows:

            person_id = row.person_id
            if not person_id:
                continue

            new_pool_id = rules(person_id)
            if not new_pool_id:
                info(".")
                continue
            else:
                if update_pool(person_id, new_pool_id):
                    updated += 1
                    info("+")
                else:
                    info(".")
        infoln("...done (%s volunteers re-assigned)" % updated)
    else:
        infoln("No volunteer records to check")

    return True
Exemple #11
0
def template_read():
    """
        Show the details of all the questions of a particular template
    """

    if len(get_vars) > 0:
        dummy, template_id = get_vars.viewing.split(".")
    else:
        template_id = request.args[0]

    def postp(r, output):
        if r.interactive:
            template_id = r.id
            form = s3db.survey_buildQuestionnaireFromTemplate(template_id)
            output["items"] = None
            output["form"] = None
            output["item"] = form
            output["title"] = s3.crud_strings[
                "survey_template"].title_question_details
            return output

    s3.postp = postp

    # remove CRUD generated buttons in the tabs
    s3db.configure(
        "survey_template",
        listadd=False,
        editable=False,
        deletable=False,
    )

    from s3 import s3_request
    r = s3_request(
        "survey",
        "template",
        args=[template_id],
    )
    return r(
        method="read",
        rheader=s3db.survey_template_rheader,
    )
Exemple #12
0
    def __call__(self):

        auth = current.auth
        if not auth.s3_logged_in():
            auth.permission.fail()

        # Use custom method
        current.s3db.set_method("pr", "person",
                                method = "dashboard",
                                action = PersonalDashboard,
                                )

        # Call for currently logged-in person
        r = s3_request("pr", "person",
                       args=[str(auth.s3_logged_in_person()),
                             "dashboard.%s" % auth.permission.format,
                             ],
                       r = current.request,
                       )

        return r()
Exemple #13
0
    def _groups():
        """
        """

        from s3 import S3FieldSelector, s3_request
        T = current.T

        s3request = s3_request("org", "organisation", extension="aadata")
        #(S3FieldSelector("project.id") != None) & \
        f = (S3FieldSelector("organisation_type_id$name").anyof(["Committees/Mechanism/Forum",
                                                                 "Network"]))
        s3request.resource.add_filter(f)

        field_list = [
            "id",
            "name",
            "acronym",
            (T("Type"), "organisation_type_id"),
            "year",
            "address",
            (T("Notes"), "comments")
        ]
        return (s3request, field_list)
Exemple #14
0
def sync():
    """ Synchronization """

    tablename = get_vars.get("resource")
    if not tablename or tablename == "mixed":
        # Sync adapter to determine/negotiate the resource(s)
        mixed = True
        tablename = "sync_repository"
    else:
        # Resource determined by request
        mixed = False

    if tablename and "_" in tablename:

        get_vars_new = Storage(include_deleted=True)

        # Copy URL variables from peer:
        # repository ID, msince and sync filters
        for k, v in get_vars.items():
            if k in ("repository", "msince") or \
               k[0] == "[" and "]" in k:
                get_vars_new[k] = v

        # Request
        prefix, name = tablename.split("_", 1)
        from s3 import s3_request
        r = s3_request(prefix = prefix,
                       name = name,
                       args = ["sync"],
                       get_vars = get_vars_new,
                       )

        # Response
        return r(mixed = mixed)

    raise HTTP(400, body=current.ERROR.BAD_REQUEST)
Exemple #15
0
    def __call__(self):
        """ The userstats controller """

        # Require ORG_GROUP_ADMIN
        auth = current.auth
        if not auth.s3_has_role("ORG_GROUP_ADMIN"):
            auth.permission.fail()

        from s3 import S3CRUD, s3_get_extension, s3_request

        request = current.request
        args = request.args

        # Create an S3Request
        r = s3_request("org", "organisation",
                       c = "default",
                       f = "index/%s" % args[0],
                       args = args[1:],
                       extension = s3_get_extension(request),
                       )

        # Filter to root organisations
        resource = r.resource
        resource.add_filter(FS("id").belongs(self.root_orgs))

        # Configure field methods
        from gluon import Field
        table = resource.table
        table.total_accounts = Field.Method("total_accounts", self.total_accounts)
        table.active_accounts = Field.Method("active_accounts", self.active_accounts)
        table.disabled_accounts = Field.Method("disabled_accounts", self.disabled_accounts)
        table.active30 = Field.Method("active30", self.active30)

        # Labels for field methods
        T = current.T
        TOTAL = T("Total User Accounts")
        ACTIVE = T("Active")
        DISABLED = T("Inactive")
        ACTIVE30 = T("Logged-in Last 30 Days")

        # Configure list_fields
        list_fields = ("id",
                       "name",
                       (TOTAL, "total_accounts"),
                       (ACTIVE, "active_accounts"),
                       (DISABLED, "disabled_accounts"),
                       (ACTIVE30, "active30"),
                       )

        # Configure form
        from s3 import S3SQLCustomForm, S3SQLVirtualField
        crud_form = S3SQLCustomForm("name",
                                    S3SQLVirtualField("total_accounts",
                                                      label = TOTAL,
                                                      ),
                                    S3SQLVirtualField("active_accounts",
                                                      label = ACTIVE,
                                                      ),
                                    S3SQLVirtualField("disabled_accounts",
                                                      label = DISABLED,
                                                      ),
                                    S3SQLVirtualField("active30",
                                                      label = ACTIVE30,
                                                      ),
                                    )

        # Configure read-only
        resource.configure(insertable = False,
                           editable = False,
                           deletable = False,
                           crud_form = crud_form,
                           filter_widgets = None,
                           list_fields = list_fields,
                           )

        output = r(rheader=self.rheader)

        if isinstance(output, dict):

            output["title"] = T("User Statistics")

            # URL to open the resource
            open_url = resource.crud._linkto(r, update=False)("[id]")

            # Add action button for open
            action_buttons = S3CRUD.action_buttons
            action_buttons(r,
                           deletable = False,
                           copyable = False,
                           editable = False,
                           read_url = open_url,
                           )

        return output
Exemple #16
0
    def prep(r):

        resource = r.resource
        table = resource.table

        table.pe_label.label = T("ID")

        get_vars = r.get_vars
        if "viewing" in get_vars:

            try:
                vtablename, record_id = get_vars["viewing"].split(".")
            except ValueError:
                return False

            if vtablename == "disease_case":

                # Get the person_id from the case
                ctable = s3db[vtablename]
                query = (ctable.id == record_id)
                row = db(query).select(
                    ctable.person_id,
                    limitby=(0, 1),
                ).first()
                if not row:
                    r.error(404, current.ERROR.BAD_RECORD)

                # Update the request
                from s3 import s3_request, S3SQLInlineComponent, S3SQLCustomForm
                request = s3_request(
                    "pr",
                    "person",
                    args=[str(row.person_id)],
                    vars={},
                )
                r.resource = resource = request.resource
                r.record = request.record
                r.id = request.id

                # Name fields in name-format order
                NAMES = ("first_name", "middle_name", "last_name")
                keys = s3base.StringTemplateParser.keys(
                    settings.get_pr_name_format())
                name_fields = [fn for fn in keys if fn in NAMES]

                # Fields in form
                crud_fields = name_fields + \
                              ["gender",
                               "date_of_birth",
                               S3SQLInlineComponent(
                                    "contact",
                                    fields = [("", "value")],
                                    filterby = {"field": "contact_method",
                                                "options": "SMS",
                                                },
                                    label = settings.get_ui_label_mobile_phone(),
                                    multiple = False,
                                    name = "phone",
                                    ),
                               S3SQLInlineComponent(
                                    "contact",
                                    fields = [("", "value")],
                                    filterby = {"field": "contact_method",
                                                "options": "EMAIL",
                                                },
                                    label = T("Email"),
                                    multiple = False,
                                    name = "email",
                                    ),
                               ]

                resource.configure(
                    crud_form=S3SQLCustomForm(*crud_fields),
                    deletable=False,
                )
            return True
        else:
            return False
Exemple #17
0
    def __call__(self):
        """ The userstats controller """

        # Require ORG_GROUP_ADMIN
        auth = current.auth
        if not auth.s3_has_role("ORG_GROUP_ADMIN"):
            auth.permission.fail()

        from s3 import S3CRUD, s3_get_extension, s3_request

        request = current.request
        args = request.args

        # Create an S3Request
        r = s3_request(
            "org",
            "organisation",
            c="default",
            f="index/%s" % args[0],
            args=args[1:],
            extension=s3_get_extension(request),
        )

        # Filter to root organisations
        resource = r.resource
        resource.add_filter(FS("id").belongs(self.root_orgs))

        # Configure field methods
        from gluon import Field
        table = resource.table
        table.total_accounts = Field.Method("total_accounts",
                                            self.total_accounts)
        table.active_accounts = Field.Method("active_accounts",
                                             self.active_accounts)
        table.disabled_accounts = Field.Method("disabled_accounts",
                                               self.disabled_accounts)
        table.active30 = Field.Method("active30", self.active30)

        # Labels for field methods
        T = current.T
        TOTAL = T("Total User Accounts")
        ACTIVE = T("Active")
        DISABLED = T("Inactive")
        ACTIVE30 = T("Logged-in Last 30 Days")

        # Configure list_fields
        list_fields = (
            "id",
            "name",
            (TOTAL, "total_accounts"),
            (ACTIVE, "active_accounts"),
            (DISABLED, "disabled_accounts"),
            (ACTIVE30, "active30"),
        )

        # Configure form
        from s3 import S3SQLCustomForm, S3SQLVirtualField
        crud_form = S3SQLCustomForm(
            "name",
            S3SQLVirtualField(
                "total_accounts",
                label=TOTAL,
            ),
            S3SQLVirtualField(
                "active_accounts",
                label=ACTIVE,
            ),
            S3SQLVirtualField(
                "disabled_accounts",
                label=DISABLED,
            ),
            S3SQLVirtualField(
                "active30",
                label=ACTIVE30,
            ),
        )

        # Configure read-only
        resource.configure(
            insertable=False,
            editable=False,
            deletable=False,
            crud_form=crud_form,
            filter_widgets=None,
            list_fields=list_fields,
        )

        output = r(rheader=self.rheader)

        if isinstance(output, dict):

            output["title"] = T("User Statistics")

            # URL to open the resource
            open_url = resource.crud._linkto(r, update=False)("[id]")

            # Add action button for open
            action_buttons = S3CRUD.action_buttons
            action_buttons(
                r,
                deletable=False,
                copyable=False,
                editable=False,
                read_url=open_url,
            )

        return output
Exemple #18
0
    def __call__(self):

        from gluon import IS_INT_IN_RANGE
        from s3 import FS, \
                       s3_request, \
                       S3CRUD, \
                       S3TextFilter, \
                       S3DateFilter, \
                       S3SQLCustomForm

        s3 = current.response.s3
        controller = self.__class__.__name__

        def prep(r):

            SURPLUS_MEALS = "SURPLUS-MEALS"

            T = current.T
            db = current.db
            s3db = current.s3db

            resource = r.resource

            # Set default SURPLUS_MEALS event type
            ttable = s3db.dvr_case_event_type
            query = (ttable.code == SURPLUS_MEALS) & \
                    (ttable.deleted != True)
            event_type = db(query).select(
                ttable.id,
                limitby=(0, 1),
            ).first()
            if not event_type:
                r.error(400,
                        "No event type with code %s defined" % SURPLUS_MEALS)
            event_type_id = event_type.id

            # Filter to SURPLUS_MEALS events without person_id
            query = (FS("type_id") == event_type_id) & \
                    (FS("person_id") == None)
            resource.add_filter(query)

            # Configure fields
            table = resource.table

            field = table.person_id
            field.default = None
            field.readable = field.writable = False

            field = table.type_id
            field.default = event_type_id
            field.readable = field.writable = False

            field = table.date
            field.readable = field.writable = True

            field = table.quantity
            field.default = 0
            # Override IS_EMPTY_OR
            field.requires = IS_INT_IN_RANGE(0, None)
            field.readable = field.writable = True

            field = table.modified_by
            field.readable = True
            registered_by = (T("Registered by"), "modified_by")

            if r.interactive:
                # Custom CRUD form
                crud_form = S3SQLCustomForm(
                    "date",
                    "quantity",
                    registered_by,
                    "comments",
                )
                # Custom filter widgets
                filter_widgets = [
                    S3TextFilter(
                        [
                            "created_by$email",
                            "comments",
                        ],
                        label=T("Search"),
                    ),
                    S3DateFilter("date"),
                ]

                resource.configure(
                    crud_form=crud_form,
                    filter_widgets=filter_widgets,
                )

                # Turn off filter manager
                current.deployment_settings.search.filter_manager = False

            # Custom list fields
            list_fields = [
                "date",
                "quantity",
                registered_by,
                "comments",
            ]

            # URL of the list view
            list_url = URL(args=[controller], vars={})
            s3.datatable_ajax_source = list_url

            resource.configure(
                insertable=True,
                list_fields=list_fields,
                # Fix redirects:
                create_next=list_url,
                update_next=list_url,
                delete_next=list_url,
            )

            # Custom CRUD strings
            T = current.T
            s3.crud_strings["dvr_case_event"] = Storage(
                label_create=T("Register Surplus Meals Quantity"),
                title_display=T("Surplus Meals Quantity"),
                title_list=T("Surplus Meals"),
                title_update=T("Edit Surplus Meals Quantity"),
                label_list_button=T("List Surplus Meals"),
                label_delete_button=T("Delete Entry"),
                msg_record_created=T("Entry added"),
                msg_record_modified=T("Entry updated"),
                msg_record_deleted=T("Entry deleted"),
                msg_list_empty=T("No Surplus Meals currently registered"),
            )

            return True

        s3.prep = prep

        def postp(r, output):

            if isinstance(output, dict):

                # Inject controller name in dt action buttons
                if r.component:
                    action_args = [controller, r.id, r.component.alias, '[id]']
                else:
                    action_args = [controller, '[id]']
                action_url = lambda action: URL(args=action_args + [action],
                                                vars={})
                S3CRUD.action_buttons(
                    r,
                    read_url=action_url('read'),
                    update_url=action_url('update'),
                    delete_url=action_url('delete'),
                )

                # Inject controller name in CRUD buttons
                buttons = output.get("buttons")
                if buttons:
                    path = "%s/%s" % (r.controller, r.function)
                    full = "%s/%s" % (path, controller)
                    for element in buttons.values():
                        if not hasattr(element, "attributes"):
                            continue
                        url = element.attributes.get("_href")
                        if url:
                            element["_href"] = url.replace(path, full)

            return output

        s3.postp = postp

        # Custom REST request
        request_args = current.request.args[1:]
        r = s3_request(
            "dvr",
            "case_event",
            args=request_args,
            extension=current.auth.permission.format,
        )

        return r()
Exemple #19
0
def s3_rest_controller(prefix=None, resourcename=None, **attr):
    """
        Helper function to apply the S3Resource REST interface

        Args:
            prefix: the application prefix
            resourcename: the resource name (without prefix)
            attr: additional keyword parameters

        Any keyword parameters will be copied into the output dict (provided
        that the output is a dict). If a keyword parameter is callable, then
        it will be invoked, and its return value will be added to the output
        dict instead. The callable receives the S3Request as its first and
        only parameter.

        CRUD can be configured per table using:

            s3db.configure(tablename, **attr)

        *** Redirection:

        create_next             URL to redirect to after a record has been created
        update_next             URL to redirect to after a record has been updated
        delete_next             URL to redirect to after a record has been deleted

        *** Form configuration:

        list_fields             list of names of fields to include into list views
        subheadings             Sub-headings (see separate documentation)
        listadd                 Enable/Disable add-form in list views

        *** CRUD configuration:

        editable                Allow/Deny record updates in this table
        deletable               Allow/Deny record deletions in this table
        insertable              Allow/Deny record insertions into this table
        copyable                Allow/Deny record copying within this table

        *** Callbacks:

        create_onvalidation     Function for additional record validation on create
        create_onaccept         Function after successful record insertion

        update_onvalidation     Function for additional record validation on update
        update_onaccept         Function after successful record update

        onvalidation            Fallback for both create_onvalidation and update_onvalidation
        onaccept                Fallback for both create_onaccept and update_onaccept
        ondelete                Function after record deletion
    """

    # Parse the request
    dynamic = attr.get("dynamic")
    if dynamic:
        # Dynamic table controller
        c = request.controller
        f = request.function
        attr = settings.customise_controller("%s_%s" % (c, f), **attr)
        from s3 import DYNAMIC_PREFIX, s3_get_extension, s3_request
        r = s3_request(
            DYNAMIC_PREFIX,
            dynamic,
            f="%s/%s" % (f, dynamic),
            args=request.args[1:],
            extension=s3_get_extension(request),
        )
    else:
        # Customise Controller from Template
        attr = settings.customise_controller(
            "%s_%s" % (
                prefix or request.controller,
                resourcename or request.function,
            ), **attr)
        from s3 import s3_request
        r = s3_request(prefix, resourcename)

    # Customize target resource(s) from Template
    r.customise_resource()

    # Configure standard method handlers
    from s3 import S3Compose, S3Filter, S3GroupedItemsReport, S3HierarchyCRUD, \
                   S3Importer, S3Map, S3Merge, S3MobileCRUD, S3Organizer, \
                   S3OrgRoleManager, S3Profile, S3Report, S3Summary, \
                   S3TimePlot, S3XForms, S3Wizard, search_ac
    from s3db.cms import S3CMS

    set_handler = r.set_handler
    set_handler("cms", S3CMS)
    set_handler("compose", S3Compose)
    # @ToDo: Make work in Component Tabs:
    set_handler("copy", lambda r, **attr: \
                               redirect(URL(args = "create",
                                            vars = {"from_record":r.id},
                                            )))
    set_handler("deduplicate", S3Merge)
    set_handler("filter", S3Filter)
    set_handler("grouped", S3GroupedItemsReport)
    set_handler("hierarchy", S3HierarchyCRUD)
    set_handler("import", S3Importer)
    set_handler("map", S3Map)
    set_handler("mform", S3MobileCRUD, representation="json")
    set_handler("organize", S3Organizer)
    set_handler("profile", S3Profile)
    set_handler("report", S3Report)  # For HTML, JSON
    set_handler("report", S3Report, transform=True)  # For GeoJSON
    set_handler("search_ac", search_ac)
    set_handler("summary", S3Summary)
    set_handler("timeplot", S3TimePlot)
    set_handler("xform", S3XForms)
    set_handler("wizard", S3Wizard)

    method = r.method

    # Don't load S3PDF unless needed (very slow import with Reportlab)
    #if method == "import" and r.representation == "pdf":
    #    from s3.s3pdf import S3PDF
    #    set_handler("import", S3PDF(),
    #                http = ("GET", "POST"),
    #                representation = "pdf"
    #                )

    # Plugin OrgRoleManager when appropriate
    S3OrgRoleManager.set_method(r)

    # List of methods which can have custom action buttons
    # (defining here allows postp to add a custom method to the list)
    s3.action_methods = (
        "import",
        "review",
        "approve",
        "reject",
        "deduplicate",
        "wizard",
    )

    # Execute the request
    output = r(**attr)

    if isinstance(output, dict) and \
       method in (None,
                  "report",
                  "search",
                  "datatable",
                  "datatable_f",
                  "summary",
                  ):

        if s3.actions is None:

            # Add default action buttons
            prefix, name, table, tablename = r.target()
            authorised = auth.s3_has_permission("update", tablename)

            # If a component has components itself, then action buttons
            # can be forwarded to the native controller by setting native=True
            if r.component and s3db.has_components(table):
                native = output.get("native", False)
            else:
                native = False

            # Get table config
            get_config = s3db.get_config
            listadd = get_config(tablename, "listadd", True)

            # Which is the standard open-action?
            if settings.get_ui_open_read_first():
                # Always read, irrespective permissions
                editable = False
            else:
                editable = get_config(tablename, "editable", True)
                if editable and \
                   auth.permission.ownership_required("update", table):
                    # User cannot edit all records in the table
                    if settings.get_ui_auto_open_update():
                        # Decide automatically per-record (implicit method)
                        editable = "auto"
                    else:
                        # Always open read first (explicit read)
                        editable = False

            deletable = get_config(tablename, "deletable", True)
            copyable = get_config(tablename, "copyable", False)

            # URL to open the resource
            from s3 import S3CRUD
            open_url = S3CRUD._linkto(
                r,
                authorised=authorised,
                update=editable,
                native=native,
            )("[id]")

            # Add action buttons for Open/Delete/Copy as appropriate
            s3_action_buttons(
                r,
                deletable=deletable,
                copyable=copyable,
                editable=editable,
                read_url=open_url,
                update_url=open_url
                # To use modals
                #update_url = "%s.popup?refresh=list" % open_url
            )

            # Override Add-button, link to native controller and put
            # the primary key into get_vars for automatic linking
            if native and not listadd and \
               auth.s3_has_permission("create", tablename):
                label = S3CRUD.crud_string(tablename, "label_create")
                component = r.resource.components[name]
                fkey = "%s.%s" % (name, component.fkey)
                get_vars_copy = get_vars.copy()
                get_vars_copy.update({fkey: r.record[component.fkey]})
                url = URL(
                    prefix,
                    name,
                    args=["create"],
                    vars=get_vars_copy,
                )
                add_btn = A(
                    label,
                    _href=url,
                    _class="action-btn",
                )
                output.update(add_btn=add_btn)

    elif method not in s3.action_methods:
        s3.actions = None

    return output
Exemple #20
0
    def __call__(self):

        T = current.T
        db = current.db
        s3db = current.s3db
        user = current.auth.user
        user_id = user.id

        # Huuricane Season lasts from 1/6 to 30/11
        now = current.request.utcnow
        if 5 < now.month < 12:
            SEASON = T("this Season")
            SEASON_START = datetime.date(now.year, 6, 1)
            SEASON_END = None
        else:
            SEASON = T("last Season")
            last_year = now.year - 1
            SEASON_START = datetime.date(last_year, 6, 1)
            SEASON_END = datetime.date(last_year, 12, 1)

        # Shipments
        stable = s3db.inv_send
        fields = [
            "id",
            "send_ref",
            "date",
            "site_id",
            "to_site_id",
            "transport_type",
            "status",
            "filing_status",
        ]
        sresource = s3db.resource(
            "inv_send",
            filter=(stable.date != None),  # Don't include Unsent Shipments
        )
        srows = sresource.select(
            fields,
            as_rows=True,
            limit=5,
            orderby=~stable.date,
        )

        rtable = s3db.inv_recv
        fields = [
            "id",
            "recv_ref",
            "date",
            "site_id",
            "from_site_id",
            "transport_type",
            "status",
            "filing_status",
        ]
        rresource = s3db.resource(
            "inv_recv",
            filter=(rtable.date != None),  # Don't include Unreceived Shipments
        )
        rrows = rresource.select(
            fields,
            as_rows=True,
            limit=5,
            orderby=~rtable.date,
        )
        rtotal = len(rrows)

        # Find the most recent 5 from both lists
        shipments = []
        sappend = shipments.append
        rindex = 0
        stotal = 0
        for srow in srows:
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            send_date = srow.date
            recv_date = rrow.date
            if send_date > recv_date:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            rrow.type = "recv"
            sappend(rrow)
            if stotal == 4:
                break
            stotal += 1
            rindex += 1
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            recv_date = rrow.date
            if send_date > recv_date:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            rrow.type = "recv"
            sappend(rrow)
            if stotal == 4:
                break
            stotal += 1
            rindex += 1
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            recv_date = rrow.date
            if send_date > recv_date:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            rrow.type = "recv"
            sappend(rrow)
            if stotal == 4:
                break
            stotal += 1
            rindex += 1
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            recv_date = rrow.date
            if send_date > recv_date:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            rrow.type = "recv"
            sappend(rrow)
            if stotal == 4:
                break
            stotal += 1
            rindex += 1
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                srow.type = "send"
                sappend(srow)
                if stotal == 4:
                    break
                stotal += 1
                continue
            recv_date = rrow.date
            if send_date > recv_date:
                srow.type = "send"
                sappend(srow)
                stotal += 1
                break
            rrow.type = "recv"
            sappend(rrow)
            stotal += 1
            break

        while stotal < 5:
            if rindex < rtotal:
                rrow = rrows[rindex]
            else:
                break
            rrow.type = "recv"
            sappend(rrow)
            rindex += 1
            stotal += 1

        date_represent = stable.date.represent
        status_represent = stable.status.represent

        site_ids = []
        for row in shipments:
            if row.type == "send":
                site_ids += [
                    row.site_id,
                    row.to_site_id,
                ]
            else:
                site_ids += [
                    row.site_id,
                    row.from_site_id,
                ]
        #sites = org_SiteRepresent(show_type = False).bulk(list(set(site_ids)))
        sites = S3Represent(lookup="org_site").bulk(list(set(site_ids)))
        sites_get = sites.get

        transport_opts = {
            "Air": ICON("plane"),
            "Sea": ICON("ship"),
            "Road": ICON("truck"),
            "Hand": ICON("hand-grab"),
        }
        transport_opts_get = transport_opts.get

        filing_opts = {
            SHIP_DOC_PENDING: ICON("close"),
            SHIP_DOC_COMPLETE: ICON("check"),
        }
        filing_opts_get = filing_opts.get

        shipment_rows = [
            DIV(
                DIV(
                    T("Date"),
                    _class="columns medium-2",
                ),
                DIV(
                    T("in/out"),
                    _class="columns medium-1",
                ),
                DIV(
                    T("From"),
                    _class="columns medium-1",
                ),
                DIV(
                    T("To"),
                    _class="columns medium-1",
                ),
                DIV(
                    T("WB/GRN"),
                    _class="columns medium-4",
                ),
                DIV(
                    T("Trans."),
                    _class="columns medium-1",
                ),
                DIV(
                    T("Status"),
                    _class="columns medium-1",
                ),
                DIV(
                    ICON("briefcase"),
                    _class="columns medium-1",
                ),
                _class="ship-card row",
            ),
        ]
        sappend = shipment_rows.append

        for row in shipments:
            if row.type == "send":
                in_out = ICON("arrow-right")
                from_site_id = row.site_id
                to_site_id = row.to_site_id
                shipment_ref = row.send_ref
                url = URL(
                    c="inv",
                    f="send",
                    args=[row["inv_send.id"]],
                )
            else:
                in_out = ICON("arrow-left")
                from_site_id = row.from_site_id
                to_site_id = row.site_id
                shipment_ref = row.recv_ref
                url = URL(
                    c="inv",
                    f="recv",
                    args=[row.id],
                )

            sappend(
                DIV(
                    DIV(
                        date_represent(row.date),
                        _class="columns medium-2",
                    ),
                    DIV(
                        in_out,
                        _class="columns medium-1",
                    ),
                    DIV(
                        sites_get(from_site_id),
                        _class="columns medium-1",
                    ),
                    DIV(
                        sites_get(to_site_id),
                        _class="columns medium-1",
                    ),
                    DIV(
                        A(
                            shipment_ref,
                            _href=url,
                        ),
                        _class="columns medium-4",
                    ),
                    DIV(
                        transport_opts_get(row.transport_type),
                        _class="columns medium-1",
                    ),
                    DIV(
                        status_represent(row.status),
                        _class="columns medium-1",
                    ),
                    DIV(
                        filing_opts_get(row.filing_status),
                        _class="columns medium-1",
                    ),
                    _class="ship-card row",
                ))

        shipments = DIV(*shipment_rows)

        # Alerts
        table = s3db.auth_user_notification
        query = (table.user_id == user_id) & \
                (table.deleted == False)
        rows = db(query).select(
            table.name,
            table.url,
            orderby=~table.created_on,
        )
        alert_rows = []
        for row in rows:
            alert_rows.append(
                DIV(
                    A(
                        DIV(ICON("bell-o"), _class="columns medium-1"),
                        DIV(row.name, _class="columns medium-11"),
                        _href=row.url,
                        _target="_blank",
                    ),
                    _class="alert-card row",
                ))
        alerts = DIV(*alert_rows)

        # Capacity
        # Define the Pivot Table
        r = s3_request("inv", "inv_item")
        r.customise_resource()
        resource = s3db.resource("inv_inv_item")
        report = S3Report()
        report.resource = resource
        capacity = report.widget(
            r,
            widget_id="capacity",
            ajaxurl=URL(c="inv", f="inv_item", args="report.json"),
        )

        # KPI
        # Which Warehouses are we responsible for?
        wtable = s3db.inv_warehouse
        gtable = db.auth_group
        mtable = db.auth_membership
        query = (mtable.user_id == user_id) & \
                (mtable.deleted == False) & \
                (mtable.group_id == gtable.id) & \
                (gtable.uuid.belongs("ORG_ADMIN",
                                     "logs_manager",
                                     "wh_operator",
                                     ))
        realms = db(query).select(mtable.pe_id)
        realms = list(set([row.pe_id for row in realms]))
        if None in realms:
            realms.remove(None)
            # Lookup Default Realm
            from s3db.pr import pr_default_realms
            default_realms = pr_default_realms(user.pe_id)
            realms = realms + default_realms
        from s3db.pr import pr_get_descendants
        child_pe_ids = pr_get_descendants(realms,
                                          entity_types=["inv_warehouse"])
        warehouses = db(wtable.pe_id.belongs(realms + child_pe_ids)).select(
            wtable.site_id,
            wtable.name,
            wtable.free_capacity,
        )
        wh_site_ids = [row.site_id for row in warehouses]

        itable = s3db.inv_inv_item
        fields = [
            "site_id",
            "total_weight",
            "total_volume",
            "quantity",  # extra_fields
            "item_pack_id$quantity",  # extra_fields
            "item_id.weight",  # extra_fields
            "item_id.volume",  # extra_fields
        ]
        iresource = s3db.resource(
            "inv_inv_item",
            filter=(itable.site_id.belongs(wh_site_ids)),
        )
        rows = iresource.select(fields, as_rows=True)
        stockpile_weight = 0
        stockpile_volume = 0
        for row in rows:
            stockpile_weight += row["inv_inv_item.total_weight"]()
            stockpile_volume += row["inv_inv_item.total_volume"]()

        fields = [
            "id",
            "track_item.total_weight",
            "track_item.total_volume",
            "track_item.quantity",  # extra_fields
            "track_item.item_pack_id$quantity",  # extra_fields
            "track_item.item_id$weight",  # extra_fields
            "track_item.item_id$volume",  # extra_fields
        ]
        query = (stable.status.belongs([SHIP_STATUS_SENT,
                                        SHIP_STATUS_RECEIVED,
                                        SHIP_STATUS_RETURNING,
                                        ])) & \
                (stable.date > SEASON_START)
        if SEASON_END:
            query &= (stable.date > SEASON_END)
        sresource = s3db.resource("inv_send", filter=query)
        srows = sresource.select(fields, as_rows=True)
        num_shipments = len(set([row["inv_send.id"] for row in srows]))
        shipments_weight = 0
        shipments_volume = 0
        for row in srows:
            weight = row["inv_track_item.total_weight"]()
            try:
                shipments_weight += weight
            except TypeError:
                # NONE returned: ignore
                pass
            volume = row["inv_track_item.total_volume"]()
            try:
                shipments_volume += volume
            except TypeError:
                # NONE returned: ignore
                pass

        float_represent = IS_FLOAT_AMOUNT.represent

        free_capacities = UL()
        for row in warehouses:
            free_capacities.append(
                LI("%s: %s m3" %
                   (row.name, float_represent(row.free_capacity,
                                              precision=1))))

        kpi = UL(
            LI("%s: %s kg" % (T("Total weight stockpiled"),
                              float_represent(stockpile_weight, precision=1))),
            LI("%s: %s m3" % (T("Total volume stockpiled"),
                              float_represent(stockpile_volume, precision=1))),
            LI("%s %s: %s" %
               (T("Number of Shipments sent"), SEASON, num_shipments)),
            LI("%s %s: %s kg" %
               (T("Total weight sent"), SEASON,
                float_represent(shipments_weight, precision=1))),
            LI("%s %s: %s m3" %
               (T("Total volume sent"), SEASON,
                float_represent(shipments_volume, precision=3))),
            LI("%s: %s" % (T("Number of warehouses"), len(warehouses))),
            LI("%s:" % T("Remaining stockpile capacities available"),
               free_capacities),
        )

        # Preparedness Checklist
        #checklist = UL()

        output = {
            "title": T("Dashboard"),
            "shipments": shipments,
            "alerts": alerts,
            "capacity": capacity,
            "kpi": kpi,
            #"checklist": checklist,
        }

        # Custom view
        self._view(THEME, "inv_dashboard.html")
        return output
Exemple #21
0
    def __call__(self):

        from gluon import IS_INT_IN_RANGE
        from s3 import FS, \
                       s3_request, \
                       S3CRUD, \
                       S3TextFilter, \
                       S3DateFilter, \
                       S3SQLCustomForm

        s3 = current.response.s3
        controller = self.__class__.__name__

        def prep(r):

            FOOD = "FOOD"

            T = current.T
            db = current.db
            s3db = current.s3db

            resource = r.resource

            # Set default FOOD event type
            ttable = s3db.dvr_case_event_type
            query = (ttable.code == FOOD) & \
                    (ttable.deleted != True)
            event_type = db(query).select(ttable.id,
                                          limitby = (0, 1),
                                          ).first()
            if not event_type:
                r.error("No event type with code %s defined" % FOOD)
            event_type_id = event_type.id

            # Filter to FOOD events without person_id
            query = (FS("type_id") == event_type_id) & \
                    (FS("person_id") == None)
            resource.add_filter(query)

            # Configure fields
            table = resource.table

            field = table.person_id
            field.default = None
            field.readable = field.writable = False

            field = table.type_id
            field.default = event_type_id
            field.readable = field.writable = False

            field = table.date
            field.readable = field.writable = True

            field = table.quantity
            field.default = 0
            # Override IS_EMPTY_OR
            field.requires = IS_INT_IN_RANGE(0, None)
            field.readable = field.writable = True

            field = table.modified_by
            field.readable = True
            registered_by = (T("Registered by"), "modified_by")

            if r.interactive:
                # Custom CRUD form
                crud_form = S3SQLCustomForm("date",
                                            "quantity",
                                            registered_by,
                                            "comments",
                                            )
                # Custom filter widgets
                filter_widgets = [S3TextFilter(["created_by$email",
                                                "comments",
                                                ],
                                                label = T("Search"),
                                               ),
                                  S3DateFilter("date"),
                                  ]

                resource.configure(crud_form = crud_form,
                                   filter_widgets = filter_widgets,
                                   )

                # Turn off filter manager
                current.deployment_settings.search.filter_manager = False

            # Custom list fields
            list_fields = ["date",
                           "quantity",
                           registered_by,
                           "comments",
                           ]

            # URL of the list view
            list_url = URL(args=[controller], vars={})
            s3.datatable_ajax_source = list_url

            resource.configure(insertable = True,
                               list_fields = list_fields,
                               # Fix redirects:
                               create_next = list_url,
                               update_next = list_url,
                               delete_next = list_url,
                               )

            # Custom CRUD strings
            T = current.T
            s3.crud_strings["dvr_case_event"] = Storage(
                label_create = T("Register Surplus Meals Quantity"),
                title_display = T("Surplus Meals Quantity"),
                title_list = T("Surplus Meals"),
                title_update = T("Edit Surplus Meals Quantity"),
                label_list_button = T("List Surplus Meals"),
                label_delete_button = T("Delete Entry"),
                msg_record_created = T("Entry added"),
                msg_record_modified = T("Entry updated"),
                msg_record_deleted = T("Entry deleted"),
                msg_list_empty = T("No Surplus Meals currently registered"),
            )

            return True
        s3.prep = prep

        def postp(r, output):

            if isinstance(output, dict):

                # Inject controller name in dt action buttons
                if r.component:
                    action_args = [controller, r.id, r.component.alias, '[id]']
                else:
                    action_args = [controller, '[id]']
                action_url = lambda action: URL(args=action_args + [action], vars={})
                S3CRUD.action_buttons(r,
                                      read_url = action_url('read'),
                                      update_url = action_url('update'),
                                      delete_url = action_url('delete'),
                                      )

                # Inject controller name in CRUD buttons
                buttons = output.get("buttons")
                if buttons:
                    path = "%s/%s" % (r.controller, r.function)
                    full = "%s/%s" % (path, controller)
                    for element in buttons.values():
                        if not hasattr(element, "attributes"):
                            continue
                        url = element.attributes.get("_href")
                        if url:
                            element["_href"] = url.replace(path, full)

            return output
        s3.postp = postp

        # Custom REST request
        request_args = current.request.args[1:]
        r = s3_request("dvr", "case_event",
                       args = request_args,
                       extension = current.auth.permission.format,
                       )

        return r()