From 314024585767d2beb6cced275b7340954ba9e997 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Mon, 6 Dec 2021 20:07:42 -0600 Subject: [PATCH] OMG a ridiculous commit to overhaul import handler config etc. - register all import/export handlers via setup.py and config - use "handler key" lookup for all import/export commands - fix logic bugs w/ CORE -> Trainwreck importer --- rattail_corepos/commands.py | 31 +------ rattail_corepos/config.py | 82 +++++++++++++++++++ rattail_corepos/corepos/commands.py | 50 ++--------- .../corepos/importing/db/corepos.py | 4 +- rattail_corepos/corepos/importing/rattail.py | 14 +++- rattail_corepos/corepos/office/commands.py | 11 +-- rattail_corepos/trainwreck/commands.py | 2 +- .../trainwreck/importing/corepos.py | 16 ++-- setup.py | 9 +- 9 files changed, 122 insertions(+), 97 deletions(-) diff --git a/rattail_corepos/commands.py b/rattail_corepos/commands.py index 389270a..299844d 100644 --- a/rattail_corepos/commands.py +++ b/rattail_corepos/commands.py @@ -34,15 +34,7 @@ class ExportCore(commands.ImportSubcommand): """ name = 'export-corepos' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.corepos.importing.rattail:FromRattailToCore' - - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail.exporting', 'corepos.handler', - default=self.default_handler_spec) - else: - spec = self.default_handler_spec - return load_object(spec) + handler_key = 'to_corepos_api.from_rattail.export' class ImportCOREPOSAPI(commands.ImportSubcommand): @@ -51,15 +43,7 @@ class ImportCOREPOSAPI(commands.ImportSubcommand): """ name = 'import-corepos-api' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.importing.corepos.api:FromCOREPOSToRattail' - - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail.importing', 'corepos_api.handler', - default=self.default_handler_spec) - else: - spec = self.default_handler_spec - return load_object(spec) + handler_key = 'to_rattail.from_corepos_api.import' class ImportCOREPOSDB(commands.ImportSubcommand): @@ -68,6 +52,7 @@ class ImportCOREPOSDB(commands.ImportSubcommand): """ name = 'import-corepos-db' description = __doc__.strip() + handler_key = 'to_rattail.from_corepos_db_office_op.import' def add_parser_args(self, parser): super(ImportCOREPOSDB, self).add_parser_args(parser) @@ -77,14 +62,6 @@ class ImportCOREPOSDB(commands.ImportSubcommand): "defined in the [rattail_corepos.db] section of your config file. " "Defaults to 'default'.") - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail.importing', 'corepos.handler', - default='rattail_corepos.importing.corepos:FromCOREPOSToRattail') - else: - spec = 'rattail_corepos.importing.corepos:FromCOREPOSToRattail' - return load_object(spec) - def get_handler_kwargs(self, **kwargs): if 'args' in kwargs: kwargs['corepos_dbkey'] = kwargs['args'].corepos_dbkey @@ -97,4 +74,4 @@ class CoreImportSquare(commands.ImportFromCSV): """ name = 'corepos-import-square' description = __doc__.strip() - handler_spec = 'rattail_corepos.corepos.importing.square:FromSquareToCoreTrans' + handler_key = 'to_corepos_db_office_trans.from_square_csv.import' diff --git a/rattail_corepos/config.py b/rattail_corepos/config.py index 1d9994b..7084e63 100644 --- a/rattail_corepos/config.py +++ b/rattail_corepos/config.py @@ -63,6 +63,88 @@ class RattailCOREPOSExtension(ConfigExtension): config.core_lane_op_engine = engines.get('default') Session.configure(bind=config.core_lane_op_engine) + # rattail corepos-import-square + config.setdefault('rattail.importing', 'to_corepos_db_office_trans.from_square_csv.import.default_handler', + 'rattail_corepos.corepos.importing.db.square:FromSquareToCoreTrans') + config.setdefault('rattail.importing', 'to_corepos_db_office_trans.from_square_csv.import.default_cmd', + 'rattail corepos-import-square') + # TODO: there was not a legacy setting in place for this one + # config.setdefault('rattail.importing', 'to_corepos_db_office_trans.from_square_csv.import.legacy_handler_setting', + # 'corepos.importing, square.handler') + + # rattail export-corepos + config.setdefault('rattail.importing', 'to_corepos_api.from_rattail.export.default_handler', + 'rattail_corepos.corepos.importing.rattail:FromRattailToCore') + config.setdefault('rattail.importing', 'to_corepos_api.from_rattail.export.default_cmd', + 'rattail export-corepos') + config.setdefault('rattail.importing', 'to_corepos_api.from_rattail.export.legacy_handler_setting', + 'rattail.exporting, corepos.handler') + + # rattail import-corepos-api + config.setdefault('rattail.importing', 'to_rattail.from_corepos_api.import.default_handler', + 'rattail_corepos.importing.corepos.api:FromCOREPOSToRattail') + config.setdefault('rattail.importing', 'to_rattail.from_corepos_api.import.default_cmd', + 'rattail import-corepos-api') + config.setdefault('rattail.importing', 'to_rattail.from_corepos_api.import.legacy_handler_setting', + 'rattail.importing, corepos_api.handler') + + # rattail import-corepos-db + config.setdefault('rattail.importing', 'to_rattail.from_corepos_db_office_op.import.default_handler', + 'rattail_corepos.importing.corepos.db:FromCOREPOSToRattail') + config.setdefault('rattail.importing', 'to_rattail.from_corepos_db_office_op.import.default_cmd', + 'rattail import-corepos-db') + config.setdefault('rattail.importing', 'to_rattail.from_corepos_db_office_op.import.legacy_handler_setting', + 'rattail.importing, corepos.handler') + + # trainwreck import-corepos + config.setdefault('rattail.importing', 'to_trainwreck.from_corepos_db_office_trans.import.default_handler', + 'rattail_corepos.trainwreck.importing.corepos:FromCoreToTrainwreck') + config.setdefault('rattail.importing', 'to_trainwreck.from_corepos_db_office_trans.import.default_cmd', + 'trainwreck import-corepos') + # TODO: there was not a legacy setting in place for this one + # config.setdefault('rattail.importing', 'to_trainwreck.from_corepos_db_office_trans.import.legacy_handler_setting', + # 'trainwreck.importing, corepos.handler') + + # core-office export-lane-op + config.setdefault('rattail.importing', 'to_corepos_db_lane_op.from_corepos_db_office_op.export.default_handler', + 'rattail_corepos.corepos.lane.importing.op.office:FromCoreOfficeToCoreLane') + config.setdefault('rattail.importing', 'to_corepos_db_lane_op.from_corepos_db_office_op.export.default_cmd', + 'core-office export-lane-op') + config.setdefault('rattail.importing', 'to_corepos_db_lane_op.from_corepos_db_office_op.export.legacy_setting', + 'corepos.lane.importing, office.handler') + + # crepes export-core + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.export.default_handler', + 'rattail_corepos.corepos.importing.db.corepos:FromCoreToCoreExport') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.export.default_cmd', + 'crepes export-core') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.export.legacy_setting', + 'rattail_corepos.exporting, corepos.handler') + + # crepes export-csv + config.setdefault('rattail.importing', 'to_csv.from_corepos_db_office_op.export.default_handler', + 'rattail_corepos.corepos.importing.db.exporters.csv:FromCoreToCSV') + config.setdefault('rattail.importing', 'to_csv.from_corepos_db_office_op.export.default_cmd', + 'crepes export-csv') + config.setdefault('rattail.importing', 'to_csv.from_corepos_db_office_op.export.legacy_setting', + 'rattail_corepos.exporting, csv.handler') + + # crepes import-core + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.import.default_handler', + 'rattail_corepos.corepos.importing.db.corepos:FromCoreToCoreImport') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.import.default_cmd', + 'crepes import-core') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_corepos_db_office_op.import.legacy_setting', + 'rattail_corepos.importing, corepos.handler') + + # crepes import-csv + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_csv.import.default_handler', + 'rattail_corepos.corepos.importing.db.csv:FromCSVToCore') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_csv.import.default_cmd', + 'crepes import-csv') + config.setdefault('rattail.importing', 'to_corepos_db_office_op.from_csv.import.legacy_setting', + 'rattail_corepos.importing, csv.handler') + def core_office_url(config, require=False, **kwargs): """ diff --git a/rattail_corepos/corepos/commands.py b/rattail_corepos/corepos/commands.py index ab7eb2f..6a61af5 100644 --- a/rattail_corepos/corepos/commands.py +++ b/rattail_corepos/corepos/commands.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2019 Lance Edgar +# Copyright © 2010-2021 Lance Edgar # # This file is part of Rattail. # @@ -60,18 +60,6 @@ class ImportToCore(commands.ImportSubcommand): """ Generic base class for commands which import *to* a CORE DB. """ - # subclass must set these! - handler_key = None - default_handler_spec = None - - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail.corepos.importing', '{}.handler'.format(self.handler_key), - default=self.default_handler_spec) - else: - # just use default, for sake of cmd line help - spec = self.default_handler_spec - return load_object(spec) class ExportCore(commands.ImportSubcommand): @@ -80,18 +68,9 @@ class ExportCore(commands.ImportSubcommand): """ name = 'export-core' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.corepos.importing.db.corepos:FromCoreToCoreExport' + handler_key = 'to_corepos_db_office_op.from_corepos_db_office_op.export' default_dbkey = 'host' - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail_corepos.exporting', 'corepos.handler', - default=self.default_handler_spec) - else: - # just use default, for sake of cmd line help - spec = self.default_handler_spec - return load_object(spec) - def add_parser_args(self, parser): super(ExportCore, self).add_parser_args(parser) parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey, @@ -111,16 +90,7 @@ class ExportCSV(commands.ExportFileSubcommand): """ name = 'export-csv' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.corepos.importing.db.exporters.csv:FromCoreToCSV' - - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail_corepos.exporting', 'csv.handler', - default=self.default_handler_spec) - else: - # just use default, for sake of cmd line help - spec = self.default_handler_spec - return load_object(spec) + handler_key = 'to_csv.from_corepos_db_office_op.export' class ImportCore(ImportToCore): @@ -129,8 +99,7 @@ class ImportCore(ImportToCore): """ name = 'import-core' description = __doc__.strip() - handler_key = 'corepos' - default_handler_spec = 'rattail_corepos.corepos.importing.db.corepos:FromCoreToCoreImport' + handler_key = 'to_corepos_db_office_op.from_corepos_db_office_op.import' accepts_dbkey_param = True def add_parser_args(self, parser): @@ -155,7 +124,7 @@ class ImportCSV(commands.ImportFileSubcommand): """ name = 'import-csv' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.corepos.importing.db.csv:FromCSVToCore' + handler_key = 'to_corepos_db_office_op.from_csv.import' def add_parser_args(self, parser): super(ImportCSV, self).add_parser_args(parser) @@ -170,12 +139,3 @@ class ImportCSV(commands.ImportFileSubcommand): args = kwargs['args'] kwargs['dbkey'] = args.dbkey return kwargs - - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('rattail_corepos.importing', 'csv.handler', - default=self.default_handler_spec) - else: - # just use default, for sake of cmd line help - spec = self.default_handler_spec - return load_object(spec) diff --git a/rattail_corepos/corepos/importing/db/corepos.py b/rattail_corepos/corepos/importing/db/corepos.py index ea02791..8c024bc 100644 --- a/rattail_corepos/corepos/importing/db/corepos.py +++ b/rattail_corepos/corepos/importing/db/corepos.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2020 Lance Edgar +# Copyright © 2010-2021 Lance Edgar # # This file is part of Rattail. # @@ -37,6 +37,7 @@ class FromCoreHandler(FromSQLAlchemyHandler): Base class for import handlers which use a CORE database as the host / source. """ host_title = "CORE" + host_key = 'corepos_db_office_op' def make_host_session(self): return CoreSession() @@ -47,6 +48,7 @@ class ToCoreHandler(ToSQLAlchemyHandler): Base class for import handlers which target a CORE database on the local side. """ local_title = "CORE" + local_key = 'corepos_db_office_op' def make_session(self): return CoreSession() diff --git a/rattail_corepos/corepos/importing/rattail.py b/rattail_corepos/corepos/importing/rattail.py index b0b9bf7..0363f09 100644 --- a/rattail_corepos/corepos/importing/rattail.py +++ b/rattail_corepos/corepos/importing/rattail.py @@ -39,12 +39,22 @@ from rattail_corepos.corepos.util import get_max_existing_vendor_id log = logging.getLogger(__name__) -class FromRattailToCore(importing.FromRattailHandler): +class ToCOREAPIHandler(importing.ImportHandler): """ - Rattail -> CORE-POS export handler + Base class for handlers targeting the CORE API. """ local_key = 'corepos_api' generic_local_title = "CORE Office (API)" + + @property + def local_title(self): + return "CORE-POS (API)" + + +class FromRattailToCore(importing.FromRattailHandler, ToCOREAPIHandler): + """ + Rattail -> CORE-POS export handler + """ direction = 'export' def get_importers(self): diff --git a/rattail_corepos/corepos/office/commands.py b/rattail_corepos/corepos/office/commands.py index d4995a7..781c4e6 100644 --- a/rattail_corepos/corepos/office/commands.py +++ b/rattail_corepos/corepos/office/commands.py @@ -60,18 +60,9 @@ class ExportLaneOp(commands.ImportSubcommand): """ name = 'export-lane-op' description = __doc__.strip() - default_handler_spec = 'rattail_corepos.corepos.lane.importing.op.office:FromCoreOfficeToCoreLane' + handler_key = 'to_corepos_db_lane_op.from_corepos_db_office_op.export' default_dbkey = 'default' - def get_handler_factory(self, **kwargs): - if self.config: - spec = self.config.get('corepos.lane.importing', 'office.handler', - default=self.default_handler_spec) - else: - # just use default, for sake of cmd line help - spec = self.default_handler_spec - return load_object(spec) - def add_parser_args(self, parser): super(ExportLaneOp, self).add_parser_args(parser) parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey, diff --git a/rattail_corepos/trainwreck/commands.py b/rattail_corepos/trainwreck/commands.py index f7bbbdc..77690d2 100644 --- a/rattail_corepos/trainwreck/commands.py +++ b/rattail_corepos/trainwreck/commands.py @@ -33,4 +33,4 @@ class ImportCore(commands.ImportSubcommand): """ name = 'import-corepos' description = __doc__.strip() - handler_spec = 'rattail_corepos.trainwreck.importing.corepos:FromCoreToTrainwreck' + handler_key = 'to_trainwreck.from_corepos_db_office_trans.import' diff --git a/rattail_corepos/trainwreck/importing/corepos.py b/rattail_corepos/trainwreck/importing/corepos.py index 62e08b5..41522b1 100644 --- a/rattail_corepos/trainwreck/importing/corepos.py +++ b/rattail_corepos/trainwreck/importing/corepos.py @@ -37,7 +37,9 @@ class FromCoreToTrainwreck(importing.FromSQLAlchemyHandler, trainwreck_importing """ Import data from CORE-POS into Trainwreck """ + host_key = 'corepos_db_office_trans' host_title = "CORE-POS" + generic_host_title = 'CORE Office (DB "trans")' corepos_dbkey = 'default' def make_host_session(self): @@ -150,23 +152,23 @@ class TransactionImporter(FromCore, trainwreck_importing.model.TransactionImport current = {} def collect(detail, i): - receipt_number = str(detail.transaction_number) + + system_id = self.make_system_id(detail) + if current and current['system_id'] != system_id: + transactions.append(dict(current)) + current.clear() date_time = detail.date_time if date_time: date_time = localtime(self.config, date_time) date_time = make_utc(date_time) - if current and current['receipt_number'] != receipt_number: - transactions.append(dict(current)) - current.clear() - if not current: current.update({ 'system': self.enum.TRAINWRECK_SYSTEM_COREPOS, - 'system_id': self.make_system_id(detail), + 'system_id': system_id, 'terminal_id': str(detail.register_number), - 'receipt_number': receipt_number, + 'receipt_number': str(detail.transaction_number), 'cashier_id': str(detail.employee_number) if detail.employee_number else None, 'customer_id': str(detail.card_number) if detail.card_number else None, 'start_time': date_time, diff --git a/setup.py b/setup.py index 43a7f48..f71c70e 100644 --- a/setup.py +++ b/setup.py @@ -124,10 +124,11 @@ setup( ], 'rattail.importing': [ - 'to_rattail.from_corepos_api = rattail_corepos.importing.corepos.api:FromCOREPOSToRattail', - 'to_rattail.from_corepos_db_office_op = rattail_corepos.importing.corepos.db:FromCOREPOSToRattail', - 'to_corepos_api.from_rattail = rattail_corepos.corepos.importing.rattail:FromRattailToCore', - 'to_corepos_db_lane_op.from_corepos_db_office_op = rattail_corepos.corepos.lane.importing.op.office:FromCoreOfficeToCoreLane', + 'to_rattail.from_corepos_api.import = rattail_corepos.importing.corepos.api:FromCOREPOSToRattail', + 'to_rattail.from_corepos_db_office_op.import = rattail_corepos.importing.corepos.db:FromCOREPOSToRattail', + 'to_corepos_api.from_rattail.export = rattail_corepos.corepos.importing.rattail:FromRattailToCore', + 'to_corepos_db_lane_op.from_corepos_db_office_op.export = rattail_corepos.corepos.lane.importing.op.office:FromCoreOfficeToCoreLane', + 'to_trainwreck.from_corepos_db_office_trans = rattail_corepos.trainwreck.importing.corepos:FromCoreToTrainwreck', ], 'trainwreck.commands': [