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
This commit is contained in:
Lance Edgar 2021-12-06 20:07:42 -06:00
parent 0e28a6ee2b
commit 3140245857
9 changed files with 122 additions and 97 deletions

View file

@ -34,15 +34,7 @@ class ExportCore(commands.ImportSubcommand):
""" """
name = 'export-corepos' name = 'export-corepos'
description = __doc__.strip() description = __doc__.strip()
default_handler_spec = 'rattail_corepos.corepos.importing.rattail:FromRattailToCore' handler_key = 'to_corepos_api.from_rattail.export'
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)
class ImportCOREPOSAPI(commands.ImportSubcommand): class ImportCOREPOSAPI(commands.ImportSubcommand):
@ -51,15 +43,7 @@ class ImportCOREPOSAPI(commands.ImportSubcommand):
""" """
name = 'import-corepos-api' name = 'import-corepos-api'
description = __doc__.strip() description = __doc__.strip()
default_handler_spec = 'rattail_corepos.importing.corepos.api:FromCOREPOSToRattail' handler_key = 'to_rattail.from_corepos_api.import'
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)
class ImportCOREPOSDB(commands.ImportSubcommand): class ImportCOREPOSDB(commands.ImportSubcommand):
@ -68,6 +52,7 @@ class ImportCOREPOSDB(commands.ImportSubcommand):
""" """
name = 'import-corepos-db' name = 'import-corepos-db'
description = __doc__.strip() description = __doc__.strip()
handler_key = 'to_rattail.from_corepos_db_office_op.import'
def add_parser_args(self, parser): def add_parser_args(self, parser):
super(ImportCOREPOSDB, self).add_parser_args(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. " "defined in the [rattail_corepos.db] section of your config file. "
"Defaults to 'default'.") "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): def get_handler_kwargs(self, **kwargs):
if 'args' in kwargs: if 'args' in kwargs:
kwargs['corepos_dbkey'] = kwargs['args'].corepos_dbkey kwargs['corepos_dbkey'] = kwargs['args'].corepos_dbkey
@ -97,4 +74,4 @@ class CoreImportSquare(commands.ImportFromCSV):
""" """
name = 'corepos-import-square' name = 'corepos-import-square'
description = __doc__.strip() description = __doc__.strip()
handler_spec = 'rattail_corepos.corepos.importing.square:FromSquareToCoreTrans' handler_key = 'to_corepos_db_office_trans.from_square_csv.import'

View file

@ -63,6 +63,88 @@ class RattailCOREPOSExtension(ConfigExtension):
config.core_lane_op_engine = engines.get('default') config.core_lane_op_engine = engines.get('default')
Session.configure(bind=config.core_lane_op_engine) 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): def core_office_url(config, require=False, **kwargs):
""" """

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2019 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # 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. 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): class ExportCore(commands.ImportSubcommand):
@ -80,18 +68,9 @@ class ExportCore(commands.ImportSubcommand):
""" """
name = 'export-core' name = 'export-core'
description = __doc__.strip() 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' 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): def add_parser_args(self, parser):
super(ExportCore, self).add_parser_args(parser) super(ExportCore, self).add_parser_args(parser)
parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey, parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey,
@ -111,16 +90,7 @@ class ExportCSV(commands.ExportFileSubcommand):
""" """
name = 'export-csv' name = 'export-csv'
description = __doc__.strip() description = __doc__.strip()
default_handler_spec = 'rattail_corepos.corepos.importing.db.exporters.csv:FromCoreToCSV' handler_key = 'to_csv.from_corepos_db_office_op.export'
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)
class ImportCore(ImportToCore): class ImportCore(ImportToCore):
@ -129,8 +99,7 @@ class ImportCore(ImportToCore):
""" """
name = 'import-core' name = 'import-core'
description = __doc__.strip() description = __doc__.strip()
handler_key = 'corepos' handler_key = 'to_corepos_db_office_op.from_corepos_db_office_op.import'
default_handler_spec = 'rattail_corepos.corepos.importing.db.corepos:FromCoreToCoreImport'
accepts_dbkey_param = True accepts_dbkey_param = True
def add_parser_args(self, parser): def add_parser_args(self, parser):
@ -155,7 +124,7 @@ class ImportCSV(commands.ImportFileSubcommand):
""" """
name = 'import-csv' name = 'import-csv'
description = __doc__.strip() 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): def add_parser_args(self, parser):
super(ImportCSV, self).add_parser_args(parser) super(ImportCSV, self).add_parser_args(parser)
@ -170,12 +139,3 @@ class ImportCSV(commands.ImportFileSubcommand):
args = kwargs['args'] args = kwargs['args']
kwargs['dbkey'] = args.dbkey kwargs['dbkey'] = args.dbkey
return kwargs 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)

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # 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. Base class for import handlers which use a CORE database as the host / source.
""" """
host_title = "CORE" host_title = "CORE"
host_key = 'corepos_db_office_op'
def make_host_session(self): def make_host_session(self):
return CoreSession() return CoreSession()
@ -47,6 +48,7 @@ class ToCoreHandler(ToSQLAlchemyHandler):
Base class for import handlers which target a CORE database on the local side. Base class for import handlers which target a CORE database on the local side.
""" """
local_title = "CORE" local_title = "CORE"
local_key = 'corepos_db_office_op'
def make_session(self): def make_session(self):
return CoreSession() return CoreSession()

View file

@ -39,12 +39,22 @@ from rattail_corepos.corepos.util import get_max_existing_vendor_id
log = logging.getLogger(__name__) 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' local_key = 'corepos_api'
generic_local_title = "CORE Office (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' direction = 'export'
def get_importers(self): def get_importers(self):

View file

@ -60,18 +60,9 @@ class ExportLaneOp(commands.ImportSubcommand):
""" """
name = 'export-lane-op' name = 'export-lane-op'
description = __doc__.strip() 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' 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): def add_parser_args(self, parser):
super(ExportLaneOp, self).add_parser_args(parser) super(ExportLaneOp, self).add_parser_args(parser)
parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey, parser.add_argument('--dbkey', metavar='KEY', default=self.default_dbkey,

View file

@ -33,4 +33,4 @@ class ImportCore(commands.ImportSubcommand):
""" """
name = 'import-corepos' name = 'import-corepos'
description = __doc__.strip() description = __doc__.strip()
handler_spec = 'rattail_corepos.trainwreck.importing.corepos:FromCoreToTrainwreck' handler_key = 'to_trainwreck.from_corepos_db_office_trans.import'

View file

@ -37,7 +37,9 @@ class FromCoreToTrainwreck(importing.FromSQLAlchemyHandler, trainwreck_importing
""" """
Import data from CORE-POS into Trainwreck Import data from CORE-POS into Trainwreck
""" """
host_key = 'corepos_db_office_trans'
host_title = "CORE-POS" host_title = "CORE-POS"
generic_host_title = 'CORE Office (DB "trans")'
corepos_dbkey = 'default' corepos_dbkey = 'default'
def make_host_session(self): def make_host_session(self):
@ -150,23 +152,23 @@ class TransactionImporter(FromCore, trainwreck_importing.model.TransactionImport
current = {} current = {}
def collect(detail, i): 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 date_time = detail.date_time
if date_time: if date_time:
date_time = localtime(self.config, date_time) date_time = localtime(self.config, date_time)
date_time = make_utc(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: if not current:
current.update({ current.update({
'system': self.enum.TRAINWRECK_SYSTEM_COREPOS, 'system': self.enum.TRAINWRECK_SYSTEM_COREPOS,
'system_id': self.make_system_id(detail), 'system_id': system_id,
'terminal_id': str(detail.register_number), '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, 'cashier_id': str(detail.employee_number) if detail.employee_number else None,
'customer_id': str(detail.card_number) if detail.card_number else None, 'customer_id': str(detail.card_number) if detail.card_number else None,
'start_time': date_time, 'start_time': date_time,

View file

@ -124,10 +124,11 @@ setup(
], ],
'rattail.importing': [ 'rattail.importing': [
'to_rattail.from_corepos_api = rattail_corepos.importing.corepos.api:FromCOREPOSToRattail', 'to_rattail.from_corepos_api.import = rattail_corepos.importing.corepos.api:FromCOREPOSToRattail',
'to_rattail.from_corepos_db_office_op = rattail_corepos.importing.corepos.db:FromCOREPOSToRattail', 'to_rattail.from_corepos_db_office_op.import = rattail_corepos.importing.corepos.db:FromCOREPOSToRattail',
'to_corepos_api.from_rattail = rattail_corepos.corepos.importing.rattail:FromRattailToCore', 'to_corepos_api.from_rattail.export = 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_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': [ 'trainwreck.commands': [