fix: format all code with black
and from now on should not deviate from that...
This commit is contained in:
parent
925235f0d3
commit
2107e9ee1d
47 changed files with 5729 additions and 3977 deletions
36
docs/conf.py
36
docs/conf.py
|
@ -8,36 +8,36 @@
|
||||||
|
|
||||||
from importlib.metadata import version as get_version
|
from importlib.metadata import version as get_version
|
||||||
|
|
||||||
project = 'Sideshow'
|
project = "Sideshow"
|
||||||
copyright = '2025, Lance Edgar'
|
copyright = "2025, Lance Edgar"
|
||||||
author = 'Lance Edgar'
|
author = "Lance Edgar"
|
||||||
release = get_version('Sideshow')
|
release = get_version("Sideshow")
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
'sphinx.ext.autodoc',
|
"sphinx.ext.autodoc",
|
||||||
'sphinx.ext.intersphinx',
|
"sphinx.ext.intersphinx",
|
||||||
'sphinx.ext.viewcode',
|
"sphinx.ext.viewcode",
|
||||||
'sphinx.ext.todo',
|
"sphinx.ext.todo",
|
||||||
'sphinxcontrib.programoutput',
|
"sphinxcontrib.programoutput",
|
||||||
'enum_tools.autoenum',
|
"enum_tools.autoenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||||
|
|
||||||
intersphinx_mapping = {
|
intersphinx_mapping = {
|
||||||
'pyramid': ('https://docs.pylonsproject.org/projects/pyramid/en/latest/', None),
|
"pyramid": ("https://docs.pylonsproject.org/projects/pyramid/en/latest/", None),
|
||||||
'python': ('https://docs.python.org/3/', None),
|
"python": ("https://docs.python.org/3/", None),
|
||||||
'wuttjamaican': ('https://docs.wuttaproject.org/wuttjamaican/', None),
|
"wuttjamaican": ("https://docs.wuttaproject.org/wuttjamaican/", None),
|
||||||
'wuttaweb': ('https://docs.wuttaproject.org/wuttaweb/', None),
|
"wuttaweb": ("https://docs.wuttaproject.org/wuttaweb/", None),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
html_theme = 'furo'
|
html_theme = "furo"
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
|
@ -49,8 +49,9 @@ class SideshowAppProvider(base.AppProvider):
|
||||||
|
|
||||||
:returns: Instance of :class:`~sideshow.orders.OrderHandler`.
|
:returns: Instance of :class:`~sideshow.orders.OrderHandler`.
|
||||||
"""
|
"""
|
||||||
if 'order_handler' not in self.__dict__:
|
if "order_handler" not in self.__dict__:
|
||||||
spec = self.config.get('sideshow.orders.handler_spec',
|
spec = self.config.get(
|
||||||
default='sideshow.orders:OrderHandler')
|
"sideshow.orders.handler_spec", default="sideshow.orders:OrderHandler"
|
||||||
|
)
|
||||||
self.order_handler = self.app.load_object(spec)(self.config)
|
self.order_handler = self.app.load_object(spec)(self.config)
|
||||||
return self.order_handler
|
return self.order_handler
|
||||||
|
|
|
@ -49,6 +49,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
After the batch has executed the :term:`order handler` takes over
|
After the batch has executed the :term:`order handler` takes over
|
||||||
responsibility for the rest of the order lifecycle.
|
responsibility for the rest of the order lifecycle.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = NewOrderBatch
|
model_class = NewOrderBatch
|
||||||
|
|
||||||
def get_default_store_id(self):
|
def get_default_store_id(self):
|
||||||
|
@ -57,7 +58,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
:attr:`~sideshow.db.model.batch.neworder.NewOrderBatch.store_id`,
|
:attr:`~sideshow.db.model.batch.neworder.NewOrderBatch.store_id`,
|
||||||
or ``None``.
|
or ``None``.
|
||||||
"""
|
"""
|
||||||
return self.config.get('sideshow.orders.default_store_id')
|
return self.config.get("sideshow.orders.default_store_id")
|
||||||
|
|
||||||
def use_local_customers(self):
|
def use_local_customers(self):
|
||||||
"""
|
"""
|
||||||
|
@ -65,8 +66,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
accounts should be used. This is true by default, but may be
|
accounts should be used. This is true by default, but may be
|
||||||
false for :term:`external customer` lookups.
|
false for :term:`external customer` lookups.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.use_local_customers',
|
return self.config.get_bool("sideshow.orders.use_local_customers", default=True)
|
||||||
default=True)
|
|
||||||
|
|
||||||
def use_local_products(self):
|
def use_local_products(self):
|
||||||
"""
|
"""
|
||||||
|
@ -74,8 +74,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
records should be used. This is true by default, but may be
|
records should be used. This is true by default, but may be
|
||||||
false for :term:`external product` lookups.
|
false for :term:`external product` lookups.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.use_local_products',
|
return self.config.get_bool("sideshow.orders.use_local_products", default=True)
|
||||||
default=True)
|
|
||||||
|
|
||||||
def allow_unknown_products(self):
|
def allow_unknown_products(self):
|
||||||
"""
|
"""
|
||||||
|
@ -86,24 +85,27 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
when creating an order. This can be disabled, to force user
|
when creating an order. This can be disabled, to force user
|
||||||
to choose existing local/external product.
|
to choose existing local/external product.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.allow_unknown_products',
|
return self.config.get_bool(
|
||||||
default=True)
|
"sideshow.orders.allow_unknown_products", default=True
|
||||||
|
)
|
||||||
|
|
||||||
def allow_item_discounts(self):
|
def allow_item_discounts(self):
|
||||||
"""
|
"""
|
||||||
Returns boolean indicating whether per-item discounts are
|
Returns boolean indicating whether per-item discounts are
|
||||||
allowed when creating an order.
|
allowed when creating an order.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.allow_item_discounts',
|
return self.config.get_bool(
|
||||||
default=False)
|
"sideshow.orders.allow_item_discounts", default=False
|
||||||
|
)
|
||||||
|
|
||||||
def allow_item_discounts_if_on_sale(self):
|
def allow_item_discounts_if_on_sale(self):
|
||||||
"""
|
"""
|
||||||
Returns boolean indicating whether per-item discounts are
|
Returns boolean indicating whether per-item discounts are
|
||||||
allowed even when the item is already on sale.
|
allowed even when the item is already on sale.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.allow_item_discounts_if_on_sale',
|
return self.config.get_bool(
|
||||||
default=False)
|
"sideshow.orders.allow_item_discounts_if_on_sale", default=False
|
||||||
|
)
|
||||||
|
|
||||||
def get_default_item_discount(self):
|
def get_default_item_discount(self):
|
||||||
"""
|
"""
|
||||||
|
@ -111,7 +113,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
|
|
||||||
:rtype: :class:`~python:decimal.Decimal` or ``None``
|
:rtype: :class:`~python:decimal.Decimal` or ``None``
|
||||||
"""
|
"""
|
||||||
discount = self.config.get('sideshow.orders.default_item_discount')
|
discount = self.config.get("sideshow.orders.default_item_discount")
|
||||||
if discount:
|
if discount:
|
||||||
return decimal.Decimal(discount)
|
return decimal.Decimal(discount)
|
||||||
|
|
||||||
|
@ -157,8 +159,9 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
query = session.query(model.LocalCustomer)
|
query = session.query(model.LocalCustomer)
|
||||||
|
|
||||||
# filter query
|
# filter query
|
||||||
criteria = [model.LocalCustomer.full_name.ilike(f'%{word}%')
|
criteria = [
|
||||||
for word in term.split()]
|
model.LocalCustomer.full_name.ilike(f"%{word}%") for word in term.split()
|
||||||
|
]
|
||||||
query = query.filter(sa.and_(*criteria))
|
query = query.filter(sa.and_(*criteria))
|
||||||
|
|
||||||
# sort query
|
# sort query
|
||||||
|
@ -170,8 +173,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
|
|
||||||
# get results
|
# get results
|
||||||
def result(customer):
|
def result(customer):
|
||||||
return {'value': customer.uuid.hex,
|
return {"value": customer.uuid.hex, "label": customer.full_name}
|
||||||
'label': customer.full_name}
|
|
||||||
return [result(c) for c in customers]
|
return [result(c) for c in customers]
|
||||||
|
|
||||||
def init_batch(self, batch, session=None, progress=None, **kwargs):
|
def init_batch(self, batch, session=None, progress=None, **kwargs):
|
||||||
|
@ -251,22 +254,25 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
batch.local_customer = None
|
batch.local_customer = None
|
||||||
customer = batch.pending_customer
|
customer = batch.pending_customer
|
||||||
if not customer:
|
if not customer:
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user or batch.created_by)
|
status=enum.PendingCustomerStatus.PENDING,
|
||||||
|
created_by=user or batch.created_by,
|
||||||
|
)
|
||||||
session.add(customer)
|
session.add(customer)
|
||||||
batch.pending_customer = customer
|
batch.pending_customer = customer
|
||||||
fields = [
|
fields = [
|
||||||
'full_name',
|
"full_name",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
]
|
]
|
||||||
for key in fields:
|
for key in fields:
|
||||||
setattr(customer, key, customer_info.get(key))
|
setattr(customer, key, customer_info.get(key))
|
||||||
if 'full_name' not in customer_info:
|
if "full_name" not in customer_info:
|
||||||
customer.full_name = self.app.make_full_name(customer.first_name,
|
customer.full_name = self.app.make_full_name(
|
||||||
customer.last_name)
|
customer.first_name, customer.last_name
|
||||||
|
)
|
||||||
self.refresh_batch_from_pending_customer(batch)
|
self.refresh_batch_from_pending_customer(batch)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -361,14 +367,18 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
# filter query
|
# filter query
|
||||||
criteria = []
|
criteria = []
|
||||||
for word in term.split():
|
for word in term.split():
|
||||||
criteria.append(sa.or_(
|
criteria.append(
|
||||||
model.LocalProduct.brand_name.ilike(f'%{word}%'),
|
sa.or_(
|
||||||
model.LocalProduct.description.ilike(f'%{word}%')))
|
model.LocalProduct.brand_name.ilike(f"%{word}%"),
|
||||||
|
model.LocalProduct.description.ilike(f"%{word}%"),
|
||||||
|
)
|
||||||
|
)
|
||||||
query = query.filter(sa.and_(*criteria))
|
query = query.filter(sa.and_(*criteria))
|
||||||
|
|
||||||
# sort query
|
# sort query
|
||||||
query = query.order_by(model.LocalProduct.brand_name,
|
query = query.order_by(
|
||||||
model.LocalProduct.description)
|
model.LocalProduct.brand_name, model.LocalProduct.description
|
||||||
|
)
|
||||||
|
|
||||||
# get data
|
# get data
|
||||||
# TODO: need max_results option
|
# TODO: need max_results option
|
||||||
|
@ -376,8 +386,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
|
|
||||||
# get results
|
# get results
|
||||||
def result(product):
|
def result(product):
|
||||||
return {'value': product.uuid.hex,
|
return {"value": product.uuid.hex, "label": product.full_description}
|
||||||
'label': product.full_description}
|
|
||||||
return [result(c) for c in products]
|
return [result(c) for c in products]
|
||||||
|
|
||||||
def get_default_uom_choices(self):
|
def get_default_uom_choices(self):
|
||||||
|
@ -392,8 +402,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
corresponding to the UOM code and label, respectively.
|
corresponding to the UOM code and label, respectively.
|
||||||
"""
|
"""
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
return [{'key': key, 'value': val}
|
return [{"key": key, "value": val} for key, val in enum.ORDER_UOM.items()]
|
||||||
for key, val in enum.ORDER_UOM.items()]
|
|
||||||
|
|
||||||
def get_product_info_external(self, session, product_id, user=None):
|
def get_product_info_external(self, session, product_id, user=None):
|
||||||
"""
|
"""
|
||||||
|
@ -514,20 +523,20 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
* ``product_id`` will be set to the product UUID as string
|
* ``product_id`` will be set to the product UUID as string
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'product_id': product.uuid.hex,
|
"product_id": product.uuid.hex,
|
||||||
'scancode': product.scancode,
|
"scancode": product.scancode,
|
||||||
'brand_name': product.brand_name,
|
"brand_name": product.brand_name,
|
||||||
'description': product.description,
|
"description": product.description,
|
||||||
'size': product.size,
|
"size": product.size,
|
||||||
'full_description': product.full_description,
|
"full_description": product.full_description,
|
||||||
'weighed': product.weighed,
|
"weighed": product.weighed,
|
||||||
'special_order': product.special_order,
|
"special_order": product.special_order,
|
||||||
'department_id': product.department_id,
|
"department_id": product.department_id,
|
||||||
'department_name': product.department_name,
|
"department_name": product.department_name,
|
||||||
'case_size': product.case_size,
|
"case_size": product.case_size,
|
||||||
'unit_price_reg': product.unit_price_reg,
|
"unit_price_reg": product.unit_price_reg,
|
||||||
'vendor_name': product.vendor_name,
|
"vendor_name": product.vendor_name,
|
||||||
'vendor_item_code': product.vendor_item_code,
|
"vendor_item_code": product.vendor_item_code,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_past_orders(self, batch):
|
def get_past_orders(self, batch):
|
||||||
|
@ -605,36 +614,51 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
products[product.uuid] = self.normalize_local_product(product)
|
products[product.uuid] = self.normalize_local_product(product)
|
||||||
elif item.product_id and item.product_id not in products:
|
elif item.product_id and item.product_id not in products:
|
||||||
products[item.product_id] = self.get_product_info_external(
|
products[item.product_id] = self.get_product_info_external(
|
||||||
session, item.product_id, user=user)
|
session, item.product_id, user=user
|
||||||
|
)
|
||||||
|
|
||||||
products = list(products.values())
|
products = list(products.values())
|
||||||
for product in products:
|
for product in products:
|
||||||
|
|
||||||
price = product['unit_price_reg']
|
price = product["unit_price_reg"]
|
||||||
|
|
||||||
if 'unit_price_reg_display' not in product:
|
if "unit_price_reg_display" not in product:
|
||||||
product['unit_price_reg_display'] = self.app.render_currency(price)
|
product["unit_price_reg_display"] = self.app.render_currency(price)
|
||||||
|
|
||||||
if 'unit_price_quoted' not in product:
|
if "unit_price_quoted" not in product:
|
||||||
product['unit_price_quoted'] = price
|
product["unit_price_quoted"] = price
|
||||||
|
|
||||||
if 'unit_price_quoted_display' not in product:
|
if "unit_price_quoted_display" not in product:
|
||||||
product['unit_price_quoted_display'] = product['unit_price_reg_display']
|
product["unit_price_quoted_display"] = product["unit_price_reg_display"]
|
||||||
|
|
||||||
if ('case_price_quoted' not in product
|
if (
|
||||||
and product.get('unit_price_quoted') is not None
|
"case_price_quoted" not in product
|
||||||
and product.get('case_size') is not None):
|
and product.get("unit_price_quoted") is not None
|
||||||
product['case_price_quoted'] = product['unit_price_quoted'] * product['case_size']
|
and product.get("case_size") is not None
|
||||||
|
):
|
||||||
|
product["case_price_quoted"] = (
|
||||||
|
product["unit_price_quoted"] * product["case_size"]
|
||||||
|
)
|
||||||
|
|
||||||
if ('case_price_quoted_display' not in product
|
if (
|
||||||
and 'case_price_quoted' in product):
|
"case_price_quoted_display" not in product
|
||||||
product['case_price_quoted_display'] = self.app.render_currency(
|
and "case_price_quoted" in product
|
||||||
product['case_price_quoted'])
|
):
|
||||||
|
product["case_price_quoted_display"] = self.app.render_currency(
|
||||||
|
product["case_price_quoted"]
|
||||||
|
)
|
||||||
|
|
||||||
return products
|
return products
|
||||||
|
|
||||||
def add_item(self, batch, product_info, order_qty, order_uom,
|
def add_item(
|
||||||
discount_percent=None, user=None):
|
self,
|
||||||
|
batch,
|
||||||
|
product_info,
|
||||||
|
order_qty,
|
||||||
|
order_uom,
|
||||||
|
discount_percent=None,
|
||||||
|
user=None,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Add a new item/row to the batch, for given product and quantity.
|
Add a new item/row to the batch, for given product and quantity.
|
||||||
|
|
||||||
|
@ -695,23 +719,25 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
raise TypeError("unknown/pending product not allowed for new orders")
|
raise TypeError("unknown/pending product not allowed for new orders")
|
||||||
row.product_id = None
|
row.product_id = None
|
||||||
row.local_product = None
|
row.local_product = None
|
||||||
pending = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
pending = model.PendingProduct(
|
||||||
created_by=user or batch.created_by)
|
status=enum.PendingProductStatus.PENDING,
|
||||||
|
created_by=user or batch.created_by,
|
||||||
|
)
|
||||||
fields = [
|
fields = [
|
||||||
'scancode',
|
"scancode",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'weighed',
|
"weighed",
|
||||||
'department_id',
|
"department_id",
|
||||||
'department_name',
|
"department_name",
|
||||||
'special_order',
|
"special_order",
|
||||||
'vendor_name',
|
"vendor_name",
|
||||||
'vendor_item_code',
|
"vendor_item_code",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'notes',
|
"notes",
|
||||||
]
|
]
|
||||||
for key in fields:
|
for key in fields:
|
||||||
setattr(pending, key, product_info.get(key))
|
setattr(pending, key, product_info.get(key))
|
||||||
|
@ -735,8 +761,9 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
session.flush()
|
session.flush()
|
||||||
return row
|
return row
|
||||||
|
|
||||||
def update_item(self, row, product_info, order_qty, order_uom,
|
def update_item(
|
||||||
discount_percent=None, user=None):
|
self, row, product_info, order_qty, order_uom, discount_percent=None, user=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Update an item/row, per given product and quantity.
|
Update an item/row, per given product and quantity.
|
||||||
|
|
||||||
|
@ -794,25 +821,27 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
row.local_product = None
|
row.local_product = None
|
||||||
pending = row.pending_product
|
pending = row.pending_product
|
||||||
if not pending:
|
if not pending:
|
||||||
pending = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
pending = model.PendingProduct(
|
||||||
created_by=user or row.batch.created_by)
|
status=enum.PendingProductStatus.PENDING,
|
||||||
|
created_by=user or row.batch.created_by,
|
||||||
|
)
|
||||||
session.add(pending)
|
session.add(pending)
|
||||||
row.pending_product = pending
|
row.pending_product = pending
|
||||||
fields = [
|
fields = [
|
||||||
'scancode',
|
"scancode",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'weighed',
|
"weighed",
|
||||||
'department_id',
|
"department_id",
|
||||||
'department_name',
|
"department_name",
|
||||||
'special_order',
|
"special_order",
|
||||||
'vendor_name',
|
"vendor_name",
|
||||||
'vendor_item_code',
|
"vendor_item_code",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'notes',
|
"notes",
|
||||||
]
|
]
|
||||||
for key in fields:
|
for key in fields:
|
||||||
setattr(pending, key, product_info.get(key))
|
setattr(pending, key, product_info.get(key))
|
||||||
|
@ -885,8 +914,8 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
row.unit_price_quoted = None
|
row.unit_price_quoted = None
|
||||||
row.case_price_quoted = None
|
row.case_price_quoted = None
|
||||||
if row.unit_price_sale is not None and (
|
if row.unit_price_sale is not None and (
|
||||||
not row.sale_ends
|
not row.sale_ends or row.sale_ends > datetime.datetime.now()
|
||||||
or row.sale_ends > datetime.datetime.now()):
|
):
|
||||||
row.unit_price_quoted = row.unit_price_sale
|
row.unit_price_quoted = row.unit_price_sale
|
||||||
else:
|
else:
|
||||||
row.unit_price_quoted = row.unit_price_reg
|
row.unit_price_quoted = row.unit_price_reg
|
||||||
|
@ -906,17 +935,17 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
row.total_price = row.unit_price_quoted * row.order_qty
|
row.total_price = row.unit_price_quoted * row.order_qty
|
||||||
if row.total_price is not None:
|
if row.total_price is not None:
|
||||||
if row.discount_percent and self.allow_item_discounts():
|
if row.discount_percent and self.allow_item_discounts():
|
||||||
row.total_price = (float(row.total_price)
|
row.total_price = (
|
||||||
* (100 - float(row.discount_percent))
|
float(row.total_price) * (100 - float(row.discount_percent)) / 100.0
|
||||||
/ 100.0)
|
)
|
||||||
row.total_price = decimal.Decimal(f'{row.total_price:0.2f}')
|
row.total_price = decimal.Decimal(f"{row.total_price:0.2f}")
|
||||||
|
|
||||||
# update batch if total price changed
|
# update batch if total price changed
|
||||||
if row.total_price != old_total:
|
if row.total_price != old_total:
|
||||||
batch = row.batch
|
batch = row.batch
|
||||||
batch.total_price = ((batch.total_price or 0)
|
batch.total_price = (
|
||||||
+ (row.total_price or 0)
|
(batch.total_price or 0) + (row.total_price or 0) - (old_total or 0)
|
||||||
- (old_total or 0))
|
)
|
||||||
|
|
||||||
# all ok
|
# all ok
|
||||||
row.status_code = row.STATUS_OK
|
row.status_code = row.STATUS_OK
|
||||||
|
@ -1046,8 +1075,7 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
are "effective" - i.e. rows with other status codes will not
|
are "effective" - i.e. rows with other status codes will not
|
||||||
be created as proper order items.
|
be created as proper order items.
|
||||||
"""
|
"""
|
||||||
return [row for row in batch.rows
|
return [row for row in batch.rows if row.status_code == row.STATUS_OK]
|
||||||
if row.status_code == row.STATUS_OK]
|
|
||||||
|
|
||||||
def execute(self, batch, user=None, progress=None, **kwargs):
|
def execute(self, batch, user=None, progress=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -1181,48 +1209,47 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
session = self.app.get_session(batch)
|
session = self.app.get_session(batch)
|
||||||
|
|
||||||
batch_fields = [
|
batch_fields = [
|
||||||
'store_id',
|
"store_id",
|
||||||
'customer_id',
|
"customer_id",
|
||||||
'local_customer',
|
"local_customer",
|
||||||
'pending_customer',
|
"pending_customer",
|
||||||
'customer_name',
|
"customer_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'total_price',
|
"total_price",
|
||||||
]
|
]
|
||||||
|
|
||||||
row_fields = [
|
row_fields = [
|
||||||
'product_id',
|
"product_id",
|
||||||
'local_product',
|
"local_product",
|
||||||
'pending_product',
|
"pending_product",
|
||||||
'product_scancode',
|
"product_scancode",
|
||||||
'product_brand',
|
"product_brand",
|
||||||
'product_description',
|
"product_description",
|
||||||
'product_size',
|
"product_size",
|
||||||
'product_weighed',
|
"product_weighed",
|
||||||
'department_id',
|
"department_id",
|
||||||
'department_name',
|
"department_name",
|
||||||
'vendor_name',
|
"vendor_name",
|
||||||
'vendor_item_code',
|
"vendor_item_code",
|
||||||
'case_size',
|
"case_size",
|
||||||
'order_qty',
|
"order_qty",
|
||||||
'order_uom',
|
"order_uom",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'unit_price_quoted',
|
"unit_price_quoted",
|
||||||
'case_price_quoted',
|
"case_price_quoted",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'unit_price_sale',
|
"unit_price_sale",
|
||||||
'sale_ends',
|
"sale_ends",
|
||||||
'discount_percent',
|
"discount_percent",
|
||||||
'total_price',
|
"total_price",
|
||||||
'special_order',
|
"special_order",
|
||||||
]
|
]
|
||||||
|
|
||||||
# make order
|
# make order
|
||||||
kw = dict([(field, getattr(batch, field))
|
kw = dict([(field, getattr(batch, field)) for field in batch_fields])
|
||||||
for field in batch_fields])
|
kw["order_id"] = batch.id
|
||||||
kw['order_id'] = batch.id
|
kw["created_by"] = user
|
||||||
kw['created_by'] = user
|
|
||||||
order = model.Order(**kw)
|
order = model.Order(**kw)
|
||||||
session.add(order)
|
session.add(order)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
@ -1230,16 +1257,16 @@ class NewOrderBatchHandler(BatchHandler):
|
||||||
def convert(row, i):
|
def convert(row, i):
|
||||||
|
|
||||||
# make order item
|
# make order item
|
||||||
kw = dict([(field, getattr(row, field))
|
kw = dict([(field, getattr(row, field)) for field in row_fields])
|
||||||
for field in row_fields])
|
|
||||||
item = model.OrderItem(**kw)
|
item = model.OrderItem(**kw)
|
||||||
order.items.append(item)
|
order.items.append(item)
|
||||||
|
|
||||||
# set item status
|
# set item status
|
||||||
self.set_initial_item_status(item, user)
|
self.set_initial_item_status(item, user)
|
||||||
|
|
||||||
self.app.progress_loop(convert, rows, progress,
|
self.app.progress_loop(
|
||||||
message="Converting batch rows to order items")
|
convert, rows, progress, message="Converting batch rows to order items"
|
||||||
|
)
|
||||||
session.flush()
|
session.flush()
|
||||||
return order
|
return order
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,5 @@ from wuttjamaican.cli import make_typer
|
||||||
|
|
||||||
|
|
||||||
sideshow_typer = make_typer(
|
sideshow_typer = make_typer(
|
||||||
name='sideshow',
|
name="sideshow", help="Sideshow -- Case/Special Order Tracker"
|
||||||
help="Sideshow -- Case/Special Order Tracker"
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -38,8 +38,10 @@ def install(
|
||||||
"""
|
"""
|
||||||
config = ctx.parent.wutta_config
|
config = ctx.parent.wutta_config
|
||||||
app = config.get_app()
|
app = config.get_app()
|
||||||
install = app.get_install_handler(pkg_name='sideshow',
|
install = app.get_install_handler(
|
||||||
|
pkg_name="sideshow",
|
||||||
app_title="Sideshow",
|
app_title="Sideshow",
|
||||||
pypi_name='Sideshow',
|
pypi_name="Sideshow",
|
||||||
egg_name='Sideshow')
|
egg_name="Sideshow",
|
||||||
|
)
|
||||||
install.run()
|
install.run()
|
||||||
|
|
|
@ -33,26 +33,31 @@ class SideshowConfig(WuttaConfigExtension):
|
||||||
|
|
||||||
This establishes some config defaults specific to Sideshow.
|
This establishes some config defaults specific to Sideshow.
|
||||||
"""
|
"""
|
||||||
key = 'sideshow'
|
|
||||||
|
key = "sideshow"
|
||||||
|
|
||||||
def configure(self, config):
|
def configure(self, config):
|
||||||
""" """
|
""" """
|
||||||
|
|
||||||
# app info
|
# app info
|
||||||
config.setdefault(f'{config.appname}.app_title', "Sideshow")
|
config.setdefault(f"{config.appname}.app_title", "Sideshow")
|
||||||
config.setdefault(f'{config.appname}.app_dist', "Sideshow")
|
config.setdefault(f"{config.appname}.app_dist", "Sideshow")
|
||||||
|
|
||||||
# app model, enum
|
# app model, enum
|
||||||
config.setdefault(f'{config.appname}.model_spec', 'sideshow.db.model')
|
config.setdefault(f"{config.appname}.model_spec", "sideshow.db.model")
|
||||||
config.setdefault(f'{config.appname}.enum_spec', 'sideshow.enum')
|
config.setdefault(f"{config.appname}.enum_spec", "sideshow.enum")
|
||||||
|
|
||||||
# batch handlers
|
# batch handlers
|
||||||
config.setdefault(f'{config.appname}.batch.neworder.handler.default_spec',
|
config.setdefault(
|
||||||
'sideshow.batch.neworder:NewOrderBatchHandler')
|
f"{config.appname}.batch.neworder.handler.default_spec",
|
||||||
|
"sideshow.batch.neworder:NewOrderBatchHandler",
|
||||||
|
)
|
||||||
|
|
||||||
# web app menu
|
# web app menu
|
||||||
config.setdefault(f'{config.appname}.web.menus.handler.default_spec',
|
config.setdefault(
|
||||||
'sideshow.web.menus:SideshowMenuHandler')
|
f"{config.appname}.web.menus.handler.default_spec",
|
||||||
|
"sideshow.web.menus:SideshowMenuHandler",
|
||||||
|
)
|
||||||
|
|
||||||
# web app libcache
|
# web app libcache
|
||||||
config.setdefault('wuttaweb.static_libcache.module', 'sideshow.web.static')
|
config.setdefault("wuttaweb.static_libcache.module", "sideshow.web.static")
|
||||||
|
|
|
@ -5,6 +5,7 @@ Revises: a4273360d379
|
||||||
Create Date: 2025-02-19 19:36:30.308840
|
Create Date: 2025-02-19 19:36:30.308840
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = '13af2ffbc0e0'
|
revision: str = "13af2ffbc0e0"
|
||||||
down_revision: Union[str, None] = 'a4273360d379'
|
down_revision: Union[str, None] = "a4273360d379"
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
@ -22,20 +23,32 @@ depends_on: Union[str, Sequence[str], None] = None
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
|
|
||||||
# sideshow_batch_neworder_row
|
# sideshow_batch_neworder_row
|
||||||
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
op.add_column(
|
||||||
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
"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
|
# sideshow_order_item
|
||||||
op.add_column('sideshow_order_item', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
op.add_column(
|
||||||
op.add_column('sideshow_order_item', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
"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:
|
def downgrade() -> None:
|
||||||
|
|
||||||
# sideshow_order_item
|
# sideshow_order_item
|
||||||
op.drop_column('sideshow_order_item', 'vendor_item_code')
|
op.drop_column("sideshow_order_item", "vendor_item_code")
|
||||||
op.drop_column('sideshow_order_item', 'vendor_name')
|
op.drop_column("sideshow_order_item", "vendor_name")
|
||||||
|
|
||||||
# sideshow_batch_neworder_row
|
# sideshow_batch_neworder_row
|
||||||
op.drop_column('sideshow_batch_neworder_row', 'vendor_item_code')
|
op.drop_column("sideshow_batch_neworder_row", "vendor_item_code")
|
||||||
op.drop_column('sideshow_batch_neworder_row', 'vendor_name')
|
op.drop_column("sideshow_batch_neworder_row", "vendor_name")
|
||||||
|
|
|
@ -5,6 +5,7 @@ Revises:
|
||||||
Create Date: 2024-12-30 18:53:51.358163
|
Create Date: 2024-12-30 18:53:51.358163
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -14,253 +15,364 @@ import wuttjamaican.db.util
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = '7a6df83afbd4'
|
revision: str = "7a6df83afbd4"
|
||||||
down_revision: Union[str, None] = None
|
down_revision: Union[str, None] = None
|
||||||
branch_labels: Union[str, Sequence[str], None] = ('sideshow',)
|
branch_labels: Union[str, Sequence[str], None] = ("sideshow",)
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
|
|
||||||
# enums
|
# enums
|
||||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingcustomerstatus').create(op.get_bind())
|
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingcustomerstatus").create(
|
||||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingproductstatus').create(op.get_bind())
|
op.get_bind()
|
||||||
|
)
|
||||||
|
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingproductstatus").create(
|
||||||
|
op.get_bind()
|
||||||
|
)
|
||||||
|
|
||||||
# sideshow_customer_pending
|
# sideshow_customer_pending
|
||||||
op.create_table('sideshow_customer_pending',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_customer_pending",
|
||||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('full_name', sa.String(length=100), nullable=True),
|
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('first_name', sa.String(length=50), nullable=True),
|
sa.Column("full_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('last_name', sa.String(length=50), nullable=True),
|
sa.Column("first_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
sa.Column("last_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||||
sa.Column('status', postgresql.ENUM('PENDING', 'READY', 'RESOLVED', name='pendingcustomerstatus', create_type=False), nullable=False),
|
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
sa.Column(
|
||||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"status",
|
||||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name=op.f('fk_sideshow_customer_pending_created_by_uuid_user')),
|
postgresql.ENUM(
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_customer_pending'))
|
"PENDING",
|
||||||
|
"READY",
|
||||||
|
"RESOLVED",
|
||||||
|
name="pendingcustomerstatus",
|
||||||
|
create_type=False,
|
||||||
|
),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["created_by_uuid"],
|
||||||
|
["user.uuid"],
|
||||||
|
name=op.f("fk_sideshow_customer_pending_created_by_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_customer_pending")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_customer_local
|
# sideshow_customer_local
|
||||||
op.create_table('sideshow_customer_local',
|
op.create_table(
|
||||||
sa.Column('full_name', sa.String(length=100), nullable=True),
|
"sideshow_customer_local",
|
||||||
sa.Column('first_name', sa.String(length=50), nullable=True),
|
sa.Column("full_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('last_name', sa.String(length=50), nullable=True),
|
sa.Column("first_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
sa.Column("last_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||||
sa.Column('external_id', sa.String(length=20), nullable=True),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_customer_local'))
|
sa.Column("external_id", sa.String(length=20), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_customer_local")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_product_pending
|
# sideshow_product_pending
|
||||||
op.create_table('sideshow_product_pending',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_product_pending",
|
||||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('scancode', sa.String(length=14), nullable=True),
|
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
sa.Column("scancode", sa.String(length=14), nullable=True),
|
||||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('brand_name', sa.String(length=100), nullable=True),
|
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||||
sa.Column('description', sa.String(length=255), nullable=True),
|
sa.Column("brand_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('size', sa.String(length=30), nullable=True),
|
sa.Column("description", sa.String(length=255), nullable=True),
|
||||||
sa.Column('weighed', sa.Boolean(), nullable=True),
|
sa.Column("size", sa.String(length=30), nullable=True),
|
||||||
sa.Column('vendor_name', sa.String(length=50), nullable=True),
|
sa.Column("weighed", sa.Boolean(), nullable=True),
|
||||||
sa.Column('vendor_item_code', sa.String(length=20), nullable=True),
|
sa.Column("vendor_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('unit_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
sa.Column("vendor_item_code", sa.String(length=20), nullable=True),
|
||||||
sa.Column('case_size', sa.Numeric(precision=9, scale=4), nullable=True),
|
sa.Column("unit_cost", sa.Numeric(precision=9, scale=5), nullable=True),
|
||||||
sa.Column('unit_price_reg', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("case_size", sa.Numeric(precision=9, scale=4), nullable=True),
|
||||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
sa.Column("unit_price_reg", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('notes', sa.Text(), nullable=True),
|
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||||
sa.Column('status', postgresql.ENUM('PENDING', 'READY', 'RESOLVED', name='pendingproductstatus', create_type=False), nullable=False),
|
sa.Column("notes", sa.Text(), nullable=True),
|
||||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
sa.Column(
|
||||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"status",
|
||||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name=op.f('fk_sideshow_product_pending_created_by_uuid_user')),
|
postgresql.ENUM(
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_product_pending'))
|
"PENDING",
|
||||||
|
"READY",
|
||||||
|
"RESOLVED",
|
||||||
|
name="pendingproductstatus",
|
||||||
|
create_type=False,
|
||||||
|
),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["created_by_uuid"],
|
||||||
|
["user.uuid"],
|
||||||
|
name=op.f("fk_sideshow_product_pending_created_by_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_product_pending")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_product_local
|
# sideshow_product_local
|
||||||
op.create_table('sideshow_product_local',
|
op.create_table(
|
||||||
sa.Column('scancode', sa.String(length=14), nullable=True),
|
"sideshow_product_local",
|
||||||
sa.Column('brand_name', sa.String(length=100), nullable=True),
|
sa.Column("scancode", sa.String(length=14), nullable=True),
|
||||||
sa.Column('description', sa.String(length=255), nullable=True),
|
sa.Column("brand_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('size', sa.String(length=30), nullable=True),
|
sa.Column("description", sa.String(length=255), nullable=True),
|
||||||
sa.Column('weighed', sa.Boolean(), nullable=True),
|
sa.Column("size", sa.String(length=30), nullable=True),
|
||||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
sa.Column("weighed", sa.Boolean(), nullable=True),
|
||||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||||
sa.Column('vendor_name', sa.String(length=50), nullable=True),
|
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||||
sa.Column('vendor_item_code', sa.String(length=20), nullable=True),
|
sa.Column("vendor_name", sa.String(length=50), nullable=True),
|
||||||
sa.Column('case_size', sa.Numeric(precision=9, scale=4), nullable=True),
|
sa.Column("vendor_item_code", sa.String(length=20), nullable=True),
|
||||||
sa.Column('unit_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
sa.Column("case_size", sa.Numeric(precision=9, scale=4), nullable=True),
|
||||||
sa.Column('unit_price_reg', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_cost", sa.Numeric(precision=9, scale=5), nullable=True),
|
||||||
sa.Column('notes', sa.Text(), nullable=True),
|
sa.Column("unit_price_reg", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("notes", sa.Text(), nullable=True),
|
||||||
sa.Column('external_id', sa.String(length=20), nullable=True),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_product_local'))
|
sa.Column("external_id", sa.String(length=20), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_product_local")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_order
|
# sideshow_order
|
||||||
op.create_table('sideshow_order',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_order",
|
||||||
sa.Column('order_id', sa.Integer(), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('store_id', sa.String(length=10), nullable=True),
|
sa.Column("order_id", sa.Integer(), nullable=False),
|
||||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
sa.Column("store_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('local_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('pending_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("local_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('customer_name', sa.String(length=100), nullable=True),
|
sa.Column("pending_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
sa.Column("customer_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||||
sa.Column('total_price', sa.Numeric(precision=10, scale=3), nullable=True),
|
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
sa.Column("total_price", sa.Numeric(precision=10, scale=3), nullable=True),
|
||||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['local_customer_uuid'], ['sideshow_customer_local.uuid'], name=op.f('fk_order_local_customer_uuid_local_customer')),
|
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['pending_customer_uuid'], ['sideshow_customer_pending.uuid'], name=op.f('fk_order_pending_customer_uuid_pending_customer')),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name=op.f('fk_order_created_by_uuid_user')),
|
["local_customer_uuid"],
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_order'))
|
["sideshow_customer_local.uuid"],
|
||||||
|
name=op.f("fk_order_local_customer_uuid_local_customer"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_customer_uuid"],
|
||||||
|
["sideshow_customer_pending.uuid"],
|
||||||
|
name=op.f("fk_order_pending_customer_uuid_pending_customer"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["created_by_uuid"],
|
||||||
|
["user.uuid"],
|
||||||
|
name=op.f("fk_order_created_by_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_order")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_order_item
|
# sideshow_order_item
|
||||||
op.create_table('sideshow_order_item',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_order_item",
|
||||||
sa.Column('order_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
sa.Column("order_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||||
sa.Column('local_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('pending_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("local_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('product_scancode', sa.String(length=14), nullable=True),
|
sa.Column("pending_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('product_brand', sa.String(length=100), nullable=True),
|
sa.Column("product_scancode", sa.String(length=14), nullable=True),
|
||||||
sa.Column('product_description', sa.String(length=255), nullable=True),
|
sa.Column("product_brand", sa.String(length=100), nullable=True),
|
||||||
sa.Column('product_size', sa.String(length=30), nullable=True),
|
sa.Column("product_description", sa.String(length=255), nullable=True),
|
||||||
sa.Column('product_weighed', sa.Boolean(), nullable=True),
|
sa.Column("product_size", sa.String(length=30), nullable=True),
|
||||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
sa.Column("product_weighed", sa.Boolean(), nullable=True),
|
||||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||||
sa.Column('case_size', sa.Numeric(precision=10, scale=4), nullable=True),
|
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||||
sa.Column('order_qty', sa.Numeric(precision=10, scale=4), nullable=False),
|
sa.Column("case_size", sa.Numeric(precision=10, scale=4), nullable=True),
|
||||||
sa.Column('order_uom', sa.String(length=10), nullable=False),
|
sa.Column("order_qty", sa.Numeric(precision=10, scale=4), nullable=False),
|
||||||
sa.Column('unit_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
sa.Column("order_uom", sa.String(length=10), nullable=False),
|
||||||
sa.Column('unit_price_reg', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_cost", sa.Numeric(precision=9, scale=5), nullable=True),
|
||||||
sa.Column('unit_price_sale', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_price_reg", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('sale_ends', sa.DateTime(timezone=True), nullable=True),
|
sa.Column("unit_price_sale", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('unit_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("sale_ends", sa.DateTime(timezone=True), nullable=True),
|
||||||
sa.Column('case_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('discount_percent', sa.Numeric(precision=5, scale=3), nullable=True),
|
sa.Column("case_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('total_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("discount_percent", sa.Numeric(precision=5, scale=3), nullable=True),
|
||||||
sa.Column('status_code', sa.Integer(), 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("status_code", sa.Integer(), nullable=False),
|
||||||
sa.Column('payment_transaction_number', sa.String(length=20), nullable=True),
|
sa.Column("paid_amount", sa.Numeric(precision=8, scale=3), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['order_uuid'], ['sideshow_order.uuid'], name=op.f('fk_sideshow_order_item_order_uuid_order')),
|
sa.Column("payment_transaction_number", sa.String(length=20), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['local_product_uuid'], ['sideshow_product_local.uuid'], name=op.f('fk_sideshow_order_item_local_product_uuid_local_product')),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['pending_product_uuid'], ['sideshow_product_pending.uuid'], name=op.f('fk_sideshow_order_item_pending_product_uuid_pending_product')),
|
["order_uuid"],
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_order_item'))
|
["sideshow_order.uuid"],
|
||||||
|
name=op.f("fk_sideshow_order_item_order_uuid_order"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["local_product_uuid"],
|
||||||
|
["sideshow_product_local.uuid"],
|
||||||
|
name=op.f("fk_sideshow_order_item_local_product_uuid_local_product"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_product_uuid"],
|
||||||
|
["sideshow_product_pending.uuid"],
|
||||||
|
name=op.f("fk_sideshow_order_item_pending_product_uuid_pending_product"),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_order_item")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_order_item_event
|
# sideshow_order_item_event
|
||||||
op.create_table('sideshow_order_item_event',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_order_item_event",
|
||||||
sa.Column('item_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('type_code', sa.Integer(), nullable=False),
|
sa.Column("item_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('occurred', sa.DateTime(timezone=True), nullable=False),
|
sa.Column("type_code", sa.Integer(), nullable=False),
|
||||||
sa.Column('actor_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("occurred", sa.DateTime(timezone=True), nullable=False),
|
||||||
sa.Column('note', sa.Text(), nullable=True),
|
sa.Column("actor_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['actor_uuid'], ['user.uuid'], name=op.f('fk_sideshow_order_item_event_actor_uuid_user')),
|
sa.Column("note", sa.Text(), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['item_uuid'], ['sideshow_order_item.uuid'], name=op.f('fk_sideshow_order_item_event_item_uuid_sideshow_order_item')),
|
sa.ForeignKeyConstraint(
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_order_item_event'))
|
["actor_uuid"],
|
||||||
|
["user.uuid"],
|
||||||
|
name=op.f("fk_sideshow_order_item_event_actor_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["item_uuid"],
|
||||||
|
["sideshow_order_item.uuid"],
|
||||||
|
name=op.f("fk_sideshow_order_item_event_item_uuid_sideshow_order_item"),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_order_item_event")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_batch_neworder
|
# sideshow_batch_neworder
|
||||||
op.create_table('sideshow_batch_neworder',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_batch_neworder",
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('description', sa.String(length=255), nullable=True),
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
sa.Column('notes', sa.Text(), nullable=True),
|
sa.Column("description", sa.String(length=255), nullable=True),
|
||||||
sa.Column('row_count', sa.Integer(), nullable=True),
|
sa.Column("notes", sa.Text(), nullable=True),
|
||||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
sa.Column("row_count", sa.Integer(), nullable=True),
|
||||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
sa.Column("status_code", sa.Integer(), nullable=True),
|
||||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
sa.Column("status_text", sa.String(length=255), nullable=True),
|
||||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||||
sa.Column('executed', sa.DateTime(timezone=True), nullable=True),
|
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('executed_by_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("executed", sa.DateTime(timezone=True), nullable=True),
|
||||||
sa.Column('store_id', sa.String(length=10), nullable=True),
|
sa.Column("executed_by_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
sa.Column("store_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('local_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('pending_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("local_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('customer_name', sa.String(length=100), nullable=True),
|
sa.Column("pending_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
sa.Column("customer_name", sa.String(length=100), nullable=True),
|
||||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||||
sa.Column('total_price', sa.Numeric(precision=10, scale=3), nullable=True),
|
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], name=op.f('fk_sideshow_batch_neworder_created_by_uuid_user')),
|
sa.Column("total_price", sa.Numeric(precision=10, scale=3), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['executed_by_uuid'], ['user.uuid'], name=op.f('fk_sideshow_batch_neworder_executed_by_uuid_user')),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['local_customer_uuid'], ['sideshow_customer_local.uuid'], name=op.f('fk_sideshow_batch_neworder_local_customer_uuid_local_customer')),
|
["created_by_uuid"],
|
||||||
sa.ForeignKeyConstraint(['pending_customer_uuid'], ['sideshow_customer_pending.uuid'], name=op.f('fk_sideshow_batch_neworder_pending_customer_uuid_pending_customer')),
|
["user.uuid"],
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_batch_neworder'))
|
name=op.f("fk_sideshow_batch_neworder_created_by_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["executed_by_uuid"],
|
||||||
|
["user.uuid"],
|
||||||
|
name=op.f("fk_sideshow_batch_neworder_executed_by_uuid_user"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["local_customer_uuid"],
|
||||||
|
["sideshow_customer_local.uuid"],
|
||||||
|
name=op.f("fk_sideshow_batch_neworder_local_customer_uuid_local_customer"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_customer_uuid"],
|
||||||
|
["sideshow_customer_pending.uuid"],
|
||||||
|
name=op.f(
|
||||||
|
"fk_sideshow_batch_neworder_pending_customer_uuid_pending_customer"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_batch_neworder")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# sideshow_batch_neworder_row
|
# sideshow_batch_neworder_row
|
||||||
op.create_table('sideshow_batch_neworder_row',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_batch_neworder_row",
|
||||||
sa.Column('batch_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
sa.Column("batch_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||||
sa.Column('modified', sa.DateTime(timezone=True), nullable=True),
|
sa.Column("status_text", sa.String(length=255), nullable=True),
|
||||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
sa.Column("modified", sa.DateTime(timezone=True), nullable=True),
|
||||||
sa.Column('local_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||||
sa.Column('pending_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
sa.Column("local_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('product_scancode', sa.String(length=14), nullable=True),
|
sa.Column("pending_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||||
sa.Column('product_brand', sa.String(length=100), nullable=True),
|
sa.Column("product_scancode", sa.String(length=14), nullable=True),
|
||||||
sa.Column('product_description', sa.String(length=255), nullable=True),
|
sa.Column("product_brand", sa.String(length=100), nullable=True),
|
||||||
sa.Column('product_size', sa.String(length=30), nullable=True),
|
sa.Column("product_description", sa.String(length=255), nullable=True),
|
||||||
sa.Column('product_weighed', sa.Boolean(), nullable=True),
|
sa.Column("product_size", sa.String(length=30), nullable=True),
|
||||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
sa.Column("product_weighed", sa.Boolean(), nullable=True),
|
||||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||||
sa.Column('case_size', sa.Numeric(precision=10, scale=4), nullable=True),
|
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||||
sa.Column('order_qty', sa.Numeric(precision=10, scale=4), nullable=False),
|
sa.Column("case_size", sa.Numeric(precision=10, scale=4), nullable=True),
|
||||||
sa.Column('order_uom', sa.String(length=10), nullable=False),
|
sa.Column("order_qty", sa.Numeric(precision=10, scale=4), nullable=False),
|
||||||
sa.Column('unit_cost', sa.Numeric(precision=9, scale=5), nullable=True),
|
sa.Column("order_uom", sa.String(length=10), nullable=False),
|
||||||
sa.Column('unit_price_reg', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_cost", sa.Numeric(precision=9, scale=5), nullable=True),
|
||||||
sa.Column('unit_price_sale', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_price_reg", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('sale_ends', sa.DateTime(timezone=True), nullable=True),
|
sa.Column("unit_price_sale", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('unit_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("sale_ends", sa.DateTime(timezone=True), nullable=True),
|
||||||
sa.Column('case_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("unit_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('discount_percent', sa.Numeric(precision=5, scale=3), nullable=True),
|
sa.Column("case_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.Column('total_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
sa.Column("discount_percent", sa.Numeric(precision=5, scale=3), nullable=True),
|
||||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
sa.Column("total_price", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['batch_uuid'], ['sideshow_batch_neworder.uuid'], name=op.f('fk_sideshow_batch_neworder_row_batch_uuid_batch_neworder')),
|
sa.Column("status_code", sa.Integer(), nullable=True),
|
||||||
sa.ForeignKeyConstraint(['local_product_uuid'], ['sideshow_product_local.uuid'], name=op.f('fk_sideshow_batch_neworder_row_local_product_uuid_local_product')),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['pending_product_uuid'], ['sideshow_product_pending.uuid'], name=op.f('fk_sideshow_batch_neworder_row_pending_product_uuid_pending_product')),
|
["batch_uuid"],
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_batch_neworder_row'))
|
["sideshow_batch_neworder.uuid"],
|
||||||
|
name=op.f("fk_sideshow_batch_neworder_row_batch_uuid_batch_neworder"),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["local_product_uuid"],
|
||||||
|
["sideshow_product_local.uuid"],
|
||||||
|
name=op.f(
|
||||||
|
"fk_sideshow_batch_neworder_row_local_product_uuid_local_product"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_product_uuid"],
|
||||||
|
["sideshow_product_pending.uuid"],
|
||||||
|
name=op.f(
|
||||||
|
"fk_sideshow_batch_neworder_row_pending_product_uuid_pending_product"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_batch_neworder_row")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
|
|
||||||
# sideshow_batch_neworder*
|
# sideshow_batch_neworder*
|
||||||
op.drop_table('sideshow_batch_neworder_row')
|
op.drop_table("sideshow_batch_neworder_row")
|
||||||
op.drop_table('sideshow_batch_neworder')
|
op.drop_table("sideshow_batch_neworder")
|
||||||
|
|
||||||
# sideshow_order_item_event
|
# sideshow_order_item_event
|
||||||
op.drop_table('sideshow_order_item_event')
|
op.drop_table("sideshow_order_item_event")
|
||||||
|
|
||||||
# sideshow_order_item
|
# sideshow_order_item
|
||||||
op.drop_table('sideshow_order_item')
|
op.drop_table("sideshow_order_item")
|
||||||
|
|
||||||
# sideshow_order
|
# sideshow_order
|
||||||
op.drop_table('sideshow_order')
|
op.drop_table("sideshow_order")
|
||||||
|
|
||||||
# sideshow_product_local
|
# sideshow_product_local
|
||||||
op.drop_table('sideshow_product_local')
|
op.drop_table("sideshow_product_local")
|
||||||
|
|
||||||
# sideshow_product_pending
|
# sideshow_product_pending
|
||||||
op.drop_table('sideshow_product_pending')
|
op.drop_table("sideshow_product_pending")
|
||||||
|
|
||||||
# sideshow_customer_local
|
# sideshow_customer_local
|
||||||
op.drop_table('sideshow_customer_local')
|
op.drop_table("sideshow_customer_local")
|
||||||
|
|
||||||
# sideshow_customer_pending
|
# sideshow_customer_pending
|
||||||
op.drop_table('sideshow_customer_pending')
|
op.drop_table("sideshow_customer_pending")
|
||||||
|
|
||||||
# enums
|
# enums
|
||||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingproductstatus').drop(op.get_bind())
|
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingproductstatus").drop(
|
||||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingcustomerstatus').drop(op.get_bind())
|
op.get_bind()
|
||||||
|
)
|
||||||
|
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingcustomerstatus").drop(
|
||||||
|
op.get_bind()
|
||||||
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ Revises: 7a6df83afbd4
|
||||||
Create Date: 2025-01-27 17:48:20.638664
|
Create Date: 2025-01-27 17:48:20.638664
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = 'a4273360d379'
|
revision: str = "a4273360d379"
|
||||||
down_revision: Union[str, None] = '7a6df83afbd4'
|
down_revision: Union[str, None] = "7a6df83afbd4"
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
@ -22,18 +23,19 @@ depends_on: Union[str, Sequence[str], None] = None
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
|
|
||||||
# sideshow_store
|
# sideshow_store
|
||||||
op.create_table('sideshow_store',
|
op.create_table(
|
||||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
"sideshow_store",
|
||||||
sa.Column('store_id', sa.String(length=10), nullable=False),
|
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||||
sa.Column('name', sa.String(length=100), nullable=False),
|
sa.Column("store_id", sa.String(length=10), nullable=False),
|
||||||
sa.Column('archived', sa.Boolean(), nullable=False),
|
sa.Column("name", sa.String(length=100), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_store')),
|
sa.Column("archived", sa.Boolean(), nullable=False),
|
||||||
sa.UniqueConstraint('store_id', name=op.f('uq_sideshow_store_store_id')),
|
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_store")),
|
||||||
sa.UniqueConstraint('name', name=op.f('uq_sideshow_store_name'))
|
sa.UniqueConstraint("store_id", name=op.f("uq_sideshow_store_store_id")),
|
||||||
|
sa.UniqueConstraint("name", name=op.f("uq_sideshow_store_name")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
|
|
||||||
# sideshow_store
|
# sideshow_store
|
||||||
op.drop_table('sideshow_store')
|
op.drop_table("sideshow_store")
|
||||||
|
|
|
@ -5,6 +5,7 @@ Revises: 13af2ffbc0e0
|
||||||
Create Date: 2025-02-20 12:08:27.374172
|
Create Date: 2025-02-20 12:08:27.374172
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Sequence, Union
|
from typing import Sequence, Union
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
||||||
from alembic_postgresql_enum import TableReference
|
from alembic_postgresql_enum import TableReference
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision: str = 'fd8a2527bd30'
|
revision: str = "fd8a2527bd30"
|
||||||
down_revision: Union[str, None] = '13af2ffbc0e0'
|
down_revision: Union[str, None] = "13af2ffbc0e0"
|
||||||
branch_labels: Union[str, Sequence[str], None] = None
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
depends_on: Union[str, Sequence[str], None] = None
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
@ -23,19 +24,31 @@ def upgrade() -> None:
|
||||||
|
|
||||||
# pendingcustomerstatus
|
# pendingcustomerstatus
|
||||||
op.sync_enum_values(
|
op.sync_enum_values(
|
||||||
enum_schema='public',
|
enum_schema="public",
|
||||||
enum_name='pendingcustomerstatus',
|
enum_name="pendingcustomerstatus",
|
||||||
new_values=['PENDING', 'READY', 'RESOLVED', 'IGNORED'],
|
new_values=["PENDING", "READY", "RESOLVED", "IGNORED"],
|
||||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_customer_pending', column_name='status')],
|
affected_columns=[
|
||||||
|
TableReference(
|
||||||
|
table_schema="public",
|
||||||
|
table_name="sideshow_customer_pending",
|
||||||
|
column_name="status",
|
||||||
|
)
|
||||||
|
],
|
||||||
enum_values_to_rename=[],
|
enum_values_to_rename=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
# pendingproductstatus
|
# pendingproductstatus
|
||||||
op.sync_enum_values(
|
op.sync_enum_values(
|
||||||
enum_schema='public',
|
enum_schema="public",
|
||||||
enum_name='pendingproductstatus',
|
enum_name="pendingproductstatus",
|
||||||
new_values=['PENDING', 'READY', 'RESOLVED', 'IGNORED'],
|
new_values=["PENDING", "READY", "RESOLVED", "IGNORED"],
|
||||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_product_pending', column_name='status')],
|
affected_columns=[
|
||||||
|
TableReference(
|
||||||
|
table_schema="public",
|
||||||
|
table_name="sideshow_product_pending",
|
||||||
|
column_name="status",
|
||||||
|
)
|
||||||
|
],
|
||||||
enum_values_to_rename=[],
|
enum_values_to_rename=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,18 +57,30 @@ def downgrade() -> None:
|
||||||
|
|
||||||
# pendingproductstatus
|
# pendingproductstatus
|
||||||
op.sync_enum_values(
|
op.sync_enum_values(
|
||||||
enum_schema='public',
|
enum_schema="public",
|
||||||
enum_name='pendingproductstatus',
|
enum_name="pendingproductstatus",
|
||||||
new_values=['PENDING', 'READY', 'RESOLVED'],
|
new_values=["PENDING", "READY", "RESOLVED"],
|
||||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_product_pending', column_name='status')],
|
affected_columns=[
|
||||||
|
TableReference(
|
||||||
|
table_schema="public",
|
||||||
|
table_name="sideshow_product_pending",
|
||||||
|
column_name="status",
|
||||||
|
)
|
||||||
|
],
|
||||||
enum_values_to_rename=[],
|
enum_values_to_rename=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
# pendingcustomerstatus
|
# pendingcustomerstatus
|
||||||
op.sync_enum_values(
|
op.sync_enum_values(
|
||||||
enum_schema='public',
|
enum_schema="public",
|
||||||
enum_name='pendingcustomerstatus',
|
enum_name="pendingcustomerstatus",
|
||||||
new_values=['PENDING', 'READY', 'RESOLVED'],
|
new_values=["PENDING", "READY", "RESOLVED"],
|
||||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_customer_pending', column_name='status')],
|
affected_columns=[
|
||||||
|
TableReference(
|
||||||
|
table_schema="public",
|
||||||
|
table_name="sideshow_customer_pending",
|
||||||
|
column_name="status",
|
||||||
|
)
|
||||||
|
],
|
||||||
enum_values_to_rename=[],
|
enum_values_to_rename=[],
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,10 +47,11 @@ class NewOrderBatch(model.BatchMixin, model.Base):
|
||||||
Generic batch attributes (undocumented below) are inherited from
|
Generic batch attributes (undocumented below) are inherited from
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.batch.BatchMixin`.
|
:class:`~wuttjamaican:wuttjamaican.db.model.batch.BatchMixin`.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_batch_neworder'
|
|
||||||
__batchrow_class__ = 'NewOrderBatchRow'
|
|
||||||
|
|
||||||
batch_type = 'neworder'
|
__tablename__ = "sideshow_batch_neworder"
|
||||||
|
__batchrow_class__ = "NewOrderBatchRow"
|
||||||
|
|
||||||
|
batch_type = "neworder"
|
||||||
"""
|
"""
|
||||||
Official :term:`batch type` key.
|
Official :term:`batch type` key.
|
||||||
"""
|
"""
|
||||||
|
@ -58,8 +59,12 @@ class NewOrderBatch(model.BatchMixin, model.Base):
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def __table_args__(cls):
|
def __table_args__(cls):
|
||||||
return cls.__default_table_args__() + (
|
return cls.__default_table_args__() + (
|
||||||
sa.ForeignKeyConstraint(['local_customer_uuid'], ['sideshow_customer_local.uuid']),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['pending_customer_uuid'], ['sideshow_customer_pending.uuid']),
|
["local_customer_uuid"], ["sideshow_customer_local.uuid"]
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_customer_uuid"], ["sideshow_customer_pending.uuid"]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
STATUS_OK = 1
|
STATUS_OK = 1
|
||||||
|
@ -68,62 +73,88 @@ class NewOrderBatch(model.BatchMixin, model.Base):
|
||||||
STATUS_OK: "ok",
|
STATUS_OK: "ok",
|
||||||
}
|
}
|
||||||
|
|
||||||
store_id = sa.Column(sa.String(length=10), nullable=True, doc="""
|
store_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the store to which the order pertains, if applicable.
|
ID of the store to which the order pertains, if applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
customer_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
customer_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Proper account ID for the :term:`external customer` to which the
|
Proper account ID for the :term:`external customer` to which the
|
||||||
order pertains, if applicable.
|
order pertains, if applicable.
|
||||||
|
|
||||||
See also :attr:`local_customer` and :attr:`pending_customer`.
|
See also :attr:`local_customer` and :attr:`pending_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
local_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
local_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def local_customer(cls):
|
def local_customer(cls):
|
||||||
return orm.relationship(
|
return orm.relationship(
|
||||||
'LocalCustomer',
|
"LocalCustomer",
|
||||||
back_populates='new_order_batches',
|
back_populates="new_order_batches",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
||||||
for the order, if applicable.
|
for the order, if applicable.
|
||||||
|
|
||||||
See also :attr:`customer_id` and :attr:`pending_customer`.
|
See also :attr:`customer_id` and :attr:`pending_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
pending_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
pending_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def pending_customer(cls):
|
def pending_customer(cls):
|
||||||
return orm.relationship(
|
return orm.relationship(
|
||||||
'PendingCustomer',
|
"PendingCustomer",
|
||||||
back_populates='new_order_batches',
|
back_populates="new_order_batches",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.customers.PendingCustomer`
|
:class:`~sideshow.db.model.customers.PendingCustomer`
|
||||||
record for the order, if applicable.
|
record for the order, if applicable.
|
||||||
|
|
||||||
See also :attr:`customer_id` and :attr:`local_customer`.
|
See also :attr:`customer_id` and :attr:`local_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
customer_name = sa.Column(sa.String(length=100), nullable=True, doc="""
|
customer_name = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name for the customer account.
|
Name for the customer account.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
phone_number = sa.Column(sa.String(length=20), nullable=True, doc="""
|
phone_number = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Phone number for the customer.
|
Phone number for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
email_address = sa.Column(sa.String(length=255), nullable=True, doc="""
|
email_address = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Email address for the customer.
|
Email address for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
total_price = sa.Column(sa.Numeric(precision=10, scale=3), nullable=True, doc="""
|
total_price = sa.Column(
|
||||||
|
sa.Numeric(precision=10, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Full price (not including tax etc.) for all items on the order.
|
Full price (not including tax etc.) for all items on the order.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
|
@ -134,14 +165,19 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
Generic row attributes (undocumented below) are inherited from
|
Generic row attributes (undocumented below) are inherited from
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.batch.BatchRowMixin`.
|
:class:`~wuttjamaican:wuttjamaican.db.model.batch.BatchRowMixin`.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_batch_neworder_row'
|
|
||||||
|
__tablename__ = "sideshow_batch_neworder_row"
|
||||||
__batch_class__ = NewOrderBatch
|
__batch_class__ = NewOrderBatch
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def __table_args__(cls):
|
def __table_args__(cls):
|
||||||
return cls.__default_table_args__() + (
|
return cls.__default_table_args__() + (
|
||||||
sa.ForeignKeyConstraint(['local_product_uuid'], ['sideshow_product_local.uuid']),
|
sa.ForeignKeyConstraint(
|
||||||
sa.ForeignKeyConstraint(['pending_product_uuid'], ['sideshow_product_pending.uuid']),
|
["local_product_uuid"], ["sideshow_product_local.uuid"]
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["pending_product_uuid"], ["sideshow_product_pending.uuid"]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
STATUS_OK = 1
|
STATUS_OK = 1
|
||||||
|
@ -172,44 +208,53 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
Dict of possible status code -> label options.
|
Dict of possible status code -> label options.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
product_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
product_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Proper ID for the :term:`external product` which the order item
|
Proper ID for the :term:`external product` which the order item
|
||||||
represents, if applicable.
|
represents, if applicable.
|
||||||
|
|
||||||
See also :attr:`local_product` and :attr:`pending_product`.
|
See also :attr:`local_product` and :attr:`pending_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
local_product_uuid = sa.Column(model.UUID(), nullable=True)
|
local_product_uuid = sa.Column(model.UUID(), nullable=True)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def local_product(cls):
|
def local_product(cls):
|
||||||
return orm.relationship(
|
return orm.relationship(
|
||||||
'LocalProduct',
|
"LocalProduct",
|
||||||
back_populates='new_order_batch_rows',
|
back_populates="new_order_batch_rows",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.products.LocalProduct` record
|
:class:`~sideshow.db.model.products.LocalProduct` record
|
||||||
for the order item, if applicable.
|
for the order item, if applicable.
|
||||||
|
|
||||||
See also :attr:`product_id` and :attr:`pending_product`.
|
See also :attr:`product_id` and :attr:`pending_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
pending_product_uuid = sa.Column(model.UUID(), nullable=True)
|
pending_product_uuid = sa.Column(model.UUID(), nullable=True)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def pending_product(cls):
|
def pending_product(cls):
|
||||||
return orm.relationship(
|
return orm.relationship(
|
||||||
'PendingProduct',
|
"PendingProduct",
|
||||||
back_populates='new_order_batch_rows',
|
back_populates="new_order_batch_rows",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.products.PendingProduct` record
|
:class:`~sideshow.db.model.products.PendingProduct` record
|
||||||
for the order item, if applicable.
|
for the order item, if applicable.
|
||||||
|
|
||||||
See also :attr:`product_id` and :attr:`local_product`.
|
See also :attr:`product_id` and :attr:`local_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_scancode = sa.Column(sa.String(length=14), nullable=True, doc="""
|
product_scancode = sa.Column(
|
||||||
|
sa.String(length=14),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Scancode for the product, as string.
|
Scancode for the product, as string.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -221,61 +266,109 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
That may change eventually, depending on POS integration
|
That may change eventually, depending on POS integration
|
||||||
scenarios that come up. Maybe a config option to declare
|
scenarios that come up. Maybe a config option to declare
|
||||||
whether check digit should be included or not, etc.
|
whether check digit should be included or not, etc.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_brand = sa.Column(sa.String(length=100), nullable=True, doc="""
|
product_brand = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Brand name for the product - up to 100 chars.
|
Brand name for the product - up to 100 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_description = sa.Column(sa.String(length=255), nullable=True, doc="""
|
product_description = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Description for the product - up to 255 chars.
|
Description for the product - up to 255 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_size = sa.Column(sa.String(length=30), nullable=True, doc="""
|
product_size = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Size of the product, as string - up to 30 chars.
|
Size of the product, as string - up to 30 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_weighed = sa.Column(sa.Boolean(), nullable=True, doc="""
|
product_weighed = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the product is sold by weight; default is null.
|
Flag indicating the product is sold by weight; default is null.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_id = sa.Column(sa.String(length=10), nullable=True, doc="""
|
department_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the department to which the product belongs, if known.
|
ID of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_name = sa.Column(sa.String(length=30), nullable=True, doc="""
|
department_name = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of the department to which the product belongs, if known.
|
Name of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
special_order = sa.Column(sa.Boolean(), nullable=True, doc="""
|
special_order = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the item is a "special order" - e.g. something not
|
Flag indicating the item is a "special order" - e.g. something not
|
||||||
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="""
|
vendor_name = sa.Column(
|
||||||
|
sa.String(length=50),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of vendor from which product may be purchased, if known. See
|
Name of vendor from which product may be purchased, if known. See
|
||||||
also :attr:`vendor_item_code`.
|
also :attr:`vendor_item_code`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
vendor_item_code = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Item code (SKU) to use when ordering this product from the vendor
|
Item code (SKU) to use when ordering this product from the vendor
|
||||||
identified by :attr:`vendor_name`, if known.
|
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.
|
||||||
|
|
||||||
If this is not set, then customer cannot order a "case" of the item.
|
If this is not set, then customer cannot order a "case" of the item.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_qty = sa.Column(sa.Numeric(precision=10, scale=4), nullable=False, doc="""
|
order_qty = sa.Column(
|
||||||
|
sa.Numeric(precision=10, scale=4),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Quantity (as decimal) of product being ordered.
|
Quantity (as decimal) of product being ordered.
|
||||||
|
|
||||||
This must be interpreted along with :attr:`order_uom` to determine
|
This must be interpreted along with :attr:`order_uom` to determine
|
||||||
the *complete* order quantity, e.g. "2 cases".
|
the *complete* order quantity, e.g. "2 cases".
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_uom = sa.Column(sa.String(length=10), nullable=False, doc="""
|
order_uom = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Code indicating the unit of measure for product being ordered.
|
Code indicating the unit of measure for product being ordered.
|
||||||
|
|
||||||
This should be one of the codes from
|
This should be one of the codes from
|
||||||
|
@ -284,31 +377,51 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
Sideshow will treat :data:`~sideshow.enum.ORDER_UOM_CASE`
|
Sideshow will treat :data:`~sideshow.enum.ORDER_UOM_CASE`
|
||||||
differently but :data:`~sideshow.enum.ORDER_UOM_UNIT` and others
|
differently but :data:`~sideshow.enum.ORDER_UOM_UNIT` and others
|
||||||
are all treated the same (i.e. "unit" is assumed).
|
are all treated the same (i.e. "unit" is assumed).
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
|
unit_cost = sa.Column(
|
||||||
|
sa.Numeric(precision=9, scale=5),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Cost of goods amount for one "unit" (not "case") of the product,
|
Cost of goods amount for one "unit" (not "case") of the product,
|
||||||
as decimal to 4 places.
|
as decimal to 4 places.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_reg = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_reg = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Regular price for the item unit. Unless a sale is in effect,
|
Regular price for the item unit. Unless a sale is in effect,
|
||||||
:attr:`unit_price_quoted` will typically match this value.
|
:attr:`unit_price_quoted` will typically match this value.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_sale = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_sale = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Sale price for the item unit, if applicable. If set, then
|
Sale price for the item unit, if applicable. If set, then
|
||||||
:attr:`unit_price_quoted` will typically match this value. See
|
:attr:`unit_price_quoted` will typically match this value. See
|
||||||
also :attr:`sale_ends`.
|
also :attr:`sale_ends`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
sale_ends = sa.Column(sa.DateTime(timezone=True), nullable=True, doc="""
|
sale_ends = sa.Column(
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
End date/time for the sale in effect, if any.
|
End date/time for the sale in effect, if any.
|
||||||
|
|
||||||
This is only relevant if :attr:`unit_price_sale` is set.
|
This is only relevant if :attr:`unit_price_sale` is set.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_quoted = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_quoted = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Quoted price for the item unit. This is the "effective" unit
|
Quoted price for the item unit. This is the "effective" unit
|
||||||
price, which is used to calculate :attr:`total_price`.
|
price, which is used to calculate :attr:`total_price`.
|
||||||
|
|
||||||
|
@ -317,21 +430,33 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
:attr:`unit_price_sale`.
|
:attr:`unit_price_sale`.
|
||||||
|
|
||||||
See also :attr:`case_price_quoted`, if applicable.
|
See also :attr:`case_price_quoted`, if applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
case_price_quoted = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
case_price_quoted = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Quoted price for a "case" of the item, if applicable.
|
Quoted price for a "case" of the item, if applicable.
|
||||||
|
|
||||||
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
||||||
used for calculations.
|
used for calculations.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
discount_percent = sa.Column(sa.Numeric(precision=5, scale=3), nullable=True, doc="""
|
discount_percent = sa.Column(
|
||||||
|
sa.Numeric(precision=5, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Discount percent to apply when calculating :attr:`total_price`, if
|
Discount percent to apply when calculating :attr:`total_price`, if
|
||||||
applicable.
|
applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
total_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
total_price = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Full price (not including tax etc.) which the customer is quoted
|
Full price (not including tax etc.) which the customer is quoted
|
||||||
for the order item.
|
for the order item.
|
||||||
|
|
||||||
|
@ -342,7 +467,8 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||||
* :attr:`order_uom`
|
* :attr:`order_uom`
|
||||||
* :attr:`case_size`
|
* :attr:`case_size`
|
||||||
* :attr:`discount_percent`
|
* :attr:`discount_percent`
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.pending_product or self.product_description or "")
|
return str(self.pending_product or self.product_description or "")
|
||||||
|
|
|
@ -42,25 +42,45 @@ class CustomerMixin:
|
||||||
* :class:`PendingCustomer`
|
* :class:`PendingCustomer`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
full_name = sa.Column(sa.String(length=100), nullable=True, doc="""
|
full_name = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Full display name for the customer account.
|
Full display name for the customer account.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
first_name = sa.Column(sa.String(length=50), nullable=True, doc="""
|
first_name = sa.Column(
|
||||||
|
sa.String(length=50),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
First name of the customer.
|
First name of the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
last_name = sa.Column(sa.String(length=50), nullable=True, doc="""
|
last_name = sa.Column(
|
||||||
|
sa.String(length=50),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Last name of the customer.
|
Last name of the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
phone_number = sa.Column(sa.String(length=20), nullable=True, doc="""
|
phone_number = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Phone number for the customer.
|
Phone number for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
email_address = sa.Column(sa.String(length=255), nullable=True, doc="""
|
email_address = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Email address for the customer.
|
Email address for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.full_name or ""
|
return self.full_name or ""
|
||||||
|
@ -78,35 +98,42 @@ class LocalCustomer(CustomerMixin, model.Base):
|
||||||
:term:`pending customer` is executed, a new record is added to
|
:term:`pending customer` is executed, a new record is added to
|
||||||
this local customers table, for lookup next time.
|
this local customers table, for lookup next time.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_customer_local'
|
|
||||||
|
__tablename__ = "sideshow_customer_local"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
external_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
external_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the proper customer account associated with this record, if
|
ID of the proper customer account associated with this record, if
|
||||||
applicable.
|
applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
orders = orm.relationship(
|
orders = orm.relationship(
|
||||||
'Order',
|
"Order",
|
||||||
order_by='Order.order_id.desc()',
|
order_by="Order.order_id.desc()",
|
||||||
back_populates='local_customer',
|
back_populates="local_customer",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`~sideshow.db.model.orders.Order` records
|
List of :class:`~sideshow.db.model.orders.Order` records
|
||||||
associated with this customer.
|
associated with this customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
new_order_batches = orm.relationship(
|
new_order_batches = orm.relationship(
|
||||||
'NewOrderBatch',
|
"NewOrderBatch",
|
||||||
order_by='NewOrderBatch.id.desc()',
|
order_by="NewOrderBatch.id.desc()",
|
||||||
back_populates='local_customer',
|
back_populates="local_customer",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of
|
List of
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
||||||
records associated with this customer.
|
records associated with this customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PendingCustomer(CustomerMixin, model.Base):
|
class PendingCustomer(CustomerMixin, model.Base):
|
||||||
|
@ -121,25 +148,38 @@ class PendingCustomer(CustomerMixin, model.Base):
|
||||||
is executed, a new record is added to the :term:`local customers
|
is executed, a new record is added to the :term:`local customers
|
||||||
<local customer>` table, for lookup next time.
|
<local customer>` table, for lookup next time.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_customer_pending'
|
|
||||||
|
__tablename__ = "sideshow_customer_pending"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
customer_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
customer_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the proper customer account associated with this record, if
|
ID of the proper customer account associated with this record, if
|
||||||
applicable.
|
applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
status = sa.Column(sa.Enum(PendingCustomerStatus), nullable=False, doc="""
|
status = sa.Column(
|
||||||
|
sa.Enum(PendingCustomerStatus),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Status code for the customer record.
|
Status code for the customer record.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created = sa.Column(sa.DateTime(timezone=True), nullable=False,
|
created = sa.Column(
|
||||||
default=datetime.datetime.now, doc="""
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=False,
|
||||||
|
default=datetime.datetime.now,
|
||||||
|
doc="""
|
||||||
Timestamp when the customer record was created.
|
Timestamp when the customer record was created.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created_by_uuid = model.uuid_fk_column('user.uuid', nullable=False)
|
created_by_uuid = model.uuid_fk_column("user.uuid", nullable=False)
|
||||||
created_by = orm.relationship(
|
created_by = orm.relationship(
|
||||||
model.User,
|
model.User,
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
|
@ -147,25 +187,28 @@ class PendingCustomer(CustomerMixin, model.Base):
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||||
created the customer record.
|
created the customer record.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
orders = orm.relationship(
|
orders = orm.relationship(
|
||||||
'Order',
|
"Order",
|
||||||
order_by='Order.order_id.desc()',
|
order_by="Order.order_id.desc()",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='pending_customer',
|
back_populates="pending_customer",
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`~sideshow.db.model.orders.Order` records
|
List of :class:`~sideshow.db.model.orders.Order` records
|
||||||
associated with this customer.
|
associated with this customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
new_order_batches = orm.relationship(
|
new_order_batches = orm.relationship(
|
||||||
'NewOrderBatch',
|
"NewOrderBatch",
|
||||||
order_by='NewOrderBatch.id.desc()',
|
order_by="NewOrderBatch.id.desc()",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='pending_customer',
|
back_populates="pending_customer",
|
||||||
doc="""
|
doc="""
|
||||||
List of
|
List of
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
||||||
records associated with this customer.
|
records associated with this customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
|
@ -41,93 +41,134 @@ class Order(model.Base):
|
||||||
Usually, orders are created by way of a
|
Usually, orders are created by way of a
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`.
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_order'
|
|
||||||
|
__tablename__ = "sideshow_order"
|
||||||
|
|
||||||
# TODO: this feels a bit hacky yet but it does avoid problems
|
# TODO: this feels a bit hacky yet but it does avoid problems
|
||||||
# showing the Orders grid for a PendingCustomer
|
# showing the Orders grid for a PendingCustomer
|
||||||
__colanderalchemy_config__ = {
|
__colanderalchemy_config__ = {
|
||||||
'excludes': ['items'],
|
"excludes": ["items"],
|
||||||
}
|
}
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
order_id = sa.Column(sa.Integer(), nullable=False, doc="""
|
order_id = sa.Column(
|
||||||
|
sa.Integer(),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Unique ID for the order.
|
Unique ID for the order.
|
||||||
|
|
||||||
When the order is created from New Order Batch, this order ID will
|
When the order is created from New Order Batch, this order ID will
|
||||||
match the batch ID.
|
match the batch ID.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
store_id = sa.Column(sa.String(length=10), nullable=True, doc="""
|
store_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the store to which the order pertains, if applicable.
|
ID of the store to which the order pertains, if applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
store = orm.relationship(
|
store = orm.relationship(
|
||||||
'Store',
|
"Store",
|
||||||
primaryjoin='Store.store_id == Order.store_id',
|
primaryjoin="Store.store_id == Order.store_id",
|
||||||
foreign_keys='Order.store_id',
|
foreign_keys="Order.store_id",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the :class:`~sideshow.db.model.stores.Store`
|
Reference to the :class:`~sideshow.db.model.stores.Store`
|
||||||
record, if applicable.
|
record, if applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
customer_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
customer_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Proper account ID for the :term:`external customer` to which the
|
Proper account ID for the :term:`external customer` to which the
|
||||||
order pertains, if applicable.
|
order pertains, if applicable.
|
||||||
|
|
||||||
See also :attr:`local_customer` and :attr:`pending_customer`.
|
See also :attr:`local_customer` and :attr:`pending_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
local_customer_uuid = model.uuid_fk_column('sideshow_customer_local.uuid', nullable=True)
|
local_customer_uuid = model.uuid_fk_column(
|
||||||
|
"sideshow_customer_local.uuid", nullable=True
|
||||||
|
)
|
||||||
local_customer = orm.relationship(
|
local_customer = orm.relationship(
|
||||||
'LocalCustomer',
|
"LocalCustomer",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='orders',
|
back_populates="orders",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
||||||
for the order, if applicable.
|
for the order, if applicable.
|
||||||
|
|
||||||
See also :attr:`customer_id` and :attr:`pending_customer`.
|
See also :attr:`customer_id` and :attr:`pending_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
pending_customer_uuid = model.uuid_fk_column('sideshow_customer_pending.uuid', nullable=True)
|
pending_customer_uuid = model.uuid_fk_column(
|
||||||
|
"sideshow_customer_pending.uuid", nullable=True
|
||||||
|
)
|
||||||
pending_customer = orm.relationship(
|
pending_customer = orm.relationship(
|
||||||
'PendingCustomer',
|
"PendingCustomer",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='orders',
|
back_populates="orders",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.customers.PendingCustomer` record
|
:class:`~sideshow.db.model.customers.PendingCustomer` record
|
||||||
for the order, if applicable.
|
for the order, if applicable.
|
||||||
|
|
||||||
See also :attr:`customer_id` and :attr:`local_customer`.
|
See also :attr:`customer_id` and :attr:`local_customer`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
customer_name = sa.Column(sa.String(length=100), nullable=True, doc="""
|
customer_name = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name for the customer account.
|
Name for the customer account.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
phone_number = sa.Column(sa.String(length=20), nullable=True, doc="""
|
phone_number = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Phone number for the customer.
|
Phone number for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
email_address = sa.Column(sa.String(length=255), nullable=True, doc="""
|
email_address = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Email address for the customer.
|
Email address for the customer.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
total_price = sa.Column(sa.Numeric(precision=10, scale=3), nullable=True, doc="""
|
total_price = sa.Column(
|
||||||
|
sa.Numeric(precision=10, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Full price (not including tax etc.) for all items on the order.
|
Full price (not including tax etc.) for all items on the order.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created = sa.Column(sa.DateTime(timezone=True), nullable=False, default=datetime.datetime.now, doc="""
|
created = sa.Column(
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=False,
|
||||||
|
default=datetime.datetime.now,
|
||||||
|
doc="""
|
||||||
Timestamp when the order was created.
|
Timestamp when the order was created.
|
||||||
|
|
||||||
If the order is created via New Order Batch, this will match the
|
If the order is created via New Order Batch, this will match the
|
||||||
batch execution timestamp.
|
batch execution timestamp.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created_by_uuid = model.uuid_fk_column('user.uuid', nullable=False)
|
created_by_uuid = model.uuid_fk_column("user.uuid", nullable=False)
|
||||||
created_by = orm.relationship(
|
created_by = orm.relationship(
|
||||||
model.User,
|
model.User,
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
|
@ -135,17 +176,19 @@ class Order(model.Base):
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||||
created the order.
|
created the order.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
items = orm.relationship(
|
items = orm.relationship(
|
||||||
'OrderItem',
|
"OrderItem",
|
||||||
collection_class=ordering_list('sequence', count_from=1),
|
collection_class=ordering_list("sequence", count_from=1),
|
||||||
cascade='all, delete-orphan',
|
cascade="all, delete-orphan",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='order',
|
back_populates="order",
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`OrderItem` records belonging to the order.
|
List of :class:`OrderItem` records belonging to the order.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.order_id)
|
return str(self.order_id)
|
||||||
|
@ -159,58 +202,77 @@ class OrderItem(model.Base):
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||||
records.
|
records.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_order_item'
|
|
||||||
|
__tablename__ = "sideshow_order_item"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
order_uuid = model.uuid_fk_column('sideshow_order.uuid', nullable=False)
|
order_uuid = model.uuid_fk_column("sideshow_order.uuid", nullable=False)
|
||||||
order = orm.relationship(
|
order = orm.relationship(
|
||||||
Order,
|
Order,
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='items',
|
back_populates="items",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the :class:`Order` to which the item belongs.
|
Reference to the :class:`Order` to which the item belongs.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
sequence = sa.Column(sa.Integer(), nullable=False, doc="""
|
sequence = sa.Column(
|
||||||
|
sa.Integer(),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
1-based numeric sequence for the item, i.e. its line number within
|
1-based numeric sequence for the item, i.e. its line number within
|
||||||
the order.
|
the order.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
product_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Proper ID for the :term:`external product` which the order item
|
Proper ID for the :term:`external product` which the order item
|
||||||
represents, if applicable.
|
represents, if applicable.
|
||||||
|
|
||||||
See also :attr:`local_product` and :attr:`pending_product`.
|
See also :attr:`local_product` and :attr:`pending_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
local_product_uuid = model.uuid_fk_column('sideshow_product_local.uuid', nullable=True)
|
local_product_uuid = model.uuid_fk_column(
|
||||||
|
"sideshow_product_local.uuid", nullable=True
|
||||||
|
)
|
||||||
local_product = orm.relationship(
|
local_product = orm.relationship(
|
||||||
'LocalProduct',
|
"LocalProduct",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='order_items',
|
back_populates="order_items",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.products.LocalProduct` record for
|
:class:`~sideshow.db.model.products.LocalProduct` record for
|
||||||
the order item, if applicable.
|
the order item, if applicable.
|
||||||
|
|
||||||
See also :attr:`product_id` and :attr:`pending_product`.
|
See also :attr:`product_id` and :attr:`pending_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
pending_product_uuid = model.uuid_fk_column('sideshow_product_pending.uuid', nullable=True)
|
pending_product_uuid = model.uuid_fk_column(
|
||||||
|
"sideshow_product_pending.uuid", nullable=True
|
||||||
|
)
|
||||||
pending_product = orm.relationship(
|
pending_product = orm.relationship(
|
||||||
'PendingProduct',
|
"PendingProduct",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='order_items',
|
back_populates="order_items",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~sideshow.db.model.products.PendingProduct` record for
|
:class:`~sideshow.db.model.products.PendingProduct` record for
|
||||||
the order item, if applicable.
|
the order item, if applicable.
|
||||||
|
|
||||||
See also :attr:`product_id` and :attr:`local_product`.
|
See also :attr:`product_id` and :attr:`local_product`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_scancode = sa.Column(sa.String(length=14), nullable=True, doc="""
|
product_scancode = sa.Column(
|
||||||
|
sa.String(length=14),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Scancode for the product, as string.
|
Scancode for the product, as string.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -222,109 +284,189 @@ class OrderItem(model.Base):
|
||||||
That may change eventually, depending on POS integration
|
That may change eventually, depending on POS integration
|
||||||
scenarios that come up. Maybe a config option to declare
|
scenarios that come up. Maybe a config option to declare
|
||||||
whether check digit should be included or not, etc.
|
whether check digit should be included or not, etc.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_brand = sa.Column(sa.String(length=100), nullable=True, doc="""
|
product_brand = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Brand name for the product - up to 100 chars.
|
Brand name for the product - up to 100 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_description = sa.Column(sa.String(length=255), nullable=True, doc="""
|
product_description = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Description for the product - up to 255 chars.
|
Description for the product - up to 255 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_size = sa.Column(sa.String(length=30), nullable=True, doc="""
|
product_size = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Size of the product, as string - up to 30 chars.
|
Size of the product, as string - up to 30 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
product_weighed = sa.Column(sa.Boolean(), nullable=True, doc="""
|
product_weighed = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the product is sold by weight; default is null.
|
Flag indicating the product is sold by weight; default is null.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_id = sa.Column(sa.String(length=10), nullable=True, doc="""
|
department_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the department to which the product belongs, if known.
|
ID of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_name = sa.Column(sa.String(length=30), nullable=True, doc="""
|
department_name = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of the department to which the product belongs, if known.
|
Name of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
special_order = sa.Column(sa.Boolean(), nullable=True, doc="""
|
special_order = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the item is a "special order" - e.g. something not
|
Flag indicating the item is a "special order" - e.g. something not
|
||||||
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="""
|
vendor_name = sa.Column(
|
||||||
|
sa.String(length=50),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of vendor from which product may be purchased, if known. See
|
Name of vendor from which product may be purchased, if known. See
|
||||||
also :attr:`vendor_item_code`.
|
also :attr:`vendor_item_code`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
vendor_item_code = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Item code (SKU) to use when ordering this product from the vendor
|
Item code (SKU) to use when ordering this product from the vendor
|
||||||
identified by :attr:`vendor_name`, if known.
|
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.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_qty = sa.Column(sa.Numeric(precision=10, scale=4), nullable=False, doc="""
|
order_qty = sa.Column(
|
||||||
|
sa.Numeric(precision=10, scale=4),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Quantity (as decimal) of product being ordered.
|
Quantity (as decimal) of product being ordered.
|
||||||
|
|
||||||
This must be interpreted along with :attr:`order_uom` to determine
|
This must be interpreted along with :attr:`order_uom` to determine
|
||||||
the *complete* order quantity, e.g. "2 cases".
|
the *complete* order quantity, e.g. "2 cases".
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_uom = sa.Column(sa.String(length=10), nullable=False, doc="""
|
order_uom = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Code indicating the unit of measure for product being ordered.
|
Code indicating the unit of measure for product being ordered.
|
||||||
|
|
||||||
This should be one of the codes from
|
This should be one of the codes from
|
||||||
:data:`~sideshow.enum.ORDER_UOM`.
|
:data:`~sideshow.enum.ORDER_UOM`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
|
unit_cost = sa.Column(
|
||||||
|
sa.Numeric(precision=9, scale=5),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Cost of goods amount for one "unit" (not "case") of the product,
|
Cost of goods amount for one "unit" (not "case") of the product,
|
||||||
as decimal to 4 places.
|
as decimal to 4 places.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_reg = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_reg = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Regular price for the item unit. Unless a sale is in effect,
|
Regular price for the item unit. Unless a sale is in effect,
|
||||||
:attr:`unit_price_quoted` will typically match this value.
|
:attr:`unit_price_quoted` will typically match this value.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_sale = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_sale = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Sale price for the item unit, if applicable. If set, then
|
Sale price for the item unit, if applicable. If set, then
|
||||||
:attr:`unit_price_quoted` will typically match this value. See
|
:attr:`unit_price_quoted` will typically match this value. See
|
||||||
also :attr:`sale_ends`.
|
also :attr:`sale_ends`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
sale_ends = sa.Column(sa.DateTime(timezone=True), nullable=True, doc="""
|
sale_ends = sa.Column(
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
End date/time for the sale in effect, if any.
|
End date/time for the sale in effect, if any.
|
||||||
|
|
||||||
This is only relevant if :attr:`unit_price_sale` is set.
|
This is only relevant if :attr:`unit_price_sale` is set.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_quoted = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_quoted = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Quoted price for the item unit. This is the "effective" unit
|
Quoted price for the item unit. This is the "effective" unit
|
||||||
price, which is used to calculate :attr:`total_price`.
|
price, which is used to calculate :attr:`total_price`.
|
||||||
|
|
||||||
This price does *not* reflect the :attr:`discount_percent`. It
|
This price does *not* reflect the :attr:`discount_percent`. It
|
||||||
normally should match either :attr:`unit_price_reg` or
|
normally should match either :attr:`unit_price_reg` or
|
||||||
:attr:`unit_price_sale`.
|
:attr:`unit_price_sale`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
case_price_quoted = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
case_price_quoted = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Quoted price for a "case" of the item, if applicable.
|
Quoted price for a "case" of the item, if applicable.
|
||||||
|
|
||||||
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
||||||
used for calculations.
|
used for calculations.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
discount_percent = sa.Column(sa.Numeric(precision=5, scale=3), nullable=True, doc="""
|
discount_percent = sa.Column(
|
||||||
|
sa.Numeric(precision=5, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Discount percent to apply when calculating :attr:`total_price`, if
|
Discount percent to apply when calculating :attr:`total_price`, if
|
||||||
applicable.
|
applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
total_price = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
total_price = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Full price (not including tax etc.) which the customer is quoted
|
Full price (not including tax etc.) which the customer is quoted
|
||||||
for the order item.
|
for the order item.
|
||||||
|
|
||||||
|
@ -335,41 +477,57 @@ class OrderItem(model.Base):
|
||||||
* :attr:`order_uom`
|
* :attr:`order_uom`
|
||||||
* :attr:`case_size`
|
* :attr:`case_size`
|
||||||
* :attr:`discount_percent`
|
* :attr:`discount_percent`
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
status_code = sa.Column(sa.Integer(), nullable=False, doc="""
|
status_code = sa.Column(
|
||||||
|
sa.Integer(),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Code indicating current status for the order item.
|
Code indicating current status for the order item.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
paid_amount = sa.Column(sa.Numeric(precision=8, scale=3), nullable=False, default=0, doc="""
|
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`
|
Amount which the customer has paid toward the :attr:`total_price`
|
||||||
of the item.
|
of the item.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
payment_transaction_number = sa.Column(sa.String(length=20), nullable=True, doc="""
|
payment_transaction_number = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Transaction number in which payment for the order was taken, if
|
Transaction number in which payment for the order was taken, if
|
||||||
applicable/known.
|
applicable/known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
events = orm.relationship(
|
events = orm.relationship(
|
||||||
'OrderItemEvent',
|
"OrderItemEvent",
|
||||||
order_by='OrderItemEvent.occurred, OrderItemEvent.uuid',
|
order_by="OrderItemEvent.occurred, OrderItemEvent.uuid",
|
||||||
cascade='all, delete-orphan',
|
cascade="all, delete-orphan",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='item',
|
back_populates="item",
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`OrderItemEvent` records for the item.
|
List of :class:`OrderItemEvent` records for the item.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_description(self):
|
def full_description(self):
|
||||||
""" """
|
""" """
|
||||||
fields = [
|
fields = [
|
||||||
self.product_brand or '',
|
self.product_brand or "",
|
||||||
self.product_description or '',
|
self.product_description or "",
|
||||||
self.product_size or '']
|
self.product_size or "",
|
||||||
|
]
|
||||||
fields = [f.strip() for f in fields if f.strip()]
|
fields = [f.strip() for f in fields if f.strip()]
|
||||||
return ' '.join(fields)
|
return " ".join(fields)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.full_description
|
return self.full_description
|
||||||
|
@ -379,8 +537,8 @@ class OrderItem(model.Base):
|
||||||
Convenience method to add a new :class:`OrderItemEvent` for
|
Convenience method to add a new :class:`OrderItemEvent` for
|
||||||
the item.
|
the item.
|
||||||
"""
|
"""
|
||||||
kwargs['type_code'] = type_code
|
kwargs["type_code"] = type_code
|
||||||
kwargs['actor'] = user
|
kwargs["actor"] = user
|
||||||
self.events.append(OrderItemEvent(**kwargs))
|
self.events.append(OrderItemEvent(**kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@ -388,37 +546,53 @@ class OrderItemEvent(model.Base):
|
||||||
"""
|
"""
|
||||||
An event in the life of an :term:`order item`.
|
An event in the life of an :term:`order item`.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_order_item_event'
|
|
||||||
|
__tablename__ = "sideshow_order_item_event"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
item_uuid = model.uuid_fk_column('sideshow_order_item.uuid', nullable=False)
|
item_uuid = model.uuid_fk_column("sideshow_order_item.uuid", nullable=False)
|
||||||
item = orm.relationship(
|
item = orm.relationship(
|
||||||
OrderItem,
|
OrderItem,
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
back_populates='events',
|
back_populates="events",
|
||||||
doc="""
|
doc="""
|
||||||
Reference to the :class:`OrderItem` to which the event
|
Reference to the :class:`OrderItem` to which the event
|
||||||
pertains.
|
pertains.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
type_code = sa.Column(sa.Integer, nullable=False, doc="""
|
type_code = sa.Column(
|
||||||
|
sa.Integer,
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Code indicating the type of event; values must be defined in
|
Code indicating the type of event; values must be defined in
|
||||||
:data:`~sideshow.enum.ORDER_ITEM_EVENT`.
|
:data:`~sideshow.enum.ORDER_ITEM_EVENT`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
occurred = sa.Column(sa.DateTime(timezone=True), nullable=False, default=datetime.datetime.now, doc="""
|
occurred = sa.Column(
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=False,
|
||||||
|
default=datetime.datetime.now,
|
||||||
|
doc="""
|
||||||
Date and time when the event occurred.
|
Date and time when the event occurred.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
actor_uuid = model.uuid_fk_column('user.uuid', nullable=False)
|
actor_uuid = model.uuid_fk_column("user.uuid", nullable=False)
|
||||||
actor = orm.relationship(
|
actor = orm.relationship(
|
||||||
model.User,
|
model.User,
|
||||||
doc="""
|
doc="""
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||||
performed the action.
|
performed the action.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
note = sa.Column(sa.Text(), nullable=True, doc="""
|
note = sa.Column(
|
||||||
|
sa.Text(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Optional note recorded for the event.
|
Optional note recorded for the event.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
|
@ -42,7 +42,10 @@ class ProductMixin:
|
||||||
* :class:`PendingProduct`
|
* :class:`PendingProduct`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
scancode = sa.Column(sa.String(length=14), nullable=True, doc="""
|
scancode = sa.Column(
|
||||||
|
sa.String(length=14),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Scancode for the product, as string.
|
Scancode for the product, as string.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -54,73 +57,123 @@ class ProductMixin:
|
||||||
That may change eventually, depending on POS integration
|
That may change eventually, depending on POS integration
|
||||||
scenarios that come up. Maybe a config option to declare
|
scenarios that come up. Maybe a config option to declare
|
||||||
whether check digit should be included or not, etc.
|
whether check digit should be included or not, etc.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
brand_name = sa.Column(sa.String(length=100), nullable=True, doc="""
|
brand_name = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Brand name for the product - up to 100 chars.
|
Brand name for the product - up to 100 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
description = sa.Column(sa.String(length=255), nullable=True, doc="""
|
description = sa.Column(
|
||||||
|
sa.String(length=255),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Description for the product - up to 255 chars.
|
Description for the product - up to 255 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
size = sa.Column(sa.String(length=30), nullable=True, doc="""
|
size = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Size of the product, as string - up to 30 chars.
|
Size of the product, as string - up to 30 chars.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
weighed = sa.Column(sa.Boolean(), nullable=True, doc="""
|
weighed = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the product is sold by weight; default is null.
|
Flag indicating the product is sold by weight; default is null.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_id = sa.Column(sa.String(length=10), nullable=True, doc="""
|
department_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the department to which the product belongs, if known.
|
ID of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
department_name = sa.Column(sa.String(length=30), nullable=True, doc="""
|
department_name = sa.Column(
|
||||||
|
sa.String(length=30),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of the department to which the product belongs, if known.
|
Name of the department to which the product belongs, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
special_order = sa.Column(sa.Boolean(), nullable=True, doc="""
|
special_order = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Flag indicating the item is a "special order" - e.g. something not
|
Flag indicating the item is a "special order" - e.g. something not
|
||||||
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="""
|
vendor_name = sa.Column(
|
||||||
|
sa.String(length=50),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Name of vendor from which product may be purchased, if known. See
|
Name of vendor from which product may be purchased, if known. See
|
||||||
also :attr:`vendor_item_code`.
|
also :attr:`vendor_item_code`.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
vendor_item_code = sa.Column(sa.String(length=20), nullable=True, doc="""
|
vendor_item_code = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Item code (SKU) to use when ordering this product from the vendor
|
Item code (SKU) to use when ordering this product from the vendor
|
||||||
identified by :attr:`vendor_name`, if known.
|
identified by :attr:`vendor_name`, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
case_size = sa.Column(sa.Numeric(precision=9, scale=4), nullable=True, doc="""
|
case_size = sa.Column(
|
||||||
|
sa.Numeric(precision=9, scale=4),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Case pack count for the product, if known.
|
Case pack count for the product, if known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_cost = sa.Column(sa.Numeric(precision=9, scale=5), nullable=True, doc="""
|
unit_cost = sa.Column(
|
||||||
|
sa.Numeric(precision=9, scale=5),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Cost of goods amount for one "unit" (not "case") of the product,
|
Cost of goods amount for one "unit" (not "case") of the product,
|
||||||
as decimal to 4 places.
|
as decimal to 4 places.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
unit_price_reg = sa.Column(sa.Numeric(precision=8, scale=3), nullable=True, doc="""
|
unit_price_reg = sa.Column(
|
||||||
|
sa.Numeric(precision=8, scale=3),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Regular price for a "unit" of the product.
|
Regular price for a "unit" of the product.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
notes = sa.Column(sa.Text(), nullable=True, doc="""
|
notes = sa.Column(
|
||||||
|
sa.Text(),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
Arbitrary notes regarding the product, if applicable.
|
Arbitrary notes regarding the product, if applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_description(self):
|
def full_description(self):
|
||||||
""" """
|
""" """
|
||||||
fields = [
|
fields = [self.brand_name or "", self.description or "", self.size or ""]
|
||||||
self.brand_name or '',
|
|
||||||
self.description or '',
|
|
||||||
self.size or '']
|
|
||||||
fields = [f.strip() for f in fields if f.strip()]
|
fields = [f.strip() for f in fields if f.strip()]
|
||||||
return ' '.join(fields)
|
return " ".join(fields)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.full_description
|
return self.full_description
|
||||||
|
@ -139,33 +192,40 @@ class LocalProduct(ProductMixin, model.Base):
|
||||||
record(s) will be added to this local products table, for lookup
|
record(s) will be added to this local products table, for lookup
|
||||||
next time.
|
next time.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_product_local'
|
|
||||||
|
__tablename__ = "sideshow_product_local"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
external_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
external_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the true external product associated with this record, if
|
ID of the true external product associated with this record, if
|
||||||
applicable.
|
applicable.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_items = orm.relationship(
|
order_items = orm.relationship(
|
||||||
'OrderItem',
|
"OrderItem",
|
||||||
back_populates='local_product',
|
back_populates="local_product",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
||||||
associated with this product.
|
associated with this product.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
new_order_batch_rows = orm.relationship(
|
new_order_batch_rows = orm.relationship(
|
||||||
'NewOrderBatchRow',
|
"NewOrderBatchRow",
|
||||||
back_populates='local_product',
|
back_populates="local_product",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of
|
List of
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||||
records associated with this product.
|
records associated with this product.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PendingProduct(ProductMixin, model.Base):
|
class PendingProduct(ProductMixin, model.Base):
|
||||||
|
@ -180,25 +240,38 @@ class PendingProduct(ProductMixin, model.Base):
|
||||||
is executed, new record(s) will be added to the :term:`local
|
is executed, new record(s) will be added to the :term:`local
|
||||||
products <local product>` table, for lookup next time.
|
products <local product>` table, for lookup next time.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_product_pending'
|
|
||||||
|
__tablename__ = "sideshow_product_pending"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
product_id = sa.Column(sa.String(length=20), nullable=True, doc="""
|
product_id = sa.Column(
|
||||||
|
sa.String(length=20),
|
||||||
|
nullable=True,
|
||||||
|
doc="""
|
||||||
ID of the :term:`external product` associated with this record, if
|
ID of the :term:`external product` associated with this record, if
|
||||||
applicable/known.
|
applicable/known.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
status = sa.Column(sa.Enum(PendingProductStatus), nullable=False, doc="""
|
status = sa.Column(
|
||||||
|
sa.Enum(PendingProductStatus),
|
||||||
|
nullable=False,
|
||||||
|
doc="""
|
||||||
Status code for the product record.
|
Status code for the product record.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created = sa.Column(sa.DateTime(timezone=True), nullable=False,
|
created = sa.Column(
|
||||||
default=datetime.datetime.now, doc="""
|
sa.DateTime(timezone=True),
|
||||||
|
nullable=False,
|
||||||
|
default=datetime.datetime.now,
|
||||||
|
doc="""
|
||||||
Timestamp when the product record was created.
|
Timestamp when the product record was created.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
created_by_uuid = model.uuid_fk_column('user.uuid', nullable=False)
|
created_by_uuid = model.uuid_fk_column("user.uuid", nullable=False)
|
||||||
created_by = orm.relationship(
|
created_by = orm.relationship(
|
||||||
model.User,
|
model.User,
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
|
@ -206,23 +279,26 @@ class PendingProduct(ProductMixin, model.Base):
|
||||||
Reference to the
|
Reference to the
|
||||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||||
created the product record.
|
created the product record.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
order_items = orm.relationship(
|
order_items = orm.relationship(
|
||||||
'OrderItem',
|
"OrderItem",
|
||||||
back_populates='pending_product',
|
back_populates="pending_product",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
||||||
associated with this product.
|
associated with this product.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
new_order_batch_rows = orm.relationship(
|
new_order_batch_rows = orm.relationship(
|
||||||
'NewOrderBatchRow',
|
"NewOrderBatchRow",
|
||||||
back_populates='pending_product',
|
back_populates="pending_product",
|
||||||
cascade_backrefs=False,
|
cascade_backrefs=False,
|
||||||
doc="""
|
doc="""
|
||||||
List of
|
List of
|
||||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||||
records associated with this product.
|
records associated with this product.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
|
@ -33,22 +33,38 @@ class Store(model.Base):
|
||||||
"""
|
"""
|
||||||
Represents a physical location for the business.
|
Represents a physical location for the business.
|
||||||
"""
|
"""
|
||||||
__tablename__ = 'sideshow_store'
|
|
||||||
|
__tablename__ = "sideshow_store"
|
||||||
|
|
||||||
uuid = model.uuid_column()
|
uuid = model.uuid_column()
|
||||||
|
|
||||||
store_id = sa.Column(sa.String(length=10), nullable=False, unique=True, doc="""
|
store_id = sa.Column(
|
||||||
|
sa.String(length=10),
|
||||||
|
nullable=False,
|
||||||
|
unique=True,
|
||||||
|
doc="""
|
||||||
Unique ID for the store.
|
Unique ID for the store.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
name = sa.Column(sa.String(length=100), nullable=False, unique=True, doc="""
|
name = sa.Column(
|
||||||
|
sa.String(length=100),
|
||||||
|
nullable=False,
|
||||||
|
unique=True,
|
||||||
|
doc="""
|
||||||
Display name for the store (must be unique!).
|
Display name for the store (must be unique!).
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
archived = sa.Column(sa.Boolean(), nullable=False, default=False, doc="""
|
archived = sa.Column(
|
||||||
|
sa.Boolean(),
|
||||||
|
nullable=False,
|
||||||
|
default=False,
|
||||||
|
doc="""
|
||||||
Indicates the store has been "retired" essentially, and mostly
|
Indicates the store has been "retired" essentially, and mostly
|
||||||
hidden from view.
|
hidden from view.
|
||||||
""")
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.get_display()
|
return self.get_display()
|
||||||
|
@ -57,6 +73,6 @@ class Store(model.Base):
|
||||||
"""
|
"""
|
||||||
Returns the display string for the store, e.g. "001 Acme Goods".
|
Returns the display string for the store, e.g. "001 Acme Goods".
|
||||||
"""
|
"""
|
||||||
return ' '.join([(self.store_id or '').strip(),
|
return " ".join(
|
||||||
(self.name or '').strip()])\
|
[(self.store_id or "").strip(), (self.name or "").strip()]
|
||||||
.strip()
|
).strip()
|
||||||
|
|
|
@ -30,7 +30,7 @@ from collections import OrderedDict
|
||||||
from wuttjamaican.enum import *
|
from wuttjamaican.enum import *
|
||||||
|
|
||||||
|
|
||||||
ORDER_UOM_CASE = 'CS'
|
ORDER_UOM_CASE = "CS"
|
||||||
"""
|
"""
|
||||||
UOM code for ordering a "case" of product.
|
UOM code for ordering a "case" of product.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ Sideshow will treat "case" orders somewhat differently as compared to
|
||||||
"unit" orders.
|
"unit" orders.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_UOM_UNIT = 'EA'
|
ORDER_UOM_UNIT = "EA"
|
||||||
"""
|
"""
|
||||||
UOM code for ordering a "unit" of product.
|
UOM code for ordering a "unit" of product.
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ the same by Sideshow, whereas "case" orders are treated somewhat
|
||||||
differently.
|
differently.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_UOM_KILOGRAM = 'KG'
|
ORDER_UOM_KILOGRAM = "KG"
|
||||||
"""
|
"""
|
||||||
UOM code for ordering a "kilogram" of product.
|
UOM code for ordering a "kilogram" of product.
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ e.g. :attr:`~sideshow.db.model.orders.OrderItem.product_weighed` is
|
||||||
true.
|
true.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_UOM_POUND = 'LB'
|
ORDER_UOM_POUND = "LB"
|
||||||
"""
|
"""
|
||||||
UOM code for ordering a "pound" of product.
|
UOM code for ordering a "pound" of product.
|
||||||
|
|
||||||
|
@ -67,12 +67,14 @@ e.g. :attr:`~sideshow.db.model.orders.OrderItem.product_weighed` is
|
||||||
true.
|
true.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_UOM = OrderedDict([
|
ORDER_UOM = OrderedDict(
|
||||||
|
[
|
||||||
(ORDER_UOM_CASE, "Cases"),
|
(ORDER_UOM_CASE, "Cases"),
|
||||||
(ORDER_UOM_UNIT, "Units"),
|
(ORDER_UOM_UNIT, "Units"),
|
||||||
(ORDER_UOM_KILOGRAM, "Kilograms"),
|
(ORDER_UOM_KILOGRAM, "Kilograms"),
|
||||||
(ORDER_UOM_POUND, "Pounds"),
|
(ORDER_UOM_POUND, "Pounds"),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
"""
|
"""
|
||||||
Dict of possible code -> label options for ordering unit of measure.
|
Dict of possible code -> label options for ordering unit of measure.
|
||||||
|
|
||||||
|
@ -88,10 +90,11 @@ class PendingCustomerStatus(Enum):
|
||||||
Enum values for
|
Enum values for
|
||||||
:attr:`sideshow.db.model.customers.PendingCustomer.status`.
|
:attr:`sideshow.db.model.customers.PendingCustomer.status`.
|
||||||
"""
|
"""
|
||||||
PENDING = 'pending'
|
|
||||||
READY = 'ready'
|
PENDING = "pending"
|
||||||
RESOLVED = 'resolved'
|
READY = "ready"
|
||||||
IGNORED = 'ignored'
|
RESOLVED = "resolved"
|
||||||
|
IGNORED = "ignored"
|
||||||
|
|
||||||
|
|
||||||
class PendingProductStatus(Enum):
|
class PendingProductStatus(Enum):
|
||||||
|
@ -99,10 +102,11 @@ class PendingProductStatus(Enum):
|
||||||
Enum values for
|
Enum values for
|
||||||
:attr:`sideshow.db.model.products.PendingProduct.status`.
|
:attr:`sideshow.db.model.products.PendingProduct.status`.
|
||||||
"""
|
"""
|
||||||
PENDING = 'pending'
|
|
||||||
READY = 'ready'
|
PENDING = "pending"
|
||||||
RESOLVED = 'resolved'
|
READY = "ready"
|
||||||
IGNORED = 'ignored'
|
RESOLVED = "resolved"
|
||||||
|
IGNORED = "ignored"
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
@ -206,7 +210,8 @@ ORDER_ITEM_STATUS_INACTIVE = 950
|
||||||
Indicates the order item has become inactive.
|
Indicates the order item has become inactive.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_ITEM_STATUS = OrderedDict([
|
ORDER_ITEM_STATUS = OrderedDict(
|
||||||
|
[
|
||||||
(ORDER_ITEM_STATUS_UNINITIATED, "uninitiated"),
|
(ORDER_ITEM_STATUS_UNINITIATED, "uninitiated"),
|
||||||
(ORDER_ITEM_STATUS_INITIATED, "initiated"),
|
(ORDER_ITEM_STATUS_INITIATED, "initiated"),
|
||||||
(ORDER_ITEM_STATUS_PAID_BEFORE, "paid"),
|
(ORDER_ITEM_STATUS_PAID_BEFORE, "paid"),
|
||||||
|
@ -223,7 +228,8 @@ ORDER_ITEM_STATUS = OrderedDict([
|
||||||
(ORDER_ITEM_STATUS_RESTOCKED, "restocked"),
|
(ORDER_ITEM_STATUS_RESTOCKED, "restocked"),
|
||||||
(ORDER_ITEM_STATUS_EXPIRED, "expired"),
|
(ORDER_ITEM_STATUS_EXPIRED, "expired"),
|
||||||
(ORDER_ITEM_STATUS_INACTIVE, "inactive"),
|
(ORDER_ITEM_STATUS_INACTIVE, "inactive"),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
"""
|
"""
|
||||||
Dict of possible code -> label options for :term:`order item` status.
|
Dict of possible code -> label options for :term:`order item` status.
|
||||||
|
|
||||||
|
@ -366,7 +372,8 @@ Arbitrary event type which does not signify anything in particular.
|
||||||
If used, the event should be given an explanatory note.
|
If used, the event should be given an explanatory note.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ORDER_ITEM_EVENT = OrderedDict([
|
ORDER_ITEM_EVENT = OrderedDict(
|
||||||
|
[
|
||||||
(ORDER_ITEM_EVENT_INITIATED, "initiated"),
|
(ORDER_ITEM_EVENT_INITIATED, "initiated"),
|
||||||
(ORDER_ITEM_EVENT_PRICE_CONFIRMED, "price confirmed"),
|
(ORDER_ITEM_EVENT_PRICE_CONFIRMED, "price confirmed"),
|
||||||
(ORDER_ITEM_EVENT_PAYMENT_RECEIVED, "payment received"),
|
(ORDER_ITEM_EVENT_PAYMENT_RECEIVED, "payment received"),
|
||||||
|
@ -388,7 +395,8 @@ ORDER_ITEM_EVENT = OrderedDict([
|
||||||
(ORDER_ITEM_EVENT_EXPIRED, "expired"),
|
(ORDER_ITEM_EVENT_EXPIRED, "expired"),
|
||||||
(ORDER_ITEM_EVENT_INACTIVE, "inactive"),
|
(ORDER_ITEM_EVENT_INACTIVE, "inactive"),
|
||||||
(ORDER_ITEM_EVENT_OTHER, "other"),
|
(ORDER_ITEM_EVENT_OTHER, "other"),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
"""
|
"""
|
||||||
Dict of possible code -> label options for :term:`order item` event
|
Dict of possible code -> label options for :term:`order item` event
|
||||||
types.
|
types.
|
||||||
|
|
|
@ -42,8 +42,7 @@ class OrderHandler(GenericHandler):
|
||||||
Returns boolean indicating whether the ``store_id`` field
|
Returns boolean indicating whether the ``store_id`` field
|
||||||
should be exposed at all. This is false by default.
|
should be exposed at all. This is false by default.
|
||||||
"""
|
"""
|
||||||
return self.config.get_bool('sideshow.orders.expose_store_id',
|
return self.config.get_bool("sideshow.orders.expose_store_id", default=False)
|
||||||
default=False)
|
|
||||||
|
|
||||||
def get_order_qty_uom_text(self, order_qty, order_uom, case_size=None, html=False):
|
def get_order_qty_uom_text(self, order_qty, order_uom, case_size=None, html=False):
|
||||||
"""
|
"""
|
||||||
|
@ -69,15 +68,15 @@ class OrderHandler(GenericHandler):
|
||||||
|
|
||||||
if order_uom == enum.ORDER_UOM_CASE:
|
if order_uom == enum.ORDER_UOM_CASE:
|
||||||
if case_size is None:
|
if case_size is None:
|
||||||
case_qty = unit_qty = '??'
|
case_qty = unit_qty = "??"
|
||||||
else:
|
else:
|
||||||
case_qty = self.app.render_quantity(case_size)
|
case_qty = self.app.render_quantity(case_size)
|
||||||
unit_qty = self.app.render_quantity(order_qty * case_size)
|
unit_qty = self.app.render_quantity(order_qty * case_size)
|
||||||
CS = enum.ORDER_UOM[enum.ORDER_UOM_CASE]
|
CS = enum.ORDER_UOM[enum.ORDER_UOM_CASE]
|
||||||
EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT]
|
EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT]
|
||||||
order_qty = self.app.render_quantity(order_qty)
|
order_qty = self.app.render_quantity(order_qty)
|
||||||
times = '×' if html else 'x'
|
times = "×" if html else "x"
|
||||||
return (f"{order_qty} {CS} ({times} {case_qty} = {unit_qty} {EA})")
|
return f"{order_qty} {CS} ({times} {case_qty} = {unit_qty} {EA})"
|
||||||
|
|
||||||
# units
|
# units
|
||||||
unit_qty = self.app.render_quantity(order_qty)
|
unit_qty = self.app.render_quantity(order_qty)
|
||||||
|
@ -97,13 +96,15 @@ class OrderHandler(GenericHandler):
|
||||||
``None``.
|
``None``.
|
||||||
"""
|
"""
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
if status_code in (enum.ORDER_ITEM_STATUS_CANCELED,
|
if status_code in (
|
||||||
|
enum.ORDER_ITEM_STATUS_CANCELED,
|
||||||
enum.ORDER_ITEM_STATUS_REFUND_PENDING,
|
enum.ORDER_ITEM_STATUS_REFUND_PENDING,
|
||||||
enum.ORDER_ITEM_STATUS_REFUNDED,
|
enum.ORDER_ITEM_STATUS_REFUNDED,
|
||||||
enum.ORDER_ITEM_STATUS_RESTOCKED,
|
enum.ORDER_ITEM_STATUS_RESTOCKED,
|
||||||
enum.ORDER_ITEM_STATUS_EXPIRED,
|
enum.ORDER_ITEM_STATUS_EXPIRED,
|
||||||
enum.ORDER_ITEM_STATUS_INACTIVE):
|
enum.ORDER_ITEM_STATUS_INACTIVE,
|
||||||
return 'warning'
|
):
|
||||||
|
return "warning"
|
||||||
|
|
||||||
def resolve_pending_product(self, pending_product, product_info, user, note=None):
|
def resolve_pending_product(self, pending_product, product_info, user, note=None):
|
||||||
"""
|
"""
|
||||||
|
@ -152,35 +153,39 @@ class OrderHandler(GenericHandler):
|
||||||
raise ValueError("pending product does not have 'ready' status")
|
raise ValueError("pending product does not have 'ready' status")
|
||||||
|
|
||||||
info = product_info
|
info = product_info
|
||||||
pending_product.product_id = info['product_id']
|
pending_product.product_id = info["product_id"]
|
||||||
pending_product.status = enum.PendingProductStatus.RESOLVED
|
pending_product.status = enum.PendingProductStatus.RESOLVED
|
||||||
|
|
||||||
items = session.query(model.OrderItem)\
|
items = (
|
||||||
.filter(model.OrderItem.pending_product == pending_product)\
|
session.query(model.OrderItem)
|
||||||
.filter(model.OrderItem.product_id == None)\
|
.filter(model.OrderItem.pending_product == pending_product)
|
||||||
|
.filter(model.OrderItem.product_id == None)
|
||||||
.all()
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
item.product_id = info['product_id']
|
item.product_id = info["product_id"]
|
||||||
item.product_scancode = info['scancode']
|
item.product_scancode = info["scancode"]
|
||||||
item.product_brand = info['brand_name']
|
item.product_brand = info["brand_name"]
|
||||||
item.product_description = info['description']
|
item.product_description = info["description"]
|
||||||
item.product_size = info['size']
|
item.product_size = info["size"]
|
||||||
item.product_weighed = info['weighed']
|
item.product_weighed = info["weighed"]
|
||||||
item.department_id = info['department_id']
|
item.department_id = info["department_id"]
|
||||||
item.department_name = info['department_name']
|
item.department_name = info["department_name"]
|
||||||
item.special_order = info['special_order']
|
item.special_order = info["special_order"]
|
||||||
item.vendor_name = info['vendor_name']
|
item.vendor_name = info["vendor_name"]
|
||||||
item.vendor_item_code = info['vendor_item_code']
|
item.vendor_item_code = info["vendor_item_code"]
|
||||||
item.case_size = info['case_size']
|
item.case_size = info["case_size"]
|
||||||
item.unit_cost = info['unit_cost']
|
item.unit_cost = info["unit_cost"]
|
||||||
item.unit_price_reg = info['unit_price_reg']
|
item.unit_price_reg = info["unit_price_reg"]
|
||||||
|
|
||||||
item.add_event(enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED, user)
|
item.add_event(enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED, user)
|
||||||
if note:
|
if note:
|
||||||
item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note)
|
item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note)
|
||||||
|
|
||||||
def process_placement(self, items, user, vendor_name=None, po_number=None, note=None):
|
def process_placement(
|
||||||
|
self, items, user, vendor_name=None, po_number=None, note=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Process the "placement" step for the given order items.
|
Process the "placement" step for the given order items.
|
||||||
|
|
||||||
|
@ -221,8 +226,15 @@ class OrderHandler(GenericHandler):
|
||||||
item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note)
|
item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note)
|
||||||
item.status_code = enum.ORDER_ITEM_STATUS_PLACED
|
item.status_code = enum.ORDER_ITEM_STATUS_PLACED
|
||||||
|
|
||||||
def process_receiving(self, items, user, vendor_name=None,
|
def process_receiving(
|
||||||
invoice_number=None, po_number=None, note=None):
|
self,
|
||||||
|
items,
|
||||||
|
user,
|
||||||
|
vendor_name=None,
|
||||||
|
invoice_number=None,
|
||||||
|
po_number=None,
|
||||||
|
note=None,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Process the "receiving" step for the given order items.
|
Process the "receiving" step for the given order items.
|
||||||
|
|
||||||
|
@ -252,7 +264,9 @@ class OrderHandler(GenericHandler):
|
||||||
|
|
||||||
received = None
|
received = None
|
||||||
if invoice_number and po_number and vendor_name:
|
if invoice_number and po_number and vendor_name:
|
||||||
received = f"invoice {invoice_number} (PO {po_number}) from vendor {vendor_name}"
|
received = (
|
||||||
|
f"invoice {invoice_number} (PO {po_number}) from vendor {vendor_name}"
|
||||||
|
)
|
||||||
elif invoice_number and vendor_name:
|
elif invoice_number and vendor_name:
|
||||||
received = f"invoice {invoice_number} from vendor {vendor_name}"
|
received = f"invoice {invoice_number} from vendor {vendor_name}"
|
||||||
elif po_number and vendor_name:
|
elif po_number and vendor_name:
|
||||||
|
|
|
@ -31,8 +31,10 @@ class WebTestCase(base.WebTestCase):
|
||||||
|
|
||||||
def make_config(self, **kwargs):
|
def make_config(self, **kwargs):
|
||||||
config = super().make_config(**kwargs)
|
config = super().make_config(**kwargs)
|
||||||
config.setdefault('wutta.model_spec', 'sideshow.db.model')
|
config.setdefault("wutta.model_spec", "sideshow.db.model")
|
||||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||||
config.setdefault(f'{config.appname}.batch.neworder.handler.default_spec',
|
config.setdefault(
|
||||||
'sideshow.batch.neworder:NewOrderBatchHandler')
|
f"{config.appname}.batch.neworder.handler.default_spec",
|
||||||
|
"sideshow.batch.neworder:NewOrderBatchHandler",
|
||||||
|
)
|
||||||
return config
|
return config
|
||||||
|
|
|
@ -26,6 +26,6 @@ Sideshow web app
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
config.include('sideshow.web.static')
|
config.include("sideshow.web.static")
|
||||||
config.include('wuttaweb.subscribers')
|
config.include("wuttaweb.subscribers")
|
||||||
config.include('sideshow.web.views')
|
config.include("sideshow.web.views")
|
||||||
|
|
|
@ -32,17 +32,20 @@ def main(global_config, **settings):
|
||||||
Make and return the WSGI app (Paste entry point).
|
Make and return the WSGI app (Paste entry point).
|
||||||
"""
|
"""
|
||||||
# prefer Sideshow templates over wuttaweb
|
# prefer Sideshow templates over wuttaweb
|
||||||
settings.setdefault('mako.directories', [
|
settings.setdefault(
|
||||||
'sideshow.web:templates',
|
"mako.directories",
|
||||||
'wuttaweb:templates',
|
[
|
||||||
])
|
"sideshow.web:templates",
|
||||||
|
"wuttaweb:templates",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# make config objects
|
# make config objects
|
||||||
wutta_config = base.make_wutta_config(settings)
|
wutta_config = base.make_wutta_config(settings)
|
||||||
pyramid_config = base.make_pyramid_config(settings)
|
pyramid_config = base.make_pyramid_config(settings)
|
||||||
|
|
||||||
# bring in the rest of Sideshow
|
# bring in the rest of Sideshow
|
||||||
pyramid_config.include('sideshow.web')
|
pyramid_config.include("sideshow.web")
|
||||||
|
|
||||||
return pyramid_config.make_wsgi_app()
|
return pyramid_config.make_wsgi_app()
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class OrderRef(ObjectRef):
|
||||||
|
|
||||||
def get_object_url(self, order):
|
def get_object_url(self, order):
|
||||||
""" """
|
""" """
|
||||||
return self.request.route_url('orders.view', uuid=order.uuid)
|
return self.request.route_url("orders.view", uuid=order.uuid)
|
||||||
|
|
||||||
|
|
||||||
class LocalCustomerRef(ObjectRef):
|
class LocalCustomerRef(ObjectRef):
|
||||||
|
@ -73,7 +73,7 @@ class LocalCustomerRef(ObjectRef):
|
||||||
|
|
||||||
def get_object_url(self, customer):
|
def get_object_url(self, customer):
|
||||||
""" """
|
""" """
|
||||||
return self.request.route_url('local_customers.view', uuid=customer.uuid)
|
return self.request.route_url("local_customers.view", uuid=customer.uuid)
|
||||||
|
|
||||||
|
|
||||||
class PendingCustomerRef(ObjectRef):
|
class PendingCustomerRef(ObjectRef):
|
||||||
|
@ -98,7 +98,7 @@ class PendingCustomerRef(ObjectRef):
|
||||||
|
|
||||||
def get_object_url(self, customer):
|
def get_object_url(self, customer):
|
||||||
""" """
|
""" """
|
||||||
return self.request.route_url('pending_customers.view', uuid=customer.uuid)
|
return self.request.route_url("pending_customers.view", uuid=customer.uuid)
|
||||||
|
|
||||||
|
|
||||||
class LocalProductRef(ObjectRef):
|
class LocalProductRef(ObjectRef):
|
||||||
|
@ -122,7 +122,7 @@ class LocalProductRef(ObjectRef):
|
||||||
|
|
||||||
def get_object_url(self, product):
|
def get_object_url(self, product):
|
||||||
""" """
|
""" """
|
||||||
return self.request.route_url('local_products.view', uuid=product.uuid)
|
return self.request.route_url("local_products.view", uuid=product.uuid)
|
||||||
|
|
||||||
|
|
||||||
class PendingProductRef(ObjectRef):
|
class PendingProductRef(ObjectRef):
|
||||||
|
@ -147,4 +147,4 @@ class PendingProductRef(ObjectRef):
|
||||||
|
|
||||||
def get_object_url(self, product):
|
def get_object_url(self, product):
|
||||||
""" """
|
""" """
|
||||||
return self.request.route_url('pending_products.view', uuid=product.uuid)
|
return self.request.route_url("pending_products.view", uuid=product.uuid)
|
||||||
|
|
|
@ -48,45 +48,45 @@ class SideshowMenuHandler(base.MenuHandler):
|
||||||
Generate the Orders menu.
|
Generate the Orders menu.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Orders",
|
"title": "Orders",
|
||||||
'type': 'menu',
|
"type": "menu",
|
||||||
'items': [
|
"items": [
|
||||||
{
|
{
|
||||||
'title': "Create New Order",
|
"title": "Create New Order",
|
||||||
'route': 'orders.create',
|
"route": "orders.create",
|
||||||
'perm': 'orders.create',
|
"perm": "orders.create",
|
||||||
},
|
},
|
||||||
{'type': 'sep'},
|
{"type": "sep"},
|
||||||
{
|
{
|
||||||
'title': "Placement",
|
"title": "Placement",
|
||||||
'route': 'order_items_placement',
|
"route": "order_items_placement",
|
||||||
'perm': 'order_items_placement.list',
|
"perm": "order_items_placement.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "Receiving",
|
"title": "Receiving",
|
||||||
'route': 'order_items_receiving',
|
"route": "order_items_receiving",
|
||||||
'perm': 'order_items_receiving.list',
|
"perm": "order_items_receiving.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "Contact",
|
"title": "Contact",
|
||||||
'route': 'order_items_contact',
|
"route": "order_items_contact",
|
||||||
'perm': 'order_items_contact.list',
|
"perm": "order_items_contact.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "Delivery",
|
"title": "Delivery",
|
||||||
'route': 'order_items_delivery',
|
"route": "order_items_delivery",
|
||||||
'perm': 'order_items_delivery.list',
|
"perm": "order_items_delivery.list",
|
||||||
},
|
},
|
||||||
{'type': 'sep'},
|
{"type": "sep"},
|
||||||
{
|
{
|
||||||
'title': "All Order Items",
|
"title": "All Order Items",
|
||||||
'route': 'order_items',
|
"route": "order_items",
|
||||||
'perm': 'order_items.list',
|
"perm": "order_items.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "All Orders",
|
"title": "All Orders",
|
||||||
'route': 'orders',
|
"route": "orders",
|
||||||
'perm': 'orders.list',
|
"perm": "orders.list",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -96,18 +96,18 @@ class SideshowMenuHandler(base.MenuHandler):
|
||||||
Generate the Customers menu.
|
Generate the Customers menu.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Customers",
|
"title": "Customers",
|
||||||
'type': 'menu',
|
"type": "menu",
|
||||||
'items': [
|
"items": [
|
||||||
{
|
{
|
||||||
'title': "Local Customers",
|
"title": "Local Customers",
|
||||||
'route': 'local_customers',
|
"route": "local_customers",
|
||||||
'perm': 'local_customers.list',
|
"perm": "local_customers.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "Pending Customers",
|
"title": "Pending Customers",
|
||||||
'route': 'pending_customers',
|
"route": "pending_customers",
|
||||||
'perm': 'pending_customers.list',
|
"perm": "pending_customers.list",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -117,18 +117,18 @@ class SideshowMenuHandler(base.MenuHandler):
|
||||||
Generate the Products menu.
|
Generate the Products menu.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Products",
|
"title": "Products",
|
||||||
'type': 'menu',
|
"type": "menu",
|
||||||
'items': [
|
"items": [
|
||||||
{
|
{
|
||||||
'title': "Local Products",
|
"title": "Local Products",
|
||||||
'route': 'local_products',
|
"route": "local_products",
|
||||||
'perm': 'local_products.list',
|
"perm": "local_products.list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'title': "Pending Products",
|
"title": "Pending Products",
|
||||||
'route': 'pending_products',
|
"route": "pending_products",
|
||||||
'perm': 'pending_products.list',
|
"perm": "pending_products.list",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -138,13 +138,13 @@ class SideshowMenuHandler(base.MenuHandler):
|
||||||
Generate the Batch menu.
|
Generate the Batch menu.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Batches",
|
"title": "Batches",
|
||||||
'type': 'menu',
|
"type": "menu",
|
||||||
'items': [
|
"items": [
|
||||||
{
|
{
|
||||||
'title': "New Orders",
|
"title": "New Orders",
|
||||||
'route': 'neworder_batches',
|
"route": "neworder_batches",
|
||||||
'perm': 'neworder_batches.list',
|
"perm": "neworder_batches.list",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -154,20 +154,23 @@ class SideshowMenuHandler(base.MenuHandler):
|
||||||
Generate the "Other" menu.
|
Generate the "Other" menu.
|
||||||
"""
|
"""
|
||||||
return {
|
return {
|
||||||
'title': "Other",
|
"title": "Other",
|
||||||
'type': 'menu',
|
"type": "menu",
|
||||||
'items': [],
|
"items": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
def make_admin_menu(self, request, **kwargs):
|
def make_admin_menu(self, request, **kwargs):
|
||||||
""" """
|
""" """
|
||||||
kwargs['include_people'] = True
|
kwargs["include_people"] = True
|
||||||
menu = super().make_admin_menu(request, **kwargs)
|
menu = super().make_admin_menu(request, **kwargs)
|
||||||
|
|
||||||
menu['items'].insert(0, {
|
menu["items"].insert(
|
||||||
'title': "Stores",
|
0,
|
||||||
'route': 'stores',
|
{
|
||||||
'perm': 'stores.list',
|
"title": "Stores",
|
||||||
})
|
"route": "stores",
|
||||||
|
"perm": "stores.list",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return menu
|
return menu
|
||||||
|
|
|
@ -28,12 +28,12 @@ from fanstatic import Library, Resource
|
||||||
|
|
||||||
|
|
||||||
# # libcache
|
# # libcache
|
||||||
libcache = Library('sideshow_libcache', 'libcache')
|
libcache = Library("sideshow_libcache", "libcache")
|
||||||
vue_js = Resource(libcache, 'vue-2.6.14.min.js')
|
vue_js = Resource(libcache, "vue-2.6.14.min.js")
|
||||||
vue_resource_js = Resource(libcache, 'vue-resource-1.5.3.min.js')
|
vue_resource_js = Resource(libcache, "vue-resource-1.5.3.min.js")
|
||||||
buefy_js = Resource(libcache, 'buefy-0.9.25.min.js')
|
buefy_js = Resource(libcache, "buefy-0.9.25.min.js")
|
||||||
buefy_css = Resource(libcache, 'buefy-0.9.25.min.css')
|
buefy_css = Resource(libcache, "buefy-0.9.25.min.css")
|
||||||
fontawesome_js = Resource(libcache, 'fontawesome-5.3.1-all.min.js')
|
fontawesome_js = Resource(libcache, "fontawesome-5.3.1-all.min.js")
|
||||||
# bb_vue_js = Resource(libcache, 'vue.esm-browser-3.3.11.prod.js')
|
# bb_vue_js = Resource(libcache, 'vue.esm-browser-3.3.11.prod.js')
|
||||||
# bb_oruga_js = Resource(libcache, 'oruga-0.8.10.js')
|
# bb_oruga_js = Resource(libcache, 'oruga-0.8.10.js')
|
||||||
# bb_oruga_bulma_js = Resource(libcache, 'oruga-bulma-0.3.0.js')
|
# bb_oruga_bulma_js = Resource(libcache, 'oruga-bulma-0.3.0.js')
|
||||||
|
@ -44,5 +44,5 @@ fontawesome_js = Resource(libcache, 'fontawesome-5.3.1-all.min.js')
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
config.include('wuttaweb.static')
|
config.include("wuttaweb.static")
|
||||||
config.add_static_view('sideshow', 'sideshow.web:static', cache_max_age=3600)
|
config.add_static_view("sideshow", "sideshow.web:static", cache_max_age=3600)
|
||||||
|
|
|
@ -30,15 +30,18 @@ from wuttaweb.views import essential
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
|
|
||||||
# core views for wuttaweb
|
# core views for wuttaweb
|
||||||
essential.defaults(config, **{
|
essential.defaults(
|
||||||
'wuttaweb.views.common': 'sideshow.web.views.common',
|
config,
|
||||||
})
|
**{
|
||||||
|
"wuttaweb.views.common": "sideshow.web.views.common",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# sideshow views
|
# sideshow views
|
||||||
config.include('sideshow.web.views.stores')
|
config.include("sideshow.web.views.stores")
|
||||||
config.include('sideshow.web.views.customers')
|
config.include("sideshow.web.views.customers")
|
||||||
config.include('sideshow.web.views.products')
|
config.include("sideshow.web.views.products")
|
||||||
config.include('sideshow.web.views.orders')
|
config.include("sideshow.web.views.orders")
|
||||||
|
|
||||||
# batch views
|
# batch views
|
||||||
config.include('sideshow.web.views.batch.neworder')
|
config.include("sideshow.web.views.batch.neworder")
|
||||||
|
|
|
@ -52,78 +52,79 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
since those should be handled by
|
since those should be handled by
|
||||||
:class:`~sideshow.web.views.orders.OrderView` instead.
|
:class:`~sideshow.web.views.orders.OrderView` instead.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = NewOrderBatch
|
model_class = NewOrderBatch
|
||||||
model_title = "New Order Batch"
|
model_title = "New Order Batch"
|
||||||
model_title_plural = "New Order Batches"
|
model_title_plural = "New Order Batches"
|
||||||
route_prefix = 'neworder_batches'
|
route_prefix = "neworder_batches"
|
||||||
url_prefix = '/batch/neworder'
|
url_prefix = "/batch/neworder"
|
||||||
creatable = False
|
creatable = False
|
||||||
editable = False
|
editable = False
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'store_id': "Store ID",
|
"store_id": "Store ID",
|
||||||
'customer_id': "Customer ID",
|
"customer_id": "Customer ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'id',
|
"id",
|
||||||
'store_id',
|
"store_id",
|
||||||
'customer_id',
|
"customer_id",
|
||||||
'customer_name',
|
"customer_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'total_price',
|
"total_price",
|
||||||
'row_count',
|
"row_count",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
]
|
]
|
||||||
|
|
||||||
filter_defaults = {
|
filter_defaults = {
|
||||||
'executed': {'active': True, 'verb': 'is_null'},
|
"executed": {"active": True, "verb": "is_null"},
|
||||||
}
|
}
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'id',
|
"id",
|
||||||
'store_id',
|
"store_id",
|
||||||
'customer_id',
|
"customer_id",
|
||||||
'local_customer',
|
"local_customer",
|
||||||
'pending_customer',
|
"pending_customer",
|
||||||
'customer_name',
|
"customer_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'total_price',
|
"total_price",
|
||||||
'row_count',
|
"row_count",
|
||||||
'status_code',
|
"status_code",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
'executed_by',
|
"executed_by",
|
||||||
]
|
]
|
||||||
|
|
||||||
row_labels = {
|
row_labels = {
|
||||||
'product_scancode': "Scancode",
|
"product_scancode": "Scancode",
|
||||||
'product_brand': "Brand",
|
"product_brand": "Brand",
|
||||||
'product_description': "Description",
|
"product_description": "Description",
|
||||||
'product_size': "Size",
|
"product_size": "Size",
|
||||||
'order_uom': "Order UOM",
|
"order_uom": "Order UOM",
|
||||||
}
|
}
|
||||||
|
|
||||||
row_grid_columns = [
|
row_grid_columns = [
|
||||||
'sequence',
|
"sequence",
|
||||||
'product_scancode',
|
"product_scancode",
|
||||||
'product_brand',
|
"product_brand",
|
||||||
'product_description',
|
"product_description",
|
||||||
'product_size',
|
"product_size",
|
||||||
'special_order',
|
"special_order",
|
||||||
'unit_price_quoted',
|
"unit_price_quoted",
|
||||||
'case_size',
|
"case_size",
|
||||||
'case_price_quoted',
|
"case_price_quoted",
|
||||||
'order_qty',
|
"order_qty",
|
||||||
'order_uom',
|
"order_uom",
|
||||||
'discount_percent',
|
"discount_percent",
|
||||||
'total_price',
|
"total_price",
|
||||||
'status_code',
|
"status_code",
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request, context=None):
|
def __init__(self, request, context=None):
|
||||||
|
@ -141,10 +142,10 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
|
|
||||||
# store_id
|
# store_id
|
||||||
if not self.order_handler.expose_store_id():
|
if not self.order_handler.expose_store_id():
|
||||||
g.remove('store_id')
|
g.remove("store_id")
|
||||||
|
|
||||||
# total_price
|
# total_price
|
||||||
g.set_renderer('total_price', 'currency')
|
g.set_renderer("total_price", "currency")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
|
@ -152,16 +153,16 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
|
|
||||||
# store_id
|
# store_id
|
||||||
if not self.order_handler.expose_store_id():
|
if not self.order_handler.expose_store_id():
|
||||||
f.remove('store_id')
|
f.remove("store_id")
|
||||||
|
|
||||||
# local_customer
|
# local_customer
|
||||||
f.set_node('local_customer', LocalCustomerRef(self.request))
|
f.set_node("local_customer", LocalCustomerRef(self.request))
|
||||||
|
|
||||||
# pending_customer
|
# pending_customer
|
||||||
f.set_node('pending_customer', PendingCustomerRef(self.request))
|
f.set_node("pending_customer", PendingCustomerRef(self.request))
|
||||||
|
|
||||||
# total_price
|
# total_price
|
||||||
f.set_node('total_price', WuttaMoney(self.request))
|
f.set_node("total_price", WuttaMoney(self.request))
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
""" """
|
""" """
|
||||||
|
@ -173,19 +174,19 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
# g.set_renderer('order_uom', self.grid_render_enum, enum=enum.ORDER_UOM)
|
# g.set_renderer('order_uom', self.grid_render_enum, enum=enum.ORDER_UOM)
|
||||||
|
|
||||||
# unit_price_quoted
|
# unit_price_quoted
|
||||||
g.set_label('unit_price_quoted', "Unit Price", column_only=True)
|
g.set_label("unit_price_quoted", "Unit Price", column_only=True)
|
||||||
g.set_renderer('unit_price_quoted', 'currency')
|
g.set_renderer("unit_price_quoted", "currency")
|
||||||
|
|
||||||
# case_price_quoted
|
# case_price_quoted
|
||||||
g.set_label('case_price_quoted', "Case Price", column_only=True)
|
g.set_label("case_price_quoted", "Case Price", column_only=True)
|
||||||
g.set_renderer('case_price_quoted', 'currency')
|
g.set_renderer("case_price_quoted", "currency")
|
||||||
|
|
||||||
# discount_percent
|
# discount_percent
|
||||||
g.set_renderer('discount_percent', 'percent')
|
g.set_renderer("discount_percent", "percent")
|
||||||
g.set_label('discount_percent', "Disc. %", column_only=True)
|
g.set_label("discount_percent", "Disc. %", column_only=True)
|
||||||
|
|
||||||
# total_price
|
# total_price
|
||||||
g.set_renderer('total_price', 'currency')
|
g.set_renderer("total_price", "currency")
|
||||||
|
|
||||||
def get_xref_buttons(self, batch):
|
def get_xref_buttons(self, batch):
|
||||||
"""
|
"""
|
||||||
|
@ -197,14 +198,19 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
session = self.Session()
|
session = self.Session()
|
||||||
|
|
||||||
if batch.executed and self.request.has_perm('orders.view'):
|
if batch.executed and self.request.has_perm("orders.view"):
|
||||||
order = session.query(model.Order)\
|
order = (
|
||||||
.filter(model.Order.order_id == batch.id)\
|
session.query(model.Order)
|
||||||
|
.filter(model.Order.order_id == batch.id)
|
||||||
.first()
|
.first()
|
||||||
|
)
|
||||||
if order:
|
if order:
|
||||||
url = self.request.route_url('orders.view', uuid=order.uuid)
|
url = self.request.route_url("orders.view", uuid=order.uuid)
|
||||||
buttons.append(
|
buttons.append(
|
||||||
self.make_button("View the Order", primary=True, icon_left='eye', url=url))
|
self.make_button(
|
||||||
|
"View the Order", primary=True, icon_left="eye", url=url
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return buttons
|
return buttons
|
||||||
|
|
||||||
|
@ -212,7 +218,7 @@ class NewOrderBatchView(BatchMasterView):
|
||||||
def defaults(config, **kwargs):
|
def defaults(config, **kwargs):
|
||||||
base = globals()
|
base = globals()
|
||||||
|
|
||||||
NewOrderBatchView = kwargs.get('NewOrderBatchView', base['NewOrderBatchView'])
|
NewOrderBatchView = kwargs.get("NewOrderBatchView", base["NewOrderBatchView"])
|
||||||
NewOrderBatchView.defaults(config)
|
NewOrderBatchView.defaults(config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,54 +46,55 @@ class CommonView(base.CommonView):
|
||||||
auth = self.app.get_auth_handler()
|
auth = self.app.get_auth_handler()
|
||||||
|
|
||||||
admin = model.Role(name="Order Admin")
|
admin = model.Role(name="Order Admin")
|
||||||
admin.notes = ("this role was auto-created; "
|
admin.notes = (
|
||||||
"you can change or remove it as needed.")
|
"this role was auto-created; " "you can change or remove it as needed."
|
||||||
|
)
|
||||||
|
|
||||||
session.add(admin)
|
session.add(admin)
|
||||||
user.roles.append(admin)
|
user.roles.append(admin)
|
||||||
|
|
||||||
order_admin_perms = [
|
order_admin_perms = [
|
||||||
'local_customers.list',
|
"local_customers.list",
|
||||||
'local_customers.view',
|
"local_customers.view",
|
||||||
'local_products.list',
|
"local_products.list",
|
||||||
'local_products.view',
|
"local_products.view",
|
||||||
'neworder_batches.list',
|
"neworder_batches.list",
|
||||||
'neworder_batches.view',
|
"neworder_batches.view",
|
||||||
'order_items.add_note',
|
"order_items.add_note",
|
||||||
'order_items.change_status',
|
"order_items.change_status",
|
||||||
'order_items.list',
|
"order_items.list",
|
||||||
'order_items.view',
|
"order_items.view",
|
||||||
'order_items_contact.add_note',
|
"order_items_contact.add_note",
|
||||||
'order_items_contact.change_status',
|
"order_items_contact.change_status",
|
||||||
'order_items_contact.list',
|
"order_items_contact.list",
|
||||||
'order_items_contact.process_contact',
|
"order_items_contact.process_contact",
|
||||||
'order_items_contact.view',
|
"order_items_contact.view",
|
||||||
'order_items_delivery.add_note',
|
"order_items_delivery.add_note",
|
||||||
'order_items_delivery.change_status',
|
"order_items_delivery.change_status",
|
||||||
'order_items_delivery.list',
|
"order_items_delivery.list",
|
||||||
'order_items_delivery.process_delivery',
|
"order_items_delivery.process_delivery",
|
||||||
'order_items_delivery.process_restock',
|
"order_items_delivery.process_restock",
|
||||||
'order_items_delivery.view',
|
"order_items_delivery.view",
|
||||||
'order_items_placement.add_note',
|
"order_items_placement.add_note",
|
||||||
'order_items_placement.change_status',
|
"order_items_placement.change_status",
|
||||||
'order_items_placement.list',
|
"order_items_placement.list",
|
||||||
'order_items_placement.process_placement',
|
"order_items_placement.process_placement",
|
||||||
'order_items_placement.view',
|
"order_items_placement.view",
|
||||||
'order_items_receiving.add_note',
|
"order_items_receiving.add_note",
|
||||||
'order_items_receiving.change_status',
|
"order_items_receiving.change_status",
|
||||||
'order_items_receiving.list',
|
"order_items_receiving.list",
|
||||||
'order_items_receiving.process_receiving',
|
"order_items_receiving.process_receiving",
|
||||||
'order_items_receiving.process_reorder',
|
"order_items_receiving.process_reorder",
|
||||||
'order_items_receiving.view',
|
"order_items_receiving.view",
|
||||||
'orders.configure',
|
"orders.configure",
|
||||||
'orders.create',
|
"orders.create",
|
||||||
'orders.create_unknown_product',
|
"orders.create_unknown_product",
|
||||||
'orders.list',
|
"orders.list",
|
||||||
'orders.view',
|
"orders.view",
|
||||||
'pending_customers.list',
|
"pending_customers.list",
|
||||||
'pending_customers.view',
|
"pending_customers.view",
|
||||||
'pending_products.list',
|
"pending_products.list",
|
||||||
'pending_products.view',
|
"pending_products.view",
|
||||||
]
|
]
|
||||||
|
|
||||||
for perm in order_admin_perms:
|
for perm in order_admin_perms:
|
||||||
|
@ -101,4 +102,4 @@ class CommonView(base.CommonView):
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
base.defaults(config, **{'CommonView': CommonView})
|
base.defaults(config, **{"CommonView": CommonView})
|
||||||
|
|
|
@ -44,35 +44,36 @@ class LocalCustomerView(MasterView):
|
||||||
* ``/local/customers/XXX/edit``
|
* ``/local/customers/XXX/edit``
|
||||||
* ``/local/customers/XXX/delete``
|
* ``/local/customers/XXX/delete``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = LocalCustomer
|
model_class = LocalCustomer
|
||||||
model_title = "Local Customer"
|
model_title = "Local Customer"
|
||||||
route_prefix = 'local_customers'
|
route_prefix = "local_customers"
|
||||||
url_prefix = '/local/customers'
|
url_prefix = "/local/customers"
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'external_id': "External ID",
|
"external_id": "External ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'external_id',
|
"external_id",
|
||||||
'full_name',
|
"full_name",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
]
|
]
|
||||||
|
|
||||||
sort_defaults = 'full_name'
|
sort_defaults = "full_name"
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'external_id',
|
"external_id",
|
||||||
'full_name',
|
"full_name",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'orders',
|
"orders",
|
||||||
'new_order_batches',
|
"new_order_batches",
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
|
@ -80,11 +81,11 @@ class LocalCustomerView(MasterView):
|
||||||
super().configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
# links
|
# links
|
||||||
g.set_link('full_name')
|
g.set_link("full_name")
|
||||||
g.set_link('first_name')
|
g.set_link("first_name")
|
||||||
g.set_link('last_name')
|
g.set_link("last_name")
|
||||||
g.set_link('phone_number')
|
g.set_link("phone_number")
|
||||||
g.set_link('email_address')
|
g.set_link("email_address")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
|
@ -93,25 +94,25 @@ class LocalCustomerView(MasterView):
|
||||||
|
|
||||||
# external_id
|
# external_id
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('external_id')
|
f.remove("external_id")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('external_id')
|
f.set_readonly("external_id")
|
||||||
|
|
||||||
# full_name
|
# full_name
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('full_name')
|
f.remove("full_name")
|
||||||
|
|
||||||
# orders
|
# orders
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('orders')
|
f.remove("orders")
|
||||||
else:
|
else:
|
||||||
f.set_grid('orders', self.make_orders_grid(customer))
|
f.set_grid("orders", self.make_orders_grid(customer))
|
||||||
|
|
||||||
# new_order_batches
|
# new_order_batches
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('new_order_batches')
|
f.remove("new_order_batches")
|
||||||
else:
|
else:
|
||||||
f.set_grid('new_order_batches', self.make_new_order_batches_grid(customer))
|
f.set_grid("new_order_batches", self.make_new_order_batches_grid(customer))
|
||||||
|
|
||||||
def make_orders_grid(self, customer):
|
def make_orders_grid(self, customer):
|
||||||
"""
|
"""
|
||||||
|
@ -120,24 +121,28 @@ class LocalCustomerView(MasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.orders",
|
||||||
model_class=model.Order,
|
model_class=model.Order,
|
||||||
data=customer.orders,
|
data=customer.orders,
|
||||||
columns=[
|
columns=[
|
||||||
'order_id',
|
"order_id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'order_id': "Order ID",
|
"order_id": "Order ID",
|
||||||
})
|
},
|
||||||
grid.set_renderer('total_price', grid.render_currency)
|
)
|
||||||
|
grid.set_renderer("total_price", grid.render_currency)
|
||||||
|
|
||||||
if self.request.has_perm('orders.view'):
|
if self.request.has_perm("orders.view"):
|
||||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
url = lambda order, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"orders.view", uuid=order.uuid
|
||||||
grid.set_link('order_id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("order_id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -148,28 +153,32 @@ class LocalCustomerView(MasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.new_order_batches",
|
||||||
model_class=model.NewOrderBatch,
|
model_class=model.NewOrderBatch,
|
||||||
data=customer.new_order_batches,
|
data=customer.new_order_batches,
|
||||||
columns=[
|
columns=[
|
||||||
'id',
|
"id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'id': "Batch ID",
|
"id": "Batch ID",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'id': 'batch_id',
|
"id": "batch_id",
|
||||||
'total_price': 'currency',
|
"total_price": "currency",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('neworder_batches.view'):
|
if self.request.has_perm("neworder_batches.view"):
|
||||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
url = lambda batch, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"neworder_batches.view", uuid=batch.uuid
|
||||||
grid.set_link('id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -178,8 +187,9 @@ class LocalCustomerView(MasterView):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
customer = super().objectify(form)
|
customer = super().objectify(form)
|
||||||
|
|
||||||
customer.full_name = self.app.make_full_name(customer.first_name,
|
customer.full_name = self.app.make_full_name(
|
||||||
customer.last_name)
|
customer.first_name, customer.last_name
|
||||||
|
)
|
||||||
|
|
||||||
return customer
|
return customer
|
||||||
|
|
||||||
|
@ -198,41 +208,42 @@ class PendingCustomerView(MasterView):
|
||||||
* ``/pending/customers/XXX/edit``
|
* ``/pending/customers/XXX/edit``
|
||||||
* ``/pending/customers/XXX/delete``
|
* ``/pending/customers/XXX/delete``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = PendingCustomer
|
model_class = PendingCustomer
|
||||||
model_title = "Pending Customer"
|
model_title = "Pending Customer"
|
||||||
route_prefix = 'pending_customers'
|
route_prefix = "pending_customers"
|
||||||
url_prefix = '/pending/customers'
|
url_prefix = "/pending/customers"
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'customer_id': "Customer ID",
|
"customer_id": "Customer ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'full_name',
|
"full_name",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'customer_id',
|
"customer_id",
|
||||||
'status',
|
"status",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
]
|
]
|
||||||
|
|
||||||
sort_defaults = 'full_name'
|
sort_defaults = "full_name"
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'customer_id',
|
"customer_id",
|
||||||
'full_name',
|
"full_name",
|
||||||
'first_name',
|
"first_name",
|
||||||
'last_name',
|
"last_name",
|
||||||
'phone_number',
|
"phone_number",
|
||||||
'email_address',
|
"email_address",
|
||||||
'status',
|
"status",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'orders',
|
"orders",
|
||||||
'new_order_batches',
|
"new_order_batches",
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
|
@ -241,14 +252,14 @@ class PendingCustomerView(MasterView):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
# status
|
# status
|
||||||
g.set_renderer('status', self.grid_render_enum, enum=enum.PendingCustomerStatus)
|
g.set_renderer("status", self.grid_render_enum, enum=enum.PendingCustomerStatus)
|
||||||
|
|
||||||
# links
|
# links
|
||||||
g.set_link('full_name')
|
g.set_link("full_name")
|
||||||
g.set_link('first_name')
|
g.set_link("first_name")
|
||||||
g.set_link('last_name')
|
g.set_link("last_name")
|
||||||
g.set_link('phone_number')
|
g.set_link("phone_number")
|
||||||
g.set_link('email_address')
|
g.set_link("email_address")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
|
@ -258,41 +269,41 @@ class PendingCustomerView(MasterView):
|
||||||
|
|
||||||
# customer_id
|
# customer_id
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('customer_id')
|
f.remove("customer_id")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('customer_id')
|
f.set_readonly("customer_id")
|
||||||
|
|
||||||
# status
|
# status
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('status')
|
f.remove("status")
|
||||||
else:
|
else:
|
||||||
f.set_node('status', WuttaEnum(self.request, enum.PendingCustomerStatus))
|
f.set_node("status", WuttaEnum(self.request, enum.PendingCustomerStatus))
|
||||||
f.set_readonly('status')
|
f.set_readonly("status")
|
||||||
|
|
||||||
# created
|
# created
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('created')
|
f.remove("created")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('created')
|
f.set_readonly("created")
|
||||||
|
|
||||||
# created_by
|
# created_by
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('created_by')
|
f.remove("created_by")
|
||||||
else:
|
else:
|
||||||
f.set_node('created_by', UserRef(self.request))
|
f.set_node("created_by", UserRef(self.request))
|
||||||
f.set_readonly('created_by')
|
f.set_readonly("created_by")
|
||||||
|
|
||||||
# orders
|
# orders
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('orders')
|
f.remove("orders")
|
||||||
else:
|
else:
|
||||||
f.set_grid('orders', self.make_orders_grid(customer))
|
f.set_grid("orders", self.make_orders_grid(customer))
|
||||||
|
|
||||||
# new_order_batches
|
# new_order_batches
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('new_order_batches')
|
f.remove("new_order_batches")
|
||||||
else:
|
else:
|
||||||
f.set_grid('new_order_batches', self.make_new_order_batches_grid(customer))
|
f.set_grid("new_order_batches", self.make_new_order_batches_grid(customer))
|
||||||
|
|
||||||
def make_orders_grid(self, customer):
|
def make_orders_grid(self, customer):
|
||||||
"""
|
"""
|
||||||
|
@ -301,24 +312,28 @@ class PendingCustomerView(MasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.orders",
|
||||||
model_class=model.Order,
|
model_class=model.Order,
|
||||||
data=customer.orders,
|
data=customer.orders,
|
||||||
columns=[
|
columns=[
|
||||||
'order_id',
|
"order_id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'order_id': "Order ID",
|
"order_id": "Order ID",
|
||||||
})
|
},
|
||||||
grid.set_renderer('total_price', grid.render_currency)
|
)
|
||||||
|
grid.set_renderer("total_price", grid.render_currency)
|
||||||
|
|
||||||
if self.request.has_perm('orders.view'):
|
if self.request.has_perm("orders.view"):
|
||||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
url = lambda order, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"orders.view", uuid=order.uuid
|
||||||
grid.set_link('order_id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("order_id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -329,28 +344,32 @@ class PendingCustomerView(MasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.new_order_batches",
|
||||||
model_class=model.NewOrderBatch,
|
model_class=model.NewOrderBatch,
|
||||||
data=customer.new_order_batches,
|
data=customer.new_order_batches,
|
||||||
columns=[
|
columns=[
|
||||||
'id',
|
"id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'id': "Batch ID",
|
"id": "Batch ID",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'id': 'batch_id',
|
"id": "batch_id",
|
||||||
'total_price': 'currency',
|
"total_price": "currency",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('neworder_batches.view'):
|
if self.request.has_perm("neworder_batches.view"):
|
||||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
url = lambda batch, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"neworder_batches.view", uuid=batch.uuid
|
||||||
grid.set_link('id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -371,16 +390,20 @@ class PendingCustomerView(MasterView):
|
||||||
|
|
||||||
# avoid deleting if still referenced by order(s)
|
# avoid deleting if still referenced by order(s)
|
||||||
for order in customer.orders:
|
for order in customer.orders:
|
||||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
self.request.session.flash(
|
||||||
"to Order(s)", 'warning')
|
f"Cannot delete {model_title} still attached " "to Order(s)", "warning"
|
||||||
raise self.redirect(self.get_action_url('view', customer))
|
)
|
||||||
|
raise self.redirect(self.get_action_url("view", customer))
|
||||||
|
|
||||||
# avoid deleting if still referenced by new order batch(es)
|
# avoid deleting if still referenced by new order batch(es)
|
||||||
for batch in customer.new_order_batches:
|
for batch in customer.new_order_batches:
|
||||||
if not batch.executed:
|
if not batch.executed:
|
||||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
self.request.session.flash(
|
||||||
"to New Order Batch(es)", 'warning')
|
f"Cannot delete {model_title} still attached "
|
||||||
raise self.redirect(self.get_action_url('view', customer))
|
"to New Order Batch(es)",
|
||||||
|
"warning",
|
||||||
|
)
|
||||||
|
raise self.redirect(self.get_action_url("view", customer))
|
||||||
|
|
||||||
# go ahead and delete per usual
|
# go ahead and delete per usual
|
||||||
super().delete_instance(customer)
|
super().delete_instance(customer)
|
||||||
|
@ -389,10 +412,10 @@ class PendingCustomerView(MasterView):
|
||||||
def defaults(config, **kwargs):
|
def defaults(config, **kwargs):
|
||||||
base = globals()
|
base = globals()
|
||||||
|
|
||||||
LocalCustomerView = kwargs.get('LocalCustomerView', base['LocalCustomerView'])
|
LocalCustomerView = kwargs.get("LocalCustomerView", base["LocalCustomerView"])
|
||||||
LocalCustomerView.defaults(config)
|
LocalCustomerView.defaults(config)
|
||||||
|
|
||||||
PendingCustomerView = kwargs.get('PendingCustomerView', base['PendingCustomerView'])
|
PendingCustomerView = kwargs.get("PendingCustomerView", base["PendingCustomerView"])
|
||||||
PendingCustomerView.defaults(config)
|
PendingCustomerView.defaults(config)
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -44,47 +44,48 @@ class LocalProductView(MasterView):
|
||||||
* ``/local/products/XXX/edit``
|
* ``/local/products/XXX/edit``
|
||||||
* ``/local/products/XXX/delete``
|
* ``/local/products/XXX/delete``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = LocalProduct
|
model_class = LocalProduct
|
||||||
model_title = "Local Product"
|
model_title = "Local Product"
|
||||||
route_prefix = 'local_products'
|
route_prefix = "local_products"
|
||||||
url_prefix = '/local/products'
|
url_prefix = "/local/products"
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'external_id': "External ID",
|
"external_id": "External ID",
|
||||||
'department_id': "Department ID",
|
"department_id": "Department ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'scancode',
|
"scancode",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'department_name',
|
"department_name",
|
||||||
'special_order',
|
"special_order",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
]
|
]
|
||||||
|
|
||||||
sort_defaults = 'scancode'
|
sort_defaults = "scancode"
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'external_id',
|
"external_id",
|
||||||
'scancode',
|
"scancode",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'department_id',
|
"department_id",
|
||||||
'department_name',
|
"department_name",
|
||||||
'special_order',
|
"special_order",
|
||||||
'vendor_name',
|
"vendor_name",
|
||||||
'vendor_item_code',
|
"vendor_item_code",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'notes',
|
"notes",
|
||||||
'orders',
|
"orders",
|
||||||
'new_order_batches',
|
"new_order_batches",
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
|
@ -92,17 +93,17 @@ class LocalProductView(MasterView):
|
||||||
super().configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
# unit_cost
|
# unit_cost
|
||||||
g.set_renderer('unit_cost', 'currency', scale=4)
|
g.set_renderer("unit_cost", "currency", scale=4)
|
||||||
|
|
||||||
# unit_price_reg
|
# unit_price_reg
|
||||||
g.set_label('unit_price_reg', "Reg. Price", column_only=True)
|
g.set_label("unit_price_reg", "Reg. Price", column_only=True)
|
||||||
g.set_renderer('unit_price_reg', 'currency')
|
g.set_renderer("unit_price_reg", "currency")
|
||||||
|
|
||||||
# links
|
# links
|
||||||
g.set_link('scancode')
|
g.set_link("scancode")
|
||||||
g.set_link('brand_name')
|
g.set_link("brand_name")
|
||||||
g.set_link('description')
|
g.set_link("description")
|
||||||
g.set_link('size')
|
g.set_link("size")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
|
@ -112,40 +113,40 @@ class LocalProductView(MasterView):
|
||||||
|
|
||||||
# external_id
|
# external_id
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('external_id')
|
f.remove("external_id")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('external_id')
|
f.set_readonly("external_id")
|
||||||
|
|
||||||
# TODO: should not have to explicitly mark these nodes
|
# TODO: should not have to explicitly mark these nodes
|
||||||
# as required=False.. i guess i do for now b/c i am
|
# as required=False.. i guess i do for now b/c i am
|
||||||
# totally overriding the node from colanderlachemy
|
# totally overriding the node from colanderlachemy
|
||||||
|
|
||||||
# case_size
|
# case_size
|
||||||
f.set_node('case_size', WuttaQuantity(self.request))
|
f.set_node("case_size", WuttaQuantity(self.request))
|
||||||
f.set_required('case_size', False)
|
f.set_required("case_size", False)
|
||||||
|
|
||||||
# unit_cost
|
# unit_cost
|
||||||
f.set_node('unit_cost', WuttaMoney(self.request, scale=4))
|
f.set_node("unit_cost", WuttaMoney(self.request, scale=4))
|
||||||
f.set_required('unit_cost', False)
|
f.set_required("unit_cost", False)
|
||||||
|
|
||||||
# unit_price_reg
|
# unit_price_reg
|
||||||
f.set_node('unit_price_reg', WuttaMoney(self.request))
|
f.set_node("unit_price_reg", WuttaMoney(self.request))
|
||||||
f.set_required('unit_price_reg', False)
|
f.set_required("unit_price_reg", False)
|
||||||
|
|
||||||
# notes
|
# notes
|
||||||
f.set_widget('notes', 'notes')
|
f.set_widget("notes", "notes")
|
||||||
|
|
||||||
# orders
|
# orders
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('orders')
|
f.remove("orders")
|
||||||
else:
|
else:
|
||||||
f.set_grid('orders', self.make_orders_grid(product))
|
f.set_grid("orders", self.make_orders_grid(product))
|
||||||
|
|
||||||
# new_order_batches
|
# new_order_batches
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('new_order_batches')
|
f.remove("new_order_batches")
|
||||||
else:
|
else:
|
||||||
f.set_grid('new_order_batches', self.make_new_order_batches_grid(product))
|
f.set_grid("new_order_batches", self.make_new_order_batches_grid(product))
|
||||||
|
|
||||||
def make_orders_grid(self, product):
|
def make_orders_grid(self, product):
|
||||||
"""
|
"""
|
||||||
|
@ -157,26 +158,30 @@ class LocalProductView(MasterView):
|
||||||
orders = set([item.order for item in product.order_items])
|
orders = set([item.order for item in product.order_items])
|
||||||
orders = sorted(orders, key=lambda order: order.order_id)
|
orders = sorted(orders, key=lambda order: order.order_id)
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.orders",
|
||||||
model_class=model.Order,
|
model_class=model.Order,
|
||||||
data=orders,
|
data=orders,
|
||||||
columns=[
|
columns=[
|
||||||
'order_id',
|
"order_id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'order_id': "Order ID",
|
"order_id": "Order ID",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'total_price': 'currency',
|
"total_price": "currency",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('orders.view'):
|
if self.request.has_perm("orders.view"):
|
||||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
url = lambda order, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"orders.view", uuid=order.uuid
|
||||||
grid.set_link('order_id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("order_id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -190,28 +195,32 @@ class LocalProductView(MasterView):
|
||||||
batches = set([row.batch for row in product.new_order_batch_rows])
|
batches = set([row.batch for row in product.new_order_batch_rows])
|
||||||
batches = sorted(batches, key=lambda batch: batch.id)
|
batches = sorted(batches, key=lambda batch: batch.id)
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.new_order_batches",
|
||||||
model_class=model.NewOrderBatch,
|
model_class=model.NewOrderBatch,
|
||||||
data=batches,
|
data=batches,
|
||||||
columns=[
|
columns=[
|
||||||
'id',
|
"id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'id': "Batch ID",
|
"id": "Batch ID",
|
||||||
'status_code': "Status",
|
"status_code": "Status",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'id': 'batch_id',
|
"id": "batch_id",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('neworder_batches.view'):
|
if self.request.has_perm("neworder_batches.view"):
|
||||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
url = lambda batch, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"neworder_batches.view", uuid=batch.uuid
|
||||||
grid.set_link('id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -230,57 +239,57 @@ class PendingProductView(MasterView):
|
||||||
* ``/pending/products/XXX/edit``
|
* ``/pending/products/XXX/edit``
|
||||||
* ``/pending/products/XXX/delete``
|
* ``/pending/products/XXX/delete``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = PendingProduct
|
model_class = PendingProduct
|
||||||
model_title = "Pending Product"
|
model_title = "Pending Product"
|
||||||
route_prefix = 'pending_products'
|
route_prefix = "pending_products"
|
||||||
url_prefix = '/pending/products'
|
url_prefix = "/pending/products"
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'department_id': "Department ID",
|
"department_id": "Department ID",
|
||||||
'product_id': "Product ID",
|
"product_id": "Product ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
grid_columns = [
|
grid_columns = [
|
||||||
'scancode',
|
"scancode",
|
||||||
'department_name',
|
"department_name",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'special_order',
|
"special_order",
|
||||||
'status',
|
"status",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
]
|
]
|
||||||
|
|
||||||
sort_defaults = ('created', 'desc')
|
sort_defaults = ("created", "desc")
|
||||||
|
|
||||||
filter_defaults = {
|
filter_defaults = {
|
||||||
'status': {'active': True,
|
"status": {"active": True, "value": PendingProductStatus.READY.name},
|
||||||
'value': PendingProductStatus.READY.name},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
form_fields = [
|
form_fields = [
|
||||||
'product_id',
|
"product_id",
|
||||||
'scancode',
|
"scancode",
|
||||||
'department_id',
|
"department_id",
|
||||||
'department_name',
|
"department_name",
|
||||||
'brand_name',
|
"brand_name",
|
||||||
'description',
|
"description",
|
||||||
'size',
|
"size",
|
||||||
'vendor_name',
|
"vendor_name",
|
||||||
'vendor_item_code',
|
"vendor_item_code",
|
||||||
'unit_cost',
|
"unit_cost",
|
||||||
'case_size',
|
"case_size",
|
||||||
'unit_price_reg',
|
"unit_price_reg",
|
||||||
'special_order',
|
"special_order",
|
||||||
'notes',
|
"notes",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'orders',
|
"orders",
|
||||||
'new_order_batches',
|
"new_order_batches",
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
|
@ -289,26 +298,26 @@ class PendingProductView(MasterView):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
# unit_cost
|
# unit_cost
|
||||||
g.set_renderer('unit_cost', 'currency', scale=4)
|
g.set_renderer("unit_cost", "currency", scale=4)
|
||||||
|
|
||||||
# unit_price_reg
|
# unit_price_reg
|
||||||
g.set_label('unit_price_reg', "Reg. Price", column_only=True)
|
g.set_label("unit_price_reg", "Reg. Price", column_only=True)
|
||||||
g.set_renderer('unit_price_reg', 'currency')
|
g.set_renderer("unit_price_reg", "currency")
|
||||||
|
|
||||||
# status
|
# status
|
||||||
g.set_enum('status', enum.PendingProductStatus)
|
g.set_enum("status", enum.PendingProductStatus)
|
||||||
|
|
||||||
# links
|
# links
|
||||||
g.set_link('scancode')
|
g.set_link("scancode")
|
||||||
g.set_link('brand_name')
|
g.set_link("brand_name")
|
||||||
g.set_link('description')
|
g.set_link("description")
|
||||||
g.set_link('size')
|
g.set_link("size")
|
||||||
|
|
||||||
def grid_row_class(self, product, data, i):
|
def grid_row_class(self, product, data, i):
|
||||||
""" """
|
""" """
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
if product.status == enum.PendingProductStatus.IGNORED:
|
if product.status == enum.PendingProductStatus.IGNORED:
|
||||||
return 'has-background-warning'
|
return "has-background-warning"
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
|
@ -318,40 +327,40 @@ class PendingProductView(MasterView):
|
||||||
|
|
||||||
# product_id
|
# product_id
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('product_id')
|
f.remove("product_id")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('product_id')
|
f.set_readonly("product_id")
|
||||||
|
|
||||||
# unit_price_reg
|
# unit_price_reg
|
||||||
f.set_node('unit_price_reg', WuttaMoney(self.request))
|
f.set_node("unit_price_reg", WuttaMoney(self.request))
|
||||||
|
|
||||||
# notes
|
# notes
|
||||||
f.set_widget('notes', 'notes')
|
f.set_widget("notes", "notes")
|
||||||
|
|
||||||
# created
|
# created
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('created')
|
f.remove("created")
|
||||||
else:
|
else:
|
||||||
f.set_readonly('created')
|
f.set_readonly("created")
|
||||||
|
|
||||||
# created_by
|
# created_by
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('created_by')
|
f.remove("created_by")
|
||||||
else:
|
else:
|
||||||
f.set_node('created_by', UserRef(self.request))
|
f.set_node("created_by", UserRef(self.request))
|
||||||
f.set_readonly('created_by')
|
f.set_readonly("created_by")
|
||||||
|
|
||||||
# orders
|
# orders
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('orders')
|
f.remove("orders")
|
||||||
else:
|
else:
|
||||||
f.set_grid('orders', self.make_orders_grid(product))
|
f.set_grid("orders", self.make_orders_grid(product))
|
||||||
|
|
||||||
# new_order_batches
|
# new_order_batches
|
||||||
if self.creating or self.editing:
|
if self.creating or self.editing:
|
||||||
f.remove('new_order_batches')
|
f.remove("new_order_batches")
|
||||||
else:
|
else:
|
||||||
f.set_grid('new_order_batches', self.make_new_order_batches_grid(product))
|
f.set_grid("new_order_batches", self.make_new_order_batches_grid(product))
|
||||||
|
|
||||||
def make_orders_grid(self, product):
|
def make_orders_grid(self, product):
|
||||||
"""
|
"""
|
||||||
|
@ -363,26 +372,30 @@ class PendingProductView(MasterView):
|
||||||
orders = set([item.order for item in product.order_items])
|
orders = set([item.order for item in product.order_items])
|
||||||
orders = sorted(orders, key=lambda order: order.order_id)
|
orders = sorted(orders, key=lambda order: order.order_id)
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.orders",
|
||||||
model_class=model.Order,
|
model_class=model.Order,
|
||||||
data=orders,
|
data=orders,
|
||||||
columns=[
|
columns=[
|
||||||
'order_id',
|
"order_id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'order_id': "Order ID",
|
"order_id": "Order ID",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'total_price': 'currency',
|
"total_price": "currency",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('orders.view'):
|
if self.request.has_perm("orders.view"):
|
||||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
url = lambda order, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"orders.view", uuid=order.uuid
|
||||||
grid.set_link('order_id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("order_id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -396,28 +409,32 @@ class PendingProductView(MasterView):
|
||||||
batches = set([row.batch for row in product.new_order_batch_rows])
|
batches = set([row.batch for row in product.new_order_batch_rows])
|
||||||
batches = sorted(batches, key=lambda batch: batch.id)
|
batches = sorted(batches, key=lambda batch: batch.id)
|
||||||
|
|
||||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
grid = self.make_grid(
|
||||||
|
key=f"{route_prefix}.view.new_order_batches",
|
||||||
model_class=model.NewOrderBatch,
|
model_class=model.NewOrderBatch,
|
||||||
data=batches,
|
data=batches,
|
||||||
columns=[
|
columns=[
|
||||||
'id',
|
"id",
|
||||||
'total_price',
|
"total_price",
|
||||||
'created',
|
"created",
|
||||||
'created_by',
|
"created_by",
|
||||||
'executed',
|
"executed",
|
||||||
],
|
],
|
||||||
labels={
|
labels={
|
||||||
'id': "Batch ID",
|
"id": "Batch ID",
|
||||||
'status_code': "Status",
|
"status_code": "Status",
|
||||||
},
|
},
|
||||||
renderers={
|
renderers={
|
||||||
'id': 'batch_id',
|
"id": "batch_id",
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if self.request.has_perm('neworder_batches.view'):
|
if self.request.has_perm("neworder_batches.view"):
|
||||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
url = lambda batch, i: self.request.route_url(
|
||||||
grid.add_action('view', icon='eye', url=url)
|
"neworder_batches.view", uuid=batch.uuid
|
||||||
grid.set_link('id')
|
)
|
||||||
|
grid.add_action("view", icon="eye", url=url)
|
||||||
|
grid.set_link("id")
|
||||||
|
|
||||||
return grid
|
return grid
|
||||||
|
|
||||||
|
@ -426,11 +443,12 @@ class PendingProductView(MasterView):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
if self.viewing:
|
if self.viewing:
|
||||||
product = context['instance']
|
product = context["instance"]
|
||||||
if (product.status == enum.PendingProductStatus.READY
|
if product.status == enum.PendingProductStatus.READY and self.has_any_perm(
|
||||||
and self.has_any_perm('resolve', 'ignore')):
|
"resolve", "ignore"
|
||||||
handler = self.app.get_batch_handler('neworder')
|
):
|
||||||
context['use_local_products'] = handler.use_local_products()
|
handler = self.app.get_batch_handler("neworder")
|
||||||
|
context["use_local_products"] = handler.use_local_products()
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -441,9 +459,12 @@ class PendingProductView(MasterView):
|
||||||
for row in product.new_order_batch_rows:
|
for row in product.new_order_batch_rows:
|
||||||
if not row.batch.executed:
|
if not row.batch.executed:
|
||||||
model_title = self.get_model_title()
|
model_title = self.get_model_title()
|
||||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
self.request.session.flash(
|
||||||
"to New Order Batch(es)", 'warning')
|
f"Cannot delete {model_title} still attached "
|
||||||
raise self.redirect(self.get_action_url('view', product))
|
"to New Order Batch(es)",
|
||||||
|
"warning",
|
||||||
|
)
|
||||||
|
raise self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
# go ahead and delete per usual
|
# go ahead and delete per usual
|
||||||
super().delete_instance(product)
|
super().delete_instance(product)
|
||||||
|
@ -469,21 +490,23 @@ class PendingProductView(MasterView):
|
||||||
product = self.get_instance()
|
product = self.get_instance()
|
||||||
|
|
||||||
if product.status != enum.PendingProductStatus.READY:
|
if product.status != enum.PendingProductStatus.READY:
|
||||||
self.request.session.flash("pending product does not have 'ready' status!", 'error')
|
self.request.session.flash(
|
||||||
return self.redirect(self.get_action_url('view', product))
|
"pending product does not have 'ready' status!", "error"
|
||||||
|
)
|
||||||
|
return self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
product_id = self.request.POST.get('product_id')
|
product_id = self.request.POST.get("product_id")
|
||||||
if not product_id:
|
if not product_id:
|
||||||
self.request.session.flash("must specify valid product_id", 'error')
|
self.request.session.flash("must specify valid product_id", "error")
|
||||||
return self.redirect(self.get_action_url('view', product))
|
return self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
batch_handler = self.app.get_batch_handler('neworder')
|
batch_handler = self.app.get_batch_handler("neworder")
|
||||||
order_handler = self.app.get_order_handler()
|
order_handler = self.app.get_order_handler()
|
||||||
|
|
||||||
info = batch_handler.get_product_info_external(session, product_id)
|
info = batch_handler.get_product_info_external(session, product_id)
|
||||||
order_handler.resolve_pending_product(product, info, self.request.user)
|
order_handler.resolve_pending_product(product, info, self.request.user)
|
||||||
|
|
||||||
return self.redirect(self.get_action_url('view', product))
|
return self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
def ignore(self):
|
def ignore(self):
|
||||||
"""
|
"""
|
||||||
|
@ -499,11 +522,13 @@ class PendingProductView(MasterView):
|
||||||
product = self.get_instance()
|
product = self.get_instance()
|
||||||
|
|
||||||
if product.status != enum.PendingProductStatus.READY:
|
if product.status != enum.PendingProductStatus.READY:
|
||||||
self.request.session.flash("pending product does not have 'ready' status!", 'error')
|
self.request.session.flash(
|
||||||
return self.redirect(self.get_action_url('view', product))
|
"pending product does not have 'ready' status!", "error"
|
||||||
|
)
|
||||||
|
return self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
product.status = enum.PendingProductStatus.IGNORED
|
product.status = enum.PendingProductStatus.IGNORED
|
||||||
return self.redirect(self.get_action_url('view', product))
|
return self.redirect(self.get_action_url("view", product))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def defaults(cls, config):
|
def defaults(cls, config):
|
||||||
|
@ -519,35 +544,45 @@ class PendingProductView(MasterView):
|
||||||
model_title = cls.get_model_title()
|
model_title = cls.get_model_title()
|
||||||
|
|
||||||
# resolve
|
# resolve
|
||||||
config.add_wutta_permission(permission_prefix,
|
config.add_wutta_permission(
|
||||||
f'{permission_prefix}.resolve',
|
permission_prefix, f"{permission_prefix}.resolve", f"Resolve {model_title}"
|
||||||
f"Resolve {model_title}")
|
)
|
||||||
config.add_route(f'{route_prefix}.resolve',
|
config.add_route(
|
||||||
f'{instance_url_prefix}/resolve',
|
f"{route_prefix}.resolve",
|
||||||
request_method='POST')
|
f"{instance_url_prefix}/resolve",
|
||||||
config.add_view(cls, attr='resolve',
|
request_method="POST",
|
||||||
route_name=f'{route_prefix}.resolve',
|
)
|
||||||
permission=f'{permission_prefix}.resolve')
|
config.add_view(
|
||||||
|
cls,
|
||||||
|
attr="resolve",
|
||||||
|
route_name=f"{route_prefix}.resolve",
|
||||||
|
permission=f"{permission_prefix}.resolve",
|
||||||
|
)
|
||||||
|
|
||||||
# ignore
|
# ignore
|
||||||
config.add_wutta_permission(permission_prefix,
|
config.add_wutta_permission(
|
||||||
f'{permission_prefix}.ignore',
|
permission_prefix, f"{permission_prefix}.ignore", f"Ignore {model_title}"
|
||||||
f"Ignore {model_title}")
|
)
|
||||||
config.add_route(f'{route_prefix}.ignore',
|
config.add_route(
|
||||||
f'{instance_url_prefix}/ignore',
|
f"{route_prefix}.ignore",
|
||||||
request_method='POST')
|
f"{instance_url_prefix}/ignore",
|
||||||
config.add_view(cls, attr='ignore',
|
request_method="POST",
|
||||||
route_name=f'{route_prefix}.ignore',
|
)
|
||||||
permission=f'{permission_prefix}.ignore')
|
config.add_view(
|
||||||
|
cls,
|
||||||
|
attr="ignore",
|
||||||
|
route_name=f"{route_prefix}.ignore",
|
||||||
|
permission=f"{permission_prefix}.ignore",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def defaults(config, **kwargs):
|
def defaults(config, **kwargs):
|
||||||
base = globals()
|
base = globals()
|
||||||
|
|
||||||
LocalProductView = kwargs.get('LocalProductView', base['LocalProductView'])
|
LocalProductView = kwargs.get("LocalProductView", base["LocalProductView"])
|
||||||
LocalProductView.defaults(config)
|
LocalProductView.defaults(config)
|
||||||
|
|
||||||
PendingProductView = kwargs.get('PendingProductView', base['PendingProductView'])
|
PendingProductView = kwargs.get("PendingProductView", base["PendingProductView"])
|
||||||
PendingProductView.defaults(config)
|
PendingProductView.defaults(config)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,51 +43,51 @@ class StoreView(MasterView):
|
||||||
* ``/stores/XXX/edit``
|
* ``/stores/XXX/edit``
|
||||||
* ``/stores/XXX/delete``
|
* ``/stores/XXX/delete``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_class = Store
|
model_class = Store
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
'store_id': "Store ID",
|
"store_id": "Store ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
filter_defaults = {
|
filter_defaults = {
|
||||||
'archived': {'active': True, 'verb': 'is_false'},
|
"archived": {"active": True, "verb": "is_false"},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_defaults = 'store_id'
|
sort_defaults = "store_id"
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
""" """
|
""" """
|
||||||
super().configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
# links
|
# links
|
||||||
g.set_link('store_id')
|
g.set_link("store_id")
|
||||||
g.set_link('name')
|
g.set_link("name")
|
||||||
|
|
||||||
def grid_row_class(self, store, data, i):
|
def grid_row_class(self, store, data, i):
|
||||||
""" """
|
""" """
|
||||||
if store.archived:
|
if store.archived:
|
||||||
return 'has-background-warning'
|
return "has-background-warning"
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
""" """
|
""" """
|
||||||
super().configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# store_id
|
# store_id
|
||||||
f.set_validator('store_id', self.unique_store_id)
|
f.set_validator("store_id", self.unique_store_id)
|
||||||
|
|
||||||
# name
|
# name
|
||||||
f.set_validator('name', self.unique_name)
|
f.set_validator("name", self.unique_name)
|
||||||
|
|
||||||
def unique_store_id(self, node, value):
|
def unique_store_id(self, node, value):
|
||||||
""" """
|
""" """
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
session = self.Session()
|
session = self.Session()
|
||||||
|
|
||||||
query = session.query(model.Store)\
|
query = session.query(model.Store).filter(model.Store.store_id == value)
|
||||||
.filter(model.Store.store_id == value)
|
|
||||||
|
|
||||||
if self.editing:
|
if self.editing:
|
||||||
uuid = self.request.matchdict['uuid']
|
uuid = self.request.matchdict["uuid"]
|
||||||
query = query.filter(model.Store.uuid != uuid)
|
query = query.filter(model.Store.uuid != uuid)
|
||||||
|
|
||||||
if query.count():
|
if query.count():
|
||||||
|
@ -98,11 +98,10 @@ class StoreView(MasterView):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
session = self.Session()
|
session = self.Session()
|
||||||
|
|
||||||
query = session.query(model.Store)\
|
query = session.query(model.Store).filter(model.Store.name == value)
|
||||||
.filter(model.Store.name == value)
|
|
||||||
|
|
||||||
if self.editing:
|
if self.editing:
|
||||||
uuid = self.request.matchdict['uuid']
|
uuid = self.request.matchdict["uuid"]
|
||||||
query = query.filter(model.Store.uuid != uuid)
|
query = query.filter(model.Store.uuid != uuid)
|
||||||
|
|
||||||
if query.count():
|
if query.count():
|
||||||
|
@ -112,7 +111,7 @@ class StoreView(MasterView):
|
||||||
def defaults(config, **kwargs):
|
def defaults(config, **kwargs):
|
||||||
base = globals()
|
base = globals()
|
||||||
|
|
||||||
StoreView = kwargs.get('StoreView', base['StoreView'])
|
StoreView = kwargs.get("StoreView", base["StoreView"])
|
||||||
StoreView.defaults(config)
|
StoreView.defaults(config)
|
||||||
|
|
||||||
|
|
||||||
|
|
14
tasks.py
14
tasks.py
|
@ -15,14 +15,14 @@ def release(c, skip_tests=False):
|
||||||
Release a new version of Sideshow
|
Release a new version of Sideshow
|
||||||
"""
|
"""
|
||||||
if not skip_tests:
|
if not skip_tests:
|
||||||
c.run('pytest')
|
c.run("pytest")
|
||||||
|
|
||||||
# rebuild pkg
|
# rebuild pkg
|
||||||
if os.path.exists('dist'):
|
if os.path.exists("dist"):
|
||||||
shutil.rmtree('dist')
|
shutil.rmtree("dist")
|
||||||
if os.path.exists('Sideshow.egg-info'):
|
if os.path.exists("Sideshow.egg-info"):
|
||||||
shutil.rmtree('Sideshow.egg-info')
|
shutil.rmtree("Sideshow.egg-info")
|
||||||
c.run('python -m build --sdist')
|
c.run("python -m build --sdist")
|
||||||
|
|
||||||
# upload
|
# upload
|
||||||
c.run('twine upload dist/*')
|
c.run("twine upload dist/*")
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,6 @@ class TestInstall(ConfigTestCase):
|
||||||
def test_run(self):
|
def test_run(self):
|
||||||
ctx = MagicMock(params={})
|
ctx = MagicMock(params={})
|
||||||
ctx.parent.wutta_config = self.config
|
ctx.parent.wutta_config = self.config
|
||||||
with patch.object(InstallHandler, 'run') as run:
|
with patch.object(InstallHandler, "run") as run:
|
||||||
mod.install(ctx)
|
mod.install(ctx)
|
||||||
run.assert_called_once_with()
|
run.assert_called_once_with()
|
||||||
|
|
|
@ -16,8 +16,6 @@ class TestNewOrderBatchRow(DataTestCase):
|
||||||
row = mod.NewOrderBatchRow(product_description="Vinegar")
|
row = mod.NewOrderBatchRow(product_description="Vinegar")
|
||||||
self.assertEqual(str(row), "Vinegar")
|
self.assertEqual(str(row), "Vinegar")
|
||||||
|
|
||||||
product = PendingProduct(brand_name="Bragg",
|
product = PendingProduct(brand_name="Bragg", description="Vinegar", size="32oz")
|
||||||
description="Vinegar",
|
|
||||||
size="32oz")
|
|
||||||
row = mod.NewOrderBatchRow(pending_product=product)
|
row = mod.NewOrderBatchRow(pending_product=product)
|
||||||
self.assertEqual(str(row), "Bragg Vinegar 32oz")
|
self.assertEqual(str(row), "Bragg Vinegar 32oz")
|
||||||
|
|
|
@ -21,7 +21,7 @@ class TestOrderItem(DataTestCase):
|
||||||
|
|
||||||
def make_config(self, **kw):
|
def make_config(self, **kw):
|
||||||
config = super().make_config(**kw)
|
config = super().make_config(**kw)
|
||||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def test_full_description(self):
|
def test_full_description(self):
|
||||||
|
@ -32,9 +32,9 @@ class TestOrderItem(DataTestCase):
|
||||||
item = mod.OrderItem(product_description="Vinegar")
|
item = mod.OrderItem(product_description="Vinegar")
|
||||||
self.assertEqual(item.full_description, "Vinegar")
|
self.assertEqual(item.full_description, "Vinegar")
|
||||||
|
|
||||||
item = mod.OrderItem(product_brand='Bragg',
|
item = mod.OrderItem(
|
||||||
product_description='Vinegar',
|
product_brand="Bragg", product_description="Vinegar", product_size="32oz"
|
||||||
product_size='32oz')
|
)
|
||||||
self.assertEqual(item.full_description, "Bragg Vinegar 32oz")
|
self.assertEqual(item.full_description, "Bragg Vinegar 32oz")
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
|
@ -45,15 +45,15 @@ class TestOrderItem(DataTestCase):
|
||||||
item = mod.OrderItem(product_description="Vinegar")
|
item = mod.OrderItem(product_description="Vinegar")
|
||||||
self.assertEqual(str(item), "Vinegar")
|
self.assertEqual(str(item), "Vinegar")
|
||||||
|
|
||||||
item = mod.OrderItem(product_brand='Bragg',
|
item = mod.OrderItem(
|
||||||
product_description='Vinegar',
|
product_brand="Bragg", product_description="Vinegar", product_size="32oz"
|
||||||
product_size='32oz')
|
)
|
||||||
self.assertEqual(str(item), "Bragg Vinegar 32oz")
|
self.assertEqual(str(item), "Bragg Vinegar 32oz")
|
||||||
|
|
||||||
def test_add_event(self):
|
def test_add_event(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
item = mod.OrderItem()
|
item = mod.OrderItem()
|
||||||
self.assertEqual(item.events, [])
|
self.assertEqual(item.events, [])
|
||||||
item.add_event(enum.ORDER_ITEM_EVENT_INITIATED, user)
|
item.add_event(enum.ORDER_ITEM_EVENT_INITIATED, user)
|
||||||
|
|
|
@ -20,9 +20,9 @@ class TestPendingProduct(DataTestCase):
|
||||||
product = mod.PendingProduct(size="32oz")
|
product = mod.PendingProduct(size="32oz")
|
||||||
self.assertEqual(str(product), "32oz")
|
self.assertEqual(str(product), "32oz")
|
||||||
|
|
||||||
product = mod.PendingProduct(brand_name="Bragg",
|
product = mod.PendingProduct(
|
||||||
description="Vinegar",
|
brand_name="Bragg", description="Vinegar", size="32oz"
|
||||||
size="32oz")
|
)
|
||||||
self.assertEqual(str(product), "Bragg Vinegar 32oz")
|
self.assertEqual(str(product), "Bragg Vinegar 32oz")
|
||||||
|
|
||||||
def test_full_description(self):
|
def test_full_description(self):
|
||||||
|
@ -38,7 +38,7 @@ class TestPendingProduct(DataTestCase):
|
||||||
product = mod.PendingProduct(size="32oz")
|
product = mod.PendingProduct(size="32oz")
|
||||||
self.assertEqual(product.full_description, "32oz")
|
self.assertEqual(product.full_description, "32oz")
|
||||||
|
|
||||||
product = mod.PendingProduct(brand_name="Bragg",
|
product = mod.PendingProduct(
|
||||||
description="Vinegar",
|
brand_name="Bragg", description="Vinegar", size="32oz"
|
||||||
size="32oz")
|
)
|
||||||
self.assertEqual(product.full_description, "Bragg Vinegar 32oz")
|
self.assertEqual(product.full_description, "Bragg Vinegar 32oz")
|
||||||
|
|
|
@ -13,5 +13,5 @@ class TestSideshowConfig(TestCase):
|
||||||
config = WuttaConfig(files=[])
|
config = WuttaConfig(files=[])
|
||||||
ext = mod.SideshowConfig()
|
ext = mod.SideshowConfig()
|
||||||
ext.configure(config)
|
ext.configure(config)
|
||||||
self.assertEqual(config.get('wutta.app_title'), "Sideshow")
|
self.assertEqual(config.get("wutta.app_title"), "Sideshow")
|
||||||
self.assertEqual(config.get('wutta.app_dist'), "Sideshow")
|
self.assertEqual(config.get("wutta.app_dist"), "Sideshow")
|
||||||
|
|
|
@ -9,8 +9,8 @@ class TestOrderHandler(DataTestCase):
|
||||||
|
|
||||||
def make_config(self, **kwargs):
|
def make_config(self, **kwargs):
|
||||||
config = super().make_config(**kwargs)
|
config = super().make_config(**kwargs)
|
||||||
config.setdefault('wutta.model_spec', 'sideshow.db.model')
|
config.setdefault("wutta.model_spec", "sideshow.db.model")
|
||||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def make_handler(self):
|
def make_handler(self):
|
||||||
|
@ -23,7 +23,7 @@ class TestOrderHandler(DataTestCase):
|
||||||
self.assertFalse(handler.expose_store_id())
|
self.assertFalse(handler.expose_store_id())
|
||||||
|
|
||||||
# config can enable
|
# config can enable
|
||||||
self.config.setdefault('sideshow.orders.expose_store_id', 'true')
|
self.config.setdefault("sideshow.orders.expose_store_id", "true")
|
||||||
self.assertTrue(handler.expose_store_id())
|
self.assertTrue(handler.expose_store_id())
|
||||||
|
|
||||||
def test_get_order_qty_uom_text(self):
|
def test_get_order_qty_uom_text(self):
|
||||||
|
@ -35,7 +35,9 @@ class TestOrderHandler(DataTestCase):
|
||||||
self.assertEqual(text, "2 Cases (x 12 = 24 Units)")
|
self.assertEqual(text, "2 Cases (x 12 = 24 Units)")
|
||||||
|
|
||||||
# typical w/ html
|
# typical w/ html
|
||||||
text = handler.get_order_qty_uom_text(2, enum.ORDER_UOM_CASE, case_size=12, html=True)
|
text = handler.get_order_qty_uom_text(
|
||||||
|
2, enum.ORDER_UOM_CASE, case_size=12, html=True
|
||||||
|
)
|
||||||
self.assertEqual(text, "2 Cases (× 12 = 24 Units)")
|
self.assertEqual(text, "2 Cases (× 12 = 24 Units)")
|
||||||
|
|
||||||
# unknown case size
|
# unknown case size
|
||||||
|
@ -55,20 +57,39 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# typical
|
# typical
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_INITIATED))
|
self.assertIsNone(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_INITIATED)
|
||||||
|
)
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_READY))
|
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_READY))
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_PLACED))
|
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_PLACED))
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_RECEIVED))
|
self.assertIsNone(
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CONTACTED))
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||||
|
)
|
||||||
|
self.assertIsNone(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CONTACTED)
|
||||||
|
)
|
||||||
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_PAID))
|
self.assertIsNone(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_PAID))
|
||||||
|
|
||||||
# warning
|
# warning
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CANCELED), 'warning')
|
self.assertEqual(
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUND_PENDING), 'warning')
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CANCELED), "warning"
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUNDED), 'warning')
|
)
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_RESTOCKED), 'warning')
|
self.assertEqual(
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_EXPIRED), 'warning')
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUND_PENDING),
|
||||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_INACTIVE), 'warning')
|
"warning",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUNDED), "warning"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_RESTOCKED), "warning"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_EXPIRED), "warning"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_INACTIVE), "warning"
|
||||||
|
)
|
||||||
|
|
||||||
def test_resolve_pending_product(self):
|
def test_resolve_pending_product(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -76,65 +97,87 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
pending = model.PendingProduct(description='vinegar', unit_price_reg=5.99,
|
pending = model.PendingProduct(
|
||||||
|
description="vinegar",
|
||||||
|
unit_price_reg=5.99,
|
||||||
status=enum.PendingProductStatus.PENDING,
|
status=enum.PendingProductStatus.PENDING,
|
||||||
created_by=user)
|
created_by=user,
|
||||||
|
)
|
||||||
self.session.add(pending)
|
self.session.add(pending)
|
||||||
order = model.Order(order_id=100, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item = model.OrderItem(pending_product=pending,
|
order_id=100, customer_name="Fred Flintstone", created_by=user
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
)
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
item = model.OrderItem(
|
||||||
|
pending_product=pending,
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order.items.append(item)
|
order.items.append(item)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
'product_id': '07430500132',
|
"product_id": "07430500132",
|
||||||
'scancode': '07430500132',
|
"scancode": "07430500132",
|
||||||
'brand_name': "Bragg's",
|
"brand_name": "Bragg's",
|
||||||
'description': "Apple Cider Vinegar",
|
"description": "Apple Cider Vinegar",
|
||||||
'size': "32oz",
|
"size": "32oz",
|
||||||
'weighed': False,
|
"weighed": False,
|
||||||
'department_id': None,
|
"department_id": None,
|
||||||
'department_name': None,
|
"department_name": None,
|
||||||
'special_order': False,
|
"special_order": False,
|
||||||
'vendor_name': None,
|
"vendor_name": None,
|
||||||
'vendor_item_code': None,
|
"vendor_item_code": None,
|
||||||
'case_size': 12,
|
"case_size": 12,
|
||||||
'unit_cost': 2.99,
|
"unit_cost": 2.99,
|
||||||
'unit_price_reg': 5.99,
|
"unit_price_reg": 5.99,
|
||||||
}
|
}
|
||||||
|
|
||||||
# first try fails b/c pending status
|
# first try fails b/c pending status
|
||||||
self.assertEqual(len(item.events), 0)
|
self.assertEqual(len(item.events), 0)
|
||||||
self.assertRaises(ValueError, handler.resolve_pending_product, pending, info, user)
|
self.assertRaises(
|
||||||
|
ValueError, handler.resolve_pending_product, pending, info, user
|
||||||
|
)
|
||||||
|
|
||||||
# resolves okay if ready status
|
# resolves okay if ready status
|
||||||
pending.status = enum.PendingProductStatus.READY
|
pending.status = enum.PendingProductStatus.READY
|
||||||
handler.resolve_pending_product(pending, info, user)
|
handler.resolve_pending_product(pending, info, user)
|
||||||
self.assertEqual(len(item.events), 1)
|
self.assertEqual(len(item.events), 1)
|
||||||
self.assertEqual(item.events[0].type_code, enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED)
|
self.assertEqual(
|
||||||
|
item.events[0].type_code, enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED
|
||||||
|
)
|
||||||
self.assertIsNone(item.events[0].note)
|
self.assertIsNone(item.events[0].note)
|
||||||
|
|
||||||
# more sample data
|
# more sample data
|
||||||
pending2 = model.PendingProduct(description='vinegar', unit_price_reg=5.99,
|
pending2 = model.PendingProduct(
|
||||||
|
description="vinegar",
|
||||||
|
unit_price_reg=5.99,
|
||||||
status=enum.PendingProductStatus.READY,
|
status=enum.PendingProductStatus.READY,
|
||||||
created_by=user)
|
created_by=user,
|
||||||
|
)
|
||||||
self.session.add(pending2)
|
self.session.add(pending2)
|
||||||
order2 = model.Order(order_id=101, customer_name="Wilma Flintstone", created_by=user)
|
order2 = model.Order(
|
||||||
item2 = model.OrderItem(pending_product=pending2,
|
order_id=101, customer_name="Wilma Flintstone", created_by=user
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
)
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
item2 = model.OrderItem(
|
||||||
|
pending_product=pending2,
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order2.items.append(item2)
|
order2.items.append(item2)
|
||||||
self.session.add(order2)
|
self.session.add(order2)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
# resolve with extra note
|
# resolve with extra note
|
||||||
handler.resolve_pending_product(pending2, info, user, note='hello world')
|
handler.resolve_pending_product(pending2, info, user, note="hello world")
|
||||||
self.assertEqual(len(item2.events), 2)
|
self.assertEqual(len(item2.events), 2)
|
||||||
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED)
|
self.assertEqual(
|
||||||
|
item2.events[0].type_code, enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED
|
||||||
|
)
|
||||||
self.assertIsNone(item2.events[0].note)
|
self.assertIsNone(item2.events[0].note)
|
||||||
self.assertEqual(item2.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
|
self.assertEqual(item2.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
|
||||||
self.assertEqual(item2.events[1].note, "hello world")
|
self.assertEqual(item2.events[1].note, "hello world")
|
||||||
|
@ -145,17 +188,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -165,8 +219,9 @@ class TestOrderHandler(DataTestCase):
|
||||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
|
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
|
||||||
self.assertEqual(len(item1.events), 0)
|
self.assertEqual(len(item1.events), 0)
|
||||||
self.assertEqual(len(item2.events), 0)
|
self.assertEqual(len(item2.events), 0)
|
||||||
handler.process_placement([item1, item2], user,
|
handler.process_placement(
|
||||||
vendor_name="Acme Dist", po_number='ACME123')
|
[item1, item2], user, vendor_name="Acme Dist", po_number="ACME123"
|
||||||
|
)
|
||||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||||
self.assertEqual(len(item1.events), 1)
|
self.assertEqual(len(item1.events), 1)
|
||||||
|
@ -193,23 +248,40 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
item4 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item4 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item4)
|
order.items.append(item4)
|
||||||
item5 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item5 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item5)
|
order.items.append(item5)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -217,17 +289,26 @@ class TestOrderHandler(DataTestCase):
|
||||||
# all info provided
|
# all info provided
|
||||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||||
self.assertEqual(len(item1.events), 0)
|
self.assertEqual(len(item1.events), 0)
|
||||||
handler.process_receiving([item1], user, vendor_name="Acme Dist",
|
handler.process_receiving(
|
||||||
invoice_number='INV123', po_number='123')
|
[item1],
|
||||||
|
user,
|
||||||
|
vendor_name="Acme Dist",
|
||||||
|
invoice_number="INV123",
|
||||||
|
po_number="123",
|
||||||
|
)
|
||||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||||
self.assertEqual(len(item1.events), 1)
|
self.assertEqual(len(item1.events), 1)
|
||||||
self.assertEqual(item1.events[0].note, "invoice INV123 (PO 123) from vendor Acme Dist")
|
self.assertEqual(
|
||||||
|
item1.events[0].note, "invoice INV123 (PO 123) from vendor Acme Dist"
|
||||||
|
)
|
||||||
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
|
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
|
||||||
|
|
||||||
# missing PO number
|
# missing PO number
|
||||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||||
self.assertEqual(len(item2.events), 0)
|
self.assertEqual(len(item2.events), 0)
|
||||||
handler.process_receiving([item2], user, vendor_name="Acme Dist", invoice_number='INV123')
|
handler.process_receiving(
|
||||||
|
[item2], user, vendor_name="Acme Dist", invoice_number="INV123"
|
||||||
|
)
|
||||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||||
self.assertEqual(len(item2.events), 1)
|
self.assertEqual(len(item2.events), 1)
|
||||||
self.assertEqual(item2.events[0].note, "invoice INV123 from vendor Acme Dist")
|
self.assertEqual(item2.events[0].note, "invoice INV123 from vendor Acme Dist")
|
||||||
|
@ -236,7 +317,9 @@ class TestOrderHandler(DataTestCase):
|
||||||
# missing invoice number
|
# missing invoice number
|
||||||
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||||
self.assertEqual(len(item3.events), 0)
|
self.assertEqual(len(item3.events), 0)
|
||||||
handler.process_receiving([item3], user, vendor_name="Acme Dist", po_number='123')
|
handler.process_receiving(
|
||||||
|
[item3], user, vendor_name="Acme Dist", po_number="123"
|
||||||
|
)
|
||||||
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||||
self.assertEqual(len(item3.events), 1)
|
self.assertEqual(len(item3.events), 1)
|
||||||
self.assertEqual(item3.events[0].note, "PO 123 from vendor Acme Dist")
|
self.assertEqual(item3.events[0].note, "PO 123 from vendor Acme Dist")
|
||||||
|
@ -268,17 +351,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -315,17 +409,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -362,17 +467,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -389,8 +505,12 @@ class TestOrderHandler(DataTestCase):
|
||||||
self.assertEqual(len(item2.events), 1)
|
self.assertEqual(len(item2.events), 1)
|
||||||
self.assertIsNone(item1.events[0].note)
|
self.assertIsNone(item1.events[0].note)
|
||||||
self.assertIsNone(item2.events[0].note)
|
self.assertIsNone(item2.events[0].note)
|
||||||
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
|
self.assertEqual(
|
||||||
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
|
item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
item2.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED
|
||||||
|
)
|
||||||
|
|
||||||
# update last item, with extra note
|
# update last item, with extra note
|
||||||
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||||
|
@ -400,7 +520,9 @@ class TestOrderHandler(DataTestCase):
|
||||||
self.assertEqual(len(item3.events), 2)
|
self.assertEqual(len(item3.events), 2)
|
||||||
self.assertIsNone(item3.events[0].note)
|
self.assertIsNone(item3.events[0].note)
|
||||||
self.assertEqual(item3.events[1].note, "extra note")
|
self.assertEqual(item3.events[1].note, "extra note")
|
||||||
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
|
self.assertEqual(
|
||||||
|
item3.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED
|
||||||
|
)
|
||||||
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
|
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
|
||||||
|
|
||||||
def test_process_delivery(self):
|
def test_process_delivery(self):
|
||||||
|
@ -409,17 +531,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
@ -456,17 +589,28 @@ class TestOrderHandler(DataTestCase):
|
||||||
handler = self.make_handler()
|
handler = self.make_handler()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
order = model.Order(
|
||||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
)
|
||||||
|
item1 = model.OrderItem(
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item1)
|
order.items.append(item1)
|
||||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item2 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item2)
|
order.items.append(item2)
|
||||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item3 = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||||
|
)
|
||||||
order.items.append(item3)
|
order.items.append(item3)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
|
@ -17,10 +17,10 @@ class TestOrderRef(WebTestCase):
|
||||||
self.assertIsNot(sorted_query, query)
|
self.assertIsNot(sorted_query, query)
|
||||||
|
|
||||||
def test_get_object_url(self):
|
def test_get_object_url(self):
|
||||||
self.pyramid_config.add_route('orders.view', '/orders/{uuid}')
|
self.pyramid_config.add_route("orders.view", "/orders/{uuid}")
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, created_by=user)
|
order = model.Order(order_id=42, created_by=user)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
|
@ -29,7 +29,7 @@ class TestOrderRef(WebTestCase):
|
||||||
typ = mod.OrderRef(self.request, session=self.session)
|
typ = mod.OrderRef(self.request, session=self.session)
|
||||||
url = typ.get_object_url(order)
|
url = typ.get_object_url(order)
|
||||||
self.assertIsNotNone(url)
|
self.assertIsNotNone(url)
|
||||||
self.assertIn(f'/orders/{order.uuid}', url)
|
self.assertIn(f"/orders/{order.uuid}", url)
|
||||||
|
|
||||||
|
|
||||||
class TestLocalCustomerRef(WebTestCase):
|
class TestLocalCustomerRef(WebTestCase):
|
||||||
|
@ -43,7 +43,7 @@ class TestLocalCustomerRef(WebTestCase):
|
||||||
self.assertIsNot(sorted_query, query)
|
self.assertIsNot(sorted_query, query)
|
||||||
|
|
||||||
def test_get_object_url(self):
|
def test_get_object_url(self):
|
||||||
self.pyramid_config.add_route('local_customers.view', '/local/customers/{uuid}')
|
self.pyramid_config.add_route("local_customers.view", "/local/customers/{uuid}")
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class TestLocalCustomerRef(WebTestCase):
|
||||||
typ = mod.LocalCustomerRef(self.request, session=self.session)
|
typ = mod.LocalCustomerRef(self.request, session=self.session)
|
||||||
url = typ.get_object_url(customer)
|
url = typ.get_object_url(customer)
|
||||||
self.assertIsNotNone(url)
|
self.assertIsNotNone(url)
|
||||||
self.assertIn(f'/local/customers/{customer.uuid}', url)
|
self.assertIn(f"/local/customers/{customer.uuid}", url)
|
||||||
|
|
||||||
|
|
||||||
class TestPendingCustomerRef(WebTestCase):
|
class TestPendingCustomerRef(WebTestCase):
|
||||||
|
@ -68,21 +68,24 @@ class TestPendingCustomerRef(WebTestCase):
|
||||||
self.assertIsNot(sorted_query, query)
|
self.assertIsNot(sorted_query, query)
|
||||||
|
|
||||||
def test_get_object_url(self):
|
def test_get_object_url(self):
|
||||||
self.pyramid_config.add_route('pending_customers.view', '/pending/customers/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_customers.view", "/pending/customers/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
typ = mod.PendingCustomerRef(self.request, session=self.session)
|
typ = mod.PendingCustomerRef(self.request, session=self.session)
|
||||||
url = typ.get_object_url(customer)
|
url = typ.get_object_url(customer)
|
||||||
self.assertIsNotNone(url)
|
self.assertIsNotNone(url)
|
||||||
self.assertIn(f'/pending/customers/{customer.uuid}', url)
|
self.assertIn(f"/pending/customers/{customer.uuid}", url)
|
||||||
|
|
||||||
|
|
||||||
class TestLocalProductRef(WebTestCase):
|
class TestLocalProductRef(WebTestCase):
|
||||||
|
@ -96,7 +99,7 @@ class TestLocalProductRef(WebTestCase):
|
||||||
self.assertIsNot(sorted_query, query)
|
self.assertIsNot(sorted_query, query)
|
||||||
|
|
||||||
def test_get_object_url(self):
|
def test_get_object_url(self):
|
||||||
self.pyramid_config.add_route('local_products.view', '/local/products/{uuid}')
|
self.pyramid_config.add_route("local_products.view", "/local/products/{uuid}")
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
|
@ -107,7 +110,7 @@ class TestLocalProductRef(WebTestCase):
|
||||||
typ = mod.LocalProductRef(self.request, session=self.session)
|
typ = mod.LocalProductRef(self.request, session=self.session)
|
||||||
url = typ.get_object_url(product)
|
url = typ.get_object_url(product)
|
||||||
self.assertIsNotNone(url)
|
self.assertIsNotNone(url)
|
||||||
self.assertIn(f'/local/products/{product.uuid}', url)
|
self.assertIn(f"/local/products/{product.uuid}", url)
|
||||||
|
|
||||||
|
|
||||||
class TestPendingProductRef(WebTestCase):
|
class TestPendingProductRef(WebTestCase):
|
||||||
|
@ -121,18 +124,21 @@ class TestPendingProductRef(WebTestCase):
|
||||||
self.assertIsNot(sorted_query, query)
|
self.assertIsNot(sorted_query, query)
|
||||||
|
|
||||||
def test_get_object_url(self):
|
def test_get_object_url(self):
|
||||||
self.pyramid_config.add_route('pending_products.view', '/pending/products/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_products.view", "/pending/products/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
typ = mod.PendingProductRef(self.request, session=self.session)
|
typ = mod.PendingProductRef(self.request, session=self.session)
|
||||||
url = typ.get_object_url(product)
|
url = typ.get_object_url(product)
|
||||||
self.assertIsNotNone(url)
|
self.assertIsNotNone(url)
|
||||||
self.assertIn(f'/pending/products/{product.uuid}', url)
|
self.assertIn(f"/pending/products/{product.uuid}", url)
|
||||||
|
|
|
@ -13,7 +13,7 @@ from sideshow.web import app as mod
|
||||||
class TestMain(DataTestCase):
|
class TestMain(DataTestCase):
|
||||||
|
|
||||||
def test_coverage(self):
|
def test_coverage(self):
|
||||||
app = mod.main({}, **{'wutta_config': self.config})
|
app = mod.main({}, **{"wutta_config": self.config})
|
||||||
self.assertIsInstance(app, Router)
|
self.assertIsInstance(app, Router)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,15 @@ class TestSideshowMenuHandler(WebTestCase):
|
||||||
def test_make_menus(self):
|
def test_make_menus(self):
|
||||||
handler = mod.SideshowMenuHandler(self.config)
|
handler = mod.SideshowMenuHandler(self.config)
|
||||||
menus = handler.make_menus(self.request)
|
menus = handler.make_menus(self.request)
|
||||||
titles = [menu['title'] for menu in menus]
|
titles = [menu["title"] for menu in menus]
|
||||||
self.assertEqual(titles, [
|
self.assertEqual(
|
||||||
'Orders',
|
titles,
|
||||||
'Customers',
|
[
|
||||||
'Products',
|
"Orders",
|
||||||
'Batches',
|
"Customers",
|
||||||
'Other',
|
"Products",
|
||||||
'Admin',
|
"Batches",
|
||||||
])
|
"Other",
|
||||||
|
"Admin",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
|
@ -33,16 +33,16 @@ class TestNewOrderBatchView(WebTestCase):
|
||||||
|
|
||||||
# store_id not exposed by default
|
# store_id not exposed by default
|
||||||
grid = view.make_grid(model_class=model.NewOrderBatch)
|
grid = view.make_grid(model_class=model.NewOrderBatch)
|
||||||
self.assertIn('store_id', grid.columns)
|
self.assertIn("store_id", grid.columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertNotIn('store_id', grid.columns)
|
self.assertNotIn("store_id", grid.columns)
|
||||||
|
|
||||||
# store_id is exposed if configured
|
# store_id is exposed if configured
|
||||||
self.config.setdefault('sideshow.orders.expose_store_id', 'true')
|
self.config.setdefault("sideshow.orders.expose_store_id", "true")
|
||||||
grid = view.make_grid(model_class=model.NewOrderBatch)
|
grid = view.make_grid(model_class=model.NewOrderBatch)
|
||||||
self.assertIn('store_id', grid.columns)
|
self.assertIn("store_id", grid.columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('store_id', grid.columns)
|
self.assertIn("store_id", grid.columns)
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -50,74 +50,85 @@ class TestNewOrderBatchView(WebTestCase):
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
handler = view.batch_handler
|
handler = view.batch_handler
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
batch = handler.make_batch(self.session, pending_customer=customer, created_by=user)
|
batch = handler.make_batch(
|
||||||
|
self.session, pending_customer=customer, created_by=user
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
# viewing
|
# viewing
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
form = view.make_form(model_instance=batch)
|
form = view.make_form(model_instance=batch)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
schema = form.get_schema()
|
schema = form.get_schema()
|
||||||
self.assertIsInstance(schema['pending_customer'].typ, PendingCustomerRef)
|
self.assertIsInstance(schema["pending_customer"].typ, PendingCustomerRef)
|
||||||
self.assertIsInstance(schema['total_price'].typ, WuttaMoney)
|
self.assertIsInstance(schema["total_price"].typ, WuttaMoney)
|
||||||
|
|
||||||
# store_id not exposed by default
|
# store_id not exposed by default
|
||||||
form = view.make_form(model_instance=batch)
|
form = view.make_form(model_instance=batch)
|
||||||
self.assertIn('store_id', form)
|
self.assertIn("store_id", form)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertNotIn('store_id', form)
|
self.assertNotIn("store_id", form)
|
||||||
|
|
||||||
# store_id is exposed if configured
|
# store_id is exposed if configured
|
||||||
self.config.setdefault('sideshow.orders.expose_store_id', 'true')
|
self.config.setdefault("sideshow.orders.expose_store_id", "true")
|
||||||
form = view.make_form(model_instance=batch)
|
form = view.make_form(model_instance=batch)
|
||||||
self.assertIn('store_id', form)
|
self.assertIn("store_id", form)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('store_id', form)
|
self.assertIn("store_id", form)
|
||||||
|
|
||||||
def test_configure_row_grid(self):
|
def test_configure_row_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
grid = view.make_grid(model_class=model.NewOrderBatchRow)
|
grid = view.make_grid(model_class=model.NewOrderBatchRow)
|
||||||
self.assertNotIn('total_price', grid.renderers)
|
self.assertNotIn("total_price", grid.renderers)
|
||||||
view.configure_row_grid(grid)
|
view.configure_row_grid(grid)
|
||||||
self.assertIn('total_price', grid.renderers)
|
self.assertIn("total_price", grid.renderers)
|
||||||
|
|
||||||
def test_get_xref_buttons(self):
|
def test_get_xref_buttons(self):
|
||||||
self.pyramid_config.add_route('orders.view', '/orders/{uuid}')
|
self.pyramid_config.add_route("orders.view", "/orders/{uuid}")
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
handler = view.batch_handler
|
handler = view.batch_handler
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
|
|
||||||
# 1st batch has no order
|
# 1st batch has no order
|
||||||
batch = handler.make_batch(self.session, pending_customer=customer, created_by=user)
|
batch = handler.make_batch(
|
||||||
|
self.session, pending_customer=customer, created_by=user
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
buttons = view.get_xref_buttons(batch)
|
buttons = view.get_xref_buttons(batch)
|
||||||
self.assertEqual(len(buttons), 0)
|
self.assertEqual(len(buttons), 0)
|
||||||
|
|
||||||
# 2nd batch is executed; has order
|
# 2nd batch is executed; has order
|
||||||
batch = handler.make_batch(self.session, pending_customer=customer, created_by=user,
|
batch = handler.make_batch(
|
||||||
executed=datetime.datetime.now(), executed_by=user)
|
self.session,
|
||||||
|
pending_customer=customer,
|
||||||
|
created_by=user,
|
||||||
|
executed=datetime.datetime.now(),
|
||||||
|
executed_by=user,
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
order = model.Order(order_id=batch.id, created_by=user)
|
order = model.Order(order_id=batch.id, created_by=user)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, "Session", return_value=self.session):
|
||||||
# nb. this also requires perm
|
# nb. this also requires perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
buttons = view.get_xref_buttons(batch)
|
buttons = view.get_xref_buttons(batch)
|
||||||
self.assertEqual(len(buttons), 1)
|
self.assertEqual(len(buttons), 1)
|
||||||
|
|
|
@ -19,11 +19,11 @@ class TestCommonView(WebTestCase):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
self.assertEqual(len(user.roles), 0)
|
self.assertEqual(len(user.roles), 0)
|
||||||
view.setup_enhance_admin_user(user)
|
view.setup_enhance_admin_user(user)
|
||||||
self.assertEqual(len(user.roles), 1)
|
self.assertEqual(len(user.roles), 1)
|
||||||
self.assertEqual(user.roles[0].name, 'Order Admin')
|
self.assertEqual(user.roles[0].name, "Order Admin")
|
||||||
|
|
|
@ -25,43 +25,43 @@ class TestLocalCustomerView(WebTestCase):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
grid = view.make_grid(model_class=model.LocalCustomer)
|
grid = view.make_grid(model_class=model.LocalCustomer)
|
||||||
self.assertNotIn('full_name', grid.linked_columns)
|
self.assertNotIn("full_name", grid.linked_columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('full_name', grid.linked_columns)
|
self.assertIn("full_name", grid.linked_columns)
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# creating
|
# creating
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
form = view.make_form(model_class=model.LocalCustomer)
|
form = view.make_form(model_class=model.LocalCustomer)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertNotIn('external_id', form)
|
self.assertNotIn("external_id", form)
|
||||||
self.assertNotIn('full_name', form)
|
self.assertNotIn("full_name", form)
|
||||||
self.assertNotIn('orders', form)
|
self.assertNotIn("orders", form)
|
||||||
self.assertNotIn('new_order_batches', form)
|
self.assertNotIn("new_order_batches", form)
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.LocalCustomer()
|
customer = model.LocalCustomer()
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
# viewing
|
# viewing
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
form = view.make_form(model_instance=customer)
|
form = view.make_form(model_instance=customer)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('external_id', form)
|
self.assertIn("external_id", form)
|
||||||
self.assertIn('full_name', form)
|
self.assertIn("full_name", form)
|
||||||
self.assertIn('orders', form)
|
self.assertIn("orders", form)
|
||||||
self.assertIn('new_order_batches', form)
|
self.assertIn("new_order_batches", form)
|
||||||
|
|
||||||
def test_make_orders_grid(self):
|
def test_make_orders_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.LocalCustomer()
|
customer = model.LocalCustomer()
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
|
@ -74,21 +74,23 @@ class TestLocalCustomerView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_orders_grid(customer)
|
grid = view.make_orders_grid(customer)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_make_new_order_batches_grid(self):
|
def test_make_new_order_batches_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.LocalCustomer()
|
customer = model.LocalCustomer()
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
batch = handler.make_batch(self.session, local_customer=customer, created_by=user)
|
batch = handler.make_batch(
|
||||||
|
self.session, local_customer=customer, created_by=user
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
|
@ -97,31 +99,36 @@ class TestLocalCustomerView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_new_order_batches_grid(customer)
|
grid = view.make_new_order_batches_grid(customer)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_objectify(self):
|
def test_objectify(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
with patch.object(self.request, 'user', new=user):
|
with patch.object(self.request, "user", new=user):
|
||||||
form = view.make_model_form()
|
form = view.make_model_form()
|
||||||
with patch.object(form, 'validated', create=True, new={
|
with patch.object(
|
||||||
'first_name': 'Chuck',
|
form,
|
||||||
'last_name': 'Norris',
|
"validated",
|
||||||
}):
|
create=True,
|
||||||
|
new={
|
||||||
|
"first_name": "Chuck",
|
||||||
|
"last_name": "Norris",
|
||||||
|
},
|
||||||
|
):
|
||||||
customer = view.objectify(form)
|
customer = view.objectify(form)
|
||||||
self.assertIsInstance(customer, model.LocalCustomer)
|
self.assertIsInstance(customer, model.LocalCustomer)
|
||||||
self.assertEqual(customer.first_name, 'Chuck')
|
self.assertEqual(customer.first_name, "Chuck")
|
||||||
self.assertEqual(customer.last_name, 'Norris')
|
self.assertEqual(customer.last_name, "Norris")
|
||||||
self.assertEqual(customer.full_name, 'Chuck Norris')
|
self.assertEqual(customer.full_name, "Chuck Norris")
|
||||||
|
|
||||||
|
|
||||||
class TestPendingCustomerView(WebTestCase):
|
class TestPendingCustomerView(WebTestCase):
|
||||||
|
@ -135,7 +142,7 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
# nb. mostly just getting coverage here
|
# nb. mostly just getting coverage here
|
||||||
grid = view.make_grid(model_class=model.PendingCustomer)
|
grid = view.make_grid(model_class=model.PendingCustomer)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('full_name', grid.linked_columns)
|
self.assertIn("full_name", grid.linked_columns)
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -143,41 +150,43 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# creating
|
# creating
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
form = view.make_form(model_class=model.PendingCustomer)
|
form = view.make_form(model_class=model.PendingCustomer)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertNotIn('status', form)
|
self.assertNotIn("status", form)
|
||||||
self.assertNotIn('created', form)
|
self.assertNotIn("created", form)
|
||||||
self.assertNotIn('created_by', form)
|
self.assertNotIn("created_by", form)
|
||||||
self.assertNotIn('orders', form)
|
self.assertNotIn("orders", form)
|
||||||
self.assertNotIn('new_order_batches', form)
|
self.assertNotIn("new_order_batches", form)
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
# viewing
|
# viewing
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
form = view.make_form(model_instance=customer)
|
form = view.make_form(model_instance=customer)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('status', form)
|
self.assertIn("status", form)
|
||||||
self.assertIn('created', form)
|
self.assertIn("created", form)
|
||||||
self.assertIn('created_by', form)
|
self.assertIn("created_by", form)
|
||||||
self.assertIn('orders', form)
|
self.assertIn("orders", form)
|
||||||
self.assertIn('new_order_batches', form)
|
self.assertIn("new_order_batches", form)
|
||||||
|
|
||||||
def test_make_orders_grid(self):
|
def test_make_orders_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
order = model.Order(order_id=42, pending_customer=customer, created_by=user)
|
order = model.Order(order_id=42, pending_customer=customer, created_by=user)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
|
@ -188,10 +197,10 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_orders_grid(customer)
|
grid = view.make_orders_grid(customer)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_make_new_order_batches_grid(self):
|
def test_make_new_order_batches_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -199,12 +208,15 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
batch = handler.make_batch(self.session, pending_customer=customer, created_by=user)
|
batch = handler.make_batch(
|
||||||
|
self.session, pending_customer=customer, created_by=user
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
|
@ -213,44 +225,54 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_new_order_batches_grid(customer)
|
grid = view.make_new_order_batches_grid(customer)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_objectify(self):
|
def test_objectify(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
with patch.object(self.request, 'user', new=user):
|
with patch.object(self.request, "user", new=user):
|
||||||
form = view.make_model_form()
|
form = view.make_model_form()
|
||||||
with patch.object(form, 'validated', create=True, new={
|
with patch.object(
|
||||||
'full_name': "Fred Flinstone",
|
form,
|
||||||
}):
|
"validated",
|
||||||
|
create=True,
|
||||||
|
new={
|
||||||
|
"full_name": "Fred Flinstone",
|
||||||
|
},
|
||||||
|
):
|
||||||
customer = view.objectify(form)
|
customer = view.objectify(form)
|
||||||
self.assertIsInstance(customer, model.PendingCustomer)
|
self.assertIsInstance(customer, model.PendingCustomer)
|
||||||
self.assertIs(customer.created_by, user)
|
self.assertIs(customer.created_by, user)
|
||||||
self.assertEqual(customer.status, enum.PendingCustomerStatus.PENDING)
|
self.assertEqual(
|
||||||
|
customer.status, enum.PendingCustomerStatus.PENDING
|
||||||
|
)
|
||||||
|
|
||||||
def test_delete_instance(self):
|
def test_delete_instance(self):
|
||||||
self.pyramid_config.add_route('pending_customers.view', '/pending/customers/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_customers.view", "/pending/customers/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
|
|
||||||
# 1st customer is standalone, will be deleted
|
# 1st customer is standalone, will be deleted
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
self.assertEqual(self.session.query(model.PendingCustomer).count(), 1)
|
self.assertEqual(self.session.query(model.PendingCustomer).count(), 1)
|
||||||
|
@ -259,10 +281,13 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
self.assertEqual(self.session.query(model.PendingCustomer).count(), 0)
|
self.assertEqual(self.session.query(model.PendingCustomer).count(), 0)
|
||||||
|
|
||||||
# 2nd customer is attached to new order batch, will not be deleted
|
# 2nd customer is attached to new order batch, will not be deleted
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
batch = handler.make_batch(self.session, created_by=user, pending_customer=customer)
|
batch = handler.make_batch(
|
||||||
|
self.session, created_by=user, pending_customer=customer
|
||||||
|
)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
self.assertEqual(self.session.query(model.PendingCustomer).count(), 1)
|
self.assertEqual(self.session.query(model.PendingCustomer).count(), 1)
|
||||||
|
@ -280,8 +305,9 @@ class TestPendingCustomerView(WebTestCase):
|
||||||
self.assertEqual(self.session.query(model.PendingCustomer).count(), 0)
|
self.assertEqual(self.session.query(model.PendingCustomer).count(), 0)
|
||||||
|
|
||||||
# 3rd customer is attached to order, will not be deleted
|
# 3rd customer is attached to order, will not be deleted
|
||||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
customer = model.PendingCustomer(
|
||||||
created_by=user)
|
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(customer)
|
self.session.add(customer)
|
||||||
order = model.Order(order_id=42, created_by=user, pending_customer=customer)
|
order = model.Order(order_id=42, created_by=user, pending_customer=customer)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -25,53 +25,56 @@ class TestLocalProductView(WebTestCase):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
grid = view.make_grid(model_class=model.LocalProduct)
|
grid = view.make_grid(model_class=model.LocalProduct)
|
||||||
self.assertNotIn('scancode', grid.linked_columns)
|
self.assertNotIn("scancode", grid.linked_columns)
|
||||||
self.assertNotIn('brand_name', grid.linked_columns)
|
self.assertNotIn("brand_name", grid.linked_columns)
|
||||||
self.assertNotIn('description', grid.linked_columns)
|
self.assertNotIn("description", grid.linked_columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('scancode', grid.linked_columns)
|
self.assertIn("scancode", grid.linked_columns)
|
||||||
self.assertIn('brand_name', grid.linked_columns)
|
self.assertIn("brand_name", grid.linked_columns)
|
||||||
self.assertIn('description', grid.linked_columns)
|
self.assertIn("description", grid.linked_columns)
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# creating
|
# creating
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
form = view.make_form(model_class=model.LocalProduct)
|
form = view.make_form(model_class=model.LocalProduct)
|
||||||
self.assertIn('external_id', form)
|
self.assertIn("external_id", form)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertNotIn('external_id', form)
|
self.assertNotIn("external_id", form)
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
product = model.LocalProduct()
|
product = model.LocalProduct()
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
# viewing
|
# viewing
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
form = view.make_form(model_instance=product)
|
form = view.make_form(model_instance=product)
|
||||||
self.assertNotIn('external_id', form.readonly_fields)
|
self.assertNotIn("external_id", form.readonly_fields)
|
||||||
self.assertNotIn('local_products.view.orders', form.grid_vue_context)
|
self.assertNotIn("local_products.view.orders", form.grid_vue_context)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('external_id', form.readonly_fields)
|
self.assertIn("external_id", form.readonly_fields)
|
||||||
self.assertIn('local_products.view.orders', form.grid_vue_context)
|
self.assertIn("local_products.view.orders", form.grid_vue_context)
|
||||||
|
|
||||||
def test_make_orders_grid(self):
|
def test_make_orders_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
||||||
product = model.LocalProduct()
|
product = model.LocalProduct()
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
item = model.OrderItem(local_product=product,
|
item = model.OrderItem(
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
local_product=product,
|
||||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED,
|
||||||
|
)
|
||||||
order.items.append(item)
|
order.items.append(item)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
@ -81,10 +84,10 @@ class TestLocalProductView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_orders_grid(product)
|
grid = view.make_orders_grid(product)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_make_new_order_batches_grid(self):
|
def test_make_new_order_batches_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -92,14 +95,15 @@ class TestLocalProductView(WebTestCase):
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
batch = handler.make_batch(self.session, created_by=user)
|
batch = handler.make_batch(self.session, created_by=user)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
product = model.LocalProduct()
|
product = model.LocalProduct()
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
row = handler.make_row(local_product=product,
|
row = handler.make_row(
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
local_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||||
|
)
|
||||||
handler.add_row(batch, row)
|
handler.add_row(batch, row)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
|
@ -108,10 +112,10 @@ class TestLocalProductView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_new_order_batches_grid(product)
|
grid = view.make_new_order_batches_grid(product)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
|
|
||||||
class TestPendingProductView(WebTestCase):
|
class TestPendingProductView(WebTestCase):
|
||||||
|
@ -124,13 +128,13 @@ class TestPendingProductView(WebTestCase):
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
# nb. mostly just getting coverage here
|
# nb. mostly just getting coverage here
|
||||||
grid = view.make_grid(model_class=model.PendingProduct)
|
grid = view.make_grid(model_class=model.PendingProduct)
|
||||||
self.assertNotIn('scancode', grid.linked_columns)
|
self.assertNotIn("scancode", grid.linked_columns)
|
||||||
self.assertNotIn('brand_name', grid.linked_columns)
|
self.assertNotIn("brand_name", grid.linked_columns)
|
||||||
self.assertNotIn('description', grid.linked_columns)
|
self.assertNotIn("description", grid.linked_columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('scancode', grid.linked_columns)
|
self.assertIn("scancode", grid.linked_columns)
|
||||||
self.assertIn('brand_name', grid.linked_columns)
|
self.assertIn("brand_name", grid.linked_columns)
|
||||||
self.assertIn('description', grid.linked_columns)
|
self.assertIn("description", grid.linked_columns)
|
||||||
|
|
||||||
def test_grid_row_class(self):
|
def test_grid_row_class(self):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
|
@ -143,7 +147,7 @@ class TestPendingProductView(WebTestCase):
|
||||||
|
|
||||||
# warning for ignored
|
# warning for ignored
|
||||||
product.status = enum.PendingProductStatus.IGNORED
|
product.status = enum.PendingProductStatus.IGNORED
|
||||||
self.assertEqual(view.grid_row_class(product, {}, 1), 'has-background-warning')
|
self.assertEqual(view.grid_row_class(product, {}, 1), "has-background-warning")
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -151,41 +155,46 @@ class TestPendingProductView(WebTestCase):
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# creating
|
# creating
|
||||||
with patch.object(view, 'creating', new=True):
|
with patch.object(view, "creating", new=True):
|
||||||
form = view.make_form(model_class=model.PendingProduct)
|
form = view.make_form(model_class=model.PendingProduct)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertNotIn('created', form)
|
self.assertNotIn("created", form)
|
||||||
self.assertNotIn('created_by', form)
|
self.assertNotIn("created_by", form)
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
# viewing
|
# viewing
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
form = view.make_form(model_instance=product)
|
form = view.make_form(model_instance=product)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('status', form)
|
self.assertIn("status", form)
|
||||||
self.assertIn('created', form)
|
self.assertIn("created", form)
|
||||||
self.assertIn('created_by', form)
|
self.assertIn("created_by", form)
|
||||||
|
|
||||||
def test_make_orders_grid(self):
|
def test_make_orders_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
item = model.OrderItem(pending_product=product,
|
item = model.OrderItem(
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
pending_product=product,
|
||||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED,
|
||||||
|
)
|
||||||
order.items.append(item)
|
order.items.append(item)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
@ -195,10 +204,10 @@ class TestPendingProductView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_orders_grid(product)
|
grid = view.make_orders_grid(product)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_make_new_order_batches_grid(self):
|
def test_make_new_order_batches_grid(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -206,15 +215,17 @@ class TestPendingProductView(WebTestCase):
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
batch = handler.make_batch(self.session, created_by=user)
|
batch = handler.make_batch(self.session, created_by=user)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
row = handler.make_row(pending_product=product,
|
row = handler.make_row(
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||||
|
)
|
||||||
handler.add_row(batch, row)
|
handler.add_row(batch, row)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
|
@ -223,57 +234,60 @@ class TestPendingProductView(WebTestCase):
|
||||||
self.assertEqual(len(grid.actions), 0)
|
self.assertEqual(len(grid.actions), 0)
|
||||||
|
|
||||||
# with view perm
|
# with view perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
grid = view.make_new_order_batches_grid(product)
|
grid = view.make_new_order_batches_grid(product)
|
||||||
self.assertEqual(len(grid.actions), 1)
|
self.assertEqual(len(grid.actions), 1)
|
||||||
self.assertEqual(grid.actions[0].key, 'view')
|
self.assertEqual(grid.actions[0].key, "view")
|
||||||
|
|
||||||
def test_get_template_context(self):
|
def test_get_template_context(self):
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING)
|
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING)
|
||||||
orig_context = {'instance': product}
|
orig_context = {"instance": product}
|
||||||
|
|
||||||
# local setting omitted by default
|
# local setting omitted by default
|
||||||
context = view.get_template_context(orig_context)
|
context = view.get_template_context(orig_context)
|
||||||
self.assertNotIn('use_local_products', context)
|
self.assertNotIn("use_local_products", context)
|
||||||
|
|
||||||
# still omitted even though 'viewing'
|
# still omitted even though 'viewing'
|
||||||
with patch.object(view, 'viewing', new=True):
|
with patch.object(view, "viewing", new=True):
|
||||||
context = view.get_template_context(orig_context)
|
context = view.get_template_context(orig_context)
|
||||||
self.assertNotIn('use_local_products', context)
|
self.assertNotIn("use_local_products", context)
|
||||||
|
|
||||||
# still omitted even though correct status
|
# still omitted even though correct status
|
||||||
product.status = enum.PendingProductStatus.READY
|
product.status = enum.PendingProductStatus.READY
|
||||||
context = view.get_template_context(orig_context)
|
context = view.get_template_context(orig_context)
|
||||||
self.assertNotIn('use_local_products', context)
|
self.assertNotIn("use_local_products", context)
|
||||||
|
|
||||||
# no longer omitted if user has perm
|
# no longer omitted if user has perm
|
||||||
with patch.object(self.request, 'is_root', new=True):
|
with patch.object(self.request, "is_root", new=True):
|
||||||
context = view.get_template_context(orig_context)
|
context = view.get_template_context(orig_context)
|
||||||
self.assertIn('use_local_products', context)
|
self.assertIn("use_local_products", context)
|
||||||
# nb. true by default
|
# nb. true by default
|
||||||
self.assertTrue(context['use_local_products'])
|
self.assertTrue(context["use_local_products"])
|
||||||
|
|
||||||
# accurately reflects config
|
# accurately reflects config
|
||||||
self.config.setdefault('sideshow.orders.use_local_products', 'false')
|
self.config.setdefault("sideshow.orders.use_local_products", "false")
|
||||||
context = view.get_template_context(orig_context)
|
context = view.get_template_context(orig_context)
|
||||||
self.assertFalse(context['use_local_products'])
|
self.assertFalse(context["use_local_products"])
|
||||||
|
|
||||||
def test_delete_instance(self):
|
def test_delete_instance(self):
|
||||||
self.pyramid_config.add_route('pending_products.view', '/pending/products/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_products.view", "/pending/products/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
handler = NewOrderBatchHandler(self.config)
|
handler = NewOrderBatchHandler(self.config)
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
|
|
||||||
# 1st product is standalone, will be deleted
|
# 1st product is standalone, will be deleted
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
self.assertEqual(self.session.query(model.PendingProduct).count(), 1)
|
self.assertEqual(self.session.query(model.PendingProduct).count(), 1)
|
||||||
|
@ -284,11 +298,13 @@ class TestPendingProductView(WebTestCase):
|
||||||
# 2nd product is attached to new order batch, will not be deleted
|
# 2nd product is attached to new order batch, will not be deleted
|
||||||
batch = handler.make_batch(self.session, created_by=user)
|
batch = handler.make_batch(self.session, created_by=user)
|
||||||
self.session.add(batch)
|
self.session.add(batch)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
row = handler.make_row(pending_product=product,
|
row = handler.make_row(
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||||
|
)
|
||||||
handler.add_row(batch, row)
|
handler.add_row(batch, row)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
self.assertEqual(self.session.query(model.PendingProduct).count(), 1)
|
self.assertEqual(self.session.query(model.PendingProduct).count(), 1)
|
||||||
|
@ -306,61 +322,74 @@ class TestPendingProductView(WebTestCase):
|
||||||
self.assertEqual(self.session.query(model.PendingProduct).count(), 0)
|
self.assertEqual(self.session.query(model.PendingProduct).count(), 0)
|
||||||
|
|
||||||
def test_resolve(self):
|
def test_resolve(self):
|
||||||
self.pyramid_config.add_route('pending_products.view', '/pending/products/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_products.view", "/pending/products/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
'product_id': '07430500132',
|
"product_id": "07430500132",
|
||||||
'scancode': '07430500132',
|
"scancode": "07430500132",
|
||||||
'brand_name': "Bragg's",
|
"brand_name": "Bragg's",
|
||||||
'description': "Apple Cider Vinegar",
|
"description": "Apple Cider Vinegar",
|
||||||
'size': "32oz",
|
"size": "32oz",
|
||||||
'weighed': False,
|
"weighed": False,
|
||||||
'department_id': None,
|
"department_id": None,
|
||||||
'department_name': None,
|
"department_name": None,
|
||||||
'special_order': False,
|
"special_order": False,
|
||||||
'vendor_name': None,
|
"vendor_name": None,
|
||||||
'vendor_item_code': None,
|
"vendor_item_code": None,
|
||||||
'case_size': 12,
|
"case_size": 12,
|
||||||
'unit_cost': 2.99,
|
"unit_cost": 2.99,
|
||||||
'unit_price_reg': 5.99,
|
"unit_price_reg": 5.99,
|
||||||
}
|
}
|
||||||
|
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, "Session", return_value=self.session):
|
||||||
with patch.object(self.request, 'user', new=user):
|
with patch.object(self.request, "user", new=user):
|
||||||
with patch.object(self.request, 'matchdict', new={'uuid': product.uuid}):
|
with patch.object(
|
||||||
|
self.request, "matchdict", new={"uuid": product.uuid}
|
||||||
|
):
|
||||||
|
|
||||||
# flash error if wrong status
|
# flash error if wrong status
|
||||||
result = view.resolve()
|
result = view.resolve()
|
||||||
self.assertIsInstance(result, HTTPFound)
|
self.assertIsInstance(result, HTTPFound)
|
||||||
self.assertTrue(self.request.session.peek_flash('error'))
|
self.assertTrue(self.request.session.peek_flash("error"))
|
||||||
self.assertEqual(self.request.session.pop_flash('error'),
|
self.assertEqual(
|
||||||
["pending product does not have 'ready' status!"])
|
self.request.session.pop_flash("error"),
|
||||||
|
["pending product does not have 'ready' status!"],
|
||||||
|
)
|
||||||
|
|
||||||
# flash error if product_id not specified
|
# flash error if product_id not specified
|
||||||
product.status = enum.PendingProductStatus.READY
|
product.status = enum.PendingProductStatus.READY
|
||||||
result = view.resolve()
|
result = view.resolve()
|
||||||
self.assertIsInstance(result, HTTPFound)
|
self.assertIsInstance(result, HTTPFound)
|
||||||
self.assertTrue(self.request.session.peek_flash('error'))
|
self.assertTrue(self.request.session.peek_flash("error"))
|
||||||
self.assertEqual(self.request.session.pop_flash('error'),
|
self.assertEqual(
|
||||||
["must specify valid product_id"])
|
self.request.session.pop_flash("error"),
|
||||||
|
["must specify valid product_id"],
|
||||||
|
)
|
||||||
|
|
||||||
# more sample data
|
# more sample data
|
||||||
order = model.Order(order_id=100, created_by=user,
|
order = model.Order(
|
||||||
customer_name="Fred Flintstone")
|
order_id=100, created_by=user, customer_name="Fred Flintstone"
|
||||||
item = model.OrderItem(pending_product=product,
|
)
|
||||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
item = model.OrderItem(
|
||||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
pending_product=product,
|
||||||
|
order_qty=1,
|
||||||
|
order_uom=enum.ORDER_UOM_UNIT,
|
||||||
|
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||||
|
)
|
||||||
order.items.append(item)
|
order.items.append(item)
|
||||||
self.session.add(order)
|
self.session.add(order)
|
||||||
|
|
||||||
|
@ -369,45 +398,58 @@ class TestPendingProductView(WebTestCase):
|
||||||
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
||||||
self.assertIsNone(item.product_id)
|
self.assertIsNone(item.product_id)
|
||||||
batch_handler = NewOrderBatchHandler(self.config)
|
batch_handler = NewOrderBatchHandler(self.config)
|
||||||
with patch.object(batch_handler, 'get_product_info_external',
|
with patch.object(
|
||||||
return_value=info):
|
batch_handler, "get_product_info_external", return_value=info
|
||||||
with patch.object(self.app, 'get_batch_handler',
|
):
|
||||||
return_value=batch_handler):
|
with patch.object(
|
||||||
with patch.object(self.request, 'POST',
|
self.app, "get_batch_handler", return_value=batch_handler
|
||||||
new={'product_id': '07430500132'}):
|
):
|
||||||
with patch.object(batch_handler, 'get_product_info_external',
|
with patch.object(
|
||||||
return_value=info):
|
self.request, "POST", new={"product_id": "07430500132"}
|
||||||
|
):
|
||||||
|
with patch.object(
|
||||||
|
batch_handler,
|
||||||
|
"get_product_info_external",
|
||||||
|
return_value=info,
|
||||||
|
):
|
||||||
result = view.resolve()
|
result = view.resolve()
|
||||||
self.assertIsInstance(result, HTTPFound)
|
self.assertIsInstance(result, HTTPFound)
|
||||||
self.assertFalse(self.request.session.peek_flash('error'))
|
self.assertFalse(self.request.session.peek_flash("error"))
|
||||||
self.assertEqual(product.product_id, '07430500132')
|
self.assertEqual(product.product_id, "07430500132")
|
||||||
self.assertEqual(product.status, enum.PendingProductStatus.RESOLVED)
|
self.assertEqual(product.status, enum.PendingProductStatus.RESOLVED)
|
||||||
self.assertEqual(item.product_id, '07430500132')
|
self.assertEqual(item.product_id, "07430500132")
|
||||||
|
|
||||||
def test_ignore(self):
|
def test_ignore(self):
|
||||||
self.pyramid_config.add_route('pending_products.view', '/pending/products/{uuid}')
|
self.pyramid_config.add_route(
|
||||||
|
"pending_products.view", "/pending/products/{uuid}"
|
||||||
|
)
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
enum = self.app.enum
|
enum = self.app.enum
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
# sample data
|
# sample data
|
||||||
user = model.User(username='barney')
|
user = model.User(username="barney")
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
product = model.PendingProduct(
|
||||||
created_by=user)
|
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||||
|
)
|
||||||
self.session.add(product)
|
self.session.add(product)
|
||||||
self.session.flush()
|
self.session.flush()
|
||||||
|
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, "Session", return_value=self.session):
|
||||||
with patch.object(self.request, 'user', new=user):
|
with patch.object(self.request, "user", new=user):
|
||||||
with patch.object(self.request, 'matchdict', new={'uuid': product.uuid}):
|
with patch.object(
|
||||||
|
self.request, "matchdict", new={"uuid": product.uuid}
|
||||||
|
):
|
||||||
|
|
||||||
# flash error if wrong status
|
# flash error if wrong status
|
||||||
result = view.ignore()
|
result = view.ignore()
|
||||||
self.assertIsInstance(result, HTTPFound)
|
self.assertIsInstance(result, HTTPFound)
|
||||||
self.assertTrue(self.request.session.peek_flash('error'))
|
self.assertTrue(self.request.session.peek_flash("error"))
|
||||||
self.assertEqual(self.request.session.pop_flash('error'),
|
self.assertEqual(
|
||||||
["pending product does not have 'ready' status!"])
|
self.request.session.pop_flash("error"),
|
||||||
|
["pending product does not have 'ready' status!"],
|
||||||
|
)
|
||||||
|
|
||||||
# product updated
|
# product updated
|
||||||
product.status = enum.PendingProductStatus.READY
|
product.status = enum.PendingProductStatus.READY
|
||||||
|
@ -415,6 +457,6 @@ class TestPendingProductView(WebTestCase):
|
||||||
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
||||||
result = view.ignore()
|
result = view.ignore()
|
||||||
self.assertIsInstance(result, HTTPFound)
|
self.assertIsInstance(result, HTTPFound)
|
||||||
self.assertFalse(self.request.session.peek_flash('error'))
|
self.assertFalse(self.request.session.peek_flash("error"))
|
||||||
self.assertIsNone(product.product_id)
|
self.assertIsNone(product.product_id)
|
||||||
self.assertEqual(product.status, enum.PendingProductStatus.IGNORED)
|
self.assertEqual(product.status, enum.PendingProductStatus.IGNORED)
|
||||||
|
|
|
@ -23,11 +23,11 @@ class TestStoreView(WebTestCase):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
grid = view.make_grid(model_class=model.Store)
|
grid = view.make_grid(model_class=model.Store)
|
||||||
self.assertNotIn('store_id', grid.linked_columns)
|
self.assertNotIn("store_id", grid.linked_columns)
|
||||||
self.assertNotIn('name', grid.linked_columns)
|
self.assertNotIn("name", grid.linked_columns)
|
||||||
view.configure_grid(grid)
|
view.configure_grid(grid)
|
||||||
self.assertIn('store_id', grid.linked_columns)
|
self.assertIn("store_id", grid.linked_columns)
|
||||||
self.assertIn('name', grid.linked_columns)
|
self.assertIn("name", grid.linked_columns)
|
||||||
|
|
||||||
def test_grid_row_class(self):
|
def test_grid_row_class(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -39,7 +39,7 @@ class TestStoreView(WebTestCase):
|
||||||
|
|
||||||
store = model.Store(archived=True)
|
store = model.Store(archived=True)
|
||||||
self.assertTrue(store.archived)
|
self.assertTrue(store.archived)
|
||||||
self.assertEqual(view.grid_row_class(store, {}, 0), 'has-background-warning')
|
self.assertEqual(view.grid_row_class(store, {}, 0), "has-background-warning")
|
||||||
|
|
||||||
def test_configure_form(self):
|
def test_configure_form(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -47,48 +47,48 @@ class TestStoreView(WebTestCase):
|
||||||
|
|
||||||
# unique validators are set
|
# unique validators are set
|
||||||
form = view.make_form(model_class=model.Store)
|
form = view.make_form(model_class=model.Store)
|
||||||
self.assertNotIn('store_id', form.validators)
|
self.assertNotIn("store_id", form.validators)
|
||||||
self.assertNotIn('name', form.validators)
|
self.assertNotIn("name", form.validators)
|
||||||
view.configure_form(form)
|
view.configure_form(form)
|
||||||
self.assertIn('store_id', form.validators)
|
self.assertIn("store_id", form.validators)
|
||||||
self.assertIn('name', form.validators)
|
self.assertIn("name", form.validators)
|
||||||
|
|
||||||
def test_unique_store_id(self):
|
def test_unique_store_id(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
store = model.Store(store_id='001', name='whatever')
|
store = model.Store(store_id="001", name="whatever")
|
||||||
self.session.add(store)
|
self.session.add(store)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, "Session", return_value=self.session):
|
||||||
|
|
||||||
# invalid if same store_id in data
|
# invalid if same store_id in data
|
||||||
node = colander.SchemaNode(colander.String(), name='store_id')
|
node = colander.SchemaNode(colander.String(), name="store_id")
|
||||||
self.assertRaises(colander.Invalid, view.unique_store_id, node, '001')
|
self.assertRaises(colander.Invalid, view.unique_store_id, node, "001")
|
||||||
|
|
||||||
# but not if store_id belongs to current store
|
# but not if store_id belongs to current store
|
||||||
with patch.object(self.request, 'matchdict', new={'uuid': store.uuid}):
|
with patch.object(self.request, "matchdict", new={"uuid": store.uuid}):
|
||||||
with patch.object(view, 'editing', new=True):
|
with patch.object(view, "editing", new=True):
|
||||||
node = colander.SchemaNode(colander.String(), name='store_id')
|
node = colander.SchemaNode(colander.String(), name="store_id")
|
||||||
self.assertIsNone(view.unique_store_id(node, '001'))
|
self.assertIsNone(view.unique_store_id(node, "001"))
|
||||||
|
|
||||||
def test_unique_name(self):
|
def test_unique_name(self):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
store = model.Store(store_id='001', name='Acme Goods')
|
store = model.Store(store_id="001", name="Acme Goods")
|
||||||
self.session.add(store)
|
self.session.add(store)
|
||||||
self.session.commit()
|
self.session.commit()
|
||||||
|
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, "Session", return_value=self.session):
|
||||||
|
|
||||||
# invalid if same name in data
|
# invalid if same name in data
|
||||||
node = colander.SchemaNode(colander.String(), name='name')
|
node = colander.SchemaNode(colander.String(), name="name")
|
||||||
self.assertRaises(colander.Invalid, view.unique_name, node, 'Acme Goods')
|
self.assertRaises(colander.Invalid, view.unique_name, node, "Acme Goods")
|
||||||
|
|
||||||
# but not if name belongs to current store
|
# but not if name belongs to current store
|
||||||
with patch.object(self.request, 'matchdict', new={'uuid': store.uuid}):
|
with patch.object(self.request, "matchdict", new={"uuid": store.uuid}):
|
||||||
with patch.object(view, 'editing', new=True):
|
with patch.object(view, "editing", new=True):
|
||||||
node = colander.SchemaNode(colander.String(), name='name')
|
node = colander.SchemaNode(colander.String(), name="name")
|
||||||
self.assertIsNone(view.unique_name(node, 'Acme Goods'))
|
self.assertIsNone(view.unique_name(node, "Acme Goods"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue