Add data models for "customer order" batches
This commit is contained in:
parent
b44f45b8fd
commit
42d20a7c0b
40
rattail/batch/custorder.py
Normal file
40
rattail/batch/custorder.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2020 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Handler for "customer order" batches
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import, division
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.batch import BatchHandler
|
||||
|
||||
|
||||
class CustomerOrderBatchHandler(BatchHandler):
|
||||
"""
|
||||
Handler for all "customer order" batches, regardless of "mode". The
|
||||
handler must inspect the
|
||||
:attr:`~rattail.db.model.batch.custorder.CustomerOrderBatch.mode` attribute
|
||||
of each batch it deals with, in order to determine which logic to apply.
|
||||
"""
|
||||
batch_model_class = model.CustomerOrderBatch
|
116
rattail/db/alembic/versions/cb80a199df02_add_custorder_batch.py
Normal file
116
rattail/db/alembic/versions/cb80a199df02_add_custorder_batch.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
"""add custorder_batch
|
||||
|
||||
Revision ID: cb80a199df02
|
||||
Revises: aeea3c6fc6af
|
||||
Create Date: 2020-08-02 01:15:56.242415
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'cb80a199df02'
|
||||
down_revision = 'aeea3c6fc6af'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import rattail.db.types
|
||||
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
# custorder
|
||||
op.add_column('custorder', sa.Column('email_address', sa.String(length=255), nullable=True))
|
||||
op.add_column('custorder', sa.Column('phone_number', sa.String(length=20), nullable=True))
|
||||
op.add_column('custorder', sa.Column('created_by_uuid', sa.String(length=32), nullable=True))
|
||||
op.add_column('custorder', sa.Column('store_uuid', sa.String(length=32), nullable=True))
|
||||
op.create_foreign_key('custorder_fk_created_by', 'custorder', 'user', ['created_by_uuid'], ['uuid'])
|
||||
op.create_foreign_key('custorder_fk_store', 'custorder', 'store', ['store_uuid'], ['uuid'])
|
||||
|
||||
# custorder_batch
|
||||
op.create_table('custorder_batch',
|
||||
sa.Column('store_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('customer_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('person_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('created', sa.DateTime(), nullable=False),
|
||||
sa.Column('created_by_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('cognized', sa.DateTime(), nullable=True),
|
||||
sa.Column('cognized_by_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('rowcount', sa.Integer(), nullable=True),
|
||||
sa.Column('complete', sa.Boolean(), nullable=False),
|
||||
sa.Column('executed', sa.DateTime(), nullable=True),
|
||||
sa.Column('executed_by_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('purge', sa.Date(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('params', rattail.db.types.JSONTextDict(), nullable=True),
|
||||
sa.Column('extra_data', sa.Text(), nullable=True),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('order_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('mode', sa.Integer(), nullable=False),
|
||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
||||
sa.ForeignKeyConstraint(['cognized_by_uuid'], ['user.uuid'], name='custorder_batch_fk_cognized_by'),
|
||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name='custorder_batch_fk_created_by'),
|
||||
sa.ForeignKeyConstraint(['customer_uuid'], ['customer.uuid'], name='custorder_batch_fk_customer'),
|
||||
sa.ForeignKeyConstraint(['executed_by_uuid'], ['user.uuid'], name='custorder_batch_fk_executed_by'),
|
||||
sa.ForeignKeyConstraint(['order_uuid'], ['custorder.uuid'], name='custorder_batch_fk_order'),
|
||||
sa.ForeignKeyConstraint(['person_uuid'], ['person.uuid'], name='custorder_batch_fk_person'),
|
||||
sa.ForeignKeyConstraint(['store_uuid'], ['store.uuid'], name='custorder_batch_fk_store'),
|
||||
sa.PrimaryKeyConstraint('uuid')
|
||||
)
|
||||
|
||||
# custorder_batch_row
|
||||
op.create_table('custorder_batch_row',
|
||||
sa.Column('product_uuid', sa.String(length=32), nullable=True),
|
||||
sa.Column('product_brand', sa.String(length=100), nullable=True),
|
||||
sa.Column('product_description', sa.String(length=60), nullable=True),
|
||||
sa.Column('product_size', sa.String(length=30), nullable=True),
|
||||
sa.Column('product_unit_of_measure', sa.String(length=4), nullable=False),
|
||||
sa.Column('department_number', sa.Integer(), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('case_quantity', sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column('cases_ordered', sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column('units_ordered', sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column('product_unit_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
||||
sa.Column('unit_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('discount_percent', sa.Numeric(precision=5, scale=3), nullable=False),
|
||||
sa.Column('total_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('paid_amount', sa.Numeric(precision=8, scale=3), nullable=False),
|
||||
sa.Column('payment_transaction_number', sa.String(length=8), nullable=True),
|
||||
sa.Column('uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('batch_uuid', sa.String(length=32), nullable=False),
|
||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('modified', sa.DateTime(), nullable=True),
|
||||
sa.Column('removed', sa.Boolean(), nullable=False),
|
||||
sa.Column('item_entry', sa.String(length=32), nullable=True),
|
||||
sa.Column('item_uuid', sa.String(length=32), nullable=True),
|
||||
sa.ForeignKeyConstraint(['batch_uuid'], ['custorder_batch.uuid'], name='custorder_batch_row_fk_batch_uuid'),
|
||||
sa.ForeignKeyConstraint(['item_uuid'], ['custorder_item.uuid'], name='custorder_batch_row_fk_item'),
|
||||
sa.ForeignKeyConstraint(['product_uuid'], ['product.uuid'], name='custorder_batch_row_fk_product'),
|
||||
sa.PrimaryKeyConstraint('uuid')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
|
||||
# custorder_batch*
|
||||
op.drop_table('custorder_batch_row')
|
||||
op.drop_table('custorder_batch')
|
||||
|
||||
# custorder
|
||||
op.drop_constraint('custorder_fk_store', 'custorder', type_='foreignkey')
|
||||
op.drop_constraint('custorder_fk_created_by', 'custorder', type_='foreignkey')
|
||||
op.drop_column('custorder', 'store_uuid')
|
||||
op.drop_column('custorder', 'created_by_uuid')
|
||||
# op.drop_column('custorder', 'phone_number')
|
||||
# op.drop_column('custorder', 'email_address')
|
|
@ -71,5 +71,6 @@ from .batch.newproduct import NewProductBatch, NewProductBatchRow
|
|||
from .batch.pricing import PricingBatch, PricingBatchRow
|
||||
from .batch.product import ProductBatch, ProductBatchRow
|
||||
from .batch.purchase import PurchaseBatch, PurchaseBatchRow, PurchaseBatchRowClaim, PurchaseBatchCredit
|
||||
from .batch.custorder import CustomerOrderBatch, CustomerOrderBatchRow
|
||||
from .batch.vendorcatalog import VendorCatalog, VendorCatalogRow
|
||||
from .batch.vendorinvoice import VendorInvoice, VendorInvoiceRow
|
||||
|
|
115
rattail/db/model/batch/custorder.py
Normal file
115
rattail/db/model/batch/custorder.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2020 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Models for customer order batches
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
from rattail.db.model import (Base, BatchMixin, BatchRowMixin,
|
||||
CustomerOrderBase, CustomerOrderItemBase,
|
||||
CustomerOrder, CustomerOrderItem)
|
||||
|
||||
|
||||
class CustomerOrderBatch(BatchMixin, CustomerOrderBase, Base):
|
||||
"""
|
||||
Hopefully generic batch used for entering new customer orders into the
|
||||
system, as well as fulfilling them along the way, etc.
|
||||
"""
|
||||
batch_key = 'custorder'
|
||||
__tablename__ = 'custorder_batch'
|
||||
__batchrow_class__ = 'CustomerOrderBatchRow'
|
||||
model_title_plural = "Customer Order Batches"
|
||||
|
||||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__batch_table_args__() + cls.__customer_order_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['order_uuid'], ['custorder.uuid'],
|
||||
name='custorder_batch_fk_order'),
|
||||
)
|
||||
|
||||
STATUS_OK = 1
|
||||
|
||||
STATUS = {
|
||||
STATUS_OK : "ok",
|
||||
}
|
||||
|
||||
order_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
order = orm.relationship(
|
||||
CustomerOrder,
|
||||
doc="""
|
||||
Reference to the customer order with which the batch is associated.
|
||||
May be null, e.g. in the case of a "new order" batch.
|
||||
""",
|
||||
backref=orm.backref(
|
||||
'batches',
|
||||
order_by='CustomerOrderBatch.id',
|
||||
doc="""
|
||||
List of batches associated with the customer order.
|
||||
"""))
|
||||
|
||||
mode = sa.Column(sa.Integer(), nullable=False, doc="""
|
||||
Numeric "mode" for the customer order batch, to indicate new/fulfilling etc.
|
||||
""")
|
||||
|
||||
|
||||
class CustomerOrderBatchRow(BatchRowMixin, CustomerOrderItemBase, Base):
|
||||
"""
|
||||
Row of data within a customer order batch.
|
||||
"""
|
||||
__tablename__ = 'custorder_batch_row'
|
||||
__batch_class__ = CustomerOrderBatch
|
||||
|
||||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__batchrow_table_args__() + cls.__customer_order_item_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['item_uuid'], ['custorder_item.uuid'],
|
||||
name='custorder_batch_row_fk_item'),
|
||||
)
|
||||
|
||||
STATUS_OK = 1
|
||||
STATUS_PRODUCT_NOT_FOUND = 2
|
||||
|
||||
STATUS = {
|
||||
STATUS_OK : "ok",
|
||||
STATUS_PRODUCT_NOT_FOUND : "product not found",
|
||||
}
|
||||
|
||||
item_entry = sa.Column(sa.String(length=32), nullable=True, doc="""
|
||||
Raw entry value, as obtained from the initial data source, and which is
|
||||
used to locate the product within the system. This raw value is preserved
|
||||
in case the initial lookup fails and a refresh must attempt further
|
||||
lookup(s) later. Only used by certain batch handlers in practice.
|
||||
""")
|
||||
|
||||
item_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
item = orm.relationship(
|
||||
CustomerOrderItem,
|
||||
doc="""
|
||||
Reference to the customer order line item with which the batch row is
|
||||
associated. May be null, e.g. in the case of a "new order" batch.
|
||||
""")
|
|
@ -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 Customer, Person, Product, User
|
||||
from rattail.db.model import Store, Customer, Person, Product, User
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
|
@ -52,12 +52,24 @@ class CustomerOrderBase(object):
|
|||
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)),
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
|
||||
customer_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
|
@ -78,8 +90,12 @@ class CustomerOrderBase(object):
|
|||
Reference to the person to whom the order applies.
|
||||
""")
|
||||
|
||||
created = sa.Column(sa.DateTime(), nullable=False, default=datetime.datetime.utcnow, doc="""
|
||||
Date and time when the order/batch was first created.
|
||||
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.
|
||||
""")
|
||||
|
||||
|
||||
|
@ -90,12 +106,30 @@ class CustomerOrder(CustomerOrderBase, Base):
|
|||
"""
|
||||
__tablename__ = 'custorder'
|
||||
|
||||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__customer_order_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'],
|
||||
name='custorder_fk_created_by'),
|
||||
)
|
||||
|
||||
uuid = uuid_column()
|
||||
|
||||
id = sa.Column(sa.Integer(), doc="""
|
||||
Numeric, auto-increment ID for the order.
|
||||
""")
|
||||
|
||||
created = sa.Column(sa.DateTime(), nullable=False, default=datetime.datetime.utcnow, doc="""
|
||||
Date and time when the order/batch was first created.
|
||||
""")
|
||||
|
||||
created_by_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
created_by = orm.relationship(
|
||||
User,
|
||||
doc="""
|
||||
Reference to the user who initially created the order/batch.
|
||||
""")
|
||||
|
||||
status_code = sa.Column(sa.Integer(), nullable=False)
|
||||
|
||||
items = orm.relationship('CustomerOrderItem', back_populates='order',
|
||||
|
@ -127,12 +161,6 @@ class CustomerOrderItemBase(object):
|
|||
name='{}_fk_product'.format(table_name)),
|
||||
)
|
||||
|
||||
sequence = sa.Column(sa.Integer(), nullable=False, doc="""
|
||||
Numeric sequence for the item, i.e. its "line number". These values should
|
||||
obviously increment in sequence and be unique within the context of a
|
||||
single order.
|
||||
""")
|
||||
|
||||
product_uuid = sa.Column(sa.String(length=32), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
|
@ -238,6 +266,12 @@ class CustomerOrderItem(CustomerOrderItemBase, Base):
|
|||
Reference to the :class:`CustomerOrder` instance to which the item belongs.
|
||||
""")
|
||||
|
||||
sequence = sa.Column(sa.Integer(), nullable=False, doc="""
|
||||
Numeric sequence for the item, i.e. its "line number". These values should
|
||||
obviously increment in sequence and be unique within the context of a
|
||||
single order.
|
||||
""")
|
||||
|
||||
status_code = sa.Column(sa.Integer(), nullable=False)
|
||||
|
||||
|
||||
|
|
|
@ -72,6 +72,15 @@ BATCH_ACTION = {
|
|||
}
|
||||
|
||||
|
||||
CUSTORDER_BATCH_MODE_CREATING = 10
|
||||
CUSTORDER_BATCH_MODE_GATHERING = 20
|
||||
|
||||
CUSTORDER_BATCH_MODE = {
|
||||
CUSTORDER_BATCH_MODE_CREATING : "creating",
|
||||
CUSTORDER_BATCH_MODE_GATHERING : "gathering",
|
||||
}
|
||||
|
||||
|
||||
EMAIL_ATTEMPT_CREATED = 0
|
||||
EMAIL_ATTEMPT_SUCCESS = 1
|
||||
EMAIL_ATTEMPT_FAILURE = 2
|
||||
|
|
Loading…
Reference in a new issue