Changeset - 8f791350e938
[Not reviewed]
0 2 0
Lance Edgar (lance) - 12 years ago 2012-08-10 13:47:14
lance@edbob.org
add Customer, and Vendor/Employee contact info to model
2 files changed with 654 insertions and 390 deletions:
0 comments (0 inline, 0 general)
rattail/db/cache.py
Show inline comments
 
@@ -52,14 +52,14 @@ class DataCacher(edbob.Object):
 
        query = self.session.query(self.class_)
 
        count = query.count()
 
        if not count:
 
            return self.instances
 
        
 
        prog = None
 
        if progress:
 
            prog = progress("Reading %s records into cache" % self.name, count)
 
        # if progress:
 
        #     prog = progress("Reading %s records into cache" % self.name, count)
 

	
 
        cancel = False
 
        for i, instance in enumerate(query, 1):
 
            self.cache_instance(instance)
 
            if prog and not prog.update(i):
 
                cancel = True
 
@@ -109,6 +109,22 @@ class VendorCacher(DataCacher):
 
class ProductCacher(DataCacher):
 

	
 
    class_ = rattail.Product
 

	
 
    def cache_instance(self, prod):
 
        self.instances[prod.upc] = prod
 

	
 

	
 
class CustomerGroupCacher(DataCacher):
 

	
 
    class_ = rattail.CustomerGroup
 

	
 
    def cache_instance(self, group):
 
        self.instances[group.id] = group
 

	
 

	
 
class CustomerCacher(DataCacher):
 

	
 
    class_ = rattail.Customer
 

	
 
    def cache_instance(self, customer):
 
        self.instances[customer.id] = customer
rattail/db/extension/model.py
Show inline comments
 
@@ -36,186 +36,196 @@ from sqlalchemy import and_
 
from sqlalchemy.orm import relationship, object_session
 
from sqlalchemy.ext.associationproxy import association_proxy
 
from sqlalchemy.ext.orderinglist import ordering_list
 

	
 
import edbob
 
from edbob.db.model import Base, uuid_column
 
from edbob.db.extensions.contact import Person, Phone, PersonPhone
 
from edbob.db.extensions.contact import (Person, EmailAddress, PhoneNumber,
 
                                         PersonPhoneNumber)
 
from edbob.sqlalchemy import getset_factory
 

	
 

	
 
__all__ = ['SilColumn', 'BatchDictionaryColumn', 'BatchDictionary',
 
           'BatchTerminalColumn', 'BatchTerminal', 'BatchColumn',
 
           'Batch', 'Brand', 'Department', 'Subdepartment', 'Category',
 
           'Product', 'Employee', 'Vendor', 'VendorContact', 'VendorPhone',
 
           'ProductCost', 'ProductPrice']
 
# __all__ = ['SilColumn', 'BatchDictionaryColumn', 'BatchDictionary',
 
#            'BatchTerminalColumn', 'BatchTerminal', 'BatchColumn',
 
#            'Batch', 'Brand', 'Department', 'Subdepartment', 'Category',
 
#            'Product', 'Employee', 'Vendor', 'VendorContact', 'VendorPhoneNumber',
 
#            'ProductCost', 'ProductPrice', 'Customer', 'CustomerGroup', 
 
#            'CustomerGroupAssignment', 'CustomerPerson']
 

	
 
sil_type_pattern = re.compile(r'^(CHAR|NUMBER)\((\d+(?:\,\d+)?)\)$')
 
__all__ = ['Department', 'Subdepartment', 'Brand', 'Category', 'Vendor',
 
           'VendorContact', 'VendorPhoneNumber', 'Product', 'ProductCost',
 
           'ProductPrice', 'Customer', 'CustomerEmailAddress',
 
           'CustomerPhoneNumber', 'CustomerGroup', 'CustomerGroupAssignment',
 
           'CustomerPerson', 'Employee', 'EmployeeEmailAddress',
 
           'EmployeePhoneNumber']
 

	
 
# sil_type_pattern = re.compile(r'^(CHAR|NUMBER)\((\d+(?:\,\d+)?)\)$')
 

	
 
class SilColumn(Base):
 
    """
 
    Represents a SIL-compatible column available to the batch system.
 
    """
 

	
 
    __tablename__ = 'sil_columns'
 
# class SilColumn(Base):
 
#     """
 
#     Represents a SIL-compatible column available to the batch system.
 
#     """
 

	
 
#     __tablename__ = 'sil_columns'
 

	
 
    uuid = uuid_column()
 
    sil_name = Column(String(10))
 
    display = Column(String(20))
 
    data_type = Column(String(15))
 
#     uuid = uuid_column()
 
#     sil_name = Column(String(10))
 
#     display = Column(String(20))
 
#     data_type = Column(String(15))
 
    
 
    def __repr__(self):
 
        return "<SilColumn: %s>" % self.sil_name
 
#     def __repr__(self):
 
#         return "<SilColumn: %s>" % self.sil_name
 

	
 
    def __str__(self):
 
        return str(self.sil_name or '')
 
#     def __str__(self):
 
#         return str(self.sil_name or '')
 

	
 

	
 
class BatchDictionaryColumn(Base):
 
    """
 
    Represents a column within a :class:`BatchDictionary`.
 
    """
 
# class BatchDictionaryColumn(Base):
 
#     """
 
#     Represents a column within a :class:`BatchDictionary`.
 
#     """
 

	
 
    __tablename__ = 'batch_dictionary_columns'
 
#     __tablename__ = 'batch_dictionary_columns'
 

	
 
    uuid = uuid_column()
 
    dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
    sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
    key = Column(Boolean)
 
#     uuid = uuid_column()
 
#     dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
#     sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
#     key = Column(Boolean)
 

	
 
    sil_column = relationship(SilColumn)
 
#     sil_column = relationship(SilColumn)
 

	
 
    def __repr__(self):
 
        return "<BatchDictionaryColumn: %s>" % self.sil_column
 
#     def __repr__(self):
 
#         return "<BatchDictionaryColumn: %s>" % self.sil_column
 

	
 
    def __str__(self):
 
        return str(self.sil_column or '')
 
#     def __str__(self):
 
#         return str(self.sil_column or '')
 

	
 

	
 
class BatchDictionary(Base):
 
    """
 
    Represents a SIL-based dictionary supported by one or more
 
    :class:`BatchTerminal` classes.
 
    """
 
# class BatchDictionary(Base):
 
#     """
 
#     Represents a SIL-based dictionary supported by one or more
 
#     :class:`BatchTerminal` classes.
 
#     """
 

	
 
    __tablename__ = 'batch_dictionaries'
 
#     __tablename__ = 'batch_dictionaries'
 

	
 
    uuid = uuid_column()
 
    name = Column(String(20))
 
    description = Column(String(255))
 
#     uuid = uuid_column()
 
#     name = Column(String(20))
 
#     description = Column(String(255))
 

	
 
    columns = relationship(
 
        BatchDictionaryColumn,
 
        backref='dictionary')
 
#     columns = relationship(
 
#         BatchDictionaryColumn,
 
#         backref='dictionary')
 

	
 
    def __repr__(self):
 
        return "<BatchDictionary: %s>" % self.name
 
#     def __repr__(self):
 
#         return "<BatchDictionary: %s>" % self.name
 

	
 
    def __str__(self):
 
        return str(self.description or '')
 
#     def __str__(self):
 
#         return str(self.description or '')
 

	
 

	
 
class BatchTerminalColumn(Base):
 
    """
 
    Represents a column supported by a :class:`BatchTerminal`.
 
    """
 
# class BatchTerminalColumn(Base):
 
#     """
 
#     Represents a column supported by a :class:`BatchTerminal`.
 
#     """
 

	
 
    __tablename__ = 'batch_terminal_columns'
 
#     __tablename__ = 'batch_terminal_columns'
 

	
 
    uuid = uuid_column()
 
    terminal_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
    dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
    sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
    ordinal = Column(Integer)
 
    source = Column(Boolean)
 
    target = Column(Boolean)
 
#     uuid = uuid_column()
 
#     terminal_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
#     dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
#     sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
#     ordinal = Column(Integer)
 
#     source = Column(Boolean)
 
#     target = Column(Boolean)
 

	
 
    dictionary = relationship(BatchDictionary)
 
    sil_column = relationship(SilColumn)
 
#     dictionary = relationship(BatchDictionary)
 
#     sil_column = relationship(SilColumn)
 

	
 
    def __repr__(self):
 
        return "<BatchTerminalColumn: %s, %s, %s>" % (
 
            self.terminal, self.dictionary, self.sil_column)
 
#     def __repr__(self):
 
#         return "<BatchTerminalColumn: %s, %s, %s>" % (
 
#             self.terminal, self.dictionary, self.sil_column)
 

	
 
    def __str__(self):
 
        return str(self.sil_column or '')
 
#     def __str__(self):
 
#         return str(self.sil_column or '')
 

	
 

	
 
class BatchTerminal(Base):
 
    """
 
    Represents a terminal, or "junction" for batch data.
 
    """
 
# class BatchTerminal(Base):
 
#     """
 
#     Represents a terminal, or "junction" for batch data.
 
#     """
 

	
 
    __tablename__ = 'batch_terminals'
 
#     __tablename__ = 'batch_terminals'
 

	
 
    uuid = uuid_column()
 
    sil_id = Column(String(20), unique=True)
 
    description = Column(String(50))
 
    class_spec = Column(String(255))
 
    functional = Column(Boolean, default=False)
 
    source = Column(Boolean)
 
    target = Column(Boolean)
 
    source_kwargs = Column(Text)
 
    target_kwargs = Column(Text)
 
#     uuid = uuid_column()
 
#     sil_id = Column(String(20), unique=True)
 
#     description = Column(String(50))
 
#     class_spec = Column(String(255))
 
#     functional = Column(Boolean, default=False)
 
#     source = Column(Boolean)
 
#     target = Column(Boolean)
 
#     source_kwargs = Column(Text)
 
#     target_kwargs = Column(Text)
 

	
 
    columns = relationship(
 
        BatchTerminalColumn,
 
        backref='terminal')
 
#     columns = relationship(
 
#         BatchTerminalColumn,
 
#         backref='terminal')
 

	
 
    _terminal = 'not_got_yet'
 
#     _terminal = 'not_got_yet'
 

	
 
    def __repr__(self):
 
        return "<BatchTerminal: %s>" % self.sil_id
 
#     def __repr__(self):
 
#         return "<BatchTerminal: %s>" % self.sil_id
 

	
 
    def __str__(self):
 
        return str(self.description or '')
 
#     def __str__(self):
 
#         return str(self.description or '')
 

	
 
    def source_columns(self, dictionary):
 
        for col in self.columns:
 
            if col.dictionary is dictionary:
 
                yield col
 
#     def source_columns(self, dictionary):
 
#         for col in self.columns:
 
#             if col.dictionary is dictionary:
 
#                 yield col
 

	
 
    def get_terminal(self):
 
        """
 
        Returns the :class:`rattail.batches.BatchTerminal` instance which is
 
        associated with the database record via its ``python_spec`` field.
 
        """
 
#     def get_terminal(self):
 
#         """
 
#         Returns the :class:`rattail.batches.BatchTerminal` instance which is
 
#         associated with the database record via its ``python_spec`` field.
 
#         """
 

	
 
        if self._terminal == 'not_got_yet':
 
            self._terminal = None
 
            if self.class_spec:
 
                term = edbob.load_spec(self.class_spec)
 
                if term:
 
                    self._terminal = term()
 
        return self._terminal
 
#         if self._terminal == 'not_got_yet':
 
#             self._terminal = None
 
#             if self.class_spec:
 
#                 term = edbob.load_spec(self.class_spec)
 
#                 if term:
 
#                     self._terminal = term()
 
#         return self._terminal
 

	
 

	
 
class BatchColumn(Base):
 
    """
 
    Represents a :class:`SilColumn` associated with a :class:`Batch`.
 
    """
 
# class BatchColumn(Base):
 
#     """
 
#     Represents a :class:`SilColumn` associated with a :class:`Batch`.
 
#     """
 

	
 
    __tablename__ = 'batch_columns'
 
#     __tablename__ = 'batch_columns'
 

	
 
    uuid = uuid_column()
 
    batch_uuid = Column(String(32), ForeignKey('batches.uuid'))
 
    ordinal = Column(Integer)
 
    sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
    source_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
    targeted = Column(Boolean)
 
#     uuid = uuid_column()
 
#     batch_uuid = Column(String(32), ForeignKey('batches.uuid'))
 
#     ordinal = Column(Integer)
 
#     sil_column_uuid = Column(String(32), ForeignKey('sil_columns.uuid'))
 
#     source_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
#     targeted = Column(Boolean)
 

	
 
    sil_column = relationship(SilColumn)
 
#     sil_column = relationship(SilColumn)
 

	
 
    source = relationship(
 
        BatchTerminal,
 
        primaryjoin=BatchTerminal.uuid == source_uuid,
 
        order_by=[BatchTerminal.description],
 
        )
 
#     source = relationship(
 
#         BatchTerminal,
 
#         primaryjoin=BatchTerminal.uuid == source_uuid,
 
#         order_by=[BatchTerminal.description],
 
#         )
 

	
 
    def __repr__(self):
 
        return "<BatchColumn: %s, %s>" % (self.batch, self.sil_column)
 
#     def __repr__(self):
 
#         return "<BatchColumn: %s, %s>" % (self.batch, self.sil_column)
 

	
 

	
 
# def get_sil_column(name):
 
#     """
 
#     Returns a ``sqlalchemy.Column`` instance according to Rattail's notion of
 
#     what each SIL field ought to look like.
 
@@ -238,260 +248,260 @@ class BatchColumn(Base):
 
#             String(60), # short description, line 2
 
#         }
 

	
 
#     return Column(name, type_map[name])
 

	
 

	
 
def get_sil_type(data_type):
 
    """
 
    Returns a SQLAlchemy-based data type according to the SIL-compliant type
 
    specifier found in ``data_type``.
 
    """
 

	
 
    if data_type == 'GPC(14)':
 
        return BigInteger
 

	
 
    m = sil_type_pattern.match(data_type)
 
    if m:
 
        data_type, precision = m.groups()
 
        if precision.isdigit():
 
            precision = int(precision)
 
            scale = 0
 
        else:
 
            precision, scale = precision.split(',')
 
            precision = int(precision)
 
            scale = int(scale)
 
        if data_type == 'CHAR':
 
            assert not scale, "FIXME"
 
            return String(precision)
 
        if data_type == 'NUMBER':
 
            return Numeric(precision, scale)
 
# def get_sil_type(data_type):
 
#     """
 
#     Returns a SQLAlchemy-based data type according to the SIL-compliant type
 
#     specifier found in ``data_type``.
 
#     """
 

	
 
    assert False, "FIXME"
 
#     if data_type == 'GPC(14)':
 
#         return BigInteger
 

	
 
#     m = sil_type_pattern.match(data_type)
 
#     if m:
 
#         data_type, precision = m.groups()
 
#         if precision.isdigit():
 
#             precision = int(precision)
 
#             scale = 0
 
#         else:
 
#             precision, scale = precision.split(',')
 
#             precision = int(precision)
 
#             scale = int(scale)
 
#         if data_type == 'CHAR':
 
#             assert not scale, "FIXME"
 
#             return String(precision)
 
#         if data_type == 'NUMBER':
 
#             return Numeric(precision, scale)
 

	
 
#     assert False, "FIXME"
 
    
 

	
 
class Batch(Base):
 
    """
 
    Represents a batch of data, presumably in need of processing.
 
    """
 

	
 
    __tablename__ = 'batches'
 

	
 
    _rowclass = None
 
    _row_classes = {}
 
# class Batch(Base):
 
#     """
 
#     Represents a batch of data, presumably in need of processing.
 
#     """
 

	
 
    uuid = uuid_column()
 
    source_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
    source_description = Column(String(50))
 
    source_batch_id = Column(String(8))
 
    batch_id = Column(String(8))
 
    dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
    name = Column(String(30))
 
    target_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
    action_type = Column(String(6))
 
    elements = Column(String(255))
 
    description = Column(String(50))
 
    rowcount = Column(Integer, default=0)
 
    effective = Column(DateTime)
 
    deleted = Column(Boolean, default=False)
 
    sil_type = Column(String(2))
 
    sil_source_id = Column(String(20))
 
    sil_target_id = Column(String(20))
 
    sil_audit_file = Column(String(12))
 
    sil_response_file = Column(String(12))
 
    sil_origin_time = Column(DateTime)
 
    sil_purge_date = Column(Date)
 
    sil_user1 = Column(String(30))
 
    sil_user2 = Column(String(30))
 
    sil_user3 = Column(String(30))
 
    sil_warning_level = Column(Integer)
 
    sil_max_errors = Column(Integer)
 
    sil_level = Column(String(7))
 
    sil_software_revision = Column(String(4))
 
    sil_primary_key = Column(String(50))
 
    sil_sys_command = Column(String(512))
 
    sil_dict_revision = Column(String(8))
 
#     __tablename__ = 'batches'
 

	
 
#     _rowclass = None
 
#     _row_classes = {}
 

	
 
#     uuid = uuid_column()
 
#     source_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
#     source_description = Column(String(50))
 
#     source_batch_id = Column(String(8))
 
#     batch_id = Column(String(8))
 
#     dictionary_uuid = Column(String(32), ForeignKey('batch_dictionaries.uuid'))
 
#     name = Column(String(30))
 
#     target_uuid = Column(String(32), ForeignKey('batch_terminals.uuid'))
 
#     action_type = Column(String(6))
 
#     elements = Column(String(255))
 
#     description = Column(String(50))
 
#     rowcount = Column(Integer, default=0)
 
#     effective = Column(DateTime)
 
#     deleted = Column(Boolean, default=False)
 
#     sil_type = Column(String(2))
 
#     sil_source_id = Column(String(20))
 
#     sil_target_id = Column(String(20))
 
#     sil_audit_file = Column(String(12))
 
#     sil_response_file = Column(String(12))
 
#     sil_origin_time = Column(DateTime)
 
#     sil_purge_date = Column(Date)
 
#     sil_user1 = Column(String(30))
 
#     sil_user2 = Column(String(30))
 
#     sil_user3 = Column(String(30))
 
#     sil_warning_level = Column(Integer)
 
#     sil_max_errors = Column(Integer)
 
#     sil_level = Column(String(7))
 
#     sil_software_revision = Column(String(4))
 
#     sil_primary_key = Column(String(50))
 
#     sil_sys_command = Column(String(512))
 
#     sil_dict_revision = Column(String(8))
 
    
 
    source = relationship(
 
        BatchTerminal,
 
        primaryjoin=BatchTerminal.uuid == source_uuid,
 
        order_by=[BatchTerminal.description],
 
        )
 

	
 
    dictionary = relationship(
 
        BatchDictionary,
 
        order_by=[BatchDictionary.name],
 
        )
 

	
 
    target = relationship(
 
        BatchTerminal,
 
        primaryjoin=BatchTerminal.uuid == target_uuid,
 
        order_by=[BatchTerminal.description],
 
        )
 

	
 
    columns = relationship(
 
        BatchColumn,
 
        backref='batch',
 
        )
 

	
 
    # _table = None
 
    # # _source_junction = 'not set'
 
    # # _target_junction = 'not set'
 

	
 
    # invalid_name_chars = re.compile(r'[^A-Za-z0-9]')
 

	
 
    def __repr__(self):
 
        return "<Batch: %s>" % (self.name or '(no name)')
 

	
 
    def __str__(self):
 
        return str(self.name or '')
 
#     source = relationship(
 
#         BatchTerminal,
 
#         primaryjoin=BatchTerminal.uuid == source_uuid,
 
#         order_by=[BatchTerminal.description],
 
#         )
 

	
 
#     dictionary = relationship(
 
#         BatchDictionary,
 
#         order_by=[BatchDictionary.name],
 
#         )
 

	
 
#     target = relationship(
 
#         BatchTerminal,
 
#         primaryjoin=BatchTerminal.uuid == target_uuid,
 
#         order_by=[BatchTerminal.description],
 
#         )
 

	
 
#     columns = relationship(
 
#         BatchColumn,
 
#         backref='batch',
 
#         )
 

	
 
#     # _table = None
 
#     # # _source_junction = 'not set'
 
#     # # _target_junction = 'not set'
 

	
 
#     # invalid_name_chars = re.compile(r'[^A-Za-z0-9]')
 

	
 
    # @property
 
    # def source_junction(self):
 
    #     """
 
    #     Returns the :class:`rattail.BatchJunction` instance associated with
 
    #     this batch's :attr:`Batch.source` attribute.
 
    #     """
 

	
 
    #     if self._source_junction == 'not set':
 
    #         from rattail.sil import get_available_junctions
 
    #         self._source_junction = None
 
    #         junctions = get_available_junctions()
 
    #         if self.source in junctions:
 
    #             self._source_junction = junctions[self.source]
 
    #     return self._source_junction
 

	
 
    # @property
 
    # def table(self):
 
    #     """
 
    #     Returns the ``sqlalchemy.Table`` instance for the underlying batch
 
    #     data.
 
    #     """
 

	
 
    #     # from sqlalchemy import MetaData, Table, Column, String
 
    #     from sqlalchemy import Table, Column, String
 
    #     from rattail import metadata
 
    #     from rattail.sqlalchemy import get_sil_column
 

	
 
    #     if self._table is None:
 
    #         # assert self.uuid
 
    #         assert self.name
 
    #         name = 'batch.%s.%s' % (self.source, self.batch_id)
 
    #         if name in metadata.tables:
 
    #             self._table = metadata.tables[name]
 
    #         else:
 
    #             # session = object_session(self)
 
    #             # metadata = MetaData(session.bind)
 
    #             columns = [Column('uuid', String(32), primary_key=True, default=get_uuid)]
 
    #             # columns.extend([get_sil_column(x) for x in self.elements.split(',')])
 
    #             columns.extend([get_sil_column(x) for x in self.elements.split(',')])
 
    #             self._table = Table(name, metadata, *columns)
 
    #     return self._table
 

	
 
    # @property
 
    # def rowclass(self):
 
    #     """
 
    #     Returns a unique subclass of :class:`rattail.BatchRow`, specific to the
 
    #     batch.
 
    #     """
 

	
 
    #     if self._rowclass is None:
 
    #         name = self.invalid_name_chars.sub('_', self.name)
 
    #         self._rowclass = type('BatchRow_%s' % str(name), (BatchRow,), {})
 
    #         mapper(self._rowclass, self.table)
 
    #         # session = object_session(self)
 
    #         # engine = session.bind
 
    #         # session.configure(binds={self._rowclass:engine})
 
    #     return self._rowclass
 

	
 
    @property
 
    def rowclass(self):
 
        """
 
        Returns the SQLAlchemy-mapped class for the underlying data table.
 
        """
 

	
 
        assert self.uuid
 
        if self.uuid not in self._row_classes:
 
            kwargs = {
 
                '__tablename__':        'batch.%s' % self.name,
 
                'uuid':                 uuid_column(),
 
                }
 
            for col in self.columns:
 
                kwargs[col.sil_column.sil_name] = Column(get_sil_type(col.sil_column.data_type))
 
            self._row_classes[self.uuid] = type('BatchRow', (Base,), kwargs)
 
        return self._row_classes[self.uuid]
 

	
 
    def create_table(self):
 
        """
 
        Creates the batch's data table within the database.
 
        """
 

	
 
        self.rowclass.__table__.create()
 

	
 
    # @property
 
    # def target_junction(self):
 
    #     """
 
    #     Returns the :class:`rattail.BatchJunction` instance associated with
 
    #     this batch's :attr:`Batch.target` attribute.
 
    #     """
 

	
 
    #     if self._target_junction == 'not set':
 
    #         from rattail.sil import get_available_junctions
 
    #         self._target_junction = None
 
    #         junctions = get_available_junctions()
 
    #         if self.target in junctions:
 
    #             self._target_junction = junctions[self.target]
 
    #     return self._target_junction
 

	
 
    # def append(self, **row):
 
    #     """
 
    #     Appends a row of data to the batch.  Note that this is done
 
    #     immediately, and not within the context of any transaction.
 
    #     """
 

	
 
    #     # self.connection.execute(self.table.insert().values(**row))
 
    #     # self.rowcount += 1
 
    #     session = object_session(self)
 
    #     session.add(self.rowclass(**row))
 
    #     self.rowcount += 1
 
    #     session.flush()
 

	
 
    def add_rows(self, source, dictionary, **kwargs):
 
        session = object_session(self)
 
        source = source.get_terminal()
 
        for row in source.provide_rows(session, self.rowclass,
 
                                       dictionary, **kwargs):
 
            session.add(row)
 
            session.flush()
 

	
 
    def execute(self):
 
        """
 
        Invokes the batch execution logic.  This will instantiate the
 
        :class:`rattail.batches.BatchTerminal` instance identified by the
 
        batch's :attr:`target` attribute and ask it to process the batch
 
        according to its action type.
 

	
 
        .. note::
 
           No check is performed to verify the current time is appropriate as
 
           far as the batch's effective date is concerned.  It is assumed that
 
           other logic has already taken care of that and that yes, in fact it
 
           *is* time for the batch to be executed.
 
        """
 

	
 
        target = self.target.get_terminal()
 
        target.execute_batch(self)
 

	
 
    def provide_rows(self):
 
        """
 
        Generator which yields :class:`BatchRow` instances belonging to the
 
        batch.
 
        """
 

	
 
        session = object_session(self)
 
        for row in session.query(self.rowclass):
 
            yield row
 
#     def __repr__(self):
 
#         return "<Batch: %s>" % (self.name or '(no name)')
 

	
 
#     def __str__(self):
 
#         return str(self.name or '')
 

	
 
#     # @property
 
#     # def source_junction(self):
 
#     #     """
 
#     #     Returns the :class:`rattail.BatchJunction` instance associated with
 
#     #     this batch's :attr:`Batch.source` attribute.
 
#     #     """
 

	
 
#     #     if self._source_junction == 'not set':
 
#     #         from rattail.sil import get_available_junctions
 
#     #         self._source_junction = None
 
#     #         junctions = get_available_junctions()
 
#     #         if self.source in junctions:
 
#     #             self._source_junction = junctions[self.source]
 
#     #     return self._source_junction
 

	
 
#     # @property
 
#     # def table(self):
 
#     #     """
 
#     #     Returns the ``sqlalchemy.Table`` instance for the underlying batch
 
#     #     data.
 
#     #     """
 

	
 
#     #     # from sqlalchemy import MetaData, Table, Column, String
 
#     #     from sqlalchemy import Table, Column, String
 
#     #     from rattail import metadata
 
#     #     from rattail.sqlalchemy import get_sil_column
 

	
 
#     #     if self._table is None:
 
#     #         # assert self.uuid
 
#     #         assert self.name
 
#     #         name = 'batch.%s.%s' % (self.source, self.batch_id)
 
#     #         if name in metadata.tables:
 
#     #             self._table = metadata.tables[name]
 
#     #         else:
 
#     #             # session = object_session(self)
 
#     #             # metadata = MetaData(session.bind)
 
#     #             columns = [Column('uuid', String(32), primary_key=True, default=get_uuid)]
 
#     #             # columns.extend([get_sil_column(x) for x in self.elements.split(',')])
 
#     #             columns.extend([get_sil_column(x) for x in self.elements.split(',')])
 
#     #             self._table = Table(name, metadata, *columns)
 
#     #     return self._table
 

	
 
#     # @property
 
#     # def rowclass(self):
 
#     #     """
 
#     #     Returns a unique subclass of :class:`rattail.BatchRow`, specific to the
 
#     #     batch.
 
#     #     """
 

	
 
#     #     if self._rowclass is None:
 
#     #         name = self.invalid_name_chars.sub('_', self.name)
 
#     #         self._rowclass = type('BatchRow_%s' % str(name), (BatchRow,), {})
 
#     #         mapper(self._rowclass, self.table)
 
#     #         # session = object_session(self)
 
#     #         # engine = session.bind
 
#     #         # session.configure(binds={self._rowclass:engine})
 
#     #     return self._rowclass
 

	
 
#     @property
 
#     def rowclass(self):
 
#         """
 
#         Returns the SQLAlchemy-mapped class for the underlying data table.
 
#         """
 

	
 
#         assert self.uuid
 
#         if self.uuid not in self._row_classes:
 
#             kwargs = {
 
#                 '__tablename__':        'batch.%s' % self.name,
 
#                 'uuid':                 uuid_column(),
 
#                 }
 
#             for col in self.columns:
 
#                 kwargs[col.sil_column.sil_name] = Column(get_sil_type(col.sil_column.data_type))
 
#             self._row_classes[self.uuid] = type('BatchRow', (Base,), kwargs)
 
#         return self._row_classes[self.uuid]
 

	
 
#     def create_table(self):
 
#         """
 
#         Creates the batch's data table within the database.
 
#         """
 

	
 
#         self.rowclass.__table__.create()
 

	
 
#     # @property
 
#     # def target_junction(self):
 
#     #     """
 
#     #     Returns the :class:`rattail.BatchJunction` instance associated with
 
#     #     this batch's :attr:`Batch.target` attribute.
 
#     #     """
 

	
 
#     #     if self._target_junction == 'not set':
 
#     #         from rattail.sil import get_available_junctions
 
#     #         self._target_junction = None
 
#     #         junctions = get_available_junctions()
 
#     #         if self.target in junctions:
 
#     #             self._target_junction = junctions[self.target]
 
#     #     return self._target_junction
 

	
 
#     # def append(self, **row):
 
#     #     """
 
#     #     Appends a row of data to the batch.  Note that this is done
 
#     #     immediately, and not within the context of any transaction.
 
#     #     """
 

	
 
#     #     # self.connection.execute(self.table.insert().values(**row))
 
#     #     # self.rowcount += 1
 
#     #     session = object_session(self)
 
#     #     session.add(self.rowclass(**row))
 
#     #     self.rowcount += 1
 
#     #     session.flush()
 

	
 
#     def add_rows(self, source, dictionary, **kwargs):
 
#         session = object_session(self)
 
#         source = source.get_terminal()
 
#         for row in source.provide_rows(session, self.rowclass,
 
#                                        dictionary, **kwargs):
 
#             session.add(row)
 
#             session.flush()
 

	
 
#     def execute(self):
 
#         """
 
#         Invokes the batch execution logic.  This will instantiate the
 
#         :class:`rattail.batches.BatchTerminal` instance identified by the
 
#         batch's :attr:`target` attribute and ask it to process the batch
 
#         according to its action type.
 

	
 
#         .. note::
 
#            No check is performed to verify the current time is appropriate as
 
#            far as the batch's effective date is concerned.  It is assumed that
 
#            other logic has already taken care of that and that yes, in fact it
 
#            *is* time for the batch to be executed.
 
#         """
 

	
 
#         target = self.target.get_terminal()
 
#         target.execute_batch(self)
 

	
 
#     def provide_rows(self):
 
#         """
 
#         Generator which yields :class:`BatchRow` instances belonging to the
 
#         batch.
 
#         """
 

	
 
#         session = object_session(self)
 
#         for row in session.query(self.rowclass):
 
#             yield row
 

	
 

	
 
# class BatchRow(edbob.Object):
 
#     """
 
#     Superclass of batch row objects.
 
#     """
 
@@ -577,13 +587,21 @@ class Category(Base):
 
        return str(self.name or '')
 

	
 
    def __unicode__(self):
 
        return unicode(self.name or '')
 

	
 

	
 
class VendorPhone(Phone):
 
class VendorEmailAddress(EmailAddress):
 
    """
 
    Represents an email address associated with a :class:`Vendor`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Vendor'}
 

	
 

	
 
class VendorPhoneNumber(PhoneNumber):
 
    """
 
    Represents a phone (or fax) number associated with a :class:`Vendor`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Vendor'}
 

	
 
@@ -628,36 +646,65 @@ class Vendor(Base):
 
    def __repr__(self):
 
        return "<Vendor: %s>" % self.name
 

	
 
    def __unicode__(self):
 
        return unicode(self.name or '')
 

	
 
    def add_contact(self, person):
 
        contact = VendorContact(person=person)
 
        self.contacts.append(contact)
 

	
 
    def add_email_address(self, address, type='Info'):
 
        email = VendorEmailAddress(address=address, type=type)
 
        self.emails.append(email)
 

	
 
    def add_phone_number(self, number, type='Voice'):
 
        phone = VendorPhoneNumber(number=number, type=type)
 
        self.phones.append(phone)
 

	
 
Vendor.emails = relationship(
 
    VendorEmailAddress,
 
    backref='vendor',
 
    primaryjoin=VendorEmailAddress.parent_uuid == Vendor.uuid,
 
    foreign_keys=[VendorEmailAddress.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=VendorEmailAddress.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Vendor.email = relationship(
 
    VendorEmailAddress,
 
    primaryjoin=and_(
 
        VendorEmailAddress.parent_uuid == Vendor.uuid,
 
        VendorEmailAddress.preference == 1),
 
    foreign_keys=[VendorEmailAddress.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 
Vendor.phones = relationship(
 
    VendorPhone,
 
    VendorPhoneNumber,
 
    backref='vendor',
 
    primaryjoin=VendorPhone.parent_uuid == Vendor.uuid,
 
    foreign_keys=[VendorPhone.parent_uuid],
 
    primaryjoin=VendorPhoneNumber.parent_uuid == Vendor.uuid,
 
    foreign_keys=[VendorPhoneNumber.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=VendorPhone.preference)
 
    order_by=VendorPhoneNumber.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Vendor.phone = relationship(
 
    VendorPhone,
 
    VendorPhoneNumber,
 
    primaryjoin=and_(
 
        VendorPhone.parent_uuid == Vendor.uuid,
 
        VendorPhone.preference == 1,
 
        ),
 
    foreign_keys=[VendorPhone.parent_uuid],
 
        VendorPhoneNumber.parent_uuid == Vendor.uuid,
 
        VendorPhoneNumber.preference == 1),
 
    foreign_keys=[VendorPhoneNumber.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 
Vendor.contact = relationship(
 
    VendorContact,
 
    primaryjoin=and_(
 
        VendorContact.vendor_uuid == Vendor.uuid,
 
        VendorContact.preference == 1,
 
        ),
 
        VendorContact.preference == 1),
 
    uselist=False,
 
    viewonly=True)
 

	
 

	
 
class ProductCost(Base):
 
    """
 
@@ -785,39 +832,240 @@ Product.current_price = relationship(
 
    ProductPrice,
 
    primaryjoin=Product.current_price_uuid == ProductPrice.uuid,
 
    lazy='joined',
 
    post_update=True)
 

	
 

	
 
class EmployeeEmailAddress(EmailAddress):
 
    """
 
    Represents an email address associated with a :class:`Employee`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Employee'}
 

	
 

	
 
class EmployeePhoneNumber(PhoneNumber):
 
    """
 
    Represents a phone (or fax) number associated with a :class:`Employee`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Employee'}
 

	
 

	
 
class Employee(Base):
 
    """
 
    Represents an employee within the organization.
 
    """
 

	
 
    __tablename__ = 'employees'
 

	
 
    uuid = uuid_column()
 
    id = Column(Integer)
 
    person_uuid = Column(String(32), ForeignKey('people.uuid'))
 
    person_uuid = Column(String(32), ForeignKey('people.uuid'), nullable=False)
 
    status = Column(Integer)
 
    display_name = Column(String(100))
 

	
 
    person = relationship(Person)
 

	
 
    first_name = association_proxy('person', 'first_name')
 
    last_name = association_proxy('person', 'last_name')
 
    display_name = association_proxy('person', 'display_name')
 

	
 
    def __repr__(self):
 
        return "<Employee: %s>" % self.person
 

	
 
    def __unicode__(self):
 
        return unicode(self.person)
 
        return unicode(self.display_name or self.person)
 

	
 
    def add_email_address(self, address, type='Home'):
 
        email = EmployeeEmailAddress(address=address, type=type)
 
        self.emails.append(email)
 

	
 
    def add_phone_number(self, number, type='Home'):
 
        phone = EmployeePhoneNumber(number=number, type=type)
 
        self.phones.append(phone)
 

	
 
Employee.emails = relationship(
 
    EmployeeEmailAddress,
 
    backref='employee',
 
    primaryjoin=EmployeeEmailAddress.parent_uuid == Employee.uuid,
 
    foreign_keys=[EmployeeEmailAddress.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=EmployeeEmailAddress.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Employee.email = relationship(
 
    EmployeeEmailAddress,
 
    primaryjoin=and_(
 
        EmployeeEmailAddress.parent_uuid == Employee.uuid,
 
        EmployeeEmailAddress.preference == 1),
 
    foreign_keys=[EmployeeEmailAddress.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 
Employee.phones = relationship(
 
    EmployeePhoneNumber,
 
    backref='employee',
 
    primaryjoin=EmployeePhoneNumber.parent_uuid == Employee.uuid,
 
    foreign_keys=[EmployeePhoneNumber.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=EmployeePhoneNumber.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Employee.phone = relationship(
 
    PersonPhone,
 
    EmployeePhoneNumber,
 
    primaryjoin=and_(
 
        PersonPhone.parent_uuid == Employee.person_uuid,
 
        PersonPhone.preference == 1,
 
        ),
 
    foreign_keys=[PersonPhone.parent_uuid],
 
        EmployeePhoneNumber.parent_uuid == Employee.uuid,
 
        EmployeePhoneNumber.preference == 1),
 
    foreign_keys=[EmployeePhoneNumber.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 

	
 
class CustomerEmailAddress(EmailAddress):
 
    """
 
    Represents an email address associated with a :class:`Customer`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Customer'}
 

	
 

	
 
class CustomerPhoneNumber(PhoneNumber):
 
    """
 
    Represents a phone (or fax) number associated with a :class:`Customer`.
 
    """
 

	
 
    __mapper_args__ = {'polymorphic_identity': 'Customer'}
 

	
 

	
 
class CustomerPerson(Base):
 
    """
 
    Represents the association between a :class:`Person` and a customer account
 
    (:class:`Customer`).
 
    """
 

	
 
    __tablename__ = 'customers_people'
 

	
 
    uuid = uuid_column()
 
    customer_uuid = Column(String(32), ForeignKey('customers.uuid'))
 
    person_uuid = Column(String(32), ForeignKey('people.uuid'))
 
    ordinal = Column(Integer, nullable=False)
 

	
 
    person = relationship(Person)
 

	
 

	
 
class Customer(Base):
 
    """
 
    Represents a customer account.  Customer accounts may consist of more than
 
    one :class:`Person`, in some cases.
 
    """
 

	
 
    __tablename__ = 'customers'
 

	
 
    uuid = uuid_column()
 
    id = Column(String(20))
 
    name = Column(String(255))
 

	
 
    def add_email_address(self, address, type='Home'):
 
        email = CustomerEmailAddress(address=address, type=type)
 
        self.emails.append(email)
 

	
 
    def add_phone_number(self, number, type='Home'):
 
        phone = CustomerPhoneNumber(number=number, type=type)
 
        self.phones.append(phone)
 

	
 
Customer.emails = relationship(
 
    CustomerEmailAddress,
 
    backref='customer',
 
    primaryjoin=CustomerEmailAddress.parent_uuid == Customer.uuid,
 
    foreign_keys=[CustomerEmailAddress.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=CustomerEmailAddress.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Customer.email = relationship(
 
    CustomerEmailAddress,
 
    primaryjoin=and_(
 
        CustomerEmailAddress.parent_uuid == Customer.uuid,
 
        CustomerEmailAddress.preference == 1),
 
    foreign_keys=[CustomerEmailAddress.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 
Customer.phones = relationship(
 
    CustomerPhoneNumber,
 
    backref='customer',
 
    primaryjoin=CustomerPhoneNumber.parent_uuid == Customer.uuid,
 
    foreign_keys=[CustomerPhoneNumber.parent_uuid],
 
    collection_class=ordering_list('preference', count_from=1),
 
    order_by=CustomerPhoneNumber.preference,
 
    cascade='save-update, merge, delete, delete-orphan')
 

	
 
Customer.phone = relationship(
 
    CustomerPhoneNumber,
 
    primaryjoin=and_(
 
        CustomerPhoneNumber.parent_uuid == Customer.uuid,
 
        CustomerPhoneNumber.preference == 1),
 
    foreign_keys=[CustomerPhoneNumber.parent_uuid],
 
    uselist=False,
 
    viewonly=True)
 

	
 
Customer._people = relationship(
 
    CustomerPerson, backref='customer',
 
    primaryjoin=CustomerPerson.customer_uuid == Customer.uuid,
 
    collection_class=ordering_list('ordinal', count_from=1),
 
    order_by=CustomerPerson.ordinal)
 

	
 
Customer.people = association_proxy(
 
    '_people', 'person',
 
    getset_factory=getset_factory,
 
    creator=lambda x: CustomerPerson(person=x))
 

	
 
Customer._person = relationship(
 
    CustomerPerson,
 
    primaryjoin=and_(
 
        CustomerPerson.customer_uuid == Customer.uuid,
 
        CustomerPerson.ordinal == 1),
 
    uselist=False,
 
    viewonly=True)
 

	
 
Customer.person = association_proxy(
 
    '_person', 'person',
 
    getset_factory=getset_factory)
 

	
 

	
 
class CustomerGroup(Base):
 
    """
 
    Represents an arbitrary group to which :class:`Customer` instances may (or
 
    may not) belong.
 
    """
 

	
 
    __tablename__ = 'customer_groups'
 

	
 
    uuid = uuid_column()
 
    id = Column(String(20))
 
    name = Column(String(255))
 

	
 

	
 
class CustomerGroupAssignment(Base):
 
    """
 
    Represents the assignment of a :class:`Customer` to a
 
    :class:`CustomerGroup`.
 
    """
 

	
 
    __tablename__ = 'customers_groups'
 

	
 
    uuid = uuid_column()
 
    customer_uuid = Column(String(32), ForeignKey('customers.uuid'))
 
    group_uuid = Column(String(32), ForeignKey('customer_groups.uuid'))
 
    ordinal = Column(Integer, nullable=False)
 

	
 
    group = relationship(CustomerGroup)
 

	
 
Customer._groups = relationship(
 
    CustomerGroupAssignment, backref='customer',
 
    collection_class=ordering_list('ordinal', count_from=1),
 
    order_by=CustomerGroupAssignment.ordinal)
 

	
 
Customer.groups = association_proxy(
 
    '_groups', 'group',
 
    getset_factory=getset_factory,
 
    creator=lambda x: CustomerGroupAssignment(group=x))
0 comments (0 inline, 0 general)