From 836575a395dff08e424cff9e84930597a350e775 Mon Sep 17 00:00:00 2001 From: alex Date: Sun, 9 Jun 2024 00:22:19 +0200 Subject: [PATCH] filament roll label --- .../index.json | 4 +- .../script.py | 96 +++++++++++++-- .../shx-intern-filament-roll-label/index.html | 104 ++++++++++++++++ .../shx-intern-filament-roll-label/index.json | 42 +++++++ .../shx-intern-filament-roll-label/script.py | 85 +++++++++++++ .../shx-intern-product-bag-label/index.html | 1 - .../groupsData/google-sheet-filaments.json | 112 ++++++++++++++++++ .../filament-roll.png | Bin 0 -> 25879 bytes .../shx-intern-filament-roll-label/logo.svg | 14 +++ .../utils/__pycache__/utils.cpython-39.pyc | Bin 3630 -> 3815 bytes groupTasks/libs/utils/utils.py | 80 +++++++------ 11 files changed, 491 insertions(+), 47 deletions(-) rename groupTasks/groups/{shx-fetch-google-sheet-products => shx-fetch-google-sheet-data}/index.json (65%) rename groupTasks/groups/{shx-fetch-google-sheet-products => shx-fetch-google-sheet-data}/script.py (56%) create mode 100644 groupTasks/groups/shx-intern-filament-roll-label/index.html create mode 100644 groupTasks/groups/shx-intern-filament-roll-label/index.json create mode 100644 groupTasks/groups/shx-intern-filament-roll-label/script.py create mode 100644 groupTasks/groupsData/google-sheet-filaments.json create mode 100644 groupTasks/groupsData/shx-intern-filament-roll-label/filament-roll.png create mode 100644 groupTasks/groupsData/shx-intern-filament-roll-label/logo.svg diff --git a/groupTasks/groups/shx-fetch-google-sheet-products/index.json b/groupTasks/groups/shx-fetch-google-sheet-data/index.json similarity index 65% rename from groupTasks/groups/shx-fetch-google-sheet-products/index.json rename to groupTasks/groups/shx-fetch-google-sheet-data/index.json index 3ffd771..dfdba55 100644 --- a/groupTasks/groups/shx-fetch-google-sheet-products/index.json +++ b/groupTasks/groups/shx-fetch-google-sheet-data/index.json @@ -1,10 +1,10 @@ { "category": "Shinnex", - "name": "Produkte aus Google Sheets synchronisieren", + "name": "Daten aus Google Sheets synchronisieren", "globalInputs": [], "tasks": [ { - "name": "Produkte aus Google Sheets herunterladen", + "name": "Daten aus Google Sheets synchronisieren", "onFinish": "next", "undoPossible": false, "repeatPossible": true, diff --git a/groupTasks/groups/shx-fetch-google-sheet-products/script.py b/groupTasks/groups/shx-fetch-google-sheet-data/script.py similarity index 56% rename from groupTasks/groups/shx-fetch-google-sheet-products/script.py rename to groupTasks/groups/shx-fetch-google-sheet-data/script.py index 4a3a8f7..8577de8 100644 --- a/groupTasks/groups/shx-fetch-google-sheet-products/script.py +++ b/groupTasks/groups/shx-fetch-google-sheet-data/script.py @@ -3,6 +3,11 @@ import json import codecs import sys +SERVICE_ACCOUNT_FILENAME = "../../secrets/shinnex-424321-b88b144bc9ef.json" +GOOGLE_SPEADSHEET_KEY = "1gZkjykb55aLWumBxHxj_ZUq_ktjGK4FlJsH_9qg-ThU" # from url +WORKSHEET_PRODUCTS = "Produkte" +WORKSHEET_FILAMENTS = "Filamente" + def add_underscore_at_position(text, position): # Split the string into a list of words @@ -56,20 +61,38 @@ def update_grouptask_products_list_options(index_json_path, products_list): json.dump(data, output_file, ensure_ascii=False, indent=2) +def update_grouptask_filaments_list_options(index_json_path, filaments_list): + with open(index_json_path, 'r', encoding='utf-8') as json_file: + data = json.load(json_file) + + options_list = [] + + for filament in filaments_list: + option = f"{filament['id']} {filament['name_color']}, {filament['material']}, {filament['manufacturer']}" + options_list.append(option) + + for task in data['tasks']: + for parameter in task['parameters']: + if parameter['parameterName'] == 'filament_type_id': + parameter['options'] = options_list + + with open(index_json_path, 'w', encoding='utf-8') as output_file: + json.dump(data, output_file, ensure_ascii=False, indent=2) + + def google_sheets_products(): - gc = gspread.service_account( - filename="../../secrets/shinnex-424321-b88b144bc9ef.json") + gc = gspread.service_account(filename=SERVICE_ACCOUNT_FILENAME) - spreadsheet = gc.open_by_key( - "1gZkjykb55aLWumBxHxj_ZUq_ktjGK4FlJsH_9qg-ThU") + spreadsheet = gc.open_by_key(GOOGLE_SPEADSHEET_KEY) - worksheet = spreadsheet.worksheet("Produkte") + worksheet = spreadsheet.worksheet(WORKSHEET_PRODUCTS) data = worksheet.get_all_values() # auto get the row index numbers for the columns products = [] + rowIndexProductId = -1 rowIndexProductName = -1 rowIndexProductVariant = -1 @@ -94,7 +117,8 @@ def google_sheets_products(): rowIndexNameSplitAtPosition = i if rowIndexProductId == -1 or rowIndexProductId == -1 or rowIndexProductName == -1 or rowIndexProductVariant == -1 or rowIndexProductCharacteristicLine1 == -1 or rowIndexProductCharacteristicLine2 == -1: - sys.exit("Failed to get row index. Please check if the row names are equal to the names of the google sheet table header") + sys.exit( + f"Failed to get row index. Please check if the row names are equal to the names of the google sheet table header of {WORKSHEET_PRODUCTS}") # adding products to list @@ -112,7 +136,7 @@ def google_sheets_products(): products_dict = {"products": products} - # Write the products list to a JSON file + # write the products list to a JSON file with open('../../groupsData/google-sheet-products.json', 'w', encoding='utf-8') as json_file: json.dump(products_dict, json_file, ensure_ascii=False, indent=2) @@ -124,4 +148,62 @@ def google_sheets_products(): print("Finished. Do not forget to reload the group configuration by clicking on the 'Reload' button above the table on the right side.") +def google_sheets_filaments(): + gc = gspread.service_account(filename=SERVICE_ACCOUNT_FILENAME) + + spreadsheet = gc.open_by_key(GOOGLE_SPEADSHEET_KEY) + + worksheet = spreadsheet.worksheet(WORKSHEET_FILAMENTS) + + data = worksheet.get_all_values() + + # auto get the row index numbers for the columns + + filaments = [] + + rowIndexFilamentId = -1 + rowIndexFilamentNameColor = -1 + rowIndexFilamentMaterial = -1 + rowIndexFilamentManufacturer = -1 + + for i in range(len(data[0])): + row = data[0][i] + + if row == "id": + rowIndexFilamentId = i + elif row == "Name/Farbe": + rowIndexFilamentNameColor = i + elif row == "Material": + rowIndexFilamentMaterial = i + elif row == "Hersteller": + rowIndexFilamentManufacturer = i + + if rowIndexFilamentId == -1 or rowIndexFilamentNameColor == -1 or rowIndexFilamentMaterial == -1 or rowIndexFilamentManufacturer == -1: + sys.exit( + f"Failed to get row index. Please check if the row names are equal to the names of the google sheet table header of {WORKSHEET_FILAMENTS}") + + # adding filaments to list + + for row in data[2:]: + if row[0] == "": + continue + + filaments.append({ + "id": row[rowIndexFilamentId], + "name_color": row[rowIndexFilamentNameColor], + "material": row[rowIndexFilamentMaterial], + "manufacturer": row[rowIndexFilamentManufacturer] + }) + + filaments_dict = {"filaments": filaments} + + # write the filaments list to a JSON file + with open('../../groupsData/google-sheet-filaments.json', 'w', encoding='utf-8') as json_file: + json.dump(filaments_dict, json_file, ensure_ascii=False, indent=2) + + update_grouptask_filaments_list_options( + "../../groups/shx-intern-filament-roll-label/index.json", filaments) + + google_sheets_products() +google_sheets_filaments() diff --git a/groupTasks/groups/shx-intern-filament-roll-label/index.html b/groupTasks/groups/shx-intern-filament-roll-label/index.html new file mode 100644 index 0000000..cd7e074 --- /dev/null +++ b/groupTasks/groups/shx-intern-filament-roll-label/index.html @@ -0,0 +1,104 @@ + + + + + + Intern Filament Roll Label + + + +
+
+
+
+
+
+ + +

+ {{FILAMENT_ID}} +

+
+ + +
+ +
+

+ {{FILAMENT_NAME_COLOR}} +

+

+ {{FILAMENT_MATERIAL}} +

+

+ {{FILAMENT_MANUFACTURER}} +

+
+
+ + {{DATE}} +
+ +
+ +
+
+
+ + diff --git a/groupTasks/groups/shx-intern-filament-roll-label/index.json b/groupTasks/groups/shx-intern-filament-roll-label/index.json new file mode 100644 index 0000000..7ca04a7 --- /dev/null +++ b/groupTasks/groups/shx-intern-filament-roll-label/index.json @@ -0,0 +1,42 @@ +{ + "category": "Shinnex", + "name": "Internes Etikett für Filamentrolle", + "globalInputs": [], + "tasks": [ + { + "name": "Internes Etikett für Filamentrolle erstellen", + "onFinish": "next", + "undoPossible": false, + "repeatPossible": true, + "scriptPath": "script.py", + "parameters": [ + { + "parameterName": "filament_type_id", + "type": "select", + "displayName": "Filament auswählen", + "global": false, + "options": [ + "11 Weiß, Matte PLA, OVERTURE", + "12 Gold, Silk PLA, OVERTURE", + "13 Rot, Silk PLA, OVERTURE", + "14 Holzfarbe, Matte PLA, OVERTURE", + "15 Rot/Blau, Dual-Color Silk PLA, ERYONE", + "16 Orange/Blau/Grün, Tri-Color Silk PLA, TRONXY", + "17 Blau, Fluorescent PLA, ZIRO", + "18 Orange, Fluorescent PLA, ZIRO", + "19 Diamant-Smaragdgrün, Glitter PLA, ZIRO", + "20 Schwarz Glänzend, Silk PLA, SUNLU", + "21 Rosa, Matte PLA, OVERTURE", + "22 Hellgrau, Matte PLA, OVERTURE", + "23 Schokolade, Matte PLA, OVERTURE", + "24 Rosa/Weiß, Silk PLA, SUNLU", + "25 Blau/Weiß, TempChange Matte PLA, TRONXY", + "26 Beige, Matte PLA, OVERTURE", + "27 Marineblau, Matte PLA, OVERTURE", + "28 Gelb, Matte PLA, OVERTURE" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/groupTasks/groups/shx-intern-filament-roll-label/script.py b/groupTasks/groups/shx-intern-filament-roll-label/script.py new file mode 100644 index 0000000..d8445a3 --- /dev/null +++ b/groupTasks/groups/shx-intern-filament-roll-label/script.py @@ -0,0 +1,85 @@ +import json +import subprocess +import sys +import os +from datetime import datetime + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) + +from libs.utils import utils + +json_object = json.loads(sys.argv[1]) +filament_type_id = json_object["filament_type_id"] + +if filament_type_id is None: + print("Missing required parameters") + sys.exit(1) + +filament_type_id = filament_type_id["value"] + +def createHighDpiPng(sourceHtml, outputPng): + # Calculate scaled dimensions + scale_factor = 1 + width = int(1020 * scale_factor) # Original width in pixels multiplied by the scale factor + height = int(400 * scale_factor) # Original height in pixels multiplied by the scale factor + + command = [ + "google-chrome-stable", + "--headless", + "--no-sandbox", + "--disable-gpu", + "--screenshot=" + outputPng, + "--window-size={},{}".format(width, height), # Set window size to scaled dimensions + "--force-device-scale-factor={}".format(scale_factor), # Set device scale factor + sourceHtml, + ] + + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + _, stderr = process.communicate() + + if process.returncode != 0: + print("Error creating PNG") + print(stderr.decode()) # Decoding the stderr for better readability + sys.exit(1) + + +if __name__ == "__main__": + utils.move_files_back_from_old_files() + + # replace placeholders in index.html + f_type_id = utils.extract_filament_id(filament_type_id) + + data = { + "invex_id": "", + "shx_filament_id": f_type_id + } + + utils.create_qrcode(json.dumps(data), "./qrcode.png", "#fff") + + with open('../../groupsData/google-sheet-filaments.json', 'r', encoding='utf-8') as json_file: + data = json.load(json_file) + + for filament in data["filaments"]: + if filament["id"] == f_type_id: + with open("index.html", "r") as file: + indexhtml = file.read() + + indexhtml = indexhtml.replace("{{FILAMENT_ID}}", filament["id"]) + indexhtml = indexhtml.replace("{{FILAMENT_NAME_COLOR}}", filament["name_color"]) + indexhtml = indexhtml.replace("{{FILAMENT_MATERIAL}}", filament["material"]) + indexhtml = indexhtml.replace("{{FILAMENT_MANUFACTURER}}", filament["manufacturer"]) + + now = datetime.now() + formatted_date = now.strftime("%d.%m.%Y") + + indexhtml = indexhtml.replace("{{DATE}}", formatted_date) + + with open("index.html", "w") as file: + file.write(indexhtml) + + break + + + createHighDpiPng("index.html", "filament-roll-label.png") + + utils.clear_workspace(["index.html", "qrcode.png"]) \ No newline at end of file diff --git a/groupTasks/groups/shx-intern-product-bag-label/index.html b/groupTasks/groups/shx-intern-product-bag-label/index.html index cf677d0..d84ad8f 100644 --- a/groupTasks/groups/shx-intern-product-bag-label/index.html +++ b/groupTasks/groups/shx-intern-product-bag-label/index.html @@ -36,7 +36,6 @@ display: flex; flex-direction: column; justify-content: space-between; - height: 100%; } h3 { diff --git a/groupTasks/groupsData/google-sheet-filaments.json b/groupTasks/groupsData/google-sheet-filaments.json new file mode 100644 index 0000000..4b67f29 --- /dev/null +++ b/groupTasks/groupsData/google-sheet-filaments.json @@ -0,0 +1,112 @@ +{ + "filaments": [ + { + "id": "11", + "name_color": "Weiß", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "12", + "name_color": "Gold", + "material": "Silk PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "13", + "name_color": "Rot", + "material": "Silk PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "14", + "name_color": "Holzfarbe", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "15", + "name_color": "Rot/Blau", + "material": "Dual-Color Silk PLA", + "manufacturer": "ERYONE" + }, + { + "id": "16", + "name_color": "Orange/Blau/Grün", + "material": "Tri-Color Silk PLA", + "manufacturer": "TRONXY" + }, + { + "id": "17", + "name_color": "Blau", + "material": "Fluorescent PLA", + "manufacturer": "ZIRO" + }, + { + "id": "18", + "name_color": "Orange", + "material": "Fluorescent PLA", + "manufacturer": "ZIRO" + }, + { + "id": "19", + "name_color": "Diamant-Smaragdgrün", + "material": "Glitter PLA", + "manufacturer": "ZIRO" + }, + { + "id": "20", + "name_color": "Schwarz Glänzend", + "material": "Silk PLA", + "manufacturer": "SUNLU" + }, + { + "id": "21", + "name_color": "Rosa", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "22", + "name_color": "Hellgrau", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "23", + "name_color": "Schokolade", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "24", + "name_color": "Rosa/Weiß", + "material": "Silk PLA", + "manufacturer": "SUNLU" + }, + { + "id": "25", + "name_color": "Blau/Weiß", + "material": "TempChange Matte PLA", + "manufacturer": "TRONXY" + }, + { + "id": "26", + "name_color": "Beige", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "27", + "name_color": "Marineblau", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + }, + { + "id": "28", + "name_color": "Gelb", + "material": "Matte PLA", + "manufacturer": "OVERTURE" + } + ] +} \ No newline at end of file diff --git a/groupTasks/groupsData/shx-intern-filament-roll-label/filament-roll.png b/groupTasks/groupsData/shx-intern-filament-roll-label/filament-roll.png new file mode 100644 index 0000000000000000000000000000000000000000..40fccd2d26bf41ce17fc14d362c4d8dae6e073c3 GIT binary patch literal 25879 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 + + + + + + + + + + + + + diff --git a/groupTasks/libs/utils/__pycache__/utils.cpython-39.pyc b/groupTasks/libs/utils/__pycache__/utils.cpython-39.pyc index f36f72e8ada4988d1ce18dde054d7515dbb9d165..fb84667d67d619b86eff7a62414eb8f8510fdf01 100644 GIT binary patch delta 275 zcmZ1{^IVoUk(ZZ?0SG=`Pf0sDkyn@g8Gxp;_}vmtttcr21QMD| zMFJqUA&AX*O8}~9@;Pn^!6IXzU?mV2vj7POMy|~)Jg$t4=99g64H)YtSM$oVSpmg0 w1tu@xm14A*yqi~Dzz8S+)>j0QD&n5JkX3jRA0MOKWPUy=b}fU1g_Kx#K{<8ftVG@JZ~*MPBNvM!&zq9ssN zlfOt4NEL~L2v!im2O`u!g!$xLK6N%@5Yuw