From 8e197f347fed4453ff575521c3791379d053e6e2 2021-10-06 17:22:09 From: Lance Edgar Date: 2021-10-06 17:22:09 Subject: [PATCH] Add `PendingCustomer` model, for sake of new custorder workflow --- diff --git a/rattail/db/alembic/versions/5a256a77e6d0_add_pending_customer_table.py b/rattail/db/alembic/versions/5a256a77e6d0_add_pending_customer_table.py new file mode 100644 index 0000000000000000000000000000000000000000..49d0685aadb93b716c29463777cd33537b1cf36f --- /dev/null +++ b/rattail/db/alembic/versions/5a256a77e6d0_add_pending_customer_table.py @@ -0,0 +1,71 @@ +# -*- 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') diff --git a/rattail/db/model/__init__.py b/rattail/db/model/__init__.py index f4f95b0d35d2f91f45ecbd860d0b4d3fbcf4726c..1c114ddd4d693483c558cd3e6b3604003caa26f3 100644 --- a/rattail/db/model/__init__.py +++ b/rattail/db/model/__init__.py @@ -34,8 +34,15 @@ from .people import (Person, PersonNote, 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 diff --git a/rattail/db/model/customers.py b/rattail/db/model/customers.py index 2d9e7e1cf5cff4fe5aae031bdad73d0175dcae78..7793c1fbbb9d8f76836ce363ee4387555ae0bd33 100644 --- a/rattail/db/model/customers.py +++ b/rattail/db/model/customers.py @@ -26,14 +26,17 @@ 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 @@ -358,3 +361,66 @@ Person._customers = orm.relationship( 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 "" diff --git a/rattail/db/model/custorders.py b/rattail/db/model/custorders.py index 855fd0a725f0e970ffa109ab66b132c386be54d6..be137cbffbab3d2fbf92a2ed724363e3b1689397 100644 --- a/rattail/db/model/custorders.py +++ b/rattail/db/model/custorders.py @@ -35,7 +35,7 @@ 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 @@ -58,6 +58,8 @@ class CustomerOrderBase(object): 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) @@ -90,6 +92,17 @@ class CustomerOrderBase(object): 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. """) diff --git a/rattail/enum.py b/rattail/enum.py index a2a36e6717fab255bce549d90742fc1e9be547e6..d6b106479948f01d41421b671c969462380a83c2 100644 --- a/rattail/enum.py +++ b/rattail/enum.py @@ -232,6 +232,15 @@ MESSAGE_STATUS = { } +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'