Add basic support for CORE Office -> CORE Lane export
just products data so far
This commit is contained in:
parent
236ae12d20
commit
6c9d9964dc
|
@ -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.
|
||||||
#
|
#
|
||||||
|
@ -35,18 +35,33 @@ class RattailCOREPOSExtension(ConfigExtension):
|
||||||
key = 'rattail-corepos'
|
key = 'rattail-corepos'
|
||||||
|
|
||||||
def configure(self, config):
|
def configure(self, config):
|
||||||
from corepos.db.office_op import Session as CoreSession
|
|
||||||
from corepos.db.office_trans import Session as CoreTransSession
|
|
||||||
|
|
||||||
|
# office_op
|
||||||
|
from corepos.db.office_op import Session
|
||||||
engines = get_engines(config, section='corepos.db.office_op')
|
engines = get_engines(config, section='corepos.db.office_op')
|
||||||
|
config.core_office_op_engines = engines
|
||||||
|
config.core_office_op_engine = engines.get('default')
|
||||||
|
Session.configure(bind=config.core_office_op_engine)
|
||||||
|
# TODO: deprecate / remove these next 2 lines
|
||||||
config.corepos_engines = engines
|
config.corepos_engines = engines
|
||||||
config.corepos_engine = engines.get('default')
|
config.corepos_engine = engines.get('default')
|
||||||
CoreSession.configure(bind=config.corepos_engine)
|
|
||||||
|
|
||||||
|
# office_trans
|
||||||
|
from corepos.db.office_trans import Session
|
||||||
engines = get_engines(config, section='corepos.db.office_trans')
|
engines = get_engines(config, section='corepos.db.office_trans')
|
||||||
|
config.core_office_trans_engines = engines
|
||||||
|
config.core_office_trans_engine = engines.get('default')
|
||||||
|
Session.configure(bind=config.core_office_trans_engine)
|
||||||
|
# TODO: deprecate / remove these next 2 lines
|
||||||
config.coretrans_engines = engines
|
config.coretrans_engines = engines
|
||||||
config.coretrans_engine = engines.get('default')
|
config.coretrans_engine = engines.get('default')
|
||||||
CoreTransSession.configure(bind=config.coretrans_engine)
|
|
||||||
|
# lane_op
|
||||||
|
from corepos.db.lane_op import Session
|
||||||
|
engines = get_engines(config, section='corepos.db.lane_op')
|
||||||
|
config.core_lane_op_engines = engines
|
||||||
|
config.core_lane_op_engine = engines.get('default')
|
||||||
|
Session.configure(bind=config.core_lane_op_engine)
|
||||||
|
|
||||||
|
|
||||||
def core_office_url(config, require=False, **kwargs):
|
def core_office_url(config, require=False, **kwargs):
|
||||||
|
|
0
rattail_corepos/corepos/common/__init__.py
Normal file
0
rattail_corepos/corepos/common/__init__.py
Normal file
67
rattail_corepos/corepos/common/importing.py
Normal file
67
rattail_corepos/corepos/common/importing.py
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Common importing logic for CORE-POS
|
||||||
|
"""
|
||||||
|
|
||||||
|
from rattail import importing
|
||||||
|
|
||||||
|
|
||||||
|
class ToCore(importing.ToSQLAlchemy):
|
||||||
|
"""
|
||||||
|
Base class for all CORE model importers; i.e. anything which uses
|
||||||
|
a CORE DB for the local side.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def create_object(self, key, host_data):
|
||||||
|
|
||||||
|
# NOTE! some tables in CORE DB may be using the MyISAM storage engine,
|
||||||
|
# which means it is *not* transaction-safe and therefore we cannot rely
|
||||||
|
# on "rollback" if in dry-run mode! in other words we better not touch
|
||||||
|
# the record at all, for dry run
|
||||||
|
if self.dry_run:
|
||||||
|
return host_data
|
||||||
|
|
||||||
|
return super(ToCore, self).create_object(key, host_data)
|
||||||
|
|
||||||
|
def update_object(self, obj, host_data, **kwargs):
|
||||||
|
|
||||||
|
# NOTE! some tables in CORE DB may be using the MyISAM storage engine,
|
||||||
|
# which means it is *not* transaction-safe and therefore we cannot rely
|
||||||
|
# on "rollback" if in dry-run mode! in other words we better not touch
|
||||||
|
# the record at all, for dry run
|
||||||
|
if self.dry_run:
|
||||||
|
return obj
|
||||||
|
|
||||||
|
return super(ToCore, self).update_object(obj, host_data, **kwargs)
|
||||||
|
|
||||||
|
def delete_object(self, obj):
|
||||||
|
|
||||||
|
# NOTE! some tables in CORE DB may be using the MyISAM storage engine,
|
||||||
|
# which means it is *not* transaction-safe and therefore we cannot rely
|
||||||
|
# on "rollback" if in dry-run mode! in other words we better not touch
|
||||||
|
# the record at all, for dry run
|
||||||
|
if self.dry_run:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return super(ToCore, self).delete_object(obj)
|
0
rattail_corepos/corepos/lane/__init__.py
Normal file
0
rattail_corepos/corepos/lane/__init__.py
Normal file
0
rattail_corepos/corepos/lane/importing/__init__.py
Normal file
0
rattail_corepos/corepos/lane/importing/__init__.py
Normal file
27
rattail_corepos/corepos/lane/importing/op/__init__.py
Normal file
27
rattail_corepos/corepos/lane/importing/op/__init__.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
Importing "operational" data into CORE Lane
|
||||||
|
"""
|
||||||
|
|
||||||
|
from . import model
|
42
rattail_corepos/corepos/lane/importing/op/model.py
Normal file
42
rattail_corepos/corepos/lane/importing/op/model.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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/>.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
"""
|
||||||
|
"operational" model importers for CORE Lane
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
All classes in this module are "direct DB" importers, which will
|
||||||
|
write directly to MySQL. They are meant to be used in dry-run mode
|
||||||
|
only, and/or for sample data import to a dev system etc. They are
|
||||||
|
*NOT* meant for production use, as they will completely bypass any
|
||||||
|
CORE business rules logic which may exist.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from rattail import importing
|
||||||
|
from rattail_corepos.corepos.common.importing import ToCore
|
||||||
|
|
||||||
|
from corepos.db.lane_op import model as corepos
|
||||||
|
|
||||||
|
|
||||||
|
class ProductImporter(ToCore):
|
||||||
|
model_class = corepos.Product
|
||||||
|
key = 'id'
|
150
rattail_corepos/corepos/lane/importing/op/office.py
Normal file
150
rattail_corepos/corepos/lane/importing/op/office.py
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 Office -> CORE Lane import
|
||||||
|
"""
|
||||||
|
|
||||||
|
from corepos.db.office_op import Session as CoreOfficeSession, model as coreoffice
|
||||||
|
from corepos.db.lane_op import Session as CoreLaneSession
|
||||||
|
|
||||||
|
from rattail import importing
|
||||||
|
from rattail.importing.handlers import FromSQLAlchemyHandler, ToSQLAlchemyHandler
|
||||||
|
from rattail.util import OrderedDict
|
||||||
|
from rattail_corepos.corepos.lane.importing import op as corepos_importing
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: this surely belongs in some other/common place? (is not lane-specific)
|
||||||
|
class FromCoreOfficeHandler(FromSQLAlchemyHandler):
|
||||||
|
"""
|
||||||
|
Base class for import handlers which use CORE Office as the host.
|
||||||
|
"""
|
||||||
|
host_title = "CORE Office"
|
||||||
|
|
||||||
|
def make_host_session(self):
|
||||||
|
return CoreOfficeSession()
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: this surely belongs in some other/common place? (is not office-specific)
|
||||||
|
class ToCoreLaneHandler(ToSQLAlchemyHandler):
|
||||||
|
"""
|
||||||
|
Base class for import handlers which target CORE Lane on the local side.
|
||||||
|
"""
|
||||||
|
local_title = "CORE Lane"
|
||||||
|
|
||||||
|
def make_session(self):
|
||||||
|
return CoreLaneSession()
|
||||||
|
|
||||||
|
|
||||||
|
class FromCoreOfficeToCoreLane(FromCoreOfficeHandler, ToCoreLaneHandler):
|
||||||
|
"""
|
||||||
|
Handler for CORE Office -> CORE Lane data export.
|
||||||
|
"""
|
||||||
|
direction = 'export'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def local_title(self):
|
||||||
|
return "CORE Lane ({})".format(self.dbkey)
|
||||||
|
|
||||||
|
def make_session(self):
|
||||||
|
return CoreLaneSession(bind=self.config.core_lane_op_engines[self.dbkey])
|
||||||
|
|
||||||
|
def get_importers(self):
|
||||||
|
importers = OrderedDict()
|
||||||
|
importers['Product'] = ProductImporter
|
||||||
|
return importers
|
||||||
|
|
||||||
|
|
||||||
|
class FromCore(importing.FromSQLAlchemy):
|
||||||
|
"""
|
||||||
|
Base class for CORE Office -> CORE Lane data importers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class ProductImporter(FromCore, corepos_importing.model.ProductImporter):
|
||||||
|
host_model_class = coreoffice.Product
|
||||||
|
|
||||||
|
# these fields are held in common, between Office and Lane tables
|
||||||
|
common_fields = [
|
||||||
|
'id',
|
||||||
|
'upc',
|
||||||
|
'description',
|
||||||
|
'brand',
|
||||||
|
'formatted_name',
|
||||||
|
'normal_price',
|
||||||
|
'price_method',
|
||||||
|
'group_price',
|
||||||
|
'quantity',
|
||||||
|
'special_price',
|
||||||
|
'special_price_method',
|
||||||
|
'special_group_price',
|
||||||
|
'special_quantity',
|
||||||
|
# 'special_limit',
|
||||||
|
'start_date',
|
||||||
|
'end_date',
|
||||||
|
'department_number',
|
||||||
|
'size',
|
||||||
|
'tax_rate_id',
|
||||||
|
'foodstamp',
|
||||||
|
'scale',
|
||||||
|
'scale_price',
|
||||||
|
'mix_match_code',
|
||||||
|
# 'created',
|
||||||
|
# 'modified',
|
||||||
|
|
||||||
|
# TODO: what to do about this 'replaces' thing?
|
||||||
|
# 'batchID'=>array('type'=>'TINYINT', 'replaces'=>'advertised'),
|
||||||
|
# batch_id = sa.Column('batchID', sa.SmallInteger(), nullable=True)
|
||||||
|
# advertised = sa.Column(sa.Boolean(), nullable=True)
|
||||||
|
|
||||||
|
'tare_weight',
|
||||||
|
'discount',
|
||||||
|
'discount_type',
|
||||||
|
'line_item_discountable',
|
||||||
|
'unit_of_measure',
|
||||||
|
'wicable',
|
||||||
|
'quantity_enforced',
|
||||||
|
'id_enforced',
|
||||||
|
'cost',
|
||||||
|
# 'special_cost',
|
||||||
|
# 'received_cost',
|
||||||
|
'in_use',
|
||||||
|
'flags',
|
||||||
|
'subdepartment_number',
|
||||||
|
'deposit',
|
||||||
|
'local',
|
||||||
|
'store_id',
|
||||||
|
'default_vendor_id',
|
||||||
|
'current_origin_id',
|
||||||
|
# 'auto_par',
|
||||||
|
# 'price_rule_id',
|
||||||
|
'last_sold',
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_fields(self):
|
||||||
|
return self.common_fields
|
||||||
|
|
||||||
|
def normalize_host_object(self, product):
|
||||||
|
data = dict([(field, getattr(product, field))
|
||||||
|
for field in self.common_fields])
|
||||||
|
return data
|
0
rattail_corepos/corepos/office/__init__.py
Normal file
0
rattail_corepos/corepos/office/__init__.py
Normal file
87
rattail_corepos/corepos/office/commands.py
Normal file
87
rattail_corepos/corepos/office/commands.py
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# -*- coding: utf-8; -*-
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Rattail -- Retail Software Framework
|
||||||
|
# Copyright © 2010-2021 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 Office commands
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from rattail import commands
|
||||||
|
from rattail_corepos import __version__
|
||||||
|
from rattail.util import load_object
|
||||||
|
|
||||||
|
|
||||||
|
def main(*args):
|
||||||
|
"""
|
||||||
|
Entry point for 'core-office' commands
|
||||||
|
"""
|
||||||
|
if args:
|
||||||
|
args = list(args)
|
||||||
|
else:
|
||||||
|
args = sys.argv[1:]
|
||||||
|
|
||||||
|
cmd = Command()
|
||||||
|
cmd.run(*args)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(commands.Command):
|
||||||
|
"""
|
||||||
|
Primary command for CORE Office
|
||||||
|
"""
|
||||||
|
name = 'core-office'
|
||||||
|
version = __version__
|
||||||
|
description = "core-office -- command line interface for CORE Office"
|
||||||
|
long_description = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ExportLaneOp(commands.ImportSubcommand):
|
||||||
|
"""
|
||||||
|
Export "op" data from CORE Office to CORE Lane
|
||||||
|
"""
|
||||||
|
name = 'export-lane-op'
|
||||||
|
description = __doc__.strip()
|
||||||
|
default_handler_spec = 'rattail_corepos.corepos.lane.importing.op.office:FromCoreOfficeToCoreLane'
|
||||||
|
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,
|
||||||
|
help="Config key for database engine to be used as the "
|
||||||
|
"\"target\" CORE Lane DB, i.e. where data will be "
|
||||||
|
" exported. This key must be defined in the "
|
||||||
|
" [rattail_corepos.db.lane_op] section of your "
|
||||||
|
"config file.")
|
||||||
|
|
||||||
|
def get_handler_kwargs(self, **kwargs):
|
||||||
|
if 'args' in kwargs:
|
||||||
|
kwargs['dbkey'] = kwargs['args'].dbkey
|
||||||
|
return kwargs
|
5
setup.py
5
setup.py
|
@ -98,6 +98,11 @@ setup(
|
||||||
|
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'crepes = rattail_corepos.corepos.commands:main',
|
'crepes = rattail_corepos.corepos.commands:main',
|
||||||
|
'core-office = rattail_corepos.corepos.office.commands:main',
|
||||||
|
],
|
||||||
|
|
||||||
|
'core_office.commands': [
|
||||||
|
'export-lane-op = rattail_corepos.corepos.office.commands:ExportLaneOp',
|
||||||
],
|
],
|
||||||
|
|
||||||
'crepes.commands': [
|
'crepes.commands': [
|
||||||
|
|
Loading…
Reference in a new issue