From 37b8de91180d819b0f7c0b154d2a929becb04fd5 2021-10-18 18:28:07 From: Lance Edgar Date: 2021-10-18 18:28:07 Subject: [PATCH] Add basic "price needs confirmation" support for custorder --- diff --git a/rattail/batch/custorder.py b/rattail/batch/custorder.py index fbad967fd2ece6516069f70994fe846553690af6..e24873617df25532a369b763595b523a430c1a96 100644 --- a/rattail/batch/custorder.py +++ b/rattail/batch/custorder.py @@ -408,6 +408,8 @@ class CustomerOrderBatchHandler(BatchHandler): 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 @@ -563,22 +565,22 @@ class CustomerOrderBatchHandler(BatchHandler): '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") @@ -588,3 +590,35 @@ class CustomerOrderBatchHandler(BatchHandler): 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) diff --git a/rattail/db/alembic/versions/8856f697902d_add_custorder_item_status_text.py b/rattail/db/alembic/versions/8856f697902d_add_custorder_item_status_text.py new file mode 100644 index 0000000000000000000000000000000000000000..8aed040ae6eae1c52456f27321d8f9367f5b7674 --- /dev/null +++ b/rattail/db/alembic/versions/8856f697902d_add_custorder_item_status_text.py @@ -0,0 +1,41 @@ +# -*- 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') diff --git a/rattail/db/model/batch/custorder.py b/rattail/db/model/batch/custorder.py index 0201770afe1856ad75b1abb8a6eb5e25e211fe56..8a4366843a6a751ffaca6d7812588c1238a5e0b0 100644 --- a/rattail/db/model/batch/custorder.py +++ b/rattail/db/model/batch/custorder.py @@ -93,10 +93,12 @@ class CustomerOrderBatchRow(BatchRowMixin, CustomerOrderItemBase, Base): 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=""" diff --git a/rattail/db/model/custorders.py b/rattail/db/model/custorders.py index fc9cbb647be446229afdc7a4f4a903c89dd75cec..f1e302ca7715794caada4e03e85f6d23929cce84 100644 --- a/rattail/db/model/custorders.py +++ b/rattail/db/model/custorders.py @@ -282,6 +282,17 @@ class CustomerOrderItemBase(object): 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. """) @@ -322,6 +333,18 @@ class CustomerOrderItem(CustomerOrderItemBase, Base): 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): """ diff --git a/rattail/enum.py b/rattail/enum.py index d6b106479948f01d41421b671c969462380a83c2..c772965d5e57b0f69b94dfe16d10472d56a0ba17 100644 --- a/rattail/enum.py +++ b/rattail/enum.py @@ -95,7 +95,9 @@ CUSTORDER_STATUS = { 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 @@ -110,7 +112,8 @@ 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"), @@ -126,7 +129,10 @@ CUSTORDER_ITEM_STATUS = OrderedDict([ 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 @@ -143,7 +149,9 @@ 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"),