List of commits:
Subject Hash Author Date (UTC)
added EAN to the picklist automated the export pull 69605ee944f5b1a2f4b80238ce19ccacc15cbe80 Sebastian 2019-06-27 10:02:00
Fixed a bug with the upload folder on Windows 5d01a8a44bd2f9b77e45b082f274acb6abc4e26d Sebastian 2019-06-05 08:36:45
Added a difference check and refactoring + removal of old elements, Added a config path solution 914c5e14ba2c4051544b68d263726380e0ed4b29 Sebastian 2019-06-05 07:47:24
Fixed a bug that occured when there were 2 locations with the same sku and package and which caused the wrong writing the wrong numbers into the packagelist 75dde60e1034e5b3889b012d995fffbf4d9a296f Sebastian 2019-05-29 09:30:46
Added packlist fill script 8f3849dc0ad5fa4ad5ce9a6732429c6e647a5187 Sebastian 2019-05-10 15:42:12
Included an export to the storage list from Amazon, imporved useability by adding stops 810be612ed40559434e9ddacb904bc4a766b861d Sebastian 2019-05-09 10:24:36
Added a finish process and removed the order process fc33b421234ef320aa5a61f28cfb1e5d815477ca Sebastian 2019-05-08 13:02:21
Added a encoding sniffing to open the files in right encoding on Windows OS machines d0dbe5da1ca5810bfcc240a1e635ce053168b423 Sebastian 2019-05-06 14:54:04
Small usability improvements for the user to detect errors on different OS 2ec13ba3c85207c799eed1cf48ab1230d245a05f Sebastian 2019-05-06 08:25:54
Combined with the picklist creation project 4e5023c3c2bebc53794fe29edbcf9a7be93c826a Sebastian 2019-05-03 11:40:35
Created a building script for Linux based systems and made it possible to use the script from anywhere inside the filesystem e97b391d7b1cda885c99b6b483d414c75b288b75 Sebastian 2019-04-15 15:00:47
Added a working Linux executable Version, together with a different workspace creation process c84d49cf0f99fd3dcb7faabe82c125c8adc970cb Sebastian 2019-04-12 16:53:29
removed unnecessary files from the report and upload folder 94af82cbd9fd7f592fb6b421986c3d900f1bf532 Sebastian 2019-04-05 12:51:43
Added 2 options: a new order import to plenty and a fba shipment creation db5b9c168dabe3d6524b5674dd977044be286e0a Sebastian 2019-04-05 12:48:53
adjusted to another sync format and added a new export format that includes the sale price d33a1909c4f1ff88569509ad4510a5419e323136 Basti 2019-03-22 10:27:22
first Version of the Sync Upload de9ea87dff9ced84f635dd05d5ae039be870ae8a Basti 2019-03-19 16:32:44
First commit including Readme and folder structure 7e77aa7abd6013ce56d6878c7004973e32011a13 Basti 2019-03-19 10:44:36
Commit 69605ee944f5b1a2f4b80238ce19ccacc15cbe80 - added EAN to the picklist automated the export pull
Author: Sebastian
Author date (UTC): 2019-06-27 10:02
Committer name: Sebastian
Committer date (UTC): 2019-06-27 10:02
Parent(s): 5d01a8a44bd2f9b77e45b082f274acb6abc4e26d
Signing key:
Tree: 9358ea485bd1294169d3c8d18e485fb067110f96
File Lines added Lines deleted
inventory_synchronisation.py 56 29
packages/__pycache__/difference.cpython-37.pyc 0 0
packages/__pycache__/picklist_creation.cpython-37.pyc 0 0
packages/__pycache__/shipment_finish.cpython-37.pyc 0 0
packages/__pycache__/syncfile.cpython-37.pyc 0 0
packages/difference.py 1 0
packages/picklist_creation.py 13 4
packages/shipment_finish.py 2 2
packages/syncfile.py 27 11
File inventory_synchronisation.py changed (mode: 100644) (index 523ff69..c5cbc34)
... ... import sys
4 4 import os import os
5 5 import re import re
6 6 import chardet import chardet
7 import requests
7 8 from packages.syncfile import importFBA_Shipment, writeNewCsv from packages.syncfile import importFBA_Shipment, writeNewCsv
8 9 from packages.shipment_finish import finishShipment from packages.shipment_finish import finishShipment
9 10 from packages.plenty_export import plentyExport from packages.plenty_export import plentyExport
 
... ... def main():
19 20
20 21 use_current_dir = 'x' use_current_dir = 'x'
21 22 newpath = '' newpath = ''
22 export_file = {"filepath":"",
23 "encoding":""}
24 23 shipment_file = {"filepath":"", shipment_file = {"filepath":"",
25 24 "encoding":""} "encoding":""}
26 25 # Check if there is already a Report folder for the Amazon report files, if not create a new one. # Check if there is already a Report folder for the Amazon report files, if not create a new one.
27 26 reportpath = os.getcwd() + '/Report' reportpath = os.getcwd() + '/Report'
28 27 uploadpath = os.getcwd() + '/Upload' uploadpath = os.getcwd() + '/Upload'
29 28 configpath = os.getcwd() + '/config.txt' configpath = os.getcwd() + '/config.txt'
29 exporturl = ''
30 30
31 31 print("\nCurrent directory : {0}\n".format(os.getcwd())) print("\nCurrent directory : {0}\n".format(os.getcwd()))
32 32 if( not( os.path.exists(reportpath) ) or not( os.path.exists(uploadpath) ) ): if( not( os.path.exists(reportpath) ) or not( os.path.exists(uploadpath) ) ):
 
... ... def main():
47 47 else: else:
48 48 print("y|n\n") print("y|n\n")
49 49
50 with open(configpath , mode = 'w') as config:
51 config.write( "#-Config file for the FBA Shipment Script;\n" )
52 config.write( "#= '#= marks the beginning of a comment', '= splits between name and value';\n" )
53 config.write( "#=location of upload and report folder;\n" )
54 config.write( "upload_folder = {0};\n".format(uploadpath) )
55 config.write( "report_folder = {0};\n".format(reportpath) )
56 50 else: else:
57 51 if(os.path.isfile(configpath)): if(os.path.isfile(configpath)):
58 52 with open(configpath, mode = 'r') as config: with open(configpath, mode = 'r') as config:
 
... ... def main():
68 62 uploadpath = option[1].strip(' ') uploadpath = option[1].strip(' ')
69 63 if(option[0].strip(' ') == 'report_folder'): if(option[0].strip(' ') == 'report_folder'):
70 64 reportpath = option[1].strip(' ') reportpath = option[1].strip(' ')
65
71 66 else: else:
72 67 if( not( os.path.exists(configpath) ) ): if( not( os.path.exists(configpath) ) ):
73 68 with open(configpath , mode = 'w') as config: with open(configpath , mode = 'w') as config:
 
... ... def main():
76 71 config.write( "#=location of upload and report folder;\n" ) config.write( "#=location of upload and report folder;\n" )
77 72 config.write( "upload_folder = {0};\n".format(uploadpath) ) config.write( "upload_folder = {0};\n".format(uploadpath) )
78 73 config.write( "report_folder = {0};\n".format(reportpath) ) config.write( "report_folder = {0};\n".format(reportpath) )
74 config.write( "export_url = {0};\n".format(exporturl) )
79 75
80 76 if(not(os.path.exists(uploadpath) or os.path.exists(reportpath))): if(not(os.path.exists(uploadpath) or os.path.exists(reportpath))):
81 newpath = askdirectory(title="Choose the directory for the folders")
82 uploadpath = os.path.join(newpath, os.sep, 'Upload')
83 reportpath = os.path.join(newpath, os.sep, 'Report')
84 configpath = os.path.join(newpath, os.sep, 'Config.txt')
85 with open(configpath , mode = 'w') as config:
86 config.write( "#-Config file for the FBA Shipment Script;\n" )
87 config.write( "#= '#= marks the beginning of a comment', '= splits between name and value';\n" )
88 config.write( "#=location of upload and report folder;\n" )
89 config.write( "upload_folder = {0};\n".format(uploadpath) )
90 config.write( "report_folder = {0};\n".format(reportpath) )
77 write_new_config(exporturl='')
78
79 # Get the Export URL
80 if(os.path.exists(configpath)):
81 with open(configpath, mode='r') as config:
82 # Take every row into a list rows and strip them of spaces and new lines
83 rows = (row.strip(' ').strip('\n').split(';') for row in config)
84
85 for row in rows:
86 # combine the list to a string and split it at the '='
87 option = "".join(row[0]).split('=')
88
89 if(not(option[0].strip(' ') == '#')):
90 if(option[0].strip(' ') == 'export_url'):
91 exporturl = option[1].strip(' ').strip("'")
92
91 93
92 94
93 95 # Ask the user if the task is to import received items at amazon or to # Ask the user if the task is to import received items at amazon or to
 
... ... def main():
96 98 print("{0}\n".format(line)) print("{0}\n".format(line))
97 99 print(" Preparation for the Script / Vorbereitung für den Script\n") print(" Preparation for the Script / Vorbereitung für den Script\n")
98 100 print("{0}\n".format(line)) print("{0}\n".format(line))
99 print(" Get a export of all variations from plentymarkets\n & save it in Report\n")
100 print(" Lade einen Export von allen Varianten in Plentymarkets\n & speichere diesen in Report\n")
101 print(" The export is going to be downloaded automatically, if there are new items:\n Go to ElasticExport and download the 'Versand-Export'\n")
102 print(" Der Export wird automatisch heruntergeladen, falls neue Produkte erstellt wurden:\n Gehe zum ElasticExport und lade den 'Versand-Export'\n")
101 103 print("{0}\n".format(altline)) print("{0}\n".format(altline))
102 104 print(" Save your Storagereport from Amazon as .csv and name the column\n of the units to be sent as FBA-SHIPMENT\n") print(" Save your Storagereport from Amazon as .csv and name the column\n of the units to be sent as FBA-SHIPMENT\n")
103 105 print(" Speichere deine Lagerbestandsdatei as .csv und benenne die Spalte\n mit den zu versendenden Artikeln als FBA-SHIPMENT\n") print(" Speichere deine Lagerbestandsdatei as .csv und benenne die Spalte\n mit den zu versendenden Artikeln als FBA-SHIPMENT\n")
 
... ... def main():
120 122 root.withdraw() root.withdraw()
121 123 if(task.lower() == 'ama' or task.lower() == 'fba'): if(task.lower() == 'ama' or task.lower() == 'fba'):
122 124 print("\n{0}\n".format(line)) print("\n{0}\n".format(line))
123 print("Open the export file of all items, to get the Variation ID which is needed for the Upload.\n")
124 export_file['filepath'] = askopenfilename(initialdir=reportpath
125 , title="Export from Plentymarkets"
126 , filetypes=[ ("csv files" ,"*.csv" ) ] )
127 # detect the encoding of the file
128 with open(export_file['filepath'], mode='rb') as item:
129 raw_data = item.read(10000)
130 export_file['encoding'] = chardet.detect(raw_data)['encoding']
125 try:
126 print("Check if the current URL of the Export from Plentymarkets is valid: {0}\n"
127 .format(requests.get(exporturl).status_code == 200))
128 if(not( requests.get(exporturl).status_code == 200 )):
129 print("The Url : {0} isn't pointing to a valid file!".format(exporturl))
130 print("(If you want to change the URL go to the config and edit it)")
131 except Exception as err:
132 print("ERROR @ checking export url: {0}".format(err))
133 exporturl = input("Failed to load the url please enter it directly:\n")
134 print("Check if the current URL of the Export from Plentymarkets is valid: {0}\n"
135 .format(requests.get(exporturl).status_code == 200))
136 if( requests.get(exporturl).status_code == 200 ):
137 write_new_config(exporturl=exporturl, newpath=os.path.normpath(reportpath + os.sep + os.pardir),
138 uploadpath=uploadpath, reportpath=reportpath, configpath=configpath)
139
140
131 141
132 142 # FINISH SHIPMENT PART # FINISH SHIPMENT PART
133 143 if(task.lower() == 'fin'): if(task.lower() == 'fin'):
 
... ... def main():
172 182 raw_data = item.read(12000) raw_data = item.read(12000)
173 183 shipment_file['encoding'] = chardet.detect(raw_data)['encoding'] shipment_file['encoding'] = chardet.detect(raw_data)['encoding']
174 184
175 importFBA_Shipment(export=export_file, reportfolder=reportpath, folder=uploadpath,
185 importFBA_Shipment(exporturl=exporturl, reportfolder=reportpath, folder=uploadpath,
176 186 stockreport=shipment_file stockreport=shipment_file
177 187 ) )
178 188
 
... ... def main():
209 219
210 220 if __name__ == '__main__': if __name__ == '__main__':
211 221 main() main()
222
223 def write_new_config(exporturl, newpath='', uploadpath='', reportpath='', configpath=''):
224 if(not(newpath)):
225 newpath = askdirectory(title="Choose the directory for the folders")
226 if(not(uploadpath or reportpath or configpath)):
227 uploadpath = os.path.join(newpath, os.sep, 'Upload')
228 reportpath = os.path.join(newpath, os.sep, 'Report')
229 configpath = os.path.join(newpath, os.sep, 'Config.txt')
230
231 with open(configpath , mode = 'w') as config:
232 config.write( "#-Config file for the FBA Shipment Script;\n" )
233 config.write( "#= '#= marks the beginning of a comment', '= splits between name and value';\n" )
234 config.write( "#=location of upload and report folder;\n" )
235 config.write( "upload_folder = {0};\n".format(uploadpath) )
236 config.write( "report_folder = {0};\n".format(reportpath) )
237 config.write( "export_url = {0};\n".format(exporturl) )
238
File packages/__pycache__/difference.cpython-37.pyc changed (mode: 100644) (index e4669ac..b4c0a52)
File packages/__pycache__/picklist_creation.cpython-37.pyc changed (mode: 100644) (index 708a981..577e790)
File packages/__pycache__/shipment_finish.cpython-37.pyc changed (mode: 100644) (index d5753af..6e41164)
File packages/__pycache__/syncfile.cpython-37.pyc changed (mode: 100644) (index cf76ffb..1cbcab3)
File packages/difference.py changed (mode: 100644) (index ba319d8..ad1125e)
... ... def compare_locations(locationlist, folder, pickdata, export='', exportdata='',
38 38 for row in reader: for row in reader:
39 39 if(not( row['VariationNo'] in [*Data] )): if(not( row['VariationNo'] in [*Data] )):
40 40 try: try:
41 row['Stock'] = int(float(str( row['Stock'] ).replace(',','.')))
41 42 values = [row['VariationNo'], row['Barcode'], int( row['Stock'] ), 0, values = [row['VariationNo'], row['Barcode'], int( row['Stock'] ), 0,
42 43 '','','', '','','',
43 44 row['LocationName'], int( row['Stock'] ), 0, row['LocationName'], int( row['Stock'] ), 0,
File packages/picklist_creation.py changed (mode: 100644) (index 332e2e3..bf26c91)
1 1 from tkinter import Tk from tkinter import Tk
2 2 import csv import csv
3 3 import chardet import chardet
4 import re
4 5 from tkinter.filedialog import askopenfilename from tkinter.filedialog import askopenfilename
5 6 from packages import syncfile from packages import syncfile
6 7
 
... ... def picklist_creation(shipmentlist, folder, uploadfolder):
19 20 location_file['encoding'] = chardet.detect(raw_data)['encoding'] location_file['encoding'] = chardet.detect(raw_data)['encoding']
20 21
21 22 # The headers of the outputfile # The headers of the outputfile
22 column_names = ['Sku', 'location', 'Barcode', '@location', 'Shipment', 'Versand', 'Kiste']
23 column_names = ['Sku', 'location', 'EAN-Barcode', 'FNSKU-Barcode',
24 '@location', 'Shipment', 'Versand', 'Kiste']
23 25
24 26 # Define the Dictionary for the datasets and the list for multiple locations # Define the Dictionary for the datasets and the list for multiple locations
25 27 # on a single SKU # on a single SKU
 
... ... def picklist_creation(shipmentlist, folder, uploadfolder):
52 54 shipping_items.append(row['SKU']) shipping_items.append(row['SKU'])
53 55
54 56 items_in_skulist = 0 items_in_skulist = 0
57
55 58 for skulist in locations: for skulist in locations:
56 59 number = 0 number = 0
57 60 for index, row in enumerate( locations[ skulist ] ): for index, row in enumerate( locations[ skulist ] ):
61 stock = 0
58 62 if(row['VariationNo'] in [*shipping_items]): if(row['VariationNo'] in [*shipping_items]):
63 if(row['Stock']):
64 stock = int(float(str( row['Stock']).replace(',', '.') ))
59 65 items_in_skulist += 1 items_in_skulist += 1
60 66 number += 1 number += 1
61 values = [row['VariationNo'], row['LocationName'], row['Barcode'], row['Stock'], '']
67 values = [row['VariationNo'], row['LocationName'], '', row['Barcode'], stock, '']
62 68
63 69 Data[row['VariationNo'] + '+' + str(number)] = dict(zip(column_names, values)) Data[row['VariationNo'] + '+' + str(number)] = dict(zip(column_names, values))
64 70
 
... ... def picklist_creation(shipmentlist, folder, uploadfolder):
69 75 for row in reader: for row in reader:
70 76 if(row['SKU']+'+1' in [*Data]): if(row['SKU']+'+1' in [*Data]):
71 77 Data[row['SKU']+'+1']['Shipment'] = row['QTY'] Data[row['SKU']+'+1']['Shipment'] = row['QTY']
78 try:
79 for index, search_match in enumerate( re.findall(row['SKU'], ",".join([*Data])) ):
80 Data[search_match + '+' + str(index + 1)]['EAN-Barcode'] = row['EAN']
81 except KeyError as err:
82 print("KeyError: {0}\n".format(err))
72 83
73 84 syncfile.writeNewCsv(dataset=Data,path=uploadfolder, header=column_names,name='picklist') syncfile.writeNewCsv(dataset=Data,path=uploadfolder, header=column_names,name='picklist')
74 85
75 print("press ENTER to continue...\n")
76 input()
File packages/shipment_finish.py changed (mode: 100644) (index a8f15e4..c211813)
... ... def finishShipment(picklist, folder, uploadfolder):
49 49 elif(row['Sku'] in [*shipped_items]): elif(row['Sku'] in [*shipped_items]):
50 50 shipped_items[row['Sku']].append(row) shipped_items[row['Sku']].append(row)
51 51
52 if(not(row['Barcode'])):
52 if(not(row['FNSKU-Barcode'])):
53 53 print("WARNING: SKU: {0}\t has no Barcode!\n".format(row['Sku'])) print("WARNING: SKU: {0}\t has no Barcode!\n".format(row['Sku']))
54 54 else: else:
55 55 print("There is no column 'Versand'!\n") print("There is no column 'Versand'!\n")
 
... ... def finishShipment(picklist, folder, uploadfolder):
78 78 'packet':row['Kiste'], 'packet':row['Kiste'],
79 79 'location':row['location']} 'location':row['location']}
80 80
81 values = [shipped_items[ sku ][0]['Barcode'], packages]
81 values = [shipped_items[ sku ][0]['FNSKU-Barcode'], packages]
82 82
83 83 Data[sku] = dict(zip(column_names, values)) Data[sku] = dict(zip(column_names, values))
84 84 except Exception as err: except Exception as err:
File packages/syncfile.py changed (mode: 100644) (index dfe86b0..aba9469)
... ... import sys
2 2 import csv import csv
3 3 import re import re
4 4 import tkinter import tkinter
5 import pandas
5 6 import tkinter.filedialog import tkinter.filedialog
6 7 from os.path import isfile from os.path import isfile
7 8 from packages import picklist_creation from packages import picklist_creation
 
... ... def writeNewCsv(dataset, path, header, name):
33 34 return output_path return output_path
34 35
35 36
36 def importFBA_Shipment(export, reportfolder, folder, stockreport=''):
37 def importFBA_Shipment(exporturl, reportfolder, folder, stockreport=''):
37 38 # Define the headers of the new Sync File # Define the headers of the new Sync File
38 column_names = ['SKU', 'ID', 'QTY']
39 column_names = ['SKU', 'ID', 'EAN', 'QTY']
39 40
40 41 # The beginning of the name of the file # The beginning of the name of the file
41 42 syncname = '' syncname = ''
 
... ... def importFBA_Shipment(export, reportfolder, folder, stockreport=''):
44 45 # initialize a dictionary to save the necessary data # initialize a dictionary to save the necessary data
45 46 Data = {} Data = {}
46 47 syncname = 'fba_shipment' syncname = 'fba_shipment'
48 sku = ''
49 amount = ''
50 exportEAN = ''
51 exportID = ''
52
53 # Load the export from the URL that the elastic export created
54 export = pandas.read_csv(exporturl, sep=';')
47 55
48 56 with open(stockreport['filepath'], mode = 'r', encoding=stockreport['encoding']) as item: with open(stockreport['filepath'], mode = 'r', encoding=stockreport['encoding']) as item:
49 57 reader = csv.DictReader(item, delimiter=';') reader = csv.DictReader(item, delimiter=';')
 
... ... def importFBA_Shipment(export, reportfolder, folder, stockreport=''):
65 73 if(int(amount) > 8): if(int(amount) > 8):
66 74 amount = 5 * round(int( amount ) / 5) amount = 5 * round(int( amount ) / 5)
67 75
68 values = [sku, '', amount]
76 exportEAN = ''
77 exportFNSKU = ''
78 if(export.loc[export['Variation.number'] == sku]['Variation.EAN'].values.any()):
79 exportEAN = export.loc[export['Variation.number'] == sku]['Variation.EAN'].iloc[0]
80 if(exportEAN == 'nan'):
81 exportEAN = ''
82 if(re.match(r'7', str( exportEAN ))):
83 exportEAN = '0' + str(exportEAN)
84 if(export.loc[export['Variation.number'] == sku]['Variation.id'].values.any()):
85 exportID = export.loc[export['Variation.number'] == sku]['Variation.id'].iloc[0]
69 86
70 Data[sku] = dict(zip(column_names, values))
87 # locate the right value for the sku by looking up via .loc method in the export
88 try:
89 values = [sku, exportID,int( exportEAN ), amount]
90 except Exception:
91 values = [sku, exportID, exportEAN, amount]
71 92
72 # Open the Export file to get the right Variation ID for each SKU on the List
73 with open(export['filepath'], mode='r', encoding=export['encoding']) as item:
74 reader = csv.DictReader(item, delimiter=";")
75 93
76 for row in reader:
77 # Check if the row contains one of the SKU from the list
78 if(row['VariationNumber'] in [*Data] and row['VariationID']):
79 Data[row['VariationNumber']]['ID'] = row['VariationID']
94 Data[sku] = dict(zip(column_names, values))
95
80 96 # Write the finished Data dictionary into a new file # Write the finished Data dictionary into a new file
81 97
82 98 shipment = writeNewCsv(dataset=Data, path=folder, header=column_names, name=syncname) shipment = writeNewCsv(dataset=Data, path=folder, header=column_names, name=syncname)
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/initBasti/Complete_Order_Plenty_Update

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/initBasti/Complete_Order_Plenty_Update

Clone this repository using git:
git clone git://git.rocketgit.com/user/initBasti/Complete_Order_Plenty_Update

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main