Changeset - 8e197f347fed
[Not reviewed]
0 4 1
Lance Edgar (lance) - 3 years ago 2021-10-06 17:22:09
lance@edbob.org
Add `PendingCustomer` model, for sake of new custorder workflow
5 files changed with 171 insertions and 5 deletions:
0 comments (0 inline, 0 general)
rattail/db/alembic/versions/5a256a77e6d0_add_pending_customer_table.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8; -*-
 
"""add pending_customer table
 

	
 
Revision ID: 5a256a77e6d0
 
Revises: 51f7773bb07a
 
Create Date: 2021-10-06 16:35:39.749555
 

	
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
# revision identifiers, used by Alembic.
 
revision = '5a256a77e6d0'
 
down_revision = u'51f7773bb07a'
 
branch_labels = None
 
depends_on = None
 

	
 
from alembic import op
 
import sqlalchemy as sa
 
import rattail.db.types
 

	
 

	
 

	
 
def upgrade():
 

	
 
    # pending_customer
 
    op.create_table('pending_customer',
 
                    sa.Column('uuid', sa.String(length=32), nullable=False),
 
                    sa.Column('user_uuid', sa.String(length=32), nullable=False),
 
                    sa.Column('created', sa.DateTime(), nullable=False),
 
                    sa.Column('id', sa.String(length=20), nullable=True),
 
                    sa.Column('first_name', sa.String(length=50), nullable=True),
 
                    sa.Column('middle_name', sa.String(length=50), nullable=True),
 
                    sa.Column('last_name', sa.String(length=50), nullable=True),
 
                    sa.Column('display_name', sa.String(length=100), nullable=True),
 
                    sa.Column('phone_number', sa.String(length=20), nullable=True),
 
                    sa.Column('phone_type', sa.String(length=15), nullable=True),
 
                    sa.Column('email_address', sa.String(length=255), nullable=True),
 
                    sa.Column('email_type', sa.String(length=15), nullable=True),
 
                    sa.Column('address_street', sa.String(length=100), nullable=True),
 
                    sa.Column('address_street2', sa.String(length=100), nullable=True),
 
                    sa.Column('address_city', sa.String(length=60), nullable=True),
 
                    sa.Column('address_state', sa.String(length=2), nullable=True),
 
                    sa.Column('address_zipcode', sa.String(length=10), nullable=True),
 
                    sa.Column('address_type', sa.String(length=15), nullable=True),
 
                    sa.Column('status_code', sa.Integer(), nullable=True),
 
                    sa.ForeignKeyConstraint(['user_uuid'], [u'user.uuid'], name=u'pending_customer_fk_user'),
 
                    sa.PrimaryKeyConstraint('uuid')
 
    )
 

	
 
    # batch_custorder
 
    op.add_column(u'batch_custorder', sa.Column('pending_customer_uuid', sa.String(length=32), nullable=True))
 
    op.create_foreign_key(u'batch_custorder_fk_pending_customer', 'batch_custorder', 'pending_customer', ['pending_customer_uuid'], ['uuid'])
 

	
 
    # custorder
 
    op.add_column(u'custorder', sa.Column('pending_customer_uuid', sa.String(length=32), nullable=True))
 
    op.create_foreign_key(u'custorder_fk_pending_customer', 'custorder', 'pending_customer', ['pending_customer_uuid'], ['uuid'])
 

	
 

	
 
def downgrade():
 

	
 
    # custorder
 
    op.drop_constraint(u'custorder_fk_pending_customer', 'custorder', type_='foreignkey')
 
    op.drop_column(u'custorder', 'pending_customer_uuid')
 

	
 
    # batch_custorder
 
    op.drop_constraint(u'batch_custorder_fk_pending_customer', 'batch_custorder', type_='foreignkey')
 
    op.drop_column(u'batch_custorder', 'pending_customer_uuid')
 

	
 
    # pending_customer
 
    op.drop_table('pending_customer')
rattail/db/model/__init__.py
Show inline comments
 
@@ -25,26 +25,33 @@ Rattail data models
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
from .core import Base, ModelBase, uuid_column, getset_factory, GPCType, Setting, Change, Note
 
from .contact import PhoneNumber, EmailAddress, MailingAddress
 

	
 
from .people import (Person, PersonNote,
 
                     PersonPhoneNumber, PersonEmailAddress, PersonMailingAddress,
 
                     MergePeopleRequest)
 
from .users import Role, Permission, User, UserRole, UserEvent
 
from .stores import Store, StorePhoneNumber, StoreEmailAddress
 
from .customers import (Customer, CustomerPhoneNumber, CustomerEmailAddress, CustomerMailingAddress,
 
                        CustomerGroup, CustomerGroupAssignment, CustomerPerson, CustomerNote)
 
from .customers import (Customer,
 
                        CustomerPhoneNumber,
 
                        CustomerEmailAddress,
 
                        CustomerMailingAddress,
 
                        CustomerGroup,
 
                        CustomerGroupAssignment,
 
                        CustomerPerson,
 
                        CustomerNote,
 
                        PendingCustomer)
 
from .members import Member, MemberPhoneNumber, MemberEmailAddress, MemberMailingAddress
 

	
 
from .org import Department, Subdepartment, Category, Family, ReportCode, DepositLink
 
from .employees import (Employee, EmployeePhoneNumber, EmployeeEmailAddress,
 
                        EmployeeStore, EmployeeDepartment, EmployeeHistory)
 
from .shifts import ScheduledShift, WorkedShift
 

	
 
from .vendors import Vendor, VendorPhoneNumber, VendorEmailAddress, VendorContact
 
from .products import (UnitOfMeasure, Brand, Tax, Product, ProductImage, ProductCode,
 
                       ProductCost, ProductFutureCost, ProductPrice,
 
                       ProductInventory, ProductStoreInfo, ProductVolatile,
 
                       InventoryAdjustmentReason)
rattail/db/model/customers.py
Show inline comments
 
@@ -17,32 +17,35 @@
 
#  details.
 
#
 
#  You should have received a copy of the GNU General Public License along with
 
#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
 
#
 
################################################################################
 
"""
 
Data Models for Customers
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
import datetime
 

	
 
import six
 
import sqlalchemy as sa
 
from sqlalchemy import orm
 
from sqlalchemy.ext.associationproxy import association_proxy
 
from sqlalchemy.ext.orderinglist import ordering_list
 

	
 
from rattail.db.model import Base, uuid_column, getset_factory
 
from rattail.db.model import PhoneNumber, EmailAddress, MailingAddress, Person, Note
 
from rattail.db.model import (Base, uuid_column, getset_factory,
 
                              PhoneNumber, EmailAddress, MailingAddress,
 
                              Person, Note, User)
 
from .contact import ContactMixin
 

	
 

	
 
class Customer(ContactMixin, Base):
 
    """
 
    Represents a customer account.
 

	
 
    Customer accounts may consist of more than one person, in some cases.
 
    """
 
    __tablename__ = 'customer'
 
    __versioned__ = {}
 

	
 
@@ -349,12 +352,75 @@ Customer._person = orm.relationship(
 
Customer.person = association_proxy(
 
    '_person', 'person',
 
    getset_factory=getset_factory)
 

	
 
Person._customers = orm.relationship(
 
    CustomerPerson,
 
    primaryjoin=CustomerPerson.person_uuid == Person.uuid,
 
    viewonly=True)
 

	
 
Person.customers = association_proxy('_customers', 'customer',
 
                                     getset_factory=getset_factory,
 
                                     creator=lambda c: CustomerPerson(customer=c))
 

	
 

	
 
class PendingCustomer(Base):
 
    """
 
    A "pending" customer record, used for new customer entry workflow.
 
    """
 
    __tablename__ = 'pending_customer'
 
    __table_args__ = (
 
        sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], name='pending_customer_fk_user'),
 
    )
 

	
 
    uuid = uuid_column()
 

	
 
    user_uuid = sa.Column(sa.String(length=32), nullable=False)
 
    user = orm.relationship(
 
        User,
 
        doc="""
 
        Referencef to the :class:`~rattail:rattail.db.model.User` who
 
        first entered the record.
 
        """)
 

	
 
    created = sa.Column(sa.DateTime(), nullable=False, default=datetime.datetime.utcnow, doc="""
 
    Timestamp when the record was first created.
 
    """)
 

	
 
    # Customer fields
 
    id = sa.Column(sa.String(length=20), nullable=True)
 

	
 
    # Person fields
 
    first_name = sa.Column(sa.String(length=50), nullable=True)
 
    middle_name = sa.Column(sa.String(length=50), nullable=True)
 
    last_name = sa.Column(sa.String(length=50), nullable=True)
 
    display_name = sa.Column(sa.String(length=100), nullable=True)
 

	
 
    # Phone fields
 
    phone_number = sa.Column(sa.String(length=20), nullable=True)
 
    phone_type = sa.Column(sa.String(length=15), nullable=True)
 

	
 
    # Email fields
 
    email_address = sa.Column(sa.String(length=255), nullable=True)
 
    email_type = sa.Column(sa.String(length=15), nullable=True)
 

	
 
    # Address fields
 
    address_street = sa.Column(sa.String(length=100), nullable=True)
 
    address_street2 = sa.Column(sa.String(length=100), nullable=True)
 
    address_city = sa.Column(sa.String(length=60), nullable=True)
 
    address_state = sa.Column(sa.String(length=2), nullable=True)
 
    address_zipcode = sa.Column(sa.String(length=10), nullable=True)
 
    address_type = sa.Column(sa.String(length=15), nullable=True)
 

	
 
    # workflow fields
 
    status_code = sa.Column(sa.Integer(), nullable=True, doc="""
 
    Status indicator for the new customer record.
 
    """)
 

	
 
    def __str__(self):
 
        if six.PY2:
 
            return (self.display_name or "").encode('utf_8')
 
        return self.display_name or ""
 

	
 
    if six.PY2:
 
        def __unicode__(self):
 
            return self.display_name or ""
rattail/db/model/custorders.py
Show inline comments
 
@@ -26,47 +26,49 @@ Data Models for Customer Orders
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
import datetime
 

	
 
import six
 
import sqlalchemy as sa
 
from sqlalchemy import orm
 
from sqlalchemy.ext.orderinglist import ordering_list
 
from sqlalchemy.ext.declarative import declared_attr
 

	
 
from rattail.db.model import Base, uuid_column
 
from rattail.db.model import Store, Customer, Person, Product, User, Note
 
from rattail.db.model import Store, Customer, PendingCustomer, Person, Product, User, Note
 
from rattail.db.types import GPCType
 

	
 

	
 
class CustomerOrderBase(object):
 
    """
 
    Base class for customer orders; defines common fields.
 
    """
 

	
 
    @declared_attr
 
    def __table_args__(cls):
 
        return cls.__customer_order_table_args__()
 

	
 
    @classmethod
 
    def __customer_order_table_args__(cls):
 
        table_name = cls.__tablename__
 
        return (
 
            sa.ForeignKeyConstraint(['store_uuid'], ['store.uuid'],
 
                                    name='{}_fk_store'.format(table_name)),
 
            sa.ForeignKeyConstraint(['customer_uuid'], ['customer.uuid'],
 
                                    name='{}_fk_customer'.format(table_name)),
 
            sa.ForeignKeyConstraint(['person_uuid'], ['person.uuid'],
 
                                    name='{}_fk_person'.format(table_name)),
 
            sa.ForeignKeyConstraint(['pending_customer_uuid'], ['pending_customer.uuid'],
 
                                    name='{}_fk_pending_customer'.format(table_name)),
 
        )
 

	
 
    store_uuid = sa.Column(sa.String(length=32), nullable=True)
 

	
 
    @declared_attr
 
    def store(cls):
 
        return orm.relationship(
 
            Store,
 
            doc="""
 
            Reference to the store to which the order applies.
 
            """)
 

	
 
@@ -81,24 +83,35 @@ class CustomerOrderBase(object):
 
            """)
 

	
 
    person_uuid = sa.Column(sa.String(length=32), nullable=True)
 

	
 
    @declared_attr
 
    def person(cls):
 
        return orm.relationship(
 
            Person,
 
            doc="""
 
            Reference to the person to whom the order applies.
 
            """)
 

	
 
    pending_customer_uuid = sa.Column(sa.String(length=32), nullable=True)
 

	
 
    @declared_attr
 
    def pending_customer(cls):
 
        return orm.relationship(
 
            PendingCustomer,
 
            doc="""
 
            Reference to the *pending* customer account for the order,
 
            if applicable.
 
            """)
 

	
 
    phone_number = sa.Column(sa.String(length=20), nullable=True, doc="""
 
    Customer contact phone number for sake of this order.
 
    """)
 

	
 
    email_address = sa.Column(sa.String(length=255), nullable=True, doc="""
 
    Customer contact email address for sake of this order.
 
    """)
 

	
 
    total_price = sa.Column(sa.Numeric(precision=10, scale=3), nullable=True, doc="""
 
    Full price (not including tax etc.) for all items on the order.
 
    """)
 

	
rattail/enum.py
Show inline comments
 
@@ -223,24 +223,33 @@ INVENTORY_MODE = {
 
}
 

	
 

	
 
MESSAGE_STATUS_INBOX            = 1
 
MESSAGE_STATUS_ARCHIVE          = 2
 

	
 
MESSAGE_STATUS = {
 
    MESSAGE_STATUS_INBOX        : "Inbox",
 
    MESSAGE_STATUS_ARCHIVE      : "Archive",
 
}
 

	
 

	
 
PENDING_CUSTOMER_STATUS_PENDING         = 1
 
PENDING_CUSTOMER_STATUS_READY           = 2
 

	
 
PENDING_CUSTOMER_STATUS = OrderedDict([
 
    (PENDING_CUSTOMER_STATUS_PENDING,           "pending"),
 
    (PENDING_CUSTOMER_STATUS_READY,             "ready"),
 
])
 

	
 

	
 
PHONE_TYPE_HOME                 = 'home'
 
PHONE_TYPE_MOBILE               = 'mobile'
 
PHONE_TYPE_OTHER                = 'other'
 

	
 
PHONE_TYPE = {
 
    PHONE_TYPE_HOME             : "Home",
 
    PHONE_TYPE_MOBILE           : "Mobile",
 
    PHONE_TYPE_OTHER            : "Other",
 
    }
 

	
 

	
 
PRICE_TYPE_REGULAR              = 0
0 comments (0 inline, 0 general)