Add core-office import-self command, to fix custdata.blueLine

This commit is contained in:
Lance Edgar 2023-05-18 15:55:56 -05:00
parent 5e1afa2c5c
commit 80084e13da
8 changed files with 237 additions and 4 deletions

View file

@ -3,4 +3,6 @@ include *.txt
include *.rst
include *.md
recursive-include rattail_corepos/corepos/office/scripts *.php
recursive-include rattail_corepos/db/alembic *.py

View file

@ -131,6 +131,12 @@ class RattailCOREPOSExtension(ConfigExtension):
config.setdefault('rattail.importing', 'to_corepos_db_lane_op.from_corepos_db_office_op.export.legacy_setting',
'corepos.lane.importing, office.handler')
# core-office import-self
config.setdefault('rattail.importing', 'to_self.from_corepos_db_office_op.import.default_handler',
'rattail_corepos.corepos.office.importing.db.local:FromCoreOfficeToSelf')
config.setdefault('rattail.importing', 'to_self.from_corepos_db_office_op.import.default_cmd',
'core-office import-self')
# 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')

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -29,6 +29,7 @@ import sys
from rattail import commands
from rattail_corepos import __version__
from rattail.util import load_object
from rattail_corepos.corepos.office.util import get_fannie_config_value
def main(*args):
@ -76,3 +77,29 @@ class ExportLaneOp(commands.ImportSubcommand):
if 'args' in kwargs:
kwargs['dbkey'] = kwargs['args'].dbkey
return kwargs
class GetConfigValue(commands.Subcommand):
"""
Get a value from CORE Office `fannie/config.php`
"""
name = 'get-config-value'
description = __doc__.strip()
def add_parser_args(self, parser):
parser.add_argument('name', metavar='NAME',
help="Name of the config value to get. "
"Prefix of `FANNIE_` is not required.")
def run(self, args):
value = get_fannie_config_value(self.config, args.name)
self.stdout.write(f"{value}\n")
class ImportSelf(commands.ImportSubcommand):
"""
Import data from CORE Office ("op" DB) to "self"
"""
name = 'import-self'
description = __doc__.strip()
handler_key = 'to_self.from_corepos_db_office_op.import'

View file

@ -0,0 +1,99 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 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 -> "self" data import
"""
from collections import OrderedDict
from corepos.db.office_op import model as corepos
from rattail import importing
from rattail_corepos.corepos.office.importing import db as corepos_importing
from rattail_corepos.corepos.office.importing.db.corepos import FromCoreHandler
from rattail_corepos.corepos.office.util import get_fannie_config_value
class FromCoreOfficeToSelf(FromCoreHandler, corepos_importing.model.ToCoreHandler):
"""
Common base class for import handlers which read data from the
CORE Office DB for the sake of updating misc. other tables in that
same DB.
"""
local_key = 'self'
def begin_local_transaction(self):
self.session = self.host_session
def rollback_transaction(self):
self.rollback_host_transaction()
def commit_transaction(self):
self.commit_host_transaction()
def get_importers(self):
importers = OrderedDict()
importers['CustData'] = CustDataImporter
return importers
class FromCoreOffice(importing.FromSQLAlchemy):
"""
Common base class for the "host" side of importers which read data
from the CORE Office DB for the sake of updating misc. other
tables in that same DB.
"""
class CustDataImporter(FromCoreOffice, corepos_importing.model.CustDataImporter):
"""
custdata -> custdata
Primarily used to update the ``blueLine`` field.
"""
host_model_class = corepos.CustData
supported_fields = [
'id',
'blue_line',
]
allow_create = False
allow_delete = False
def setup(self):
super().setup()
self.blueline_template = get_fannie_config_value(self.config,
'BLUELINE_TEMPLATE')
def normalize_host_object(self, customer):
blueline = self.blueline_template
blueline = blueline.replace('{{ACCOUNTNO}}', str(customer.card_number))
blueline = blueline.replace('{{ACCOUNTTYPE}}', customer.member_type.description)
blueline = blueline.replace('{{FIRSTNAME}}', customer.first_name or '')
blueline = blueline.replace('{{FIRSTINITIAL}}', customer.first_name[0] if customer.first_name else '')
blueline = blueline.replace('{{LASTNAME}}', customer.last_name or '')
blueline = blueline.replace('{{LASTINITIAL}}', customer.last_name[0] if customer.last_name else '')
return {
'id': customer.id,
'blue_line': blueline,
}

View file

@ -198,12 +198,13 @@ class MemberInfoImporter(ToCore):
data['first_name'] = customer.first_name
data['last_name'] = customer.last_name
if self.normalize_phone_numbers:
if self.normalize_phone_numbers and 'phone' in self.fields:
data['phone'] = self.app.normalize_phone_number(data['phone'])
if self.strip_address_street or self.strip_address_all:
if ((self.strip_address_street or self.strip_address_all)
and 'street' in self.fields):
data['street'] = (data['street'] or '').strip()
if self.strip_address_all:
if self.strip_address_all and self.fields_active(['city', 'state', 'zip']):
data['city'] = (data['city'] or '').strip()
data['state'] = (data['state'] or '').strip()
data['zip'] = (data['zip'] or '').strip()

View file

@ -0,0 +1,34 @@
<?php
$options = getopt('h', array(
'help',
'path:',
'setting:',
));
$help = isset($options['h']) or isset($options['help']);
$path = isset($options['path']) ? $options['path'] : null;
$setting = isset($options['setting']) ? $options['setting'] : null;
if ($help or !$path or !$setting) {
$script = basename($argv[0]);
echo "Usage: $script --path FANNIE_CONFIG_PATH --setting NAME_OF_SETTING\n";
exit($help ? 0 : 1);
}
if (!is_file(realpath($path))) {
echo "Config file does not exist: $path\n";
exit(2);
}
$path = realpath($path);
include($path);
if (!isset($$setting)) {
echo "Config file does not contain setting: $setting\n";
exit(3);
}
$value = $$setting;
echo json_encode($value);
?>

View file

@ -0,0 +1,62 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 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 utility logic
"""
import json
import os
import subprocess
from rattail.files import resource_path
def get_fannie_config_value(config, name):
"""
Retrieve a config value from `fannie/config.php`
:param config: Rattail config object.
:param name: Name of the config value to be returned. This need
not be prefixed with ``FANNIE_`` although it can be.
:returns: Config value as Python object, e.g. a string or dict.
This is believed to work okay but since the Fannie config file
represents data with PHP code, which is then converted to JSON
and finally to Python, some discrepancies may be possible.
"""
if not name.startswith('FANNIE_'):
name = f'FANNIE_{name}'
is4c = config.require('corepos', 'srcdir')
path = os.path.join(is4c, 'fannie', 'config.php')
script = resource_path('rattail_corepos.corepos.office:scripts/parse-fannie-config.php')
try:
output = subprocess.check_output(['php', script,
'--path', path,
'--setting', name])
except subprocess.CalledProcessError as error:
raise ValueError(f"failed to read value: {error.output.decode('utf_8')}")
return json.loads(output.decode('utf_8'))

View file

@ -42,6 +42,8 @@ console_scripts =
core_office.commands =
export-lane-op = rattail_corepos.corepos.office.commands:ExportLaneOp
import-self = rattail_corepos.corepos.office.commands:ImportSelf
get-config-value = rattail_corepos.corepos.office.commands:GetConfigValue
crepes.commands =
export-core = rattail_corepos.corepos.commands:ExportCore