Ejemplo n.º 1
0
def sales_employee():
    year = quorum.get_field("year", None, cast=int)
    month = quorum.get_field("month", None, cast=int)

    api = util.get_api()
    employee = api.self_employee()

    operations,\
    target,\
    sales_total,\
    sales,\
    returns,\
    previous_month,\
    previous_year,\
    next_month,\
    next_year,\
    has_next = util.get_sales(year = year, month = month)

    return flask.render_template("employee/sales.html.tpl",
                                 link="employees",
                                 sub_link="sales",
                                 is_self=True,
                                 employee=employee,
                                 operations=operations,
                                 commission_rate=util.COMMISSION_RATE,
                                 title=target,
                                 sales_total=sales_total,
                                 sales_count=len(sales),
                                 returns_count=len(returns),
                                 previous=(previous_month, previous_year),
                                 next=(next_month, next_year),
                                 has_next=has_next)
Ejemplo n.º 2
0
def browser_extras():
    object_id = quorum.get_field("id", None, cast = int)
    return flask.render_template(
        "extra/browser.html.tpl",
        link = "extras",
        object_id = object_id
    )
Ejemplo n.º 3
0
def show_employees(id):
    api = util.get_api()
    employee = api.get_employee(id)
    return flask.render_template("employee/show.html.tpl",
                                 link="employees",
                                 sub_link="info",
                                 employee=employee)
Ejemplo n.º 4
0
def sales_employee():
    year = quorum.get_field("year", None, cast = int)
    month = quorum.get_field("month", None, cast = int)

    api = util.get_api()
    employee = api.self_employee()

    operations,\
    target,\
    sales_total,\
    sales,\
    returns,\
    previous_month,\
    previous_year,\
    next_month,\
    next_year,\
    has_next = util.get_sales(year = year, month = month)

    return flask.render_template(
        "employee/sales.html.tpl",
        link = "employees",
        sub_link = "sales",
        is_self = True,
        employee = employee,
        operations = operations,
        commission_rate = util.COMMISSION_RATE,
        title = target,
        sales_total = sales_total,
        sales_count = len(sales),
        returns_count = len(returns),
        previous = (previous_month, previous_year),
        next = (next_month, next_year),
        has_next = has_next
    )
Ejemplo n.º 5
0
def browser_extras():
    object_id = quorum.get_field("id", None, cast = int)
    return flask.render_template(
        "extra/browser.html.tpl",
        link = "extras",
        object_id = object_id
    )
Ejemplo n.º 6
0
def show_media(id):
    api = util.get_api()
    media = api.info_media(id)
    media["image_url"] = api.get_media_url(media["secret"])
    return flask.render_template("media/show.html.tpl",
                                 link="media",
                                 sub_link="info",
                                 media=media)
Ejemplo n.º 7
0
def handler_exception(error):
    formatted = traceback.format_exc()
    lines = formatted.splitlines() if quorum.is_devel() else []

    return flask.Response(flask.render_template("error.html.tpl",
                                                error=str(error),
                                                traceback=lines),
                          status=500)
Ejemplo n.º 8
0
def about():
    access_token = flask.session.get("omnix.access_token", None)
    session_id = flask.session.get("omnix.session_id", None)

    return flask.render_template("about.html.tpl",
                                 link="about",
                                 access_token=access_token,
                                 session_id=session_id)
Ejemplo n.º 9
0
def show_customers(id):
    api = util.get_api()
    customer = api.get_person(id)
    return flask.render_template(
        "customer/show.html.tpl",
        link = "customers",
        customer = customer
    )
Ejemplo n.º 10
0
def edit_media(id):
    api = util.get_api()
    media = api.info_media(id)
    return flask.render_template("media/edit.html.tpl",
                                 link="media",
                                 sub_link="edit",
                                 media=media,
                                 errors=dict())
Ejemplo n.º 11
0
def new_media_browser(id):
    return flask.render_template(
        "extra/browser/new_media.html.tpl",
        link = "extras",
        object_id = id,
        media = dict(),
        errors = dict()
    )
Ejemplo n.º 12
0
def show_employee():
    api = util.get_api()
    employee = api.self_employee()
    return flask.render_template("employee/show.html.tpl",
                                 link="employees",
                                 sub_link="info",
                                 is_self=True,
                                 employee=employee)
Ejemplo n.º 13
0
def show_suppliers(id):
    api = util.get_api()
    supplier = api.get_company(id)
    return flask.render_template(
        "supplier/show.html.tpl",
        link = "suppliers",
        supplier = supplier
    )
Ejemplo n.º 14
0
def handler_404(error):
    return flask.Response(
        flask.render_template(
            "error.html.tpl",
            error = "404 - Page not found"
        ),
        status = 404
    )
Ejemplo n.º 15
0
def handler_413(error):
    return flask.Response(
        flask.render_template(
            "error.html.tpl",
            error = "412 - Precondition failed"
        ),
        status = 413
    )
Ejemplo n.º 16
0
def new_media_browser(id):
    return flask.render_template(
        "extra/browser/new_media.html.tpl",
        link = "extras",
        object_id = id,
        media = dict(),
        errors = dict()
    )
Ejemplo n.º 17
0
def show_employees(id):
    api = util.get_api()
    employee = api.get_employee(id)
    return flask.render_template(
        "employee/show.html.tpl",
        link = "employees",
        sub_link = "info",
        employee = employee
    )
Ejemplo n.º 18
0
def show_stores(id):
    api = util.get_api()
    store = api.get_store(id)
    return flask.render_template(
        "store/show.html.tpl",
        link = "stores",
        sub_link = "info",
        store = store
    )
Ejemplo n.º 19
0
def show_entities(id):
    api = util.get_api()
    entity = api.get_entity(id)
    metadata = entity.get("metadata", None)
    entity["metadata_s"] = _metadata_s(metadata)
    return flask.render_template("entity/show.html.tpl",
                                 link="entities",
                                 sub_link="info",
                                 entity=entity)
Ejemplo n.º 20
0
def show_stores(id):
    api = util.get_api()
    id = int(id)
    is_global = id == -1
    store = _global() if is_global else api.get_store(id)
    return flask.render_template("store/show.html.tpl",
                                 link="stores",
                                 sub_link="info",
                                 store=store)
Ejemplo n.º 21
0
def show_media(id):
    api = util.get_api()
    media = api.info_media(id)
    media["image_url"] = api.get_media_url(media["secret"])
    return flask.render_template(
        "media/show.html.tpl",
        link = "media",
        sub_link = "info",
        media = media
    )
Ejemplo n.º 22
0
def show_employee():
    api = util.get_api()
    employee = api.self_employee()
    return flask.render_template(
        "employee/show.html.tpl",
        link = "employees",
        sub_link = "info",
        is_self = True,
        employee = employee
    )
Ejemplo n.º 23
0
def edit_media(id):
    api = util.get_api()
    media = api.info_media(id)
    return flask.render_template(
        "media/edit.html.tpl",
        link = "media",
        sub_link = "edit",
        media = media,
        errors = dict()
    )
Ejemplo n.º 24
0
def edit_entities(id):
    api = util.get_api()
    entity = api.get_entity(id)
    metadata = entity.get("metadata", None)
    entity["metadata_s"] = _metadata_s(metadata)
    return flask.render_template("entity/edit.html.tpl",
                                 link="entities",
                                 sub_link="edit",
                                 entity=entity,
                                 errors=dict())
Ejemplo n.º 25
0
def about():
    access_token = flask.session.get("omnix.access_token", None)
    session_id = flask.session.get("omnix.session_id", None)

    return flask.render_template(
        "about.html.tpl",
        link = "about",
        access_token = access_token,
        session_id = session_id
    )
Ejemplo n.º 26
0
def sales_stores(id):
    api = util.get_api()

    now = datetime.datetime.utcnow()
    current_day = datetime.datetime(now.year, now.month, now.day)

    store = api.get_store(id)

    contents = api.stats_sales(unit = "day", store_id = id)
    stats = contents[str(id)]
    current = dict(
        net_price_vat = stats["net_price_vat"][-1],
        net_number_sales = stats["net_number_sales"][-1],
        date = current_day
    )

    days = []

    count = len(stats["net_price_vat"]) - 1
    count_r = range(count)
    count_r = list(count_r)
    count_r.reverse()
    _current_day = current_day
    for index in count_r:
        _current_day -= datetime.timedelta(1)
        day = dict(
            net_price_vat = stats["net_price_vat"][index],
            net_number_sales = stats["net_number_sales"][index],
            date = _current_day
        )
        days.append(day)

    previous_s = days[0] if days else dict()
    current["amount_delta"] = current["net_price_vat"] -\
        previous_s.get("net_price_vat", 0)
    current["number_delta"] = current["net_number_sales"] -\
        previous_s.get("net_number_sales", 0)

    if current["amount_delta"] == 0: current["amount_direction"] = "equal"
    elif current["amount_delta"] > 0: current["amount_direction"] = "up"
    else: current["amount_direction"] = "down"

    if current["number_delta"] == 0: current["number_direction"] = "equal"
    elif current["number_delta"] > 0: current["number_direction"] = "up"
    else: current["number_direction"] = "down"

    return flask.render_template(
        "store/sales.html.tpl",
        link = "stores",
        sub_link = "sales",
        store = store,
        stats = stats,
        current = current,
        days = days
    )
Ejemplo n.º 27
0
def show_stores(id):
    api = util.get_api()
    id = int(id)
    is_global = id == -1
    store = _global() if is_global else api.get_store(id)
    return flask.render_template(
        "store/show.html.tpl",
        link = "stores",
        sub_link = "info",
        store = store
    )
Ejemplo n.º 28
0
def show_entities(id):
    api = util.get_api()
    entity = api.get_entity(id)
    metadata = entity.get("metadata", None)
    entity["metadata_s"] = _metadata_s(metadata)
    return flask.render_template(
        "entity/show.html.tpl",
        link = "entities",
        sub_link = "info",
        entity = entity
    )
Ejemplo n.º 29
0
def sales_stores(id):
    api = util.get_api()

    id = int(id)
    is_global = id == -1

    now = datetime.datetime.utcnow()
    current_day = datetime.datetime(now.year, now.month, now.day)

    store = _global() if is_global else api.get_store(id)

    contents = api.stats_sales(unit="day",
                               store_id=None if is_global else id,
                               has_global=True)
    stats = contents[str(id)]
    current = dict(net_price_vat=stats["net_price_vat"][-1],
                   net_number_sales=stats["net_number_sales"][-1],
                   date=current_day)

    days = []

    count = len(stats["net_price_vat"]) - 1
    count_r = range(count)
    count_r = list(count_r)
    count_r.reverse()
    _current_day = current_day
    for index in count_r:
        _current_day -= datetime.timedelta(1)
        day = dict(net_price_vat=stats["net_price_vat"][index],
                   net_number_sales=stats["net_number_sales"][index],
                   date=_current_day)
        days.append(day)

    previous_s = days[0] if days else dict()
    current["amount_delta"] = current["net_price_vat"] -\
        previous_s.get("net_price_vat", 0)
    current["number_delta"] = current["net_number_sales"] -\
        previous_s.get("net_number_sales", 0)

    if current["amount_delta"] == 0: current["amount_direction"] = "equal"
    elif current["amount_delta"] > 0: current["amount_direction"] = "up"
    else: current["amount_direction"] = "down"

    if current["number_delta"] == 0: current["number_direction"] = "equal"
    elif current["number_delta"] > 0: current["number_direction"] = "up"
    else: current["number_direction"] = "down"

    return flask.render_template("store/sales.html.tpl",
                                 link="stores",
                                 sub_link="sales",
                                 store=store,
                                 stats=stats,
                                 current=current,
                                 days=days)
Ejemplo n.º 30
0
def edit_entities(id):
    api = util.get_api()
    entity = api.get_entity(id)
    metadata = entity.get("metadata", None)
    entity["metadata_s"] = _metadata_s(metadata)
    return flask.render_template(
        "entity/edit.html.tpl",
        link = "entities",
        sub_link = "edit",
        entity = entity,
        errors = dict()
    )
Ejemplo n.º 31
0
def handler_exception(error):
    formatted = traceback.format_exc()
    lines = formatted.splitlines() if quorum.is_devel() else []

    return flask.Response(
        flask.render_template(
            "error.html.tpl",
            error = str(error),
            traceback = lines
        ),
        status = 500
    )
Ejemplo n.º 32
0
def do_costs_extras():
    # retrieves the reference to the API object that is going
    # to be used for the updating of costs operation
    api = util.get_api()

    # tries to retrieve the costs file from the current
    # form in case it's not available renders the current
    # template with an error message
    costs_file = quorum.get_field("costs_file", None)
    if costs_file == None or not costs_file.filename:
        return flask.render_template(
            "extra/costs.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory
    fd, file_path = tempfile.mkstemp()
    costs_file.save(file_path)

    try:
        # parses the temporary file containing the spreadsheet according
        # to the provided set of keys (to create the correct structures)
        items = quorum.xlsx_to_map(
            file_path,
            keys = ("company_product_code", "cost"),
            types = (quorum.legacy.UNICODE, None)
        )
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # uses the "resolved" items structure in the put operation to
    # the Omni API so that the costs for them get updated
    api.costs_merchandise(items)

    # redirects the user back to the costs list page with a success
    # message indicating that everything went ok
    return flask.redirect(
        flask.url_for(
            "costs_extras",
            message = "Costs file processed with success"
        )
    )
Ejemplo n.º 33
0
def do_costs_extras():
    # retrieves the reference to the api object that is going
    # to be used for the updating of costs operation
    api = util.get_api()

    # tries to retrieve the costs file from the current
    # form in case it's not available renders the current
    # template with an error message
    costs_file = quorum.get_field("costs_file", None)
    if costs_file == None or not costs_file.filename:
        return flask.render_template(
            "extra/costs.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory
    fd, file_path = tempfile.mkstemp()
    costs_file.save(file_path)

    try:
        # parses the temporary file containing the spreadsheet according
        # to the provided set of keys (to create the correct structures)
        items = quorum.xlsx_to_map(
            file_path,
            keys = ("company_product_code", "cost"),
            types = (quorum.legacy.UNICODE, None)
        )
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # uses the "resolved" items structure in the put operation to
    # the omni api so that the costs for them get updated
    api.costs_merchandise(items)

    # redirects the user back to the costs list page with a success
    # message indicating that everything went ok
    return flask.redirect(
        flask.url_for(
            "costs_extras",
            message = "Costs file processed with success"
        )
    )
Ejemplo n.º 34
0
def top():
    year = quorum.get_field("year", None, cast=int)
    month = quorum.get_field("month", None, cast=int)

    top_employees,\
    target_s, \
    previous_month,\
    previous_year,\
    next_month,\
    next_year,\
    has_next = util.get_top(year = year, month = month)

    return flask.render_template("top.html.tpl",
                                 link="top",
                                 title=target_s,
                                 top_employees=top_employees,
                                 previous=(previous_month, previous_year),
                                 next=(next_month, next_year),
                                 has_next=has_next)
Ejemplo n.º 35
0
def top():
    year = quorum.get_field("year", None, cast = int)
    month = quorum.get_field("month", None, cast = int)

    top_employees,\
    target_s, \
    previous_month,\
    previous_year,\
    next_month,\
    next_year,\
    has_next = util.get_top(year = year, month = month)

    return flask.render_template(
        "top.html.tpl",
        link = "top",
        title = target_s,
        top_employees = top_employees,
        previous = (previous_month, previous_year),
        next = (next_month, next_year),
        has_next = has_next
    )
Ejemplo n.º 36
0
def signin():
    next = quorum.get_field("next", None)
    return flask.render_template(
        "signin.html.tpl",
        next = next
    )
Ejemplo n.º 37
0
def index():
    return flask.render_template(
        "index.html.tpl",
        link = "home"
    )
Ejemplo n.º 38
0
def inventory_extras():
    return flask.render_template(
        "extra/inventory.html.tpl",
        link = "extras"
    )
Ejemplo n.º 39
0
def prices_extras():
    return flask.render_template(
        "extra/prices.html.tpl",
        link = "extras"
    )
Ejemplo n.º 40
0
def media_extras():
    return flask.render_template(
        "extra/media.html.tpl",
        link = "extras"
    )
Ejemplo n.º 41
0
def inventory_extras():
    return flask.render_template(
        "extra/inventory.html.tpl",
        link = "extras"
    )
Ejemplo n.º 42
0
def list_entities():
    return flask.render_template(
        "entity/list.html.tpl",
        link = "entities"
    )
Ejemplo n.º 43
0
def do_media_extras():
    # retrieves the reference to the (Omni) API object that
    # is going to be used for the operations of updating of
    # the merchandise in bulk (multiple operations at a time)
    api = util.get_api()

    # tries to retrieve the media file from the current
    # form in case it's not available renders the current
    # template with an error message
    media_file = quorum.get_field("media_file", None)
    if media_file == None or not media_file.filename:
        return flask.render_template(
            "extra/media.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory, closing the same
    # file afterwards, as it has been properly saved
    fd, file_path = tempfile.mkstemp()
    try: media_file.save(file_path)
    finally: media_file.close()

    try:
        # creates a new temporary directory that is going to be used
        # in the extraction of the media zip file
        temp_path = tempfile.mkdtemp()
        try:
            # creates the zip file reference with the current file path
            # and then extracts the complete set of contents to the "target"
            # temporary path closing the zip file afterwards
            zip = zipfile.ZipFile(file_path)
            try: zip.extractall(temp_path)
            finally: zip.close()

            # iterates over the complete set of names in the temporary path
            # to try to upload the media to the target data source, note that
            # only the media files are considered and the base name of them
            # are going to be validation for existence in the data source
            for name in os.listdir(temp_path):
                # splits the file name into base name and extension and validates
                # the extension, so that only media files are considered
                base, extension = os.path.splitext(name)
                if not extension.lower() in (".png", ".jpg", ".jpeg"):
                    quorum.info("Skipping, '%s' not a valid media file" % name)
                    continue

                # splits the base value of the file name so that it's possible to
                # extract the proper position of the image if that's required
                base_s = base.rsplit("_", 1)
                if len(base_s) > 1: position = int(base_s[1])
                else: position = 1

                # tries to "cast" the base file name value as an integer and in case
                # it's possible assumes that this value is the object identifier
                try: object_id = int(base_s[0])
                except Exception: object_id = None

                # in case no object id was retrieved from the base file name value
                # a secondary strategy is used, so that the merchandise database
                # is searched using the base string value as the company product code
                if not object_id:
                    # creates the keyword arguments map so that the the merchandise
                    # with the provided company product code is retrieved
                    kwargs = {
                        "start_record" : 0,
                        "number_records" : 1,
                        "filters[]" : [
                            "company_product_code:equals:%s" % base_s[0]
                        ]
                    }

                    # runs the list merchandise operation in order to try to find a
                    # merchandise entity for the requested (unique) product code in
                    # case there's at least one merchandise its object id is used
                    try: merchandise = api.list_merchandise(**kwargs)
                    except Exception: merchandise = []
                    if merchandise: object_id = merchandise[0]["object_id"]

                # in case no object id was retrieved must skip the current loop
                # with a proper information message (as expected)
                if not object_id:
                    quorum.info("Skipping, could not resolve Object ID id for '%s'" % base)
                    continue

                # prints a logging message about the upload of media file that
                # is going to be performed for the current entity
                quorum.debug(
                    "Adding media file for entity '%d' in position '%d'" %\
                    (object_id, position)
                )

                # creates the target temporary media path from the temporary directory
                # path and then "read" the complete set of contents from it closing the
                # file afterwards (no more reading allowed)
                media_path = os.path.join(temp_path, name)
                media_file = open(media_path, "rb")
                try: contents = media_file.read()
                finally: media_file.close()

                # tries to guess the proper image type for the image located at the
                # provided path and the uses this value to construct the mime type
                image_type = imghdr.what(media_path)
                mime_type = "image/" + image_type if image_type else "image/unknown"

                # sets/updates the media for the associated root entity using the
                # data extracted from the file and the information in its name
                api.set_media_entity(
                    object_id,
                    contents,
                    position = position,
                    mime_type = mime_type,
                    engine = "fs",
                    thumbnails = True
                )
        finally:
            # removes the temporary path as it's no longer going to be
            # required for the operation (errors are ignored)
            shutil.rmtree(temp_path, ignore_errors = True)
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # redirects the user back to the media list page with a success
    # message indicating that everything went as expected
    return flask.redirect(
        flask.url_for(
            "media_extras",
            message = "Media file processed with success"
        )
    )
Ejemplo n.º 44
0
def list_customers():
    return flask.render_template("customer/list.html.tpl", link="customers")
Ejemplo n.º 45
0
def do_transfers_extras():
    # retrieves the reference to the API object that is going
    # to be used for the updating of prices operation
    api = util.get_api()

    # tries to retrieve the origin value from the provided set
    # of fields and in case it's not defined re-renders the template
    origin = quorum.get_field("origin", None, cast = int)
    if not origin:
        return flask.render_template(
            "extra/transfers.html.tpl",
            link = "extras",
            error = "No origin defined"
        )

    # tries to retrieve the transfers file from the current
    # form in case it's not available renders the current
    # template with an error message
    transfers_file = quorum.get_field("transfers_file", None)
    if transfers_file == None or not transfers_file.filename:
        return flask.render_template(
            "extra/transfers.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory
    fd, file_path = tempfile.mkstemp()
    transfers_file.save(file_path)

    # creates the file object that is going to be used in the
    # reading of the CSV file (underlying object)
    file = open(file_path, "rb")
    try: data = file.read()
    finally: file.close()

    # constructs the bytes based buffer object from the data that
    # has just been loaded from the file
    buffer = quorum.legacy.BytesIO(data)

    # creates the maps that are going to be used to cache the
    # resolution processes for both the stores and the merchandise
    stores_map = dict()
    merchandise_map = dict()

    # creates the map that is going to hold the complete state
    # to be used in the process of the various transfers (context)
    state = dict()

    def get_transfer():
        return state.get("transfer", None)

    def new_transfer(target_id, workflow_state = 6):
        flush_transfer()
        transfer = dict(
            origin = dict(
                object_id = origin
            ),
            destination = dict(
                object_id = target_id
            ),
            transfer_lines = [],
            _parameters = dict(
                target_workflow_state = workflow_state
            )
        )
        state["transfer"] = transfer
        return transfer

    def flush_transfer():
        transfer = get_transfer()
        state["transfer"] = None
        if not transfer: return
        payload = dict(transfer = transfer)
        transfer = api.create_transfer(payload)
        transfer_id = transfer["object_id"]
        quorum.debug(
            "Created stock transfer '%d'" % transfer_id
        )
        return transfer

    def add_transfer_line(merchandise_id, quantity = 1):
        transfer = get_transfer()
        if not transfer: raise quorum.OperationalError(
            "No transfer in context"
        )
        lines = transfer["transfer_lines"]
        line = dict(
            quantity = quantity,
            merchandise = dict(
                object_id = merchandise_id
            )
        )
        lines.append(line)

    def get_store_id(store_code):
        object_id = stores_map.get(store_code, None)
        if object_id: return object_id

        kwargs = {
            "start_record" : 0,
            "number_records" : 1,
            "filters[]" : [
                "store_code:equals:%s" % store_code
            ]
        }

        try: stores = api.list_stores(**kwargs)
        except Exception: stores = []
        if stores: object_id = stores[0]["object_id"]

        stores_map[store_code] = object_id
        return object_id

    def get_merchandise_id(company_product_code):
        # tries to retrieve the object id of the merchandise from the
        # cache and in case it succeeds returns it immediately
        object_id = merchandise_map.get(company_product_code, None)
        if object_id: return object_id

        # creates the map containing the (filter) keyword arguments that
        # are going to be send to the list merchandise operation
        kwargs = {
            "start_record" : 0,
            "number_records" : 1,
            "filters[]" : [
                "company_product_code:equals:%s" % company_product_code
            ]
        }

        # runs the list merchandise operation in order to try to find a
        # merchandise entity for the requested (unique) product code in
        # case there's at least one merchandise its object id is used
        try: merchandise = api.list_merchandise(**kwargs)
        except Exception: merchandise = []
        if merchandise: object_id = merchandise[0]["object_id"]

        # updates the (cache) map for the merchandise with the reference
        # new object id to company product code reference and then returns
        # the object id of the merchandise to the caller method
        merchandise_map[company_product_code] = object_id
        return object_id

    def callback(line, header = None):
        code, quantity, _date, _time = line[:4]

        code = code.strip()
        quantity = quantity.strip()
        quantity = int(quantity)

        is_store = len(code) < 4
        if is_store: store_id = get_store_id(code)
        else: merchandise_id = get_merchandise_id(code)

        if is_store:
            if store_id: new_transfer(store_id)
            else: flush_transfer()
        elif merchandise_id:
            try: add_transfer_line(
                merchandise_id,
                quantity = quantity
            )
            except Exception: pass

    try:
        # start the CSV import operation that is going to import the
        # various lines of the CSV in the buffer and for each of them
        # call the function passed as callback
        util.csv_import(buffer, callback, delimiter = ";")
        flush_transfer()
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # redirects the user back to the transfers list page with a success
    # message indicating that everything went ok
    return flask.redirect(
        flask.url_for(
            "transfers_extras",
            message = "Transfers file processed with success"
        )
    )
Ejemplo n.º 46
0
def signin():
    next = quorum.get_field("next", None)
    return flask.render_template("signin.html.tpl", next=next)
Ejemplo n.º 47
0
def costs_extras():
    return flask.render_template(
        "extra/costs.html.tpl",
        link = "extras"
    )
Ejemplo n.º 48
0
def handler_404(error):
    return flask.Response(flask.render_template("error.html.tpl",
                                                error="404 - Page not found"),
                          status=404)
Ejemplo n.º 49
0
def transfers_extras():
    return flask.render_template(
        "extra/transfers.html.tpl",
        link = "extras"
    )
Ejemplo n.º 50
0
def list_entities():
    return flask.render_template("entity/list.html.tpl", link="entities")
Ejemplo n.º 51
0
def do_media_extras():
    # retrieves the reference to the (omni) api object that
    # is going to be used for the operations of updating of
    # the merchandise in bulk (multiple operations at a time)
    api = util.get_api()

    # tries to retrieve the media file from the current
    # form in case it's not available renders the current
    # template with an error message
    media_file = quorum.get_field("media_file", None)
    if media_file == None or not media_file.filename:
        return flask.render_template(
            "extra/media.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory, closing the same
    # file afterwards, as it has been properly saved
    fd, file_path = tempfile.mkstemp()
    try: media_file.save(file_path)
    finally: media_file.close()

    try:
        # creates a new temporary directory that is going to be used
        # in the extraction of the media zip file
        temp_path = tempfile.mkdtemp()
        try:
            # creates the zip file reference with the current file path
            # and then extracts the complete set of contents to the "target"
            # temporary path closing the zip file afterwards
            zip = zipfile.ZipFile(file_path)
            try: zip.extractall(temp_path)
            finally: zip.close()

            # iterates over the complete set of names in the temporary path
            # to try to upload the media to the target data source, note that
            # only the media files are considered and the base name of them
            # are going to be validation for existence in the data source
            for name in os.listdir(temp_path):
                # splits the file name into base name and extension and validates
                # the extension, so that only media files are considered
                base, extension = os.path.splitext(name)
                if not extension.lower() in (".png", ".jpg", ".jpeg"):
                    quorum.info("Skipping, '%s' not a valid media file" % name)
                    continue

                # splits the base value of the file name so that it's possible to
                # extract the proper position of the image if that's required
                base_s = base.rsplit("_", 1)
                if len(base_s) > 1: position = int(base_s[1])
                else: position = 1

                # tries to "cast" the base file name value as an integer and in case
                # it's possible assumes that this value is the object identifier
                try: object_id = int(base_s[0])
                except: object_id = None

                # in case no object id was retrieved from the base file name value
                # a secondary strategy is used, so that the merchandise database
                # is searched using the base string value as the company product code
                if not object_id:
                    # creates the keyword arguments map so that the the merchandise
                    # with the provided company product code is retrieved
                    kwargs = {
                        "start_record" : 0,
                        "number_records" : 1,
                        "filters[]" : [
                            "company_product_code:equals:%s" % base_s[0]
                        ]
                    }

                    # runs the list merchandise operation in order to try to find a
                    # merchandise entity for the requested (unique) product code in
                    # case there's at least one merchandise its object id is used
                    try: merchandise = api.list_merchandise(**kwargs)
                    except: merchandise = []
                    if merchandise: object_id = merchandise[0]["object_id"]

                # in case no object id was retrieved must skip the current loop
                # with a proper information message (as expected)
                if not object_id:
                    quorum.info("Skipping, could not resolve object id for '%s'" % base)
                    continue

                # prints a logging message about the upload of media file that
                # is going to be performed for the current entity
                quorum.debug(
                    "Adding media file for entity '%d' in position '%d'" %\
                    (object_id, position)
                )

                # creates the target temporary media path from the temporary directory
                # path and then "read" the complete set of contents from it closing the
                # file afterwards (no more reading allowed)
                media_path = os.path.join(temp_path, name)
                media_file = open(media_path, "rb")
                try: contents = media_file.read()
                finally: media_file.close()

                # tries to guess the proper image type for the image located at the
                # provided path and the uses this value to construct the mime type
                image_type = imghdr.what(media_path)
                mime_type = "image/" + image_type if image_type else "image/unknown"

                # sets/updates the media for the associated root entity using the
                # data extracted from the file and the information in its name
                api.set_media_entity(
                    object_id,
                    contents,
                    position = position,
                    mime_type = mime_type,
                    engine = "fs",
                    thumbnails = True
                )
        finally:
            # removes the temporary path as it's no longer going to be
            # required for the operation (errors are ignored)
            shutil.rmtree(temp_path, ignore_errors = True)
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # redirects the user back to the media list page with a success
    # message indicating that everything went as expected
    return flask.redirect(
        flask.url_for(
            "media_extras",
            message = "Media file processed with success"
        )
    )
Ejemplo n.º 52
0
def media_extras():
    return flask.render_template(
        "extra/media.html.tpl",
        link = "extras"
    )
Ejemplo n.º 53
0
def handler_413(error):
    return flask.Response(flask.render_template(
        "error.html.tpl", error="412 - Precondition failed"),
                          status=413)
Ejemplo n.º 54
0
def transfers_extras():
    return flask.render_template(
        "extra/transfers.html.tpl",
        link = "extras"
    )
Ejemplo n.º 55
0
def index():
    return flask.render_template("index.html.tpl", link="home")
Ejemplo n.º 56
0
def do_transfers_extras():
    # retrieves the reference to the api object that is going
    # to be used for the updating of prices operation
    api = util.get_api()

    # tries to retrieve the origin value from the provided set
    # of fields and in case it's not defined re-renders the template
    origin = quorum.get_field("origin", None, cast = int)
    if not origin:
        return flask.render_template(
            "extra/transfers.html.tpl",
            link = "extras",
            error = "No origin defined"
        )

    # tries to retrieve the transfers file from the current
    # form in case it's not available renders the current
    # template with an error message
    transfers_file = quorum.get_field("transfers_file", None)
    if transfers_file == None or not transfers_file.filename:
        return flask.render_template(
            "extra/transfers.html.tpl",
            link = "extras",
            error = "No file defined"
        )

    # creates a temporary file path for the storage of the file
    # and then saves it into that directory
    fd, file_path = tempfile.mkstemp()
    transfers_file.save(file_path)

    # creates the file object that is going to be used in the
    # reading of the csv file (underlying object)
    file = open(file_path, "rb")
    try: data = file.read()
    finally: file.close()

    # constructs the bytes based buffer object from the data that
    # has just been loaded from the file
    buffer = quorum.legacy.BytesIO(data)

    # creates the maps that are going to be used to cache the
    # resolution processes for both the stores and the merchandise
    stores_map = dict()
    merchandise_map = dict()

    # creates the map that is going to hold the complete state
    # to be used in the process of the various transfers (context)
    state = dict()

    def get_transfer():
        return state.get("transfer", None)

    def new_transfer(target_id, workflow_state = 6):
        flush_transfer()
        transfer = dict(
            origin = dict(
                object_id = origin
            ),
            destination = dict(
                object_id = target_id
            ),
            transfer_lines = [],
            _parameters = dict(
                target_workflow_state = workflow_state
            )
        )
        state["transfer"] = transfer
        return transfer

    def flush_transfer():
        transfer = get_transfer()
        state["transfer"] = None
        if not transfer: return
        payload = dict(transfer = transfer)
        transfer = api.create_transfer(payload)
        transfer_id = transfer["object_id"]
        quorum.debug(
            "Created stock transfer '%d'" % transfer_id
        )
        return transfer

    def add_transfer_line(merchandise_id, quantity = 1):
        transfer = get_transfer()
        if not transfer: raise quorum.OperationalError(
            "No transfer in context"
        )
        lines = transfer["transfer_lines"]
        line = dict(
            quantity = quantity,
            merchandise = dict(
                object_id = merchandise_id
            )
        )
        lines.append(line)

    def get_store_id(store_code):
        object_id = stores_map.get(store_code, None)
        if object_id: return object_id

        kwargs = {
            "start_record" : 0,
            "number_records" : 1,
            "filters[]" : [
                "store_code:equals:%s" % store_code
            ]
        }

        try: stores = api.list_stores(**kwargs)
        except: stores = []
        if stores: object_id = stores[0]["object_id"]

        stores_map[store_code] = object_id
        return object_id

    def get_merchandise_id(company_product_code):
        # tries to retrieve the object id of the merchandise from the
        # cache and in case it succeeds returns it immediately
        object_id = merchandise_map.get(company_product_code, None)
        if object_id: return object_id

        # creates the map containing the (filter) keyword arguments that
        # are going to be send to the list merchandise operation
        kwargs = {
            "start_record" : 0,
            "number_records" : 1,
            "filters[]" : [
                "company_product_code:equals:%s" % company_product_code
            ]
        }

        # runs the list merchandise operation in order to try to find a
        # merchandise entity for the requested (unique) product code in
        # case there's at least one merchandise its object id is used
        try: merchandise = api.list_merchandise(**kwargs)
        except: merchandise = []
        if merchandise: object_id = merchandise[0]["object_id"]

        # updates the (cache) map for the merchandise with the reference
        # new object id to company product code reference and then returns
        # the object id of the merchandise to the caller method
        merchandise_map[company_product_code] = object_id
        return object_id

    def callback(line, header = None):
        code, quantity, _date, _time = line[:4]

        code = code.strip()
        quantity = quantity.strip()
        quantity = int(quantity)

        is_store = len(code) < 4
        if is_store: store_id = get_store_id(code)
        else: merchandise_id = get_merchandise_id(code)

        if is_store:
            if store_id: new_transfer(store_id)
            else: flush_transfer()
        elif merchandise_id:
            try: add_transfer_line(
                merchandise_id,
                quantity = quantity
            )
            except: pass

    try:
        # start the csv import operation that is going to import the
        # various lines of the csv in the buffer and for each of them
        # call the function passed as callback
        util.csv_import(buffer, callback, delimiter = ";")
        flush_transfer()
    finally:
        # closes the temporary file descriptor and removes the temporary
        # file (avoiding any memory leaks)
        os.close(fd)
        os.remove(file_path)

    # redirects the user back to the transfers list page with a success
    # message indicating that everything went ok
    return flask.redirect(
        flask.url_for(
            "transfers_extras",
            message = "Transfers file processed with success"
        )
    )
Ejemplo n.º 57
0
def list_suppliers():
    return flask.render_template(
        "supplier/list.html.tpl",
        link = "suppliers"
    )
Ejemplo n.º 58
0
def costs_extras():
    return flask.render_template(
        "extra/costs.html.tpl",
        link = "extras"
    )
Ejemplo n.º 59
0
def show_customers(id):
    api = util.get_api()
    customer = api.get_person(id)
    return flask.render_template("customer/show.html.tpl",
                                 link="customers",
                                 customer=customer)
Ejemplo n.º 60
0
def list_stores():
    return flask.render_template("store/list.html.tpl", link="stores")