Our custom ordering system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

369 lines
11 KiB

import argparse
import sqlite3
import sys
from datetime import datetime
from pathlib import Path
from urllib.parse import urlparse
from pyramid.paster import bootstrap, get_appsettings, setup_logging
from sqlalchemy import func
from sqlalchemy.exc import OperationalError
from sqlalchemy.orm.exc import NoResultFound
from .. import adapters, models, services
vendor_map = {
"Accurion GmbH": ["accurion"],
"Acros Organics": ["acros"],
"Agilent Technologies": ["agilent"],
"Alfa Aesar": [
"alefa aesar",
"alfa",
"aesar",
"alfa aesar - vwr",
"alfa-aesar",
"alfaaesar",
],
"Amazon": [],
"analytics-shop.com": ["analytics-shop"],
"architekturbedarf.de": ["architekturbedarf"],
"Avanti Polar Lipids": ["avanti"],
"Biesterfeld Spezialchemie": [
"biesterfeld",
"biesterfeld gmbh",
"biesterfeld spezialchemie gmbh",
],
"Bio-Rad": ["bio rad"],
"Biocat": [],
"Bioleague": ["Bioleague GmbH & co.Kg", "bioleague gmbh"],
"Biomol": [],
"Bürkert Indelfingen": ["bürkert"],
"Carl Roth": [
"carl roth gmbh",
"carl-roth",
"carlroth",
"cr",
"karl roth",
"roth",
],
"Cellsystems Biotech": ["cellsystems"],
"Chemicell": ["chemicell gmbh"],
"Clickbox e.k.": ["clickbox"],
"Cole Parmer": ["coleparmer"],
"Conrad Electronics": [
"conrad",
"conrad electronic",
"conrad, fax 09604408937, k-nr 6043142",
],
"Cytoskeleton": ["cytoskeleton inc"],
"Daniel Maas Dichtstoffhandel": [
"daniel maas",
"daniel maas dichtstoffhandel & co.",
],
"Delta Mask": ["delta mask b.v.", "deltamask"],
"der-rollende-shop.de": ["der-rollende-shop"],
"Dianova": [],
"Distrelec": ["distrilec"],
"Edmund Optics": ["edmund optics gmbh", "edmund"],
"Faust Lab Science": ["faust", "faust lab", "faust lab science gmbh"],
"Fisher Scientific": [
"fischer scientific",
"fisher scientific/acros organic",
],
"form.in Lasercenter": ["form.in"],
"Uwe Markus (Glasbläser)": [
"glasbläser markus",
"markus",
"markus, glasbläser",
"uwe markus",
"glasbläser",
],
"Goodfellow": ["good fellow"],
"Greiner Bio-One": [
"greiner bio one",
"greiner",
"greiner bio",
"greiner bioone",
],
"Hach": [],
"Hellma GmbH": [
"hellma analytics",
"hellma optics",
"hellma optik jena",
"hellma gmbh & co kg",
],
"Hiss dx": ["hiss", "hiss-dx"],
"HJ-Bioanalytik": [
"hj bioanalytik gmbh",
"hj bioanalytik",
"hj-bioanalytik gmbh",
],
"laborhandel24.de": ["laborhandel24"],
"locheisen.com": ["locheisen"],
"praezisionsmesstechnik.de": ["praezisionsmesstechnik"],
"siebgewebeshop.de": ["siebgewebeshop"],
"Häberle Labortechnik": ["häberle"],
"High-Tech-Flon": ["hightechflon"],
"hygie.de": ["hygie"],
"Iolitec": [
"ionic liquids technologie",
"ionic liquids technologies",
"iolitec ionic liquids technologies",
],
"Iris Biotech": ["iris biotech gmbh"],
"Ismatec": ["ismatec/idex"],
"Jackson Immunoresearch": ["jacksonimmuno", "jackson"],
"Kinesis Abimed": ["kinesis", "kinesisgmbh", "abimed"],
"Kisker Biotech": ["kisker", "kisker biotech gmbh & co. kg"],
"Knick Elektronische Messgeräte": [
"knick",
"knick elektronische messgeräte gmbh",
],
"Kummer Laborbedarf": ["kummer"],
"Laborhandel Krumpholz": ["krumpholz"],
"leuchtmittelmarkt.com": ["leuchtmittelmarkt"],
"Life Sciences Advanced Technologies": [
"life sciences advanced technologies inc"
],
"Life Technologies": ["lifetechnologies", "ife technologies"],
"Macherey Nagel": ["m-n", "mn", "macherey-nagel"],
"magnets4you GmbH": ["magnets4you"],
"magnet-shop.com": ["magnet-shop"],
"Mercateo ag": ["mercateo"],
"Merck": ["merck über vwr"],
"merck berufsbekleidung": [
"merck berufskleidung",
"merck-berufsbekleidung",
],
"Merck Millipore inc.": ["merck millipore", "merckmillipore", "millipore"],
"Mettler-Toledo": ["mettler toledo", "mettler-toledo gmbh", "mettler"],
"Micro Particles": ["micro particles gmbh"],
"Microdyn-Nadir": ["microdyn-nadir gmbh"],
"Molecular Devices / Genetix": ["molecular devices", "genetix"],
"Nanoandmore": ["nano-and-more", "nanoandmore gmbh"],
"Nanocyl": ["nanocyl s.a."],
"Neo Lab": ["neolab"],
"Newport Spectra-Physics": ["newport"],
"OCO Ortenauer Gase": ["oco ortenauer gase gmbh", "oco"],
"Pall Corporation": ["pall"],
"Plano GmbH": ["plano", "plano-eu", "plano-em"],
"Polyan": ["polyan gmbh"],
"Polyscience Europe": [
"polysciences",
"polysciences europe gmbh",
"polysciences, inc.",
],
"ProLiquid": ["pro-liquid", "proliquid gmbh"],
"Qiagen": ["quiagen"],
"R&D Systems": ["r&d system"],
"Reichelt Elektronik": ["reichelt"],
"RS Components": ["rs"],
"S-Polytec": ["s-polytech"],
"Sarstedt": ["sarstedt ag & co. kg"],
"Science Services": ["science services gmbh"],
"Scienion": ["scienion ag"],
"Sigma Aldrich": [
"aldrich",
"adrich",
"aldich",
"aldritch",
"aldrích",
"fluka",
"sa",
"sigma - aldrich",
"sigma adrich",
"sigma aldich",
"sigma aldritch",
"sigma aldrích",
"sigma- aldrich",
"sigma-adrich",
"sigma-aldrich",
"sigma-aldrich (fluka)",
"sigmaaldrich",
"roche, sigma-aldrich",
"sigmar",
"sigma",
],
"Sterlitech": [],
"Supermagnete": ["supermagnet"],
"taq-dna.com": ["taq-dna"],
"TCI Deutschland": [
"tci",
"tci chemical",
"tci chemicals",
"tci deutschland gmbh",
"tci europe",
"tci europe n.v.",
],
"Thermo Fisher Scientific": [
"themofisher",
"thermofischer",
"thermofisher",
"thermo fisher",
"thermofisher scientific",
"thermo scientific",
"thermo scientific - www.perbio.com",
"perbio",
"thermo scientific / pierce",
"thermo ",
"pierce",
],
"Tib MolBiol": ["tibmolbiol", "tibmolbio"],
"Tse Systems": ["tse systems gmbh"],
"Vilber Lourmat": ["vilber", "vilber lourmat gmbh"],
"VWR": [
"vwr (lenz laborglas gmbh & co.kg)",
"vwr chemicals",
"vwr collection",
"vwt",
"vwr international gmbh",
"vwr international",
],
"Weigert": ["drweigert"],
"Xantec Bioanalytics": ["xantec", "xantec bioanalyticss"],
"Zitt-Thoma": ["zitt thoma"],
}
def _query_table(cursor, table):
cursor.execute("SELECT * FROM :year", {"table": table})
columns = [d[0] for d in cursor.description]
return (dict(zip(columns, values)) for values in cursor)
def _case_insensitive_query_user_by_username(repo, reference):
try:
user = (
repo.session.query(models.User)
.filter(func.lower(models.User.username) == func.lower(reference))
.one()
)
except NoResultFound:
return reference
else:
return user.username
def migrate(old_db, repo):
inpsql3 = sqlite3.connect(old_db)
cursor = inpsql3.cursor()
migrate_users(cursor, repo)
migrate_vendors(cursor, repo)
migrate_orders(cursor, repo)
def migrate_users(cursor, repo):
for old_user in _query_table(cursor, "users"):
user = models.User(
old_user["id"],
old_user["user_name"],
old_user["first_name"],
old_user["last_name"],
old_user["email"],
old_user["password_hash"],
models.UserRole[old_user["role"]],
)
repo.add_user(user)
def migrate_vendors(cursor, repo): # noqa: ARG001
for name, replacements in vendor_map.items():
vendor = models.Vendor(name.lower(), name)
repo._add_item_to_db(vendor) # noqa: SLF001
for replacement in replacements:
vendor = models.Vendor(replacement.lower(), name)
repo._add_item_to_db(vendor) # noqa: SLF001
def migrate_orders(cursor, repo):
status_fields = [
("created", models.OrderStatus.OPEN),
("approval", models.OrderStatus.APPROVAL),
("ordered", models.OrderStatus.ORDERED),
("completed", models.OrderStatus.COMPLETED),
]
for old_order in _query_table(cursor, "orders"):
result = services.check_vendor_name(repo, old_order["vendor"])
if result.found:
vendor = result.name
else:
vendor = old_order["vendor"]
repo._add_item_to_db(models.Vendor(result.name.lower(), vendor)) # noqa: SLF001
order = models.OrderItem(
old_order["id"],
old_order["cas_description"],
old_order["catalog_nr"],
vendor,
models.OrderCategory[old_order["category"]],
old_order["package_size"],
old_order["unit_price"],
old_order["amount"],
old_order["currency"],
old_order["account"],
old_order["comment"],
)
repo.add_order(order)
for old_field, status in status_fields:
field_by = old_order[f"{old_field}_by"]
if field_by:
field_date = datetime.fromisoformat(
old_order[f"{old_field}_date"]
)
user = _case_insensitive_query_user_by_username(repo, field_by)
log_entry = models.LogEntry(order.id, status, user, field_date)
order.add_to_log(log_entry)
if order.created_on < datetime(2018, 1, 1):
log_entry = models.LogEntry(
order.id,
models.OrderStatus.COMPLETED,
"OrderSystem",
datetime.utcnow(),
)
order.add_to_log(log_entry)
def parse_args(argv):
parser = argparse.ArgumentParser()
parser.add_argument(
"config_uri", help="Configuration file, e.g., development.ini"
)
parser.add_argument("old_db", help="ordr2 sqlite database file")
return parser.parse_args(argv[1:])
def main(argv=sys.argv):
args = parse_args(argv)
setup_logging(args.config_uri)
env = bootstrap(args.config_uri)
settings = get_appsettings(args.config_uri)
# remove an existing sqlite database to issue a restart
database_url = urlparse(settings["sqlalchemy.url"])
dabase_path = Path(database_url.path)
if database_url.scheme == "sqlite" and dabase_path.is_file():
dabase_path.unlink()
try:
with env["request"].tm:
repo = env["request"].repo
adapters.metadata.create_all(repo.session.get_bind())
migrate(args.old_db, repo)
except OperationalError:
print( # noqa: T201
"""
Pyramid is having a problem using your SQL database. The problem
might be caused by one of the following things:
1. You may need to initialize your database tables with `alembic`.
Check your README.txt for description and try to run it.
2. Your database server may not be running. Check that the
database server referred to by the "sqlalchemy.url" setting in
your "development.ini" file is running.
"""
)