Changeset - 37b8de91180d
[Not reviewed]
0 4 1
Lance Edgar (lance) - 3 years ago 2021-10-18 18:28:07
lance@edbob.org
Add basic "price needs confirmation" support for custorder
5 files changed with 117 insertions and 9 deletions:
0 comments (0 inline, 0 general)
rattail/batch/custorder.py
Show inline comments
 
@@ -363,96 +363,98 @@ class CustomerOrderBatchHandler(BatchHandler):
 
            email = batch.customer.first_email()
 
            if email:
 
                info['email_address'] = email.address
 

	
 
        if batch.person:
 
            info['person_uuid'] = batch.person.uuid
 
            if not info['phone_number']:
 
                phone = batch.person.first_phone()
 
                if phone:
 
                    info['phone_number'] = phone.number
 
                email = batch.person.first_email()
 
                if email:
 
                    info['email_address'] = email.address
 

	
 
        return info
 

	
 
    def custom_product_autocomplete(self, session, term, **kwargs):
 
        """
 
        For the given term, this should return a (possibly empty) list
 
        of products which "match" the term.  Each element in the list
 
        should be a dict with "label" and "value" keys.
 
        """
 
        raise NotImplementedError("Please define the "
 
                                  "{}.custom_product_autocomplete() "
 
                                  "method.".format(__class__.__name__))
 

	
 
    def why_not_add_product(self, product, batch):
 
        """
 
        This method can inspect the given product, and batch, to
 
        determine if the product may be added to the batch as a new
 
        row.  Useful to e.g. prevent one customer from ordering too
 
        many things, etc.
 

	
 
        :returns: If there is a reason not to add the product, should
 
           return that reason as a string; otherwise ``None``.
 
        """
 

	
 
    def add_product(self, batch, product, order_quantity, order_uom,
 
                    **kwargs):
 
        """
 
        Add a new row to the batch, for the given product and order
 
        quantity.
 
        """
 
        row = self.make_row()
 
        row.item_entry = product.uuid
 
        row.product = product
 
        row.order_quantity = order_quantity
 
        row.order_uom = order_uom
 
        if 'price_needs_confirmation' in kwargs:
 
            row.price_needs_confirmation = kwargs['price_needs_confirmation']
 
        self.add_row(batch, row)
 
        return row
 

	
 
    def refresh_row(self, row):
 
        if not row.product:
 
            if row.item_entry:
 
                session = orm.object_session(row)
 
                # TODO: should do more than just query for uuid here
 
                product = session.query(model.Product).get(row.item_entry)
 
                if product:
 
                    row.product = product
 
            if not row.product:
 
                row.status_code = row.STATUS_PRODUCT_NOT_FOUND
 
                return
 

	
 
        product = row.product
 
        row.product_upc = product.upc
 
        row.product_brand = six.text_type(product.brand or "")
 
        row.product_description = product.description
 
        row.product_size = product.size
 
        row.product_weighed = product.weighed
 
        row.case_quantity = self.get_case_size_for_product(product)
 

	
 
        department = product.department
 
        row.department_number = department.number if department else None
 
        row.department_name = department.name if department else None
 

	
 
        cost = product.cost
 
        row.product_unit_cost = cost.unit_cost if cost else None
 

	
 
        regprice = product.regular_price
 
        row.unit_price = regprice.price if regprice else None
 

	
 
        # we need to know if total price is updated
 
        old_total = row.total_price
 

	
 
        # maybe update total price
 
        if row.unit_price is None:
 
            row.total_price = None
 
        elif not row.unit_price:
 
            row.total_price = 0
 
        else:
 
            row.total_price = row.unit_price * row.order_quantity
 
            if row.order_uom == self.enum.UNIT_OF_MEASURE_CASE:
 
                row.total_price *= (row.case_quantity or 1)
 

	
 
        # update total price for batch too, if it changed
 
        if row.total_price != old_total:
 
@@ -518,73 +520,105 @@ class CustomerOrderBatchHandler(BatchHandler):
 
        update request.
 
        """
 
        self.app.send_email('new_email_requested', {
 
            'user': user,
 
            'user_display': user.display_name if user else "(unknown user)",
 
            'contact': self.get_contact(batch),
 
            'contact_id': self.get_contact_id(batch),
 
            'email_address': batch.email_address,
 
        })
 

	
 
    def make_new_order(self, batch, user=None, progress=None, **kwargs):
 
        """
 
        Create and return a new rattail Customer Order based on the
 
        batch contents.
 
        """
 
        batch_fields = [
 
            'store',
 
            'id',
 
            'customer',
 
            'person',
 
            'pending_customer',
 
            'phone_number',
 
            'email_address',
 
            'total_price',
 
        ]
 

	
 
        order = model.CustomerOrder()
 
        order.created_by = user
 
        order.status_code = self.enum.CUSTORDER_STATUS_ORDERED
 
        for field in batch_fields:
 
            setattr(order, field, getattr(batch, field))
 

	
 
        row_fields = [
 
            'product',
 
            'product_upc',
 
            'product_brand',
 
            'product_description',
 
            'product_size',
 
            'product_weighed',
 
            'department_number',
 
            'department_name',
 
            'case_quantity',
 
            'order_quantity',
 
            'order_uom',
 
            'product_unit_cost',
 
            'unit_price',
 
            'discount_percent',
 
            'total_price',
 
            'price_needs_confirmation',
 
            'paid_amount',
 
            'payment_transaction_number',
 
        ]
 

	
 
        def convert(row, i):
 

	
 
            # add new order item
 
            item = model.CustomerOrderItem()
 
            item.sequence = i
 
            item.status_code = self.enum.CUSTORDER_ITEM_STATUS_INITIATED
 
            for field in row_fields:
 
                setattr(item, field, getattr(row, field))
 
            order.items.append(item)
 

	
 
            # attach event
 
            item.events.append(model.CustomerOrderItemEvent(
 
                type_code=self.enum.CUSTORDER_ITEM_EVENT_INITIATED,
 
                user=user))
 
            # set initial status and attach events
 
            self.set_initial_item_status(item, user)
 

	
 
        self.progress_loop(convert, batch.active_rows(), progress,
 
                           message="Converting batch rows to order items")
 

	
 
        session = orm.object_session(batch)
 
        session.add(order)
 
        session.flush()
 

	
 
        return order
 

	
 
    def set_initial_item_status(self, item, user, **kwargs):
 
        """
 
        Set the initial status for the given order item, and attach
 
        any events.
 

	
 
        The first logical status is ``CUSTORDER_ITEM_STATUS_INITIATED``
 
        and an item may stay there if there is some other step(s)
 
        which must occur before the item is ready to proceed.  For
 
        instance the default logic will leave it there if the price
 
        needs to be confirmed, but you can override as needed, for
 
        instance if you require payment up-front.
 

	
 
        The second status is ``CUSTORDER_ITEM_STATUS_READY`` which
 
        indicates the item is ready to proceed.  The default logic
 
        will auto-advance the item to this status if the price does
 
        *not* need to be confirmed.  Again you may need to override
 
        e.g. to prevent this until up-front payment is received.
 
        """
 
        # set "initiated" status
 
        item.status_code = self.enum.CUSTORDER_ITEM_STATUS_INITIATED
 
        item.add_event(self.enum.CUSTORDER_ITEM_EVENT_INITIATED, user)
 

	
 
        # but if the price is good...
 
        if not item.price_needs_confirmation:
 

	
 
            # then we set "ready" status
 
            item.status_code = self.enum.CUSTORDER_ITEM_STATUS_READY
 
            item.status_text = "everything looks normal"
 

	
 
            item.add_event(self.enum.CUSTORDER_ITEM_EVENT_READY, user,
 
                           note=item.status_text)
rattail/db/alembic/versions/8856f697902d_add_custorder_item_status_text.py
Show inline comments
 
new file 100644
 
# -*- coding: utf-8 -*-
 
"""add custorder_item.status_text
 

	
 
Revision ID: 8856f697902d
 
Revises: 8b78ef45a36c
 
Create Date: 2021-10-18 11:51:34.326750
 

	
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
# revision identifiers, used by Alembic.
 
revision = '8856f697902d'
 
down_revision = '8b78ef45a36c'
 
branch_labels = None
 
depends_on = None
 

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

	
 

	
 

	
 
def upgrade():
 

	
 
    # custorder_item
 
    op.add_column('custorder_item', sa.Column('price_needs_confirmation', sa.Boolean(), nullable=True))
 
    op.add_column('custorder_item', sa.Column('status_text', sa.String(length=255), nullable=True))
 

	
 
    # batch_custorder_row
 
    op.add_column('batch_custorder_row', sa.Column('price_needs_confirmation', sa.Boolean(), nullable=True))
 

	
 

	
 
def downgrade():
 

	
 
    # batch_custorder_row
 
    op.drop_column('batch_custorder_row', 'price_needs_confirmation')
 

	
 
    # custorder_item
 
    op.drop_column('custorder_item', 'status_text')
 
    op.drop_column('custorder_item', 'price_needs_confirmation')
rattail/db/model/batch/custorder.py
Show inline comments
 
@@ -48,68 +48,70 @@ class CustomerOrderBatch(BatchMixin, CustomerOrderBase, Base):
 
    @declared_attr
 
    def __table_args__(cls):
 
        return cls.__batch_table_args__() + cls.__customer_order_table_args__() + (
 
            sa.ForeignKeyConstraint(['order_uuid'], ['custorder.uuid'],
 
                                    name='batch_custorder_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__ = 'batch_custorder_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='batch_custorder_row_fk_item'),
 
        )
 

	
 
    STATUS_OK                           = 1
 
    STATUS_PRODUCT_NOT_FOUND            = 2
 
    # STATUS_PRICE_NEEDS_CONFIRMATION     = 3
 

	
 
    STATUS = {
 
        STATUS_OK                       : "ok",
 
        STATUS_PRODUCT_NOT_FOUND        : "product not found",
 
        # STATUS_PRICE_NEEDS_CONFIRMATION : "price needs to be confirmed",
 
    }
 

	
 
    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.
 
        """)
rattail/db/model/custorders.py
Show inline comments
 
@@ -237,136 +237,159 @@ class CustomerOrderItemBase(object):
 

	
 
    case_quantity = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
 
    Case pack count for the product being ordered.  This should be a cache of
 
    :attr:`Product.case_size`.
 
    """)
 

	
 
    # TODO: i now think that cases_ordered and units_ordered should go away.
 
    # but will wait until that idea has proven itself before removing.  am
 
    # pretty sure they are obviated by order_quantity and order_uom.
 

	
 
    cases_ordered = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
 
    Number of cases of product which were initially ordered.
 
    """)
 

	
 
    units_ordered = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
 
    Number of units of product which were initially ordered.
 
    """)
 

	
 
    order_quantity = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
 
    Quantity being ordered by the customer.
 
    """)
 

	
 
    order_uom = sa.Column(sa.String(length=4), nullable=True, doc="""
 
    Code indicating the unit of measure for the order itself.  Does not
 
    directly reflect the :attr:`~rattail.db.model.Product.unit_of_measure`.
 
    """)
 

	
 
    product_unit_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
 
    Unit cost of the product being ordered.  This should be a cache of the
 
    relevant :attr:`rattail.db.model.ProductCost.unit_cost`.
 
    """)
 

	
 
    unit_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
 
    Unit price for the product being ordered.  This is the price which is
 
    quoted to the customer and/or charged to the customer, but for a unit only
 
    and *before* any discounts are applied.  It generally will be a cache of
 
    the relevant :attr:`ProductPrice.price`.
 
    """)
 

	
 
    discount_percent = sa.Column(sa.Numeric(precision=5, scale=3), nullable=False, default=0, doc="""
 
    Discount percentage which will be applied to the product's price as part of
 
    calculating the :attr:`total_price` for the item.
 
    """)
 

	
 
    total_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
 
    Full price (not including tax etc.) which the customer is asked to pay for the item.
 
    """)
 

	
 
    price_needs_confirmation = sa.Column(sa.Boolean(), nullable=True, doc="""
 
    Flag indicating that the price for this item should be confirmed
 
    by someone, before the order advances to the procurement phase.
 

	
 
    Items/rows with this flag set will probably indicate that also via
 
    their status.
 

	
 
    When the price is eventually confirmed by someone, this flag
 
    should be cleared and probably the status will update as well.
 
    """)
 

	
 
    paid_amount = sa.Column(sa.Numeric(precision=8, scale=3), nullable=False, default=0, doc="""
 
    Amount which the customer has paid toward the :attr:`total_price` of theitem.
 
    """)
 

	
 
    payment_transaction_number = sa.Column(sa.String(length=8), nullable=True, doc="""
 
    Transaction number in which payment for the order was taken, if applicable.
 
    """)
 

	
 
    def __str__(self):
 
        return str(self.product or "(no product)")
 

	
 

	
 
class CustomerOrderItem(CustomerOrderItemBase, Base):
 
    """
 
    Represents a particular line item (product) within a customer order.
 
    """
 
    __tablename__ = 'custorder_item'
 

	
 
    @declared_attr
 
    def __table_args__(cls):
 
        return cls.__customer_order_item_table_args__() + (
 
            sa.ForeignKeyConstraint(['order_uuid'], ['custorder.uuid'],
 
                                    name='custorder_item_fk_order'),
 
        )
 

	
 
    uuid = uuid_column()
 

	
 
    order_uuid = sa.Column(sa.String(length=32), nullable=False)
 
    order = orm.relationship(CustomerOrder, back_populates='items', doc="""
 
    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)
 

	
 
    status_text = sa.Column(sa.String(length=255), nullable=True, doc="""
 
    Text which may briefly explain the batch status code, if needed.
 
    """)
 

	
 
    def add_event(self, type_code, user, **kwargs):
 
        """
 
        Convenience method to add an event for the order item.
 
        """
 
        self.events.append(CustomerOrderItemEvent(type_code=type_code,
 
                                                  user=user,
 
                                                  **kwargs))
 

	
 

	
 
class CustomerOrderItemEvent(Base):
 
    """
 
    An event in the life of a customer order item
 
    """
 
    __tablename__ = 'custorder_item_event'
 
    __table_args__ = (
 
        sa.ForeignKeyConstraint(['item_uuid'], ['custorder_item.uuid'], name='custorder_item_event_fk_item'),
 
        sa.ForeignKeyConstraint(['user_uuid'], ['user.uuid'], name='custorder_item_event_fk_user'),
 
    )
 

	
 
    uuid = uuid_column()
 

	
 
    item_uuid = sa.Column(sa.String(length=32), nullable=False)
 

	
 
    item = orm.relationship(
 
        CustomerOrderItem,
 
        doc="""
 
        Reference to the :class:`CustomerOrder` instance to which the item belongs.
 
        """,
 
        backref=orm.backref(
 
            'events',
 
            order_by='CustomerOrderItemEvent.occurred'))
 

	
 
    type_code = sa.Column(sa.Integer, nullable=False)
 

	
 
    occurred = sa.Column(sa.DateTime(), nullable=False, default=datetime.datetime.utcnow, doc="""
 
    Date and time when the event occurred.
 
    """)
 

	
 
    user_uuid = sa.Column(sa.String(length=32), nullable=False)
 

	
 
    user = orm.relationship(
 
        User,
 
        doc="""
 
        User who was the "actor" for the event.
 
        """)
 

	
 
    note = sa.Column(sa.Text(), nullable=True, doc="""
 
    Optional note recorded for the event.
 
    """)
 

	
 

	
 
class CustomerOrderItemNote(Note):
 
    """
 
    Represents a note attached to an order item.
 
    """
 
    __mapper_args__ = {'polymorphic_identity': 'CustomerOrderItem'}
rattail/enum.py
Show inline comments
 
@@ -50,145 +50,153 @@ The following enumerations are provided:
 

	
 
.. attribute:: UNIT_OF_MEASURE
 

	
 
   Units of measure for use with products (e.g. each, pound).  These are taken
 
   from the SIL specification.
 
"""
 

	
 
from __future__ import unicode_literals, absolute_import
 

	
 
from rattail.util import OrderedDict
 

	
 

	
 
BATCH_ACTION_ADD                = 'ADD'
 
BATCH_ACTION_ADD_REPLACE        = 'ADDRPL'
 
BATCH_ACTION_CHANGE             = 'CHANGE'
 
BATCH_ACTION_LOAD               = 'LOAD'
 
BATCH_ACTION_REMOVE             = 'REMOVE'
 

	
 
BATCH_ACTION = {
 
    BATCH_ACTION_ADD            : "Add",
 
    BATCH_ACTION_ADD_REPLACE    : "Add/Replace",
 
    BATCH_ACTION_CHANGE         : "Change",
 
    BATCH_ACTION_LOAD           : "Load",
 
    BATCH_ACTION_REMOVE         : "Remove",
 
    }
 

	
 

	
 
CUSTORDER_BATCH_MODE_CREATING            = 10
 
CUSTORDER_BATCH_MODE_GATHERING           = 20
 

	
 
CUSTORDER_BATCH_MODE = {
 
    CUSTORDER_BATCH_MODE_CREATING        : "creating",
 
    CUSTORDER_BATCH_MODE_GATHERING       : "gathering",
 
}
 

	
 

	
 
CUSTORDER_STATUS_ORDERED                = 10
 
# CUSTORDER_STATUS_PAID                   = 20
 

	
 
CUSTORDER_STATUS = {
 
    CUSTORDER_STATUS_ORDERED            : "ordered",
 
    # CUSTORDER_STATUS_PAID               : "paid",
 
}
 

	
 

	
 
CUSTORDER_ITEM_STATUS_INITIATED         = 10
 
# TODO: deprecate / remove this one
 
CUSTORDER_ITEM_STATUS_ORDERED           = CUSTORDER_ITEM_STATUS_INITIATED
 
CUSTORDER_ITEM_STATUS_PAID              = 20
 
CUSTORDER_ITEM_STATUS_READY             = 20
 
# TODO: deprecate / remove this one
 
CUSTORDER_ITEM_STATUS_PAID              = CUSTORDER_ITEM_STATUS_READY
 
CUSTORDER_ITEM_STATUS_PLACED            = 30
 
CUSTORDER_ITEM_STATUS_RECEIVED          = 40
 
CUSTORDER_ITEM_STATUS_CONTACTED         = 50
 
CUSTORDER_ITEM_STATUS_CONTACT_FAILED    = 60
 
CUSTORDER_ITEM_STATUS_DELIVERED         = 70
 
CUSTORDER_ITEM_STATUS_CANCELED          = 900
 
CUSTORDER_ITEM_STATUS_REFUND_PENDING    = 910
 
CUSTORDER_ITEM_STATUS_REFUNDED          = 920
 
CUSTORDER_ITEM_STATUS_RESTOCKED         = 930
 
CUSTORDER_ITEM_STATUS_EXPIRED           = 940
 
CUSTORDER_ITEM_STATUS_INACTIVE          = 950
 

	
 
CUSTORDER_ITEM_STATUS = OrderedDict([
 
    (CUSTORDER_ITEM_STATUS_INITIATED,           "customer order initiated"),
 
    (CUSTORDER_ITEM_STATUS_PAID,                "payment received"),
 
    # (CUSTORDER_ITEM_STATUS_PAID,                "payment received"),
 
    (CUSTORDER_ITEM_STATUS_READY,               "ready to proceed"),
 
    (CUSTORDER_ITEM_STATUS_PLACED,              "order placed with vendor"),
 
    (CUSTORDER_ITEM_STATUS_RECEIVED,            "received from vendor"),
 
    (CUSTORDER_ITEM_STATUS_CONTACTED,           "customer contacted"),
 
    (CUSTORDER_ITEM_STATUS_CONTACT_FAILED,      "unable to contact customer"),
 
    (CUSTORDER_ITEM_STATUS_DELIVERED,           "delivered to customer"),
 
    (CUSTORDER_ITEM_STATUS_CANCELED,            "canceled"),
 
    (CUSTORDER_ITEM_STATUS_REFUND_PENDING,      "refund pending"),
 
    (CUSTORDER_ITEM_STATUS_REFUNDED,            "refunded"),
 
    (CUSTORDER_ITEM_STATUS_RESTOCKED,           "restocked"),
 
    (CUSTORDER_ITEM_STATUS_EXPIRED,             "expired"),
 
    (CUSTORDER_ITEM_STATUS_INACTIVE,            "inactive"),
 
])
 

	
 

	
 
CUSTORDER_ITEM_EVENT_INITIATED          = 10
 
CUSTORDER_ITEM_EVENT_PAID               = 20
 
CUSTORDER_ITEM_EVENT_PRICE_CONFIRMED    = 15
 
CUSTORDER_ITEM_EVENT_READY              = 20
 
# TODO: deprecate / remove this one
 
CUSTORDER_ITEM_EVENT_PAID               = CUSTORDER_ITEM_EVENT_READY
 
CUSTORDER_ITEM_EVENT_PLACED             = 30
 
CUSTORDER_ITEM_EVENT_RECEIVED           = 40
 
CUSTORDER_ITEM_EVENT_CONTACTED          = 50
 
CUSTORDER_ITEM_EVENT_CONTACT_FAILED     = 60
 
CUSTORDER_ITEM_EVENT_DELIVERED          = 70
 
CUSTORDER_ITEM_EVENT_STATUS_CHANGE      = 500 # nb. this is not in STATUS enum
 
# CUSTORDER_ITEM_EVENT_ADDED_NOTE         = 510 # nb. this is not in STATUS enum
 
CUSTORDER_ITEM_EVENT_CANCELED           = 900
 
CUSTORDER_ITEM_EVENT_REFUND_PENDING     = 910
 
CUSTORDER_ITEM_EVENT_REFUNDED           = 920
 
CUSTORDER_ITEM_EVENT_RESTOCKED          = 930
 
CUSTORDER_ITEM_EVENT_EXPIRED            = 940
 
CUSTORDER_ITEM_EVENT_INACTIVE           = 950
 

	
 
CUSTORDER_ITEM_EVENT = OrderedDict([
 
    (CUSTORDER_ITEM_EVENT_INITIATED,            "customer order initiated"),
 
    (CUSTORDER_ITEM_EVENT_PAID,                 "payment received"),
 
    (CUSTORDER_ITEM_EVENT_PRICE_CONFIRMED,      "price confirmed"),
 
    (CUSTORDER_ITEM_EVENT_READY,                "order becomes ready to proceed"),
 
    # (CUSTORDER_ITEM_EVENT_PAID,                 "payment received"),
 
    (CUSTORDER_ITEM_EVENT_PLACED,               "order placed with vendor"),
 
    (CUSTORDER_ITEM_EVENT_RECEIVED,             "received from vendor"),
 
    (CUSTORDER_ITEM_EVENT_CONTACTED,            "customer contacted"),
 
    (CUSTORDER_ITEM_EVENT_CONTACT_FAILED,       "unable to contact customer"),
 
    (CUSTORDER_ITEM_EVENT_DELIVERED,            "delivered to customer"),
 
    (CUSTORDER_ITEM_EVENT_STATUS_CHANGE,        "manual status change"),
 
    # (CUSTORDER_ITEM_EVENT_ADDED_NOTE,           "added note"),
 
    (CUSTORDER_ITEM_EVENT_CANCELED,             "canceled"),
 
    (CUSTORDER_ITEM_EVENT_REFUND_PENDING,       "refund pending"),
 
    (CUSTORDER_ITEM_EVENT_REFUNDED,             "refunded"),
 
    (CUSTORDER_ITEM_EVENT_RESTOCKED,            "restocked"),
 
    (CUSTORDER_ITEM_EVENT_EXPIRED,              "expired"),
 
    (CUSTORDER_ITEM_EVENT_INACTIVE,             "inactive"),
 
])
 

	
 

	
 
EMAIL_ATTEMPT_CREATED           = 0
 
EMAIL_ATTEMPT_SUCCESS           = 1
 
EMAIL_ATTEMPT_FAILURE           = 2
 
# EMAIL_ATTEMPT_BOUNCED           = 3
 

	
 
EMAIL_ATTEMPT = {
 
    EMAIL_ATTEMPT_CREATED       : "created",
 
    EMAIL_ATTEMPT_SUCCESS       : "success",
 
    EMAIL_ATTEMPT_FAILURE       : "failure",
 
    # EMAIL_ATTEMPT_BOUNCED       : "bounced",
 
}
 

	
 

	
 
EMAIL_PREFERENCE_NONE           = 0
 
EMAIL_PREFERENCE_TEXT           = 1
 
EMAIL_PREFERENCE_HTML           = 2
 
EMAIL_PREFERENCE_MOBILE         = 3
 

	
 
EMAIL_PREFERENCE = {
 
    EMAIL_PREFERENCE_NONE       : "No Emails",
 
    EMAIL_PREFERENCE_TEXT       : "Text",
 
    EMAIL_PREFERENCE_HTML       : "HTML",
 
    EMAIL_PREFERENCE_MOBILE     : "Mobile",
 
    }
 

	
 

	
 
HANDHELD_DEVICE_TYPE_MOTOROLA           = 'motorola'
 
HANDHELD_DEVICE_TYPE_PALMOS             = 'palmos'
 

	
 
HANDHELD_DEVICE_TYPE = {
 
    HANDHELD_DEVICE_TYPE_MOTOROLA       : "Motorola",
 
    HANDHELD_DEVICE_TYPE_PALMOS         : "PalmOS",
0 comments (0 inline, 0 general)