Rewritten from python 2.7 to python 3.11
This commit is contained in:
commit
d70da1d39d
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.11 (mssql2mysql)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (mssql2mysql)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/mssql2mysql.iml" filepath="$PROJECT_DIR$/.idea/mssql2mysql.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/mssql2mysql.iml
generated
Normal file
10
.idea/mssql2mysql.iml
generated
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
269
abacus2woo.py
Normal file
269
abacus2woo.py
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
import ast
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import pyodbc
|
||||||
|
from woocommerce import API
|
||||||
|
|
||||||
|
# import all_from_woo
|
||||||
|
|
||||||
|
conn = sqlite3.connect('imd.db') # intermediary db
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# Create table in SLQLite - we use this for syncing
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS products (id INTEGER NOT NULL PRIMARY KEY ON CONFLICT IGNORE, aid INTEGER,
|
||||||
|
sifra TEXT, naziv TEXT, price REAL, qty INTEGER, snc INTEGER, grupa INTEGER)''')
|
||||||
|
# all_from_woo.initSQLite()
|
||||||
|
|
||||||
|
# Connect to WooCommerce API
|
||||||
|
wcapi = API(
|
||||||
|
url="https://www.rasterdoo.com/",
|
||||||
|
consumer_key="ck_b3169b1723f6f39a965ed04ecfa77860fb89bbf5",
|
||||||
|
consumer_secret="cs_a83f0217ed8d6191ab7de9df06a0c2b652f6bd57",
|
||||||
|
wp_api=True,
|
||||||
|
timeout=360,
|
||||||
|
version="wc/v2"
|
||||||
|
)
|
||||||
|
print("Resting for for a bit...")
|
||||||
|
# time.sleep(50)
|
||||||
|
|
||||||
|
print("Connecting to MS SQL server")
|
||||||
|
'''
|
||||||
|
cnxn = pyodbc.connect('Driver={SQL Server};'
|
||||||
|
'Server=SERVER-BS;'
|
||||||
|
'Database=abacus_raster;'
|
||||||
|
'Trusted_Connection=yes;')
|
||||||
|
'''
|
||||||
|
cnxn = pyodbc.connect('DRIVER={SQL Server};'
|
||||||
|
'SERVER=raster.mywire.org,1433;'
|
||||||
|
'DATABASE=abacus_raster;'
|
||||||
|
'UID=sa;'
|
||||||
|
'PWD=!Pos456!;'
|
||||||
|
'TDS_Version=7.3;')
|
||||||
|
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
|
||||||
|
# Prvi artikal pocetnog stanja 2019 se vodi pod brojem "306570", za 2020 pod brojem "396498".
|
||||||
|
# Ako racunamo lager za artikle od njega dobicemo pravo stanje za 2019. Ukoliko ovo ne uradimo,
|
||||||
|
# lager se racuna od pocetka rada sa Abacusom - i vodi do gresaka.
|
||||||
|
# prvo nadjemo id_document pocetnog stanja (prvog dokumenta u godini)
|
||||||
|
# /****** Script for SelectTopNRows command from SSMS ******/
|
||||||
|
# SELECT id_dokument, id_vrsta, broj_dok, datum
|
||||||
|
# FROM abacus_raster.dbo.artikal_dokument
|
||||||
|
# WHERE (datum > CONVERT(DATETIME, '2020-12-31 00:00:00', 102))
|
||||||
|
#
|
||||||
|
# A onda nadjemo artikal u lageru - Stari kod:
|
||||||
|
# SELECT id_artikal, multiply * kol AS qty
|
||||||
|
# FROM abacus_raster.dbo.artikal_dnevnik
|
||||||
|
# WHERE (multiply <> 0) AND id_dnevnik >=396498.
|
||||||
|
cursor.execute('''SELECT a.id_artikal,
|
||||||
|
SUM (a.qty) AS stanje
|
||||||
|
INTO tmplager
|
||||||
|
FROM (SELECT artikal_dnevnik.id_artikal,
|
||||||
|
artikal_dnevnik.multiply*artikal_dnevnik.kol AS 'qty'
|
||||||
|
FROM abacus_raster.dbo.artikal_dnevnik artikal_dnevnik, abacus_raster.dbo.artikal_dokument artikal_dokument
|
||||||
|
WHERE artikal_dnevnik.id_dokument = artikal_dokument.id_dokument AND ((artikal_dokument.datum_fak>={d '2024-01-01'})) AND (artikal_dokument.id_vrsta <> 18) ) \
|
||||||
|
AS a INNER JOIN
|
||||||
|
abacus_raster.dbo.artikal ON a.id_artikal = abacus_raster.dbo.artikal.id_artikal
|
||||||
|
GROUP BY a.id_artikal ''')
|
||||||
|
|
||||||
|
cursor.execute('''SELECT abacus_raster.dbo.artikal_cijenik.id_artikal, abacus_raster.dbo.artikal_cijenik.cijena,
|
||||||
|
abacus_raster.dbo.artikal.naziv, abacus_raster.dbo.artikal.sifra,
|
||||||
|
tmplager.stanje, abacus_raster.dbo.artikal.id_grupa, tmplager.id_artikal AS tid
|
||||||
|
FROM abacus_raster.dbo.artikal_cijenik INNER JOIN
|
||||||
|
abacus_raster.dbo.artikal INNER JOIN
|
||||||
|
tmplager ON abacus_raster.dbo.artikal.id_artikal = tmplager.id_artikal ON
|
||||||
|
abacus_raster.dbo.artikal_cijenik.id_artikal = abacus_raster.dbo.artikal.id_artikal
|
||||||
|
WHERE (abacus_raster.dbo.artikal_cijenik.id_mjesto = 2) AND abacus_raster.dbo.artikal.id_grupa <> 11''')
|
||||||
|
# Save products from Abacus in SQLite table
|
||||||
|
row = cursor.fetchone()
|
||||||
|
print("Abacus row in works:"), row #
|
||||||
|
snc = 0
|
||||||
|
for row in cursor:
|
||||||
|
while row is not None:
|
||||||
|
# print("Abacus row entered for loop and it is not None")
|
||||||
|
# input("Press Enter to continue...") #
|
||||||
|
aid = row[0]
|
||||||
|
aprice = float(row[1])
|
||||||
|
aname = row[2]
|
||||||
|
asifra = row[3]
|
||||||
|
aqty = int(row[4])
|
||||||
|
agroup = row[5]
|
||||||
|
print("MS Sql group value:", agroup)
|
||||||
|
# This dictionary matches abacus product category id to equivalent id in woocommerce
|
||||||
|
groupdict = {
|
||||||
|
1: 21472, 2: 21473, 4: 21474, 5: 21475, 10: 21476, 11: 21477, 13: 21477, 15: 21477, 19: 21478, 24: 21479,
|
||||||
|
30: 21480, 32: 21481, 33: 21482, 37: 21483, 38: 21484, 44: 21485, 45: 21486, 47: 21477, 48: 21477
|
||||||
|
}
|
||||||
|
print("Coverted to Woocommerce group it becomes wgroup:", groupdict[agroup])
|
||||||
|
if agroup in groupdict:
|
||||||
|
wgroup = groupdict[agroup]
|
||||||
|
print("Group in abacusu is from dictionary:", agroup, " - while woocommerce now holds:", wgroup) #
|
||||||
|
else:
|
||||||
|
wgroup = 3557
|
||||||
|
print("Group ", agroup, "does not exist in dictionary - we put it in woocommerce group -other-:", wgroup) #
|
||||||
|
|
||||||
|
# Test id Woo product exists in SQLite table
|
||||||
|
q = (asifra,)
|
||||||
|
c.execute('SELECT * FROM products WHERE sifra=?', q)
|
||||||
|
print("Abacus data to be saved in SQLite:", aid, aprice, aname, asifra, aqty, wgroup)
|
||||||
|
# input("Press Enter to continue...") #
|
||||||
|
# We test SqlLite rows so that we update the table only with products that changed
|
||||||
|
trow = c.fetchone()
|
||||||
|
if trow is not None:
|
||||||
|
tnaziv = trow[3]
|
||||||
|
tprice = trow[4]
|
||||||
|
tqty = trow[5]
|
||||||
|
tgroup = trow[7]
|
||||||
|
# print("There is an SQLite trow we need to check for an update: "), tnaziv, tprice, tqty, tgroup
|
||||||
|
if aprice != tprice:
|
||||||
|
snc = 1
|
||||||
|
print("bad price")
|
||||||
|
if aqty != tqty:
|
||||||
|
snc = 1
|
||||||
|
print("bad qty")
|
||||||
|
if aname != tnaziv:
|
||||||
|
snc = 1
|
||||||
|
print("bad naziv")
|
||||||
|
if wgroup != tgroup:
|
||||||
|
snc = 1
|
||||||
|
print(wgroup, "bad tgroup: ", tgroup)
|
||||||
|
if snc == 1:
|
||||||
|
# print("=======")
|
||||||
|
c.execute('''UPDATE products SET aid = ?, price = ?, qty =?, naziv = ?,
|
||||||
|
snc = ?, grupa = ? WHERE sifra = ?''',
|
||||||
|
(aid, aprice, aqty, aname, snc, wgroup, asifra))
|
||||||
|
conn.commit()
|
||||||
|
c.execute('SELECT * FROM products WHERE sifra=?', q)
|
||||||
|
trow = c.fetchone()
|
||||||
|
print(trow)
|
||||||
|
print("=======")
|
||||||
|
# input("Press Enter to continue...")
|
||||||
|
else:
|
||||||
|
print("If sqlite trow does not exist (is ", trow, "), then first create one in Woo", aid, asifra, aname,
|
||||||
|
aprice, aqty, wgroup)
|
||||||
|
# input("Press Enter to continue...") #
|
||||||
|
aprice = str(aprice)
|
||||||
|
data = {
|
||||||
|
"sku": asifra,
|
||||||
|
"name": aname,
|
||||||
|
"regular_price": aprice,
|
||||||
|
"description": "",
|
||||||
|
"managing_stock": "true",
|
||||||
|
"in_stock": "true",
|
||||||
|
"status": "publish",
|
||||||
|
"stock_quantity": aqty,
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"id": wgroup
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
w = wcapi.post("products", data).json()
|
||||||
|
|
||||||
|
|
||||||
|
# w = wcapi.get("products/categories").json()
|
||||||
|
|
||||||
|
class ListStream:
|
||||||
|
def __init__(self):
|
||||||
|
self.data = []
|
||||||
|
|
||||||
|
def write(self, s):
|
||||||
|
self.data.append(s)
|
||||||
|
|
||||||
|
|
||||||
|
sys.stdout = x = ListStream()
|
||||||
|
print(w)
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
wresponse = (x.data[0])
|
||||||
|
print("Full woo response: ", wresponse)
|
||||||
|
# print("wresponse:", wresponse[38:53])
|
||||||
|
if wresponse[38:53] == "duplicirani SKU":
|
||||||
|
# if wresponse[26:40] == "duplicated SKU":
|
||||||
|
d = ast.literal_eval(wresponse)
|
||||||
|
errd = d.get('data')
|
||||||
|
print(errd)
|
||||||
|
rogueone = errd.get('resource_id')
|
||||||
|
print("We have a duplicated product in Woo: ", rogueone)
|
||||||
|
c.execute('INSERT INTO products VALUES (?,?,?,?,?,?,?,?)',
|
||||||
|
(rogueone, aid, asifra, aname, aprice, aqty, 1, wgroup)) # if no product it will create
|
||||||
|
print("Inserting rogueone in SQLlite data:", rogueone, aid, asifra, aname, aprice, aqty, 1, wgroup)
|
||||||
|
conn.commit()
|
||||||
|
# rgpath = "\"products/" + str(rogueone) + "\""
|
||||||
|
# print rgpath
|
||||||
|
# rg = wcapi.get(rogueone).json()
|
||||||
|
# print("The rogueone:", rg)
|
||||||
|
else:
|
||||||
|
print("Since trow was NONE, we had to create it on woo, get the id (woo), then save it (SQLite):",
|
||||||
|
type(w), w)
|
||||||
|
wid = w.get('id')
|
||||||
|
wsku = w.get('sku')
|
||||||
|
wname = w.get('name')
|
||||||
|
wprice = w.get('price')
|
||||||
|
wqty = w.get('qty')
|
||||||
|
if wname is None:
|
||||||
|
print("Why problems? ...:", wid, aid, wsku, wname, wprice, wqty)
|
||||||
|
else:
|
||||||
|
c.execute('INSERT INTO products VALUES (?,?,?,?,?,?,?,"")',
|
||||||
|
(wid, aid, wsku, wname, wprice, wqty, 1)) # if no product it will create
|
||||||
|
conn.commit()
|
||||||
|
row = cursor.fetchone()
|
||||||
|
# print("Resting for for a bit...")
|
||||||
|
# time.sleep(5)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Update Woo with our SQLite table
|
||||||
|
conn = sqlite3.connect('imd.db') # intermediary db
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute('''SELECT * FROM products WHERE snc = 1 ORDER BY naziv''')
|
||||||
|
trow = c.fetchone()
|
||||||
|
|
||||||
|
print("Selected for update:", trow)
|
||||||
|
# cleantrow is not None:
|
||||||
|
grupa = 0
|
||||||
|
while trow is not None:
|
||||||
|
id = trow[0]
|
||||||
|
tnaziv = trow[3]
|
||||||
|
tprice = str(trow[4])
|
||||||
|
tqty = trow[5]
|
||||||
|
tgroup = trow[7]
|
||||||
|
# print type(id), type(tnaziv), type(tprice), type(tqty), "Grupa:", type(tgroup), tgroup
|
||||||
|
# input("Press enter ...")
|
||||||
|
data = {
|
||||||
|
"id": id,
|
||||||
|
"manage_stock": "true",
|
||||||
|
"stock_quantity": tqty,
|
||||||
|
"name": tnaziv,
|
||||||
|
"status": "publish",
|
||||||
|
"regular_price": tprice,
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"id": tgroup
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
# print data
|
||||||
|
uplink = "products/" + str(id)
|
||||||
|
# print uplink
|
||||||
|
up = wcapi.put((uplink), data).json()
|
||||||
|
print(up)
|
||||||
|
# input("Press enter ...")
|
||||||
|
if trow is None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
trow = c.fetchone()
|
||||||
|
print("___________________________________________")
|
||||||
|
print("Selected next for update:", trow)
|
||||||
|
c.execute('UPDATE products SET snc = 0')
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# Drop the temporary table
|
||||||
|
|
||||||
|
print("Preparing to drop the tmptable")
|
||||||
|
cursor.execute('''drop table tmplager''')
|
||||||
|
print("Dropped the tmptable")
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
del cursor
|
||||||
|
conn.close() # close sqlite connection
|
||||||
|
print("All done!")
|
||||||
78
all_from_woo.py
Normal file
78
all_from_woo.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
def initSQLite():
|
||||||
|
# The following will download all existing woocommerce products and save them in SQLite.
|
||||||
|
# From that point the synchronization can start in local.
|
||||||
|
from woocommerce import API
|
||||||
|
import sqlite3
|
||||||
|
import pyodbc
|
||||||
|
|
||||||
|
conn = sqlite3.connect('imd.db') # intermediary db
|
||||||
|
c = conn.cursor()
|
||||||
|
# Create table in SLQLite - we use this for syncing
|
||||||
|
c.execute('DROP TABLE products')
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS products (id INTEGER NOT NULL PRIMARY KEY ON CONFLICT IGNORE, aid INTEGER,
|
||||||
|
sifra TEXT, naziv TEXT, price REAL, qty INTEGER, snc INTEGER, grupa INTEGER)''')
|
||||||
|
|
||||||
|
|
||||||
|
# Connect to WooCommerce API
|
||||||
|
wcapi = API(
|
||||||
|
url="https://www.rasterdoo.com/",
|
||||||
|
consumer_key="ck_b3169b1723f6f39a965ed04ecfa77860fb89bbf5",
|
||||||
|
consumer_secret="cs_a83f0217ed8d6191ab7de9df06a0c2b652f6bd57",
|
||||||
|
wp_api=True,
|
||||||
|
version="wc/v2"
|
||||||
|
)
|
||||||
|
r = wcapi.get("products") # get woo web page where products are
|
||||||
|
h = int(r.headers['X-WP-TotalPages']) # in the header we see number of tot pages
|
||||||
|
print("Total pages:", h)
|
||||||
|
|
||||||
|
for page_no in range(1, h+1): # lets go through pages
|
||||||
|
goto_page = 'products?page=' + str(page_no)
|
||||||
|
print(page_no, "(", h, ")")
|
||||||
|
r = wcapi.get(goto_page)
|
||||||
|
page_txt = r.json() # contents of one page ar stored in variable
|
||||||
|
# We fill our SQLite table with Woo Products
|
||||||
|
for product in page_txt: # first we go through products in this page
|
||||||
|
wsku = product.get('sku')
|
||||||
|
wid = product.get('id')
|
||||||
|
wname = product.get('name')
|
||||||
|
wprice = product.get('regular_price')
|
||||||
|
wqty = product.get('stock_quantity')
|
||||||
|
if wqty is None:
|
||||||
|
wqty = 0
|
||||||
|
# FIX THIS! - It does not update - just inserts if new ...
|
||||||
|
c.execute('INSERT INTO products VALUES (?,?,?,?,?,?,?,?)',
|
||||||
|
(wid, "", wsku, wname, wprice, wqty, 0)) # if no product it will create
|
||||||
|
c.execute('UPDATE products SET aid = ?, sifra = ?, naziv = ?, price = ?, qty = ?, snc = ? WHERE id = ?',
|
||||||
|
("", wsku, wname, wprice, wqty, 0, wid, ""))
|
||||||
|
print("Insert woocommerce data to SQLlite:", wid, "", wsku, wname, wprice, wqty, 0)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("Fixing some problems with decimals...")
|
||||||
|
c.execute('''UPDATE products SET price = replace( price, ',', '.' ) WHERE price LIKE ?''', ('%,%',))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# Sometimes woo has a product, but abacus does not, meaning we don't have them anymore. SO, qty needs to be 0.
|
||||||
|
print("Checking if products on woo exist on abacus")
|
||||||
|
# list of woo products
|
||||||
|
c.execute('''SELECT sifra, naziv, qty FROM products''')
|
||||||
|
trow = c.fetchone()
|
||||||
|
# find them on abacus
|
||||||
|
cnxn = pyodbc.connect('Driver={SQL Server};'
|
||||||
|
'Server=SERVER-BS;'
|
||||||
|
'Database=abacus_raster;'
|
||||||
|
'Trusted_Connection=yes;')
|
||||||
|
cursor = cnxn.cursor()
|
||||||
|
|
||||||
|
while trow is not None:
|
||||||
|
sifra = trow[0]
|
||||||
|
naziv = trow[1]
|
||||||
|
cursor.execute('''SELECT id_artikal, sifra, naziv FROM abacus_raster.dbo.artikal WHERE sifra = ?''', (sifra, ))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row is None:
|
||||||
|
print(sifra, naziv, " - does not exist on abacus, at least we should set qty to 0")
|
||||||
|
c.execute('''UPDATE products SET qty = 0 WHERE sifra = ?''', (sifra,))
|
||||||
|
conn.commit()
|
||||||
|
trow = c.fetchone()
|
||||||
|
|
||||||
|
conn.close()
|
||||||
Loading…
Reference in New Issue
Block a user