Add commands for import/export of data between CORE systems
just a staring point for now, only "operational" data for the most part
This commit is contained in:
parent
9ede5b339d
commit
9d2411bccb
131
rattail_corepos/corepos/commands.py
Normal file
131
rattail_corepos/corepos/commands.py
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
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
|
154
rattail_corepos/corepos/importing/corepos.py
Normal file
154
rattail_corepos/corepos/importing/corepos.py
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
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
|
|
@ -12,19 +12,79 @@ from corepos.trans.db import model as coretrans
|
||||||
|
|
||||||
|
|
||||||
class ToCore(importing.ToSQLAlchemy):
|
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):
|
class ToCoreTrans(importing.ToSQLAlchemy):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CustomerImporter(ToCore):
|
########################################
|
||||||
"""
|
# CORE Operational
|
||||||
CORE-POS customer data importer.
|
########################################
|
||||||
"""
|
|
||||||
model_class = corepos.Customer
|
|
||||||
|
|
||||||
|
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):
|
class TransactionDetailImporter(ToCoreTrans):
|
||||||
"""
|
"""
|
||||||
|
|
9
setup.py
9
setup.py
|
@ -99,6 +99,15 @@ setup(
|
||||||
|
|
||||||
entry_points = {
|
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.config.extensions': [
|
||||||
'rattail-corepos = rattail_corepos.config:RattailCOREPOSExtension',
|
'rattail-corepos = rattail_corepos.config:RattailCOREPOSExtension',
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue