From e617ad71b4756b81c66bff8ddc3a2d4979ff12ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Piqu=C3=A9?= Date: Thu, 2 Oct 2025 08:33:11 +0200 Subject: [PATCH] v1.6 init on gitea --- Install_requirements.bat | 42 +++++ ReadMe.txt | 60 +++++++ Script/.gitignore | 6 + Script/P4U-Converter.bat | 30 ++++ Script/app.py | 112 +++++++++++++ Script/main.py | 208 +++++++++++++++++++++++ Script/requirements.txt | 44 +++++ Script/templates/Warenkorb.xlsx | Bin 0 -> 18293 bytes Script/templates/index.html | 284 ++++++++++++++++++++++++++++++++ Script/templates/logo.png | Bin 0 -> 3617 bytes 10 files changed, 786 insertions(+) create mode 100644 Install_requirements.bat create mode 100644 ReadMe.txt create mode 100644 Script/.gitignore create mode 100644 Script/P4U-Converter.bat create mode 100644 Script/app.py create mode 100644 Script/main.py create mode 100644 Script/requirements.txt create mode 100644 Script/templates/Warenkorb.xlsx create mode 100644 Script/templates/index.html create mode 100644 Script/templates/logo.png diff --git a/Install_requirements.bat b/Install_requirements.bat new file mode 100644 index 0000000..9bf0111 --- /dev/null +++ b/Install_requirements.bat @@ -0,0 +1,42 @@ +@echo off + +rem Ermittle und zeige den aktuellen Pfad an +set "scriptPath=%~dp0" +echo Der aktuelle Pfad ist: %scriptPath% + +rem Überprüfe, ob Python installiert ist +python --version > nul 2>&1 +if %errorlevel% neq 0 ( + msg * Python ist nicht installiert. Bitte installiere Python und führe das Skript erneut aus. + exit /b +) + +rem Überprüfe, ob pip installiert ist +pip --version > nul 2>&1 +if %errorlevel% neq 0 ( + msg * pip ist nicht installiert. Bitte installiere pip und führe das Skript erneut aus. + exit /b +) + +rem Installiere Abhängigkeiten mit pip +pip install -r .\Script\requirements.txt + +rem Überprüfe, ob die Installation erfolgreich war +if %errorlevel% neq 0 ( + msg * Fehler: Die pip-Installation ist fehlgeschlagen. Bitte überprüfe die obige Fehlermeldung. + exit /b +) + +msg * Pip-Installation erfolgreich. + +rem Erstelle eine Verknüpfung zu P4U-Converter.bat +set "shortcutTarget=%scriptPath%Script/P4U-Converter.bat" +set "shortcutName=%scriptPath%P4U-Converter.lnk" + +echo Set oWS = WScript.CreateObject("WScript.Shell") > CreateShortcut.vbs +echo sLinkFile = "%shortcutName%" >> CreateShortcut.vbs +echo Set oLink = oWS.CreateShortcut(sLinkFile) >> CreateShortcut.vbs +echo oLink.TargetPath = "%shortcutTarget%" >> CreateShortcut.vbs +echo oLink.Save >> CreateShortcut.vbs +cscript /nologo CreateShortcut.vbs +del CreateShortcut.vbs diff --git a/ReadMe.txt b/ReadMe.txt new file mode 100644 index 0000000..8d0e80f --- /dev/null +++ b/ReadMe.txt @@ -0,0 +1,60 @@ + +################################################################################# +# +# P4U Script for converting Baskets from Digikey / Mouser to P4U format +# Created by Jonas Lingua & Noah Piqué +# Date: 02.10.2025 +# Version 1.6 +# +################################################################################ + +## New: +- Use via website + +## Infos: +- python3 script + +# Instruction Windows: +- Install Python 3 via Softwarekiosk +- Execute"Install_requirements.bat" # You only have to run this command once! +- Execute "P4U-Converter" # This link should be displayed when the requirements have been successfully installed. Drag this link to the place you want. + +# Instruction Linux/MacOS: +- Install Python 3 via Softwarekiosk +cd Script +pip install -r requirements.txt # You only have to run this command once! +python app.py # for web-based upload +or +python main.py [mouser/digikey] [filename] [fasttrack] # for console-use + evt. python3, depending on the installation environment + +# Console changes +If you still want to use the console, please put your xls/csv files in the "uploads" folder. +Your new carts will be saved in the "exports" folder. + +# Distributor informations +- mouser -> xls file in euros! +- digikey -> csv file in chf! +- please dont change this file + +# using the app.py script for any distributor: +- go to distributor and create cart +- then set currency to euros/chf (See "Distributor informations") +- download cart xls/csv (See "Distributor informations") +- excute the link/command +- upload the file in the webinterface +- click on download +- now you can upload this file to p4u + +# using the main.py script for any distributor: +- go to distributor and create cart +- then set currency to euros/chf (See "Distributor informations") +- download cart xls/csv (See "Distributor informations") +- put the file in the same folder as the main.py script +- execute the command from "Instruction Windows/Linux/MacOS": +python main.py mouser name_of_my_basket.xls +- OR execute this command for fasttrack order: +python main.py mouser name_of_my_basket.xls fasttrack +- outputs file -> Warenkorb_distributor.xlsx +- now you can upload this file to p4u + diff --git a/Script/.gitignore b/Script/.gitignore new file mode 100644 index 0000000..6e473ac --- /dev/null +++ b/Script/.gitignore @@ -0,0 +1,6 @@ +.idea +*.xls +*.csv +__pycache__ +Warenkorb_*.xlsx +*.lnk diff --git a/Script/P4U-Converter.bat b/Script/P4U-Converter.bat new file mode 100644 index 0000000..c0454eb --- /dev/null +++ b/Script/P4U-Converter.bat @@ -0,0 +1,30 @@ +@echo off +chcp 65001 >nul +setlocal enabledelayedexpansion +set "script_directory=%~dp0" + +:: Überprüfe, ob 'python3' oder 'python' verfügbar ist +set python_cmd= +for %%P in (python3 python) do ( + %%P --version >nul 2>&1 + if !errorlevel! equ 0 ( + set python_cmd=%%P + goto :found_python + ) +) + +:found_python +if "%python_cmd%"=="" ( + echo [FEHLER] Kein funktionierender Python-Interpreter gefunden. + exit /b 1 +) + +echo [INFO] Python-Interpreter gefunden: %python_cmd% + +cd /d "%script_directory%" + +:: Starte die Python-Anwendung und zeige die Ausgabe in der Konsole +echo [INFO] Starte die Python-Anwendung... +%python_cmd% "app.py" + +exit /b 0 \ No newline at end of file diff --git a/Script/app.py b/Script/app.py new file mode 100644 index 0000000..3c78e06 --- /dev/null +++ b/Script/app.py @@ -0,0 +1,112 @@ + +################################################################################# +# +# P4U Script for converting Baskets from Digikey / Mouser to P4U format +# Created by Jonas Lingua & Noah Piqué +# Date: 02.10.2025 +# Version 1.6 +# +################################################################################ + +# Importieren der erforderlichen Module +from flask import Flask, request, render_template, send_file +import os +import main +import csv +import webbrowser + +url = "http://127.0.0.1:5000" +webbrowser.open_new_tab(url) + + +# Erstellen einer Flask-App-Instanz +app = Flask(__name__) + +# Überprüfe, ob der Ausgabeordner existiert, und erstelle ihn, falls nicht +if not os.path.exists('exports'): + os.makedirs('exports') +# Überprüfe, ob der Eingabeordner existiert, und erstelle ihn, falls nicht +if not os.path.exists('uploads'): + os.makedirs('uploads') +# Festlegen des Upload-Verzeichnisses +UPLOAD_FOLDER = 'uploads' +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER + +# Globale Variable zur Speicherung des Slider-Status +fasttrack_status = True + +# Routen-Handler für die Startseite +@app.route('/') +def index(): + return render_template('index.html') + + +# Routen-Handler für das Aktualisieren des Slider-Status +@app.route('/update_slider_status', methods=['POST']) +def update_slider_status(): + global fasttrack_status + data = request.get_json() + new_status = data.get('fasttrack_status') + fasttrack_status = new_status + return 'Slider-Status aktualisiert' + +# Routen-Handler für das Hochladen von Dateien +@app.route('/upload', methods=['POST']) +def upload_file(): + if 'file' in request.files: + file = request.files['file'] + if file: + # Speichern der hochgeladenen Datei im Upload-Verzeichnis + uploaded_file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename) + file.save(uploaded_file_path) + dist = distributor(uploaded_file_path) + global new_file + new_file = 'Warenkorb_' + dist + '.xlsx' + web_in = ['main.py', dist, file.filename] + if fasttrack_status: + web_in.append('fasttrack') + else: + web_in = web_in[0:3] + main.p4u(web_in) + clearFolder("uploads") + return main.printout + return 'Error uploading the file. See console' + +# Routen-Handler für das Herunterladen der output-Datei +@app.route('/download_output') +def download_output_file(): + output_file_path = os.path.join('exports', new_file) + return send_file(output_file_path, as_attachment=True) + +def clearFolder(path): + try: + dateien = os.listdir(path) + for datei in dateien: + datei_pfad = os.path.join(path, datei) + if os.path.isfile(datei_pfad): + os.remove(datei_pfad) # Lösche die Datei + elif os.path.isdir(datei_pfad): + os.rmdir(datei_pfad) # Lösche den Ordner + except Exception as e: + print(f"Error during deleting the folder: {str(e)}") + +def distributor(filename): + if filename[-4:] == '.csv': + try: + with open(filename, 'r') as CSV: + read_csv = csv.reader(CSV, delimiter=",") + read_csv = list(read_csv) + if read_csv[1][2][-3:] == '-ND': + return 'digikey' + else: + return 'not found' + except: + print("Error: could not open the file") + exit(1) + else: + return 'mouser' + +# Starten der Flask-Anwendung, wenn die Datei direkt ausgeführt wird +if __name__ == '__main__': + app.run(debug=False) + clearFolder('exports') diff --git a/Script/main.py b/Script/main.py new file mode 100644 index 0000000..b8063f3 --- /dev/null +++ b/Script/main.py @@ -0,0 +1,208 @@ +################################################################################# +# +# P4U Script for converting Baskets from Digikey / Mouser to P4U format +# Created by Jonas Lingua & Noah Piqué +# Date: 02.10.2025 +# Version 1.6 +# +################################################################################ + + +from xlrd import open_workbook +from openpyxl import load_workbook +import sys +import csv + +printout = "" +def prints(string): + global printout + printout += str(string) + "
" + print(string) + +# converting mouser xls file to array +def load_mouser(file_mouser, fast=False): + try: + wb = open_workbook(file_mouser) + except: + prints("Error(Mouser): could not open the file") + return 0 + + prints('Reading File Succeded') + + sh = wb.sheet_by_index(0) + + col = sh.col_values(0) + offset_mouser = col.index(1) + if offset_mouser == -1: + prints('Error(Mouser): did not find a part') + return 0 + + nparts = col.index('', offset_mouser) - offset_mouser + if nparts <= -1: + prints('Error(Mouser): did not the end of the file') + return 0 + + vertrag = 'Mouser Electronics, Elsenheimerstrasse 11, 80687, München, DE (EUR)' + if fast: + vertrag = 'Mouser Electronics (EUR) (Fasttrack)' + part_mouser = ['', '', vertrag, 'Mouser Electronics', '', '', '', '', '', 820, 0, 'Stück', '', '', '', '', '', '8.1', 0, 'EUR'] + parts_mouser = [] + + for part in range(nparts): + parts_mouser.append(part_mouser.copy()) + + for x, y in enumerate(range(offset_mouser, offset_mouser + nparts)): + parts_old = sh.row_values(y, 0, 11) + parts_mouser[x][0] = str(int(parts_old[0])) + parts_mouser[x][1] = parts_old[1] + parts_mouser[x][4] = parts_old[3] + parts_mouser[x][5] = parts_old[2] + parts_mouser[x][6] = parts_old[3] + " " + parts_old[2] + parts_mouser[x][7] = parts_old[5] + parts_mouser[x][10] = int(parts_old[8]) + w = parts_old[9][-1] + if w != '€': + prints('Error: please change mouser currency to euro and retry') + return 0 + try: + p = float(parts_old[9][0:-2].replace(',', '.')) + except ValueError: + prints("Error: mouser price is not in right format") + return 0 + parts_mouser[x][18] = p + + #prints(parts_mouser) + + return parts_mouser + + +# converting digikey csv file to array +def load_digikey(file_digikey, fast=False): + try: + with open(file_digikey, 'r') as CSV: + read_csv = csv.reader(CSV, delimiter=",") + read_csv = list(read_csv) + except: + prints("Error: could not open the file") + return 0 + + prints('Reading File Succeded') + + offset_digikey = -1 + for i, row in enumerate(read_csv): + if (row[0]) == '1': + offset_digikey = i + break + + if offset_digikey <= -1: + prints('Error(Digikey): did not the start of the file') + return 0 + + nparts = len(read_csv) - offset_digikey + + vertrag = 'Digi-Key Corporation, Brooks Avenue South 701, 56701, Thief River Falls, US (CHF)' + if fast: + vertrag = 'Digi-Key Corporation (CHF) (Fasttrack)' + # Index,"Menge","Teilenummer","Hersteller-Teilenummer","Beschreibung","Kundenreferenz","Verfügbar","Lieferrückstände","Stückpreis","Gesamtpreis EUR" + # Position Artikelnummer Vertrag Lieferant Hersteller Herstellernummer Kurztext Langtext Materialnummer Standardwarengruppe Menge Einheiten ppppp MwSt-Satz Preis Währung + part_digikey = ['', '', vertrag, 'Digi-Key Corporation', '', '', '', '', '', 820, 0, 'Stück', '', '', '', '', '', '8.1', 0, 'CHF'] + parts_digikey = [] + + for part in range(nparts): + parts_digikey.append(part_digikey.copy()) + + for x, y in enumerate(range(offset_digikey, offset_digikey + nparts)): + parts_old = read_csv[y] + parts_digikey[x][0] = str(int(parts_old[0])) + parts_digikey[x][1] = parts_old[2] + parts_digikey[x][5] = parts_old[3] + parts_digikey[x][6] = parts_old[3] + parts_digikey[x][7] = parts_old[4] + parts_digikey[x][10] = int(parts_old[1]) + w = parts_old[9][-3:] + if w != 'Fr.': + prints('Error: please change digikey currency to chf and retry') + return 0 + try: + p = float(parts_old[8].replace(',', '.')) + except ValueError: + prints("Error: digikey price is not in right format") + return 0 + parts_digikey[x][18] = p + + # prints(parts_digikey) + + return parts_digikey + +load_functions = {'mouser': load_mouser, 'digikey': load_digikey} +fasttrack = ['mouser', 'digikey'] + +def p4u(args): + global printout + printout = "" + + if len(args) <= 2: + prints("Error: please specify a type(mouser/digikey) and a file") + return 0 + else: + file_type = args[1] + file = "uploads/" + args[2] + fast = '' + if len(args) == 4: + fast = args[3] + + parts = [] + + if file_type in load_functions.keys(): + prints("Found load function for " + file_type) + try: + if fast == 'fasttrack' and file_type in fasttrack: + prints('Fasttrack Order found') + parts.extend(load_functions[file_type](file, True)) + else: + prints('No Fasttrack') + parts.extend(load_functions[file_type](file)) + except: + prints("Error: could not open the file") + return 0 + else: + prints("Error: wrong type of file(mouser/digikey)") + return 0 + + if not parts: + prints('Error: no data recieved (empty files?)(wrong filename?)') + return 0 + + new_file = './Warenkorb_' + file_type + '.xlsx' + prints('Writing to new File: ' + new_file) + + try: + wb_neu = load_workbook('./templates/Warenkorb.xlsx') + except: + prints("Error: template Warenkorb.xlsx is missing, please put it back in the templates folder") + return 0 + + sh_neu = wb_neu.active + + offset = 0 + + for i, row in enumerate(sh_neu.values): + if (row[0]) == 'Position': + offset = i + 1 + + for i in range(len(parts)): + for j in range(len(parts[i])): + sh_neu.cell(offset + i + 1, j + 1, parts[i][j]) + + wb_neu.save('./exports/' + new_file) + + prints('Finished') + return new_file + +if __name__ == '__main__': + + if(not p4u(sys.argv)): + print(printout) + sys.exit(1) + print("Done") + #print(printout) \ No newline at end of file diff --git a/Script/requirements.txt b/Script/requirements.txt new file mode 100644 index 0000000..d0be68e --- /dev/null +++ b/Script/requirements.txt @@ -0,0 +1,44 @@ +altgraph==0.17.4 +attrs==23.1.0 +auto-py-to-exe==2.41.0 +blinker==1.7.0 +bottle==0.12.25 +bottle-websocket==0.2.9 +certifi==2023.7.22 +cffi==1.16.0 +click==8.1.7 +colorama==0.4.6 +Eel==0.16.0 +et-xmlfile==1.1.0 +Flask==3.0.0 +future==0.18.3 +gevent==23.9.1 +gevent-websocket==0.10.1 +greenlet==3.0.1 +h11==0.14.0 +idna==3.4 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +openpyxl==3.0.10 +outcome==1.3.0.post0 +packaging==23.2 +pefile==2023.2.7 +pycparser==2.21 +pyinstaller==6.1.0 +pyinstaller-hooks-contrib==2023.10 +pyparsing==3.1.1 +PySocks==1.7.1 +pywin32-ctypes==0.2.2 +selenium==4.15.2 +sniffio==1.3.0 +sortedcontainers==2.4.0 +trio==0.23.1 +trio-websocket==0.11.1 +urllib3==2.0.7 +Werkzeug==3.0.1 +whichcraft==0.6.1 +wsproto==1.2.0 +xlrd==2.0.1 +zope.event==5.0 +zope.interface==6.1 diff --git a/Script/templates/Warenkorb.xlsx b/Script/templates/Warenkorb.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3e54997d4856c6d3897d06ab24466279082770a2 GIT binary patch literal 18293 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

e<-**Cv6+_~$1jrqycpK35q049R~lY|etx zpI=$Nf(Fi_9js$_FjR^{@O4k5D(Up`j`W#+mL;=oosidp*zHM)Y<6Msc~~E3Xb+T5 zV4oTt zD;yY2Q@ruo=v?9XilTC;K-)$)p2Z``=GaR zH3i9KAy3~8BiqBWJ}cr>cQB#spq*ai9<1%2h%D`*6^0)1rs&+A?R*`ml}x#vTq7cB zx_f&|+?Ge?6xNF(!}q@PtUL`F5kH0P42l#Hej_D^JYdVX(O1k`4;g{ z`wlPT3v1`zx7oav?%)eDQwM5}lgPJUzxaE-SfR<=pV%KY(D3IXa!b5%kuR$1S2+9} zp3H$c4vx%IxA4so-oxjszEmpO?6F&)9y(9ng&bFmO_>0psgujINmrTWnTpqrB@{3Cd$v<-W@hZwgE)S2wesK|^ z{=wzp!Pr9v4>$9EF=%`7gTb$@y@#X^7u&x`wOIckeYo^~$l>A2>KBL4>_0gCyLHw> zMh_$9UyNwDelYr<;^v18AI6x!7z%R#VEDI)^C9)$1Cw90ARv;wARzw|raUD7`xNp! f`4azc + + + + + + + + + + + + + + + + + P4U-Converter + + + + + + +

+ Created by Jonas Lingua & + Noah Piqué +
+ + +

P4U-Converter

+ + +
+ Upload-Informations:
+ Convert your Digikey, Mouser and Farnell baskets to P4U standard.
+ Just upload your files here.
+ File conditions:
+ Digikey -> csv file in chf!
+ Mouser -> xls file in euros! +
+ + +
+ + +
+ + +
+ Drop a file to upload +
+ + +
+ + +
+ + +

+ + + + + + + + diff --git a/Script/templates/logo.png b/Script/templates/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ed0ba8e9723075b7e7166b139cb5b9e42913aefe GIT binary patch literal 3617 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 literal 0 HcmV?d00001