File inventory_synchronisation.py changed (mode: 100644) (index f1c7df8..bb3cb81) |
... |
... |
import sys |
4 |
4 |
import os |
import os |
5 |
5 |
import re |
import re |
6 |
6 |
import chardet |
import chardet |
7 |
|
from packages.syncfile import importAmazonOrder, importNewOrder |
|
|
7 |
|
from packages.syncfile import importAmazonOrder, writeNewCsv |
|
8 |
|
from packages.shipment_finish import finishShipment |
8 |
9 |
#from packages.excelfile import createExcelSheet |
#from packages.excelfile import createExcelSheet |
9 |
10 |
|
|
10 |
11 |
def main(): |
def main(): |
|
... |
... |
def main(): |
96 |
97 |
config.write( "producer_list = ;\n" ) |
config.write( "producer_list = ;\n" ) |
97 |
98 |
config.write( "#=Enter your plentymarkets ID here;\n" ) |
config.write( "#=Enter your plentymarkets ID here;\n" ) |
98 |
99 |
config.write( "plenty_id = ;\n" ) |
config.write( "plenty_id = ;\n" ) |
99 |
|
config.write( "#=Name of the adress owner\n") |
|
100 |
|
config.write( "AdressName = ;\n" ) |
|
101 |
|
config.write( "#=Adress + number\n" ) |
|
102 |
|
config.write( "AdressFieldOne = ;\n") |
|
103 |
|
config.write( "AdressCity = ;\n" ) |
|
104 |
|
config.write( "AdressStateOrRegion = ;\n") |
|
105 |
|
config.write( "AdressPostalCode = ;\n") |
|
106 |
|
config.write( "#=DE or NL or UK etc. \n") |
|
107 |
100 |
config.write( "CountryCode = ;\n") |
config.write( "CountryCode = ;\n") |
108 |
101 |
|
|
109 |
102 |
if(os.path.isfile('./config.txt')): |
if(os.path.isfile('./config.txt')): |
|
... |
... |
def main(): |
114 |
107 |
# 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 |
115 |
108 |
# create a new order for production |
# create a new order for production |
116 |
109 |
line = "#" * 70 |
line = "#" * 70 |
117 |
|
altline = "|" * 70 |
|
|
110 |
|
altline = "-" * 70 |
118 |
111 |
print("{0}\n".format(line)) |
print("{0}\n".format(line)) |
119 |
112 |
print(" Preparation for the Script / Vorbereitung für den Script\n") |
print(" Preparation for the Script / Vorbereitung für den Script\n") |
120 |
113 |
print("{0}\n".format(line)) |
print("{0}\n".format(line)) |
|
... |
... |
def main(): |
130 |
123 |
|
|
131 |
124 |
task = '' |
task = '' |
132 |
125 |
|
|
133 |
|
while(not(task.lower() == 'amazon' or task.lower() == 'order' or task.lower() == 'fba')): |
|
134 |
|
task = input('Do you want to create a new production order (order)||DEPRECATED||\nDo you want to import received items at Amazon (amazon)?\nOr do you want to create a new Shipping to Amazon (fba)?\n') |
|
135 |
|
if(not(task.lower() == 'amazon' or task.lower() == 'fba')): |
|
136 |
|
print("Please enter either 'amazon' or 'fba'.\n") |
|
|
126 |
|
while(not(task.lower() == 'ama' or task.lower() == 'fin' or task.lower() == 'fba')): |
|
127 |
|
task = input('Do you want to create a new FBA Shipment?(fba)\nDo you want to finish a shipment?(fin)\nOr do you want to import received items at Amazon (ama)?\n') |
|
128 |
|
if(not(task.lower() == 'ama' or task.lower() == 'fin' or task.lower() == 'fba')): |
|
129 |
|
print("Please enter either 'fba', 'fin' or 'ama'.\n") |
137 |
130 |
|
|
138 |
|
# Ask the User to enter the ID of the order that he wants to change |
|
|
131 |
|
# Set to 0000 because the current state of the script doesnt need the orderid anymore |
139 |
132 |
order ='0000' |
order ='0000' |
140 |
133 |
|
|
141 |
134 |
# A filedialog for the export and the report file |
# A filedialog for the export and the report file |
142 |
135 |
root = Tk() |
root = Tk() |
143 |
136 |
root.withdraw() |
root.withdraw() |
144 |
|
print("\n{0}\n".format(line)) |
|
145 |
|
print("Open the export file of all items, to get the Variation ID which is needed for the Upload.\n") |
|
146 |
|
export_file['filepath'] = askopenfilename(initialdir=reportpath |
|
147 |
|
, title="Export from Plentymarkets" |
|
148 |
|
, filetypes=[ ("csv files" ,"*.csv" ) ] ) |
|
149 |
|
# detect the encoding of the file |
|
150 |
|
with open(export_file['filepath'], mode='rb') as item: |
|
151 |
|
raw_data = item.read() |
|
152 |
|
export_file['encoding'] = chardet.detect(raw_data)['encoding'] |
|
|
137 |
|
if(task.lower() == 'ama' or task.lower() == 'fba'): |
|
138 |
|
print("\n{0}\n".format(line)) |
|
139 |
|
print("Open the export file of all items, to get the Variation ID which is needed for the Upload.\n") |
|
140 |
|
export_file['filepath'] = askopenfilename(initialdir=reportpath |
|
141 |
|
, title="Export from Plentymarkets" |
|
142 |
|
, filetypes=[ ("csv files" ,"*.csv" ) ] ) |
|
143 |
|
# detect the encoding of the file |
|
144 |
|
with open(export_file['filepath'], mode='rb') as item: |
|
145 |
|
raw_data = item.read() |
|
146 |
|
export_file['encoding'] = chardet.detect(raw_data)['encoding'] |
153 |
147 |
|
|
154 |
148 |
# AMAZON RECEIVED PART |
# AMAZON RECEIVED PART |
155 |
|
if(task.lower() == 'amazon'): |
|
|
149 |
|
if(task.lower() == 'ama'): |
156 |
150 |
print("Open the report file of the recent delivered FBA packages,\nthis will contain the amount of items that amazon received.\n") |
print("Open the report file of the recent delivered FBA packages,\nthis will contain the amount of items that amazon received.\n") |
157 |
151 |
print("\n{0}\n".format(line)) |
print("\n{0}\n".format(line)) |
158 |
152 |
shipment_file['filepath'] = askopenfilename(initialdir=reportpath |
shipment_file['filepath'] = askopenfilename(initialdir=reportpath |
|
... |
... |
def main(): |
171 |
165 |
print("Something went terribly wrong...") |
print("Something went terribly wrong...") |
172 |
166 |
print(Err) |
print(Err) |
173 |
167 |
|
|
174 |
|
# NEW ORDER IMPORT PART |
|
175 |
|
if(task.lower() == 'order'): |
|
176 |
|
print("Open the Excel list of items to be ordered.\n") |
|
177 |
|
print("\n{0}\n".format(line)) |
|
|
168 |
|
# FINISH SHIPMENT PART |
|
169 |
|
if(task.lower() == 'fin'): |
|
170 |
|
print("{0}\n".format(line)) |
|
171 |
|
print("Open the finished picklist as .csv\n") |
|
172 |
|
print("{0}\n".format(altline)) |
|
173 |
|
print("Öffne die fertig gestellte Pickliste im .csv Format\n") |
178 |
174 |
shipment_file['filepath'] = askopenfilename(initialdir=reportpath |
shipment_file['filepath'] = askopenfilename(initialdir=reportpath |
179 |
|
, title="Order list for production" |
|
|
175 |
|
, title="Finished picklist from the shipment" |
180 |
176 |
, filetypes=[ ("csv files" ,"*.csv" ) ] ) |
, filetypes=[ ("csv files" ,"*.csv" ) ] ) |
181 |
177 |
# detect the encoding of the file |
# detect the encoding of the file |
182 |
178 |
with open(shipment_file['filepath'], mode='rb') as item: |
with open(shipment_file['filepath'], mode='rb') as item: |
|
... |
... |
def main(): |
184 |
180 |
shipment_file['encoding'] = chardet.detect(raw_data)['encoding'] |
shipment_file['encoding'] = chardet.detect(raw_data)['encoding'] |
185 |
181 |
|
|
186 |
182 |
try: |
try: |
187 |
|
order = importNewOrder(export=export_file, folder=uploadpath, orderlist=shipment_file, |
|
188 |
|
orderid=order, producerlist=producer, |
|
189 |
|
plentyid=configid) |
|
|
183 |
|
plenty_Data = {} |
|
184 |
|
plenty_Data = finishShipment(picklist=shipment_file, folder=reportpath) |
|
185 |
|
writeNewCsv(dataset=plenty_Data['data'], |
|
186 |
|
path=uploadpath, |
|
187 |
|
header=plenty_Data['fields'], |
|
188 |
|
name='Plenty_Stock') |
190 |
189 |
except Exception as Err: |
except Exception as Err: |
191 |
190 |
print("Something went terribly wrong...") |
print("Something went terribly wrong...") |
192 |
191 |
print(Err) |
print(Err) |
|
... |
... |
def main(): |
207 |
206 |
importAmazonOrder(export=export_file, reportfolder=reportpath, folder=uploadpath, |
importAmazonOrder(export=export_file, reportfolder=reportpath, folder=uploadpath, |
208 |
207 |
orderid=order, plentyid=configid, stockreport=shipment_file |
orderid=order, plentyid=configid, stockreport=shipment_file |
209 |
208 |
) |
) |
210 |
|
#try: |
|
211 |
|
#print("here will be the function for the ExcelSheet") |
|
212 |
|
#createExcelSheet(export, report) |
|
213 |
|
#except Exception as Err: |
|
214 |
|
#print("Something went terribly wrong...") |
|
215 |
|
#print(Err) |
|
216 |
209 |
|
|
217 |
210 |
if __name__ == '__main__': |
if __name__ == '__main__': |
218 |
211 |
main() |
main() |
File packages/shipment_finish.py added (mode: 100644) (index 0000000..98276cb) |
|
1 |
|
"""Finish the shipment by taking the the completed picking list |
|
2 |
|
and sorting them into the official lists of Amazon""" |
|
3 |
|
|
|
4 |
|
import tkinter |
|
5 |
|
import tkinter.filedialog |
|
6 |
|
import os |
|
7 |
|
import sys |
|
8 |
|
import csv |
|
9 |
|
import chardet |
|
10 |
|
|
|
11 |
|
# Define and initialize the line seperators |
|
12 |
|
line = "#"*70 |
|
13 |
|
altline = "-"*70 |
|
14 |
|
|
|
15 |
|
|
|
16 |
|
def finishShipment(picklist, folder): |
|
17 |
|
# keys: barcode, packages : { package : {qty, location, packet} } |
|
18 |
|
# for the inboundplan for loop through all packages |
|
19 |
|
|
|
20 |
|
Data = {} |
|
21 |
|
shipped_items = {} |
|
22 |
|
|
|
23 |
|
column_names = ['barcode', 'packages'] |
|
24 |
|
|
|
25 |
|
# Check the picklist for encoding |
|
26 |
|
with open(picklist['filepath'], mode='rb') as item: |
|
27 |
|
raw_data = item.read() |
|
28 |
|
picklist['encoding'] = chardet.detect(raw_data)['encoding'] |
|
29 |
|
|
|
30 |
|
# Open the picklist and get combine all rows where the same sku was taken from |
|
31 |
|
# multiple locations |
|
32 |
|
with open(picklist['filepath'], mode='r', encoding=picklist['encoding']) as item: |
|
33 |
|
reader = csv.DictReader(item, delimiter=';') |
|
34 |
|
|
|
35 |
|
for row in reader: |
|
36 |
|
try: |
|
37 |
|
if('Versand' in [*row]): |
|
38 |
|
if(row['Versand']): |
|
39 |
|
if(not(row['Sku'] in [*shipped_items])): |
|
40 |
|
# Create a list of rows for each SKU |
|
41 |
|
shipped_items[row['Sku']] = list() |
|
42 |
|
shipped_items[row['Sku']].append(row) |
|
43 |
|
elif(row['Sku'] in [*shipped_items]): |
|
44 |
|
shipped_items[row['Sku']].append(row) |
|
45 |
|
|
|
46 |
|
if(not(row['Barcode'])): |
|
47 |
|
print("WARNING: SKU: {0}\t has no Barcode!\n".format(row['Sku'])) |
|
48 |
|
else: |
|
49 |
|
print("There is no column 'Versand'!\n") |
|
50 |
|
print("press ENTER to continue...\n") |
|
51 |
|
input() |
|
52 |
|
sys.exit() |
|
53 |
|
except KeyError: |
|
54 |
|
print("The keys of the picklist are:\n{0}\n".format("\n".join([*row]))) |
|
55 |
|
print("press ENTER to continue...\n") |
|
56 |
|
input() |
|
57 |
|
sys.exit() |
|
58 |
|
except Exception as err: |
|
59 |
|
print("ERROR: {0} at {1}.\n".format(err, sys.exc_info()[2].tb_lineno)) |
|
60 |
|
print("press ENTER to continue...\n") |
|
61 |
|
input() |
|
62 |
|
sys.exit() |
|
63 |
|
|
|
64 |
|
# Go through the shipped_items dictionary and fill the Data dictionary |
|
65 |
|
try: |
|
66 |
|
for sku in shipped_items: |
|
67 |
|
packages = {} |
|
68 |
|
|
|
69 |
|
for index, row in enumerate( shipped_items[ sku ] ): |
|
70 |
|
packages[int( index )] = {'quantity':row['Versand'], |
|
71 |
|
'packet':row['Kiste'], |
|
72 |
|
'location':row['location']} |
|
73 |
|
|
|
74 |
|
values = [shipped_items[ sku ][0]['Barcode'], packages] |
|
75 |
|
|
|
76 |
|
Data[sku] = dict(zip(column_names, values)) |
|
77 |
|
except Exception as err: |
|
78 |
|
print("ERROR: {0} at {1}.\n".format(err, sys.exc_info()[2].tb_lineno)) |
|
79 |
|
print("press ENTER to continue...\n") |
|
80 |
|
input() |
|
81 |
|
sys.exit() |
|
82 |
|
|
|
83 |
|
# Check the values of Data TEST |
|
84 |
|
#for row in Data: |
|
85 |
|
# print("SKU: {0}, Barcode: {1}\n".format( row, Data[ row ]['barcode'] )) |
|
86 |
|
# for package in Data[ row ]['packages']: |
|
87 |
|
# print("QTY: {0}, PACKET: {1}, from LOCATION: {2}\n" |
|
88 |
|
# .format(Data[row]['packages'][ package ]['quantity'], |
|
89 |
|
# Data[row]['packages'][ package ]['packet'], |
|
90 |
|
# Data[row]['packages'][ package ]['location'])) |
|
91 |
|
|
|
92 |
|
#Filling out a inbound plan from amazon |
|
93 |
|
createInboundPlan(dataset=Data, folder=folder) |
|
94 |
|
#Reducing the storage location quantity in plentymarkets |
|
95 |
|
plenty_Data = {} |
|
96 |
|
plenty_Data = reducePlentyMarketsQty(dataset=Data, folder=folder) |
|
97 |
|
|
|
98 |
|
return plenty_Data |
|
99 |
|
|
|
100 |
|
def createInboundPlan(dataset, folder): |
|
101 |
|
root = tkinter.Tk() |
|
102 |
|
root.withdraw() |
|
103 |
|
|
|
104 |
|
print("{0}\n".format(line)) |
|
105 |
|
print("In order to fill out the Inbound plan, please go to\n") |
|
106 |
|
print("Amazon->Inventory->Manage FBA Shipments->Upload Inbound Plan File\n") |
|
107 |
|
print("Download a Template and save the sheet 'create inboundplan template'\n") |
|
108 |
|
print("as .csv, in the Report folder.\n") |
|
109 |
|
print("{0}\n".format(altline)) |
|
110 |
|
print("Um den Anlieferplan auszufüllen, bitte gehe auf\n") |
|
111 |
|
print("Amazon->Lagerbestand->Sendungen an Amazon verwalten->Anlieferplan hochladen\n") |
|
112 |
|
print("Lade eine Vorlage herunter und speichere den sheet\n") |
|
113 |
|
print("'Vorlage für Anlieferplan erstellen' als .csv in Report\n") |
|
114 |
|
print("{0}\n".format(line)) |
|
115 |
|
|
|
116 |
|
print("press ENTER to continue...\n") |
|
117 |
|
input() |
|
118 |
|
|
|
119 |
|
inboundplan = {'filepath':'', |
|
120 |
|
'encoding':''} |
|
121 |
|
|
|
122 |
|
inboundplan['filepath'] = tkinter.filedialog.askopenfilename(initialdir=folder, |
|
123 |
|
title="Inbound-plan Template file") |
|
124 |
|
|
|
125 |
|
if(inboundplan['filepath']): |
|
126 |
|
# Get encoding of the file |
|
127 |
|
with open(inboundplan['filepath'], mode='rb') as item: |
|
128 |
|
raw_data = item.read() |
|
129 |
|
inboundplan['encoding'] = chardet.detect(raw_data)['encoding'] |
|
130 |
|
|
|
131 |
|
# Check if the file has the right template |
|
132 |
|
with open(inboundplan['filepath'], mode='r', encoding=inboundplan['encoding']) as item: |
|
133 |
|
reader = csv.DictReader(item, delimiter="\t") |
|
134 |
|
|
|
135 |
|
for i in range(10): |
|
136 |
|
next(reader) |
|
137 |
|
|
|
138 |
|
for row in reader: |
|
139 |
|
if(not( 'PlanName' in [*row])): |
|
140 |
|
print("Wrong File Type!\n") |
|
141 |
|
print("press ENTER to continue...\n") |
|
142 |
|
input() |
|
143 |
|
sys.exit() |
|
144 |
|
else: |
|
145 |
|
break |
|
146 |
|
|
|
147 |
|
with open(inboundplan['filepath'], mode='a', encoding=inboundplan['encoding']) as item: |
|
148 |
|
writer = csv.DictWriter(item, delimiter='\t', fieldnames=['MerchantSKU', 'Quantity']) |
|
149 |
|
|
|
150 |
|
for row in dataset: |
|
151 |
|
sku_total_qty = 0 |
|
152 |
|
for package in dataset[row]['packages']: |
|
153 |
|
sku_total_qty += int( dataset[row]['packages'][ package ]['quantity'] ) |
|
154 |
|
|
|
155 |
|
try: |
|
156 |
|
writer.writerow({ 'MerchantSKU':row, 'Quantity':sku_total_qty }) |
|
157 |
|
except Exception as err: |
|
158 |
|
print("ERROR: {0}\n".format(err)) |
|
159 |
|
print("press ENTER to continue...\n") |
|
160 |
|
input() |
|
161 |
|
|
|
162 |
|
if(os.path.isfile(inboundplan['filepath'])): |
|
163 |
|
print("{0}\n".format(line)) |
|
164 |
|
print("File was created at\n{0}.\n".format(folder)) |
|
165 |
|
print("Please make sure to fill out all delivery data.\n") |
|
166 |
|
print("{0}\n".format(altline)) |
|
167 |
|
print("Datei wurde erstellt in\n{0}.\n".format(folder)) |
|
168 |
|
print("Bitte stelle sicher das alle Versandsinformationen eingetragen sind.\n") |
|
169 |
|
print("{0}\n".format(line)) |
|
170 |
|
else: |
|
171 |
|
print("{0}\n".format(line)) |
|
172 |
|
print("Something went wrong..\n") |
|
173 |
|
print("{0}\n".format(line)) |
|
174 |
|
print("press ENTER to continue...\n") |
|
175 |
|
input() |
|
176 |
|
else: |
|
177 |
|
print("{0}\n".format(line)) |
|
178 |
|
print("No file choosen, skipping inbound plan creation...\n") |
|
179 |
|
|
|
180 |
|
def reducePlentyMarketsQty(dataset, folder): |
|
181 |
|
root = tkinter.Tk() |
|
182 |
|
root.withdraw() |
|
183 |
|
|
|
184 |
|
print("{0}\n".format(line)) |
|
185 |
|
print("Please get an export of the Plentymarkets locations\n") |
|
186 |
|
# This part changes when dynamic export get deprecated |
|
187 |
|
print("Go to Plentymarkets->Data->dynamic export->ID 49(location dataformat)\n") |
|
188 |
|
print("choose only positive physical content and click on the cog symbol.\n") |
|
189 |
|
print("Save it inside the Report folder.\n") |
|
190 |
|
print("{0}\n".format(altline)) |
|
191 |
|
print("Bitte exportiere die aktuellen Plentymarkets Lagerplätze\n") |
|
192 |
|
print("Gehe auf Plentymarkets->Daten->dynamischer Export->ID 49(Lagerplatz Datenformat)\n") |
|
193 |
|
print("Wähle nur positven physischen Lagerbestand und klicke auf das Zahnrad Symbol.\n") |
|
194 |
|
print("Speichere diesen Export im Report Ordner.\n") |
|
195 |
|
print("{0}\n".format(line)) |
|
196 |
|
|
|
197 |
|
print("press ENTER to continue...\n") |
|
198 |
|
input() |
|
199 |
|
|
|
200 |
|
locationlist = {'filepath':'', |
|
201 |
|
'encoding':''} |
|
202 |
|
|
|
203 |
|
locationlist['filepath'] = tkinter.filedialog.askopenfilename(initialdir=folder, |
|
204 |
|
title="Current locationlist from Plentymarkets") |
|
205 |
|
|
|
206 |
|
if(locationlist['filepath']): |
|
207 |
|
# Get encoding of the file |
|
208 |
|
with open(locationlist['filepath'], mode='rb') as item: |
|
209 |
|
raw_data = item.read() |
|
210 |
|
locationlist['encoding'] = chardet.detect(raw_data)['encoding'] |
|
211 |
|
|
|
212 |
|
# Read the Data from the location list into a Data Dictionary |
|
213 |
|
Data = {} |
|
214 |
|
|
|
215 |
|
column_names = ['LocationName', 'LocationID', 'ItemID', |
|
216 |
|
'VariationNo', 'VariationString', 'ItemTextName', |
|
217 |
|
'Barcode', 'Stock', 'WarehouseID', 'VariationID'] |
|
218 |
|
|
|
219 |
|
with open(locationlist['filepath'], mode='r', encoding=locationlist['encoding']) as item: |
|
220 |
|
reader = csv.DictReader(item, delimiter=";") |
|
221 |
|
|
|
222 |
|
for row in reader: |
|
223 |
|
value = '' |
|
224 |
|
values = [value for value in range( len(column_names) )] |
|
225 |
|
for index, name in enumerate( column_names ): |
|
226 |
|
values[index] = row[column_names[index]] |
|
227 |
|
# remove the ,00 from every stock number |
|
228 |
|
if(name == 'Stock'): |
|
229 |
|
try: |
|
230 |
|
values[index] = int( float( values[index].replace(',','.') ) ) |
|
231 |
|
except Exception as err: |
|
232 |
|
print("ERROR @ ,00 removal : {0}\n".format(err)) |
|
233 |
|
print("values[index] : {0}, values[index] type : {1}\n".format(values[index], type(values[index]))) |
|
234 |
|
print("row['VariationNo'] : {0} \n Header List: {1}\n".format(row['VariationNo'], " , ".join([*row]))) |
|
235 |
|
print("press ENTER to continue...\n") |
|
236 |
|
input() |
|
237 |
|
|
|
238 |
|
Data[row['VariationNo'] + '-' + str(row['LocationID'])] = dict(zip(column_names, values)) |
|
239 |
|
|
|
240 |
|
# subtract the shipping quantity (dataset dictionary) from the Stock (Data dictionary) |
|
241 |
|
# When the SKU and the LocationName match |
|
242 |
|
for data_row in Data: |
|
243 |
|
for pick_row in dataset: |
|
244 |
|
for package in dataset[pick_row]['packages']: |
|
245 |
|
if(dataset[pick_row]['barcode'] == Data[data_row]['Barcode']\ |
|
246 |
|
and dataset[pick_row]['packages'][package]['location'] == Data[data_row]['LocationName']): |
|
247 |
|
#print("OLD: {0}\t".format( Data[data_row]['Stock'] )) |
|
248 |
|
#print("SHIPPED: {0}\t".format(int(dataset[pick_row]['packages'][package]['quantity']))) |
|
249 |
|
|
|
250 |
|
Data[data_row]['Stock'] = int(Data[data_row]['Stock']) - int(dataset[pick_row]['packages'][package]['quantity']) |
|
251 |
|
|
|
252 |
|
#print("NEW: {0}\n".format( Data[data_row]['Stock'] )) |
|
253 |
|
|
|
254 |
|
Data_and_fields = {'data':Data, 'fields':column_names} |
|
255 |
|
return Data_and_fields |
|
256 |
|
|