diff --git a/rattail_corepos/corepos/commands.py b/rattail_corepos/corepos/commands.py
new file mode 100644
index 0000000..998e10d
--- /dev/null
+++ b/rattail_corepos/corepos/commands.py
@@ -0,0 +1,131 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# Rattail -- Retail Software Framework
+# Copyright © 2010-2019 Lance Edgar
+#
+# This file is part of Rattail.
+#
+# Rattail is free software: you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Rattail. If not, see .
+#
+################################################################################
+"""
+CORE-POS commands
+"""
+
+from __future__ import unicode_literals, absolute_import
+
+import sys
+
+from rattail import commands
+from rattail_corepos import __version__
+from rattail.util import load_object
+
+
+def main(*args):
+ """
+ Primary entry point for Crepes command system
+ """
+ if args:
+ args = list(args)
+ else:
+ args = sys.argv[1:]
+
+ cmd = Command()
+ cmd.run(*args)
+
+
+class Command(commands.Command):
+ """
+ Primary command for Crepes (CORE-POS)
+ """
+ name = 'crepes'
+ version = __version__
+ description = "Crepes -- command line interface for CORE-POS"
+ long_description = ""
+
+
+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):
+ """
+ Export data to another CORE database
+ """
+ name = 'export-core'
+ description = __doc__.strip()
+ default_handler_spec = 'rattail_corepos.corepos.importing.corepos:FromCoreToCoreExport'
+ 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,
+ help="Config key for database engine to be used as the \"target\" "
+ "CORE DB, i.e. where data will be exported. This key must be "
+ "defined in the [rattail_corepos.db] section of your config file.")
+
+ def get_handler_kwargs(self, **kwargs):
+ if 'args' in kwargs:
+ kwargs['dbkey'] = kwargs['args'].dbkey
+ return kwargs
+
+
+class ImportCore(ImportToCore):
+ """
+ Import data from another CORE database
+ """
+ name = 'import-core'
+ description = __doc__.strip()
+ handler_key = 'corepos'
+ default_handler_spec = 'rattail_corepos.corepos.importing.corepos:FromCoreToCoreImport'
+ accepts_dbkey_param = True
+
+ def add_parser_args(self, parser):
+ super(ImportCore, self).add_parser_args(parser)
+ if self.accepts_dbkey_param:
+ parser.add_argument('--dbkey', metavar='KEY', default='host',
+ help="Config key for database engine to be used as the CORE "
+ "\"host\", i.e. the source of the data to be imported. This key "
+ "must be defined in the [rattail_corepos.db] section of your config file. "
+ "Defaults to 'host'.")
+
+ def get_handler_kwargs(self, **kwargs):
+ if self.accepts_dbkey_param:
+ if 'args' in kwargs:
+ kwargs['dbkey'] = kwargs['args'].dbkey
+ return kwargs
diff --git a/rattail_corepos/corepos/importing/corepos.py b/rattail_corepos/corepos/importing/corepos.py
new file mode 100644
index 0000000..d673da5
--- /dev/null
+++ b/rattail_corepos/corepos/importing/corepos.py
@@ -0,0 +1,154 @@
+# -*- coding: utf-8; -*-
+################################################################################
+#
+# Rattail -- Retail Software Framework
+# Copyright © 2010-2019 Lance Edgar
+#
+# This file is part of Rattail.
+#
+# Rattail is free software: you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# Rattail. If not, see .
+#
+################################################################################
+"""
+CORE-POS -> CORE-POS data import
+"""
+
+from __future__ import unicode_literals, absolute_import
+
+from rattail.importing.handlers import FromSQLAlchemyHandler, ToSQLAlchemyHandler
+from rattail.importing.sqlalchemy import FromSQLAlchemySameToSame
+from rattail.util import OrderedDict
+from rattail_corepos.db import Session as CoreSession
+from rattail_corepos.corepos import importing as corepos_importing
+
+
+class FromCoreHandler(FromSQLAlchemyHandler):
+ """
+ Base class for import handlers which use a CORE database as the host / source.
+ """
+ host_title = "CORE"
+
+ def make_host_session(self):
+ return CoreSession()
+
+
+class ToCoreHandler(ToSQLAlchemyHandler):
+ """
+ Base class for import handlers which target a CORE database on the local side.
+ """
+ local_title = "CORE"
+
+ def make_session(self):
+ return CoreSession()
+
+
+class FromCoreToCoreBase(object):
+ """
+ Common base class for Core -> Core data import/export handlers.
+ """
+
+ def get_importers(self):
+ importers = OrderedDict()
+ importers['Department'] = DepartmentImporter
+ importers['Subdepartment'] = SubdepartmentImporter
+ importers['Vendor'] = VendorImporter
+ importers['VendorContact'] = VendorContactImporter
+ importers['Product'] = ProductImporter
+ importers['ProductFlag'] = ProductFlagImporter
+ importers['Employee'] = EmployeeImporter
+ importers['Customer'] = CustomerImporter
+ importers['MemberType'] = MemberTypeImporter
+ importers['MemberInfo'] = MemberInfoImporter
+ importers['HouseCoupon'] = HouseCouponImporter
+ return importers
+
+
+class FromCoreToCoreImport(FromCoreToCoreBase, FromCoreHandler, ToCoreHandler):
+ """
+ Handler for CORE (other) -> CORE (local) data import.
+
+ .. attribute:: direction
+
+ Value is ``'import'`` - see also
+ :attr:`rattail.importing.handlers.ImportHandler.direction`.
+ """
+ dbkey = 'host'
+ local_title = "CORE (default)"
+
+ @property
+ def host_title(self):
+ return "CORE ({})".format(self.dbkey)
+
+ def make_host_session(self):
+ return CoreSession(bind=self.config.corepos_engines[self.dbkey])
+
+
+class FromCoreToCoreExport(FromCoreToCoreBase, FromCoreHandler, ToCoreHandler):
+ """
+ Handler for CORE (local) -> CORE (other) data export.
+
+ .. attribute:: direction
+
+ Value is ``'export'`` - see also
+ :attr:`rattail.importing.handlers.ImportHandler.direction`.
+ """
+ direction = 'export'
+ host_title = "CORE (default)"
+
+ @property
+ def local_title(self):
+ return "CORE ({})".format(self.dbkey)
+
+ def make_session(self):
+ return CoreSession(bind=self.config.corepos_engines[self.dbkey])
+
+
+class FromCore(FromSQLAlchemySameToSame):
+ """
+ Base class for CORE -> CORE data importers.
+ """
+
+
+class DepartmentImporter(FromCore, corepos_importing.model.DepartmentImporter):
+ pass
+
+class SubdepartmentImporter(FromCore, corepos_importing.model.SubdepartmentImporter):
+ pass
+
+class VendorImporter(FromCore, corepos_importing.model.VendorImporter):
+ pass
+
+class VendorContactImporter(FromCore, corepos_importing.model.VendorContactImporter):
+ pass
+
+class ProductImporter(FromCore, corepos_importing.model.ProductImporter):
+ pass
+
+class ProductFlagImporter(FromCore, corepos_importing.model.ProductFlagImporter):
+ pass
+
+class EmployeeImporter(FromCore, corepos_importing.model.EmployeeImporter):
+ pass
+
+class CustomerImporter(FromCore, corepos_importing.model.CustomerImporter):
+ pass
+
+class MemberTypeImporter(FromCore, corepos_importing.model.MemberTypeImporter):
+ pass
+
+class MemberInfoImporter(FromCore, corepos_importing.model.MemberInfoImporter):
+ pass
+
+class HouseCouponImporter(FromCore, corepos_importing.model.HouseCouponImporter):
+ pass
diff --git a/rattail_corepos/corepos/importing/model.py b/rattail_corepos/corepos/importing/model.py
index 08fad0f..a3a9fdb 100644
--- a/rattail_corepos/corepos/importing/model.py
+++ b/rattail_corepos/corepos/importing/model.py
@@ -12,19 +12,79 @@ from corepos.trans.db import model as coretrans
class ToCore(importing.ToSQLAlchemy):
- pass
+ """
+ Base class for all CORE (operational) model importers
+ """
+ # TODO: should we standardize on the 'id' primary key? (can we even?)
+ # key = 'id'
class ToCoreTrans(importing.ToSQLAlchemy):
pass
-class CustomerImporter(ToCore):
- """
- CORE-POS customer data importer.
- """
- model_class = corepos.Customer
+########################################
+# CORE Operational
+########################################
+class DepartmentImporter(ToCore):
+ model_class = corepos.Department
+ key = 'number'
+
+
+class SubdepartmentImporter(ToCore):
+ model_class = corepos.Subdepartment
+ key = 'number'
+
+
+class VendorImporter(ToCore):
+ model_class = corepos.Vendor
+ key = 'id'
+
+
+class VendorContactImporter(ToCore):
+ model_class = corepos.VendorContact
+ key = 'vendor_id'
+
+
+class ProductImporter(ToCore):
+ model_class = corepos.Product
+ key = 'id'
+
+
+class ProductFlagImporter(ToCore):
+ model_class = corepos.ProductFlag
+ key = 'bit_number'
+
+
+class EmployeeImporter(ToCore):
+ model_class = corepos.Employee
+ key = 'emp_no'
+
+
+class CustomerImporter(ToCore):
+ model_class = corepos.Customer
+ key = 'id'
+
+
+class MemberTypeImporter(ToCore):
+ model_class = corepos.MemberType
+ key = 'id'
+
+
+class MemberInfoImporter(ToCore):
+ model_class = corepos.MemberInfo
+ key = 'card_no'
+
+
+class HouseCouponImporter(ToCore):
+ model_class = corepos.HouseCoupon
+ key = 'coupon_id'
+
+
+########################################
+# CORE Transactions
+########################################
class TransactionDetailImporter(ToCoreTrans):
"""
diff --git a/setup.py b/setup.py
index 493b798..3cbc59a 100644
--- a/setup.py
+++ b/setup.py
@@ -99,6 +99,15 @@ setup(
entry_points = {
+ 'console_scripts': [
+ 'crepes = rattail_corepos.corepos.commands:main',
+ ],
+
+ 'crepes.commands': [
+ 'export-core = rattail_corepos.corepos.commands:ExportCore',
+ 'import-core = rattail_corepos.corepos.commands:ImportCore',
+ ],
+
'rattail.config.extensions': [
'rattail-corepos = rattail_corepos.config:RattailCOREPOSExtension',
],