From 8eb097867e6a9930ce7ddcb062086425affa3201 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 8 May 2024 14:54:16 -0500 Subject: [PATCH] Add basic support for importing from CSV to `office_arch.bigArchive` still requires CSV file header column names to match the SA model, and *not* the underlying mysql names --- rattail_corepos/corepos/office/commands.py | 29 +++---------- .../corepos/office/importing/db/csv.py | 20 ++++++--- .../corepos/office/importing/db/model.py | 43 ++++++++++++------- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/rattail_corepos/corepos/office/commands.py b/rattail_corepos/corepos/office/commands.py index a5f45b8..f92ffb2 100644 --- a/rattail_corepos/corepos/office/commands.py +++ b/rattail_corepos/corepos/office/commands.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2024 Lance Edgar # # This file is part of Rattail. # @@ -33,7 +33,6 @@ from requests.auth import HTTPDigestAuth from rattail import commands from rattail_corepos import __version__ -from rattail.util import load_object from rattail_corepos.corepos.office.util import get_fannie_config_value, get_blueline_template, make_blueline from rattail_corepos.corepos.util import get_core_members from rattail_corepos.config import core_office_url @@ -223,7 +222,7 @@ class CoreDBImportSubcommand(commands.ImportSubcommand): super().add_parser_args(parser) parser.add_argument('--corepos-dbtype', metavar='TYPE', default='office_op', - choices=['office_op', 'office_trans'], + choices=['office_op', 'office_trans', 'office_arch'], help="Config *type* for CORE-POS database engine to which data " "should be written. Default type is 'office_op' - this determines " "which config section is used with regard to the --corepos-dbkey arg.") @@ -234,6 +233,7 @@ class CoreDBImportSubcommand(commands.ImportSubcommand): "determiend by the --corpos-dbtype arg.") def get_handler_kwargs(self, **kwargs): + kwargs = super().get_handler_kwargs(**kwargs) if 'args' in kwargs: kwargs['corepos_dbtype'] = kwargs['args'].corepos_dbtype kwargs['corepos_dbkey'] = kwargs['args'].corepos_dbkey @@ -250,7 +250,7 @@ class ExportLaneOp(commands.ImportSubcommand): default_dbkey = 'default' def add_parser_args(self, parser): - super(ExportLaneOp, self).add_parser_args(parser) + super().add_parser_args(parser) parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey, help="Config key for database engine to be used as the " "\"target\" CORE Lane DB, i.e. where data will be " @@ -290,31 +290,14 @@ class ExportCSV(commands.ExportFileSubcommand): handler_key = 'to_csv.from_corepos_db_office_op.export' -class ImportCSV(commands.ImportFileSubcommand): +class ImportCSV(commands.ImportFileSubcommand, CoreDBImportSubcommand): """ - Import data from CSV to CORE Office "op" DB + Import data from CSV to a CORE Office DB """ name = 'import-csv' description = __doc__.strip() handler_key = 'to_corepos_db_office_op.from_csv.import' - def add_parser_args(self, parser): - super().add_parser_args(parser) - - parser.add_argument('--dbkey', metavar='KEY', default='default', - help="Config key for database engine to be used as the \"target\" " - "CORE DB, i.e. where data will be imported *to*. This key must be " - "defined in the [corepos.db.office_op] section of your config file.") - - def get_handler_kwargs(self, **kwargs): - kwargs = super().get_handler_kwargs(**kwargs) - - if 'args' in kwargs: - args = kwargs['args'] - kwargs['dbkey'] = args.dbkey - - return kwargs - class ImportSelf(commands.ImportSubcommand): """ diff --git a/rattail_corepos/corepos/office/importing/db/csv.py b/rattail_corepos/corepos/office/importing/db/csv.py index 0486dcb..fa07a12 100644 --- a/rattail_corepos/corepos/office/importing/db/csv.py +++ b/rattail_corepos/corepos/office/importing/db/csv.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2023 Lance Edgar +# Copyright © 2010-2024 Lance Edgar # # This file is part of Rattail. # @@ -24,8 +24,6 @@ CSV -> CORE data import """ -from corepos.db.office_op import model as corepos, Session as CoreSession - from rattail.importing.handlers import FromFileHandler from rattail.importing.csv import FromCSVToSQLAlchemyMixin from rattail_corepos.corepos.office.importing.db.model import ToCoreHandler, ToCore @@ -39,10 +37,20 @@ class FromCSVToCore(FromCSVToSQLAlchemyMixin, FromFileHandler, ToCoreHandler): ToParent = ToCore def get_model(self): - return corepos - def make_session(self): - return CoreSession(bind=self.config.corepos_engines[self.dbkey]) + if self.corepos_dbtype == 'office_op': + from corepos.db.office_op import model + return model + + if self.corepos_dbtype == 'office_trans': + from corepos.db.office_trans import model + return model + + if self.corepos_dbtype == 'office_arch': + from corepos.db.office_arch import model + return model + + raise ValueError(f"unknown corepos_dbtype: {self.corepos_dbtype}") def get_default_keys(self): keys = super().get_default_keys() diff --git a/rattail_corepos/corepos/office/importing/db/model.py b/rattail_corepos/corepos/office/importing/db/model.py index 80e78e5..856fede 100644 --- a/rattail_corepos/corepos/office/importing/db/model.py +++ b/rattail_corepos/corepos/office/importing/db/model.py @@ -33,8 +33,8 @@ CORE-POS model importers (direct DB) import logging -from corepos.db.office_op import model as corepos, Session as CoreSession -from corepos.db.office_trans import model as coretrans, Session as CoreTransSession +from corepos.db.office_op import model as corepos +from corepos.db.office_trans import model as coretrans from rattail import importing from rattail.importing.handlers import ToSQLAlchemyHandler @@ -55,19 +55,32 @@ class ToCoreHandler(ToSQLAlchemyHandler): @property def local_title(self): - dbtype = 'op' - if self.corepos_dbtype == 'office_trans': + dbtype = '??' + + if self.corepos_dbtype == 'office_op': + dbtype = 'op' + elif self.corepos_dbtype == 'office_trans': dbtype = 'trans' + elif self.corepos_dbtype == 'office_arch': + dbtype = 'arch' + return f"CORE Office (DB '{dbtype}')" def make_session(self): - # session type depends on the --corepos-dbtype arg - if self.corepos_dbtype == 'office_trans': - return CoreTransSession(bind=self.config.coretrans_engines[self.corepos_dbkey]) + if self.corepos_dbtype == 'office_op': + from corepos.db.office_op import Session + return Session(bind=self.config.core_office_op_engines[self.corepos_dbkey]) - # assume office_op by default - return CoreSession(bind=self.config.corepos_engines[self.corepos_dbkey]) + if self.corepos_dbtype == 'office_trans': + from corepos.db.office_trans import Session + return Session(bind=self.config.core_office_trans_engines[self.corepos_dbkey]) + + if self.corepos_dbtype == 'office_arch': + from corepos.db.office_arch import Session + return Session(bind=self.config.core_office_arch_engines[self.corepos_dbkey]) + + raise ValueError(f"unknown corepos_dbtype: {self.corepos_dbtype}") class ToCore(importing.ToSQLAlchemy): @@ -84,7 +97,7 @@ class ToCore(importing.ToSQLAlchemy): if self.dry_run: return host_data - return super(ToCore, self).create_object(key, host_data) + return super().create_object(key, host_data) def update_object(self, obj, host_data, **kwargs): @@ -95,7 +108,7 @@ class ToCore(importing.ToSQLAlchemy): if self.dry_run: return obj - return super(ToCore, self).update_object(obj, host_data, **kwargs) + return super().update_object(obj, host_data, **kwargs) def delete_object(self, obj): @@ -106,7 +119,7 @@ class ToCore(importing.ToSQLAlchemy): if self.dry_run: return True - return super(ToCore, self).delete_object(obj) + return super().delete_object(obj) class ToCoreTrans(importing.ToSQLAlchemy): @@ -223,14 +236,14 @@ class MemberInfoImporter(ToCore): @property def supported_fields(self): - fields = list(super(MemberInfoImporter, self).supported_fields) + fields = list(super().supported_fields) fields.append('member_type_id') return fields def normalize_local_object(self, member): - data = super(MemberInfoImporter, self).normalize_local_object(member) + data = super().normalize_local_object(member) if self.prefer_local_names_from_custdata and member.customers: customer = member.customers[0] @@ -257,7 +270,7 @@ class MemberInfoImporter(ToCore): return data def update_object(self, member, host_data, local_data=None, **kwargs): - member = super(MemberInfoImporter, self).update_object( + member = super().update_object( member, host_data, local_data=local_data, **kwargs) if 'first_name' in self.fields: