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)
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 )
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)
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 )
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)
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)
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)
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 )
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())
def new_media_browser(id): return flask.render_template( "extra/browser/new_media.html.tpl", link = "extras", object_id = id, media = dict(), errors = dict() )
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)
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 )
def handler_404(error): return flask.Response( flask.render_template( "error.html.tpl", error = "404 - Page not found" ), status = 404 )
def handler_413(error): return flask.Response( flask.render_template( "error.html.tpl", error = "412 - Precondition failed" ), status = 413 )
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 )
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 )
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)
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)
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 )
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 )
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() )
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())
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 )
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 )
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 )
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 )
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)
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() )
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 )
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" ) )
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" ) )
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)
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 )
def signin(): next = quorum.get_field("next", None) return flask.render_template( "signin.html.tpl", next = next )
def index(): return flask.render_template( "index.html.tpl", link = "home" )
def inventory_extras(): return flask.render_template( "extra/inventory.html.tpl", link = "extras" )
def prices_extras(): return flask.render_template( "extra/prices.html.tpl", link = "extras" )
def media_extras(): return flask.render_template( "extra/media.html.tpl", link = "extras" )
def list_entities(): return flask.render_template( "entity/list.html.tpl", link = "entities" )
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" ) )
def list_customers(): return flask.render_template("customer/list.html.tpl", link="customers")
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" ) )
def signin(): next = quorum.get_field("next", None) return flask.render_template("signin.html.tpl", next=next)
def costs_extras(): return flask.render_template( "extra/costs.html.tpl", link = "extras" )
def handler_404(error): return flask.Response(flask.render_template("error.html.tpl", error="404 - Page not found"), status=404)
def transfers_extras(): return flask.render_template( "extra/transfers.html.tpl", link = "extras" )
def list_entities(): return flask.render_template("entity/list.html.tpl", link="entities")
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" ) )
def handler_413(error): return flask.Response(flask.render_template( "error.html.tpl", error="412 - Precondition failed"), status=413)
def index(): return flask.render_template("index.html.tpl", link="home")
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" ) )
def list_suppliers(): return flask.render_template( "supplier/list.html.tpl", link = "suppliers" )
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)
def list_stores(): return flask.render_template("store/list.html.tpl", link="stores")