Source code for rattail.vendors.catalogs
# -*- 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/>.
#
################################################################################
"""
Vendor Catalogs
"""
import warnings
from decimal import Decimal
from rattail.exceptions import RattailError
from rattail.util import load_entry_points
[docs]
class CatalogParser(object):
"""
Base class for all vendor catalog parsers.
.. note::
As of this writing the ``config`` param is technically optional
for the class constructor method, but that will certainly
change some day. Please be sure to pass a ``config`` param
when instantiating parsers in your code.
.. attribute:: vendor_key
Key for the vendor. This key will be used to locate an entry in the
settings table, e.g. ``'rattail.vendor.unfi'`` for a key of ``'unfi'``.
The value of this setting must be an exact match to either a
:attr:`rattail.db.model.Vendor.uuid` or
:attr:`rattail.db.model.Vendor.id` within the system. However this
value may also be ``None`` (the default), in which case the user must
ultimately specify which vendor should be used for the data import.
"""
vendor_key = None
def __init__(self, config=None, **kwargs):
if config:
self.config = config
self.app = config.get_app()
self.model = config.get_model()
self.enum = config.get_enum()
@property
def key(self):
"""
Key for the parser. Must be unique among all catalog parsers.
"""
raise NotImplementedError("Catalog parser has no key: {0}".format(repr(self)))
[docs]
def parse_effective_date(self, path):
"""
Parse the overall effective date for a catalog file.
"""
[docs]
def parse_rows(self, data_path, progress=None):
"""
Parse the given data file, returning all rows found within it.
"""
raise NotImplementedError("Catalog parser has no `parse_rows()` method: {0}".format(repr(self.key)))
[docs]
def make_row(self):
"""
Create and return a new row, suitable for use in a vendor
catalog batch. The row will be empty and not yet part of any
database session.
:returns: A
:class:`~rattail.db.model.batch.vendorcatalog.VendorCatalogBatchRow`
instance.
"""
model = self.model
return model.VendorCatalogBatchRow()
[docs]
def decimal(self, value, scale=4):
"""
Convert a value to a decimal, unless it's ``None``.
"""
if value is None:
return None
# No reason to convert integers, really.
if isinstance(value, int):
return value
if isinstance(value, Decimal):
return value
if isinstance(value, float):
value = "{{0:0.{0}f}}".format(scale).format(value)
else:
value = value.strip()
return Decimal(value)
[docs]
def int_(self, value):
"""
Convert a value to an integer.
"""
value = value.strip() or 0
return int(value)
[docs]
class CatalogParserNotFound(RattailError):
"""
Exception raised when a vendor catalog parser is required, but cannot be
located.
"""
def __init__(self, key):
self.key = key
def __str__(self):
return "Vendor catalog parser with key {} cannot be located.".format(self.key)
[docs]
def get_catalog_parsers(): # pragma: no cover
"""
Returns a dictionary of installed vendor catalog parser classes.
"""
warnings.warn("function is deprecated, please use "
"VendorHandler.get_all_catalog_parsers() instead",
DeprecationWarning, stacklevel=2)
return load_entry_points('rattail.vendors.catalogs.parsers')
[docs]
def get_catalog_parser(key): # pragma: no cover
"""
Fetch a vendor catalog parser by key. If the parser class can be located,
this will return an instance thereof; otherwise returns ``None``.
"""
warnings.warn("function is deprecated, please use "
"VendorHandler.get_catalog_parser() instead",
DeprecationWarning, stacklevel=2)
parser = get_catalog_parsers().get(key)
if parser:
return parser()
return None
[docs]
def require_catalog_parser(key): # pragma: no cover
"""
Fetch a vendor catalog parser by key. If the parser class can be located,
this will return an instance thereof; otherwise raises an exception.
"""
warnings.warn("function is deprecated, please use "
"VendorHandler.get_catalog_parser() instead",
DeprecationWarning, stacklevel=2)
parser = get_catalog_parser(key)
if not parser:
raise CatalogParserNotFound(key)
return parser
[docs]
def iter_catalog_parsers(): # pragma: no cover
"""
Returns an iterator over the installed vendor catalog parsers.
"""
warnings.warn("function is deprecated, please use "
"VendorHandler.get_all_catalog_parsers() instead",
DeprecationWarning, stacklevel=2)
parsers = get_catalog_parsers()
return parsers.values()