 Holger Frey
					
					6 years ago
						Holger Frey
					
					6 years ago
					
				
				 13 changed files with 529 additions and 27 deletions
			
			
		
									
										Binary file not shown.
									
								
							
						| @ -0,0 +1,344 @@@@ -0,0 +1,344 @@ | ||||
| import sys | ||||
| import sqlite3 | ||||
| import argparse | ||||
| from pathlib import Path | ||||
| from datetime import datetime | ||||
| from urllib.parse import urlparse | ||||
| 
 | ||||
| from sqlalchemy import func | ||||
| from pyramid.paster import bootstrap, setup_logging, get_appsettings | ||||
| from sqlalchemy.exc import OperationalError | ||||
| from sqlalchemy.orm.exc import NoResultFound | ||||
| 
 | ||||
| from .. import models, adapters, 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 GmbH": ["biesterfeld", "biesterfeld gmbh"], | ||||
|     "Bio-Rad": ["bio rad"], | ||||
|     "Biocat": [], | ||||
|     "Bioleague GmbH & co.kg": ["bioleague"], | ||||
|     "Biomol": [], | ||||
|     "Bürkert Indelfingen": ["bürkert"], | ||||
|     "Carl Roth GmbH": [ | ||||
|         "carl roth", | ||||
|         "carl-roth", | ||||
|         "carlroth", | ||||
|         "cr", | ||||
|         "karl roth", | ||||
|         "roth", | ||||
|     ], | ||||
|     "Cellsystems Biotech": ["cellsystems"], | ||||
|     "Chemicell GmbH": ["chemicell"], | ||||
|     "Clickbox e.k.": ["clickbox"], | ||||
|     "Cole Parmer": ["coleparmer"], | ||||
|     "Conrad Electronics": [ | ||||
|         "conrad", | ||||
|         "conrad electronic", | ||||
|         "conrad, fax 09604408937, k-nr 6043142", | ||||
|     ], | ||||
|     "Cytoskeleton inc": ["cytoskeleton"], | ||||
|     "Daniel Maas Dichtstoffhandel & Co.": ["daniel maas"], | ||||
|     "Delta Mask b.v.": ["delta mask", "deltamask"], | ||||
|     "der-rollende-shop.de": ["der-rollende-shop"], | ||||
|     "Dianova": [], | ||||
|     "Distrelec": ["distrilec"], | ||||
|     "Edmund Optics GmbH": ["edmund optics", "edmund"], | ||||
|     "Faust Lab Science GmbH": ["faust", "faust lab"], | ||||
|     "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"], | ||||
|     "Hach": [], | ||||
|     "Hellma GmbH & Co KG": [ | ||||
|         "hellma analytics", | ||||
|         "hellma optics", | ||||
|         "hellma optik jena", | ||||
|     ], | ||||
|     "Hiss dx": ["hiss"], | ||||
|     "HJ-Bioanalytik GmbH": ["hj bioanalytik gmbh", "hj bioanalytik"], | ||||
|     "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 GmbH": ["iris biotech"], | ||||
|     "Ismatec": ["ismatec/idex"], | ||||
|     "Jackson Immunoresearch": ["jacksonimmuno", "jackson"], | ||||
|     "Kinesis Abimed": ["kinesis", "kinesisgmbh"], | ||||
|     "Kisker Biotech GmbH & co. kg": ["kisker"], | ||||
|     "Knick Elektronische Messgeräte GmbH": ["knick"], | ||||
|     "Kummer Laborbedarf": ["kummer"], | ||||
|     "Laborhandel Krumpholz": ["krumpholz"], | ||||
|     "leuchtmittelmarkt.com": ["leuchtmittelmarkt"], | ||||
|     "Life Sciences Advanced Technologies inc": [ | ||||
|         "life sciences advanced technologies", | ||||
|     ], | ||||
|     "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"], | ||||
|     "Mettler-Toledo GmbH": ["mettler toledo", "mettler-toledo", "mettler"], | ||||
|     "Micro Particles GmbH": ["micro particles"], | ||||
|     "Microdyn-Nadir GmbH": ["microdyn-nadir"], | ||||
|     "Millipore GmbH": ["millipore"], | ||||
|     "Molecular Devices / Genetix": ["molecular devices", "genetix"], | ||||
|     "Nanoandmore GmbH": ["nano-and-more", "nanoandmore"], | ||||
|     "Nanocyl s.a.": ["nanocyl"], | ||||
|     "Neo Lab": ["neolab"], | ||||
|     "Newport Spectra-Physics": ["newport"], | ||||
|     "OCO Ortenauer Gase GmbH": ["oco ortenauer gase", "oco"], | ||||
|     "Pall Corporation": ["pall"], | ||||
|     "Plano GmbH": ["plano", "plano-eu", "plano-em"], | ||||
|     "Polyan GmbH": ["polyan"], | ||||
|     "Polyscience Europa GmbH": [ | ||||
|         "polysciences", | ||||
|         "polysciences europe gmbh", | ||||
|         "polysciences, inc.", | ||||
|     ], | ||||
|     "ProLiquid GmbH": ["pro-liquid"], | ||||
|     "Qiagen": ["quiagen"], | ||||
|     "R&D Systems": ["r&d system"], | ||||
|     "Reichelt Elektronik": ["reichelt"], | ||||
|     "RS Components": ["rs"], | ||||
|     "S-Polytec": ["s-polytech"], | ||||
|     "Sarstedt AG & Co. KG": ["sarstedt"], | ||||
|     "Science Services GmbH": ["science services"], | ||||
|     "Scienion AG": ["scienion"], | ||||
|     "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 GmbH": [ | ||||
|         "tci", | ||||
|         "tci chemical", | ||||
|         "tci chemicals", | ||||
|         "tci deutschland", | ||||
|         "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 GmbH": ["tse systems"], | ||||
|     "Vilber Lourmat GmbH": ["vilber"], | ||||
|     "VWR International GmbH": [ | ||||
|         "vwr", | ||||
|         "vwr (lenz laborglas gmbh & co.kg)", | ||||
|         "vwr chemicals", | ||||
|         "vwr collection", | ||||
|         "vwt", | ||||
|     ], | ||||
|     "Weigert": ["drweigert"], | ||||
|     "Xantec Bioanalytics": ["xantec", "xantec bioanalyticss"], | ||||
|     "Zitt-Thoma": ["zitt thoma"], | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| def _query_table(cursor, table): | ||||
|     cursor.execute(f"SELECT * FROM {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() | ||||
|         ) | ||||
|         return user.username | ||||
|     except NoResultFound: | ||||
|         return reference | ||||
| 
 | ||||
| 
 | ||||
| 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): | ||||
|     for name, replacements in vendor_map.items(): | ||||
|         vendor = models.Vendor(name.lower(), name) | ||||
|         repo._add_item_to_db(vendor) | ||||
|         for replacement in replacements: | ||||
|             vendor = models.Vendor(replacement.lower(), name) | ||||
|             repo._add_item_to_db(vendor) | ||||
| 
 | ||||
| 
 | ||||
| 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)) | ||||
| 
 | ||||
|         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) | ||||
| 
 | ||||
| 
 | ||||
| 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( | ||||
|             """ | ||||
| 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. | ||||
|             """ | ||||
|         ) | ||||
					Loading…
					
					
				
		Reference in new issue