Compare commits
4 commits
4bb4272341
...
edd1f17184
Author | SHA1 | Date | |
---|---|---|---|
|
edd1f17184 | ||
|
d8b37969c5 | ||
|
7ea83b2715 | ||
|
f3cca2e370 |
|
@ -38,7 +38,8 @@ dependencies = [
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
postgres = ["psycopg2"]
|
postgres = ["psycopg2"]
|
||||||
mysql = ["mysql-connector-python"]
|
mysql = ["mysql-connector-python"]
|
||||||
docs = ["Sphinx", "furo", "sphinxcontrib-programoutput", "enum-tools[sphinx]"]
|
# TODO: remove sphinx version cap after new sphinx-toolbox release?
|
||||||
|
docs = ["Sphinx<8.2", "furo", "sphinxcontrib-programoutput", "enum-tools[sphinx]"]
|
||||||
tests = ["pytest-cov", "tox"]
|
tests = ["pytest-cov", "tox"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -938,6 +938,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
row.department_id = product.department_id
|
row.department_id = product.department_id
|
||||||
row.department_name = product.department_name
|
row.department_name = product.department_name
|
||||||
row.special_order = product.special_order
|
row.special_order = product.special_order
|
||||||
|
row.vendor_name = product.vendor_name
|
||||||
|
row.vendor_item_code = product.vendor_item_code
|
||||||
row.case_size = product.case_size
|
row.case_size = product.case_size
|
||||||
row.unit_cost = product.unit_cost
|
row.unit_cost = product.unit_cost
|
||||||
row.unit_price_reg = product.unit_price_reg
|
row.unit_price_reg = product.unit_price_reg
|
||||||
|
@ -959,6 +961,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
row.department_id = product.department_id
|
row.department_id = product.department_id
|
||||||
row.department_name = product.department_name
|
row.department_name = product.department_name
|
||||||
row.special_order = product.special_order
|
row.special_order = product.special_order
|
||||||
|
row.vendor_name = product.vendor_name
|
||||||
|
row.vendor_item_code = product.vendor_item_code
|
||||||
row.case_size = product.case_size
|
row.case_size = product.case_size
|
||||||
row.unit_cost = product.unit_cost
|
row.unit_cost = product.unit_cost
|
||||||
row.unit_price_reg = product.unit_price_reg
|
row.unit_price_reg = product.unit_price_reg
|
||||||
|
@ -1017,8 +1021,14 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
def why_not_execute(self, batch, **kwargs):
|
def why_not_execute(self, batch, **kwargs):
|
||||||
"""
|
"""
|
||||||
By default this checks to ensure the batch has a customer with
|
By default this checks to ensure the batch has a customer with
|
||||||
phone number, and at least one item.
|
phone number, and at least one item. It also may check to
|
||||||
|
ensure the store is assigned, if applicable.
|
||||||
"""
|
"""
|
||||||
|
if not batch.store_id:
|
||||||
|
order_handler = self.app.get_order_handler()
|
||||||
|
if order_handler.expose_store_id():
|
||||||
|
return "Must assign the store"
|
||||||
|
|
||||||
if not batch.customer_name:
|
if not batch.customer_name:
|
||||||
return "Must assign the customer"
|
return "Must assign the customer"
|
||||||
|
|
||||||
|
@ -1190,6 +1200,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
'product_weighed',
|
'product_weighed',
|
||||||
'department_id',
|
'department_id',
|
||||||
'department_name',
|
'department_name',
|
||||||
|
'vendor_name',
|
||||||
|
'vendor_item_code',
|
||||||
'case_size',
|
'case_size',
|
||||||
'order_qty',
|
'order_qty',
|
||||||
'order_uom',
|
'order_uom',
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
"""add order_item.vendor*
|
||||||
|
|
||||||
|
Revision ID: 13af2ffbc0e0
|
||||||
|
Revises: a4273360d379
|
||||||
|
Create Date: 2025-02-19 19:36:30.308840
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
import wuttjamaican.db.util
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '13af2ffbc0e0'
|
||||||
|
down_revision: Union[str, None] = 'a4273360d379'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
|
||||||
|
# sideshow_batch_neworder_row
|
||||||
|
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
||||||
|
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
||||||
|
|
||||||
|
# sideshow_order_item
|
||||||
|
op.add_column('sideshow_order_item', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
||||||
|
op.add_column('sideshow_order_item', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
|
||||||
|
# sideshow_order_item
|
||||||
|
op.drop_column('sideshow_order_item', 'vendor_item_code')
|
||||||
|
op.drop_column('sideshow_order_item', 'vendor_name')
|
||||||
|
|
||||||
|
# sideshow_batch_neworder_row
|
||||||
|
op.drop_column('sideshow_batch_neworder_row', 'vendor_item_code')
|
||||||
|
op.drop_column('sideshow_batch_neworder_row', 'vendor_name')
|
|
@ -252,6 +252,16 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
normally carried by the store. Default is null.
|
normally carried by the store. Default is null.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
vendor_name = sa.Column(sa.String(length=50), nullable=True, doc="""
|
||||||
|
Name of vendor from which product may be purchased, if known. See
|
||||||
|
also :attr:`vendor_item_code`.
|
||||||
|
""")
|
||||||
|
|
||||||
|
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
||||||
|
Item code (SKU) to use when ordering this product from the vendor
|
||||||
|
identified by :attr:`vendor_name`, if known.
|
||||||
|
""")
|
||||||
|
|
||||||
case_size = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
|
case_size = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
|
||||||
Case pack count for the product, if known.
|
Case pack count for the product, if known.
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,16 @@ class OrderItem(model.Base):
|
||||||
normally carried by the store. Default is null.
|
normally carried by the store. Default is null.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
vendor_name = sa.Column(sa.String(length=50), nullable=True, doc="""
|
||||||
|
Name of vendor from which product may be purchased, if known. See
|
||||||
|
also :attr:`vendor_item_code`.
|
||||||
|
""")
|
||||||
|
|
||||||
|
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
||||||
|
Item code (SKU) to use when ordering this product from the vendor
|
||||||
|
identified by :attr:`vendor_name`, if known.
|
||||||
|
""")
|
||||||
|
|
||||||
case_size = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
|
case_size = sa.Column(sa.Numeric(precision=10, scale=4), nullable=True, doc="""
|
||||||
Case pack count for the product, if known.
|
Case pack count for the product, if known.
|
||||||
""")
|
""")
|
||||||
|
|
|
@ -243,6 +243,12 @@
|
||||||
<b-field horizontal label="Special Order">
|
<b-field horizontal label="Special Order">
|
||||||
<span>${app.render_boolean(item.special_order)}</span>
|
<span>${app.render_boolean(item.special_order)}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
<b-field horizontal label="Vendor Name">
|
||||||
|
<span>${item.vendor_name}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Vendor Item Code">
|
||||||
|
<span>${item.vendor_item_code}</span>
|
||||||
|
</b-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -1239,6 +1239,9 @@ class OrderItemView(MasterView):
|
||||||
|
|
||||||
# customer_name
|
# customer_name
|
||||||
g.set_label('customer_name', "Customer", column_only=True)
|
g.set_label('customer_name', "Customer", column_only=True)
|
||||||
|
g.set_renderer('customer_name', self.render_order_attr)
|
||||||
|
g.set_sorter('customer_name', model.Order.customer_name)
|
||||||
|
g.set_filter('customer_name', model.Order.customer_name)
|
||||||
|
|
||||||
# # sequence
|
# # sequence
|
||||||
# g.set_label('sequence', "Seq.", column_only=True)
|
# g.set_label('sequence', "Seq.", column_only=True)
|
||||||
|
@ -1562,6 +1565,26 @@ class PlacementView(OrderItemView):
|
||||||
route_prefix = 'order_items_placement'
|
route_prefix = 'order_items_placement'
|
||||||
url_prefix = '/placement'
|
url_prefix = '/placement'
|
||||||
|
|
||||||
|
grid_columns = [
|
||||||
|
'order_id',
|
||||||
|
'store_id',
|
||||||
|
'customer_name',
|
||||||
|
'product_brand',
|
||||||
|
'product_description',
|
||||||
|
'product_size',
|
||||||
|
'department_name',
|
||||||
|
'special_order',
|
||||||
|
'vendor_name',
|
||||||
|
'vendor_item_code',
|
||||||
|
'order_qty',
|
||||||
|
'order_uom',
|
||||||
|
'total_price',
|
||||||
|
]
|
||||||
|
|
||||||
|
filter_defaults = {
|
||||||
|
'vendor_name': {'active': True},
|
||||||
|
}
|
||||||
|
|
||||||
def get_query(self, session=None):
|
def get_query(self, session=None):
|
||||||
""" """
|
""" """
|
||||||
query = super().get_query(session=session)
|
query = super().get_query(session=session)
|
||||||
|
@ -1664,6 +1687,26 @@ class ReceivingView(OrderItemView):
|
||||||
route_prefix = 'order_items_receiving'
|
route_prefix = 'order_items_receiving'
|
||||||
url_prefix = '/receiving'
|
url_prefix = '/receiving'
|
||||||
|
|
||||||
|
grid_columns = [
|
||||||
|
'order_id',
|
||||||
|
'store_id',
|
||||||
|
'customer_name',
|
||||||
|
'product_brand',
|
||||||
|
'product_description',
|
||||||
|
'product_size',
|
||||||
|
'department_name',
|
||||||
|
'special_order',
|
||||||
|
'vendor_name',
|
||||||
|
'vendor_item_code',
|
||||||
|
'order_qty',
|
||||||
|
'order_uom',
|
||||||
|
'total_price',
|
||||||
|
]
|
||||||
|
|
||||||
|
filter_defaults = {
|
||||||
|
'vendor_name': {'active': True},
|
||||||
|
}
|
||||||
|
|
||||||
def get_query(self, session=None):
|
def get_query(self, session=None):
|
||||||
""" """
|
""" """
|
||||||
query = super().get_query(session=session)
|
query = super().get_query(session=session)
|
||||||
|
|
|
@ -818,6 +818,8 @@ class TestNewOrderBatchHandler(DataTestCase):
|
||||||
brand_name='Bragg',
|
brand_name='Bragg',
|
||||||
description='Vinegar',
|
description='Vinegar',
|
||||||
size='32oz',
|
size='32oz',
|
||||||
|
vendor_name='Acme Distributors',
|
||||||
|
vendor_item_code='1234',
|
||||||
created_by=user,
|
created_by=user,
|
||||||
status=enum.PendingProductStatus.PENDING)
|
status=enum.PendingProductStatus.PENDING)
|
||||||
row = handler.make_row(pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
row = handler.make_row(pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
||||||
|
@ -830,6 +832,8 @@ class TestNewOrderBatchHandler(DataTestCase):
|
||||||
self.assertEqual(row.product_brand, 'Bragg')
|
self.assertEqual(row.product_brand, 'Bragg')
|
||||||
self.assertEqual(row.product_description, 'Vinegar')
|
self.assertEqual(row.product_description, 'Vinegar')
|
||||||
self.assertEqual(row.product_size, '32oz')
|
self.assertEqual(row.product_size, '32oz')
|
||||||
|
self.assertEqual(row.vendor_name, 'Acme Distributors')
|
||||||
|
self.assertEqual(row.vendor_item_code, '1234')
|
||||||
self.assertIsNone(row.case_size)
|
self.assertIsNone(row.case_size)
|
||||||
self.assertIsNone(row.unit_cost)
|
self.assertIsNone(row.unit_cost)
|
||||||
self.assertIsNone(row.unit_price_reg)
|
self.assertIsNone(row.unit_price_reg)
|
||||||
|
@ -1114,9 +1118,15 @@ class TestNewOrderBatchHandler(DataTestCase):
|
||||||
self.session.add(row)
|
self.session.add(row)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
|
# batch is okay to execute..
|
||||||
reason = handler.why_not_execute(batch)
|
reason = handler.why_not_execute(batch)
|
||||||
self.assertIsNone(reason)
|
self.assertIsNone(reason)
|
||||||
|
|
||||||
|
# unless we also require store
|
||||||
|
self.config.setdefault('sideshow.orders.expose_store_id', 'true')
|
||||||
|
reason = handler.why_not_execute(batch)
|
||||||
|
self.assertEqual(reason, "Must assign the store")
|
||||||
|
|
||||||
def test_make_local_customer(self):
|
def test_make_local_customer(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
Loading…
Reference in a new issue