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
|
||||
|
||||
project = 'Sideshow'
|
||||
copyright = '2025, Lance Edgar'
|
||||
author = 'Lance Edgar'
|
||||
release = get_version('Sideshow')
|
||||
project = "Sideshow"
|
||||
copyright = "2025, Lance Edgar"
|
||||
author = "Lance Edgar"
|
||||
release = get_version("Sideshow")
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.todo',
|
||||
'sphinxcontrib.programoutput',
|
||||
'enum_tools.autoenum',
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx.ext.intersphinx",
|
||||
"sphinx.ext.viewcode",
|
||||
"sphinx.ext.todo",
|
||||
"sphinxcontrib.programoutput",
|
||||
"enum_tools.autoenum",
|
||||
]
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
templates_path = ["_templates"]
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
|
||||
intersphinx_mapping = {
|
||||
'pyramid': ('https://docs.pylonsproject.org/projects/pyramid/en/latest/', None),
|
||||
'python': ('https://docs.python.org/3/', None),
|
||||
'wuttjamaican': ('https://docs.wuttaproject.org/wuttjamaican/', None),
|
||||
'wuttaweb': ('https://docs.wuttaproject.org/wuttaweb/', None),
|
||||
"pyramid": ("https://docs.pylonsproject.org/projects/pyramid/en/latest/", None),
|
||||
"python": ("https://docs.python.org/3/", None),
|
||||
"wuttjamaican": ("https://docs.wuttaproject.org/wuttjamaican/", None),
|
||||
"wuttaweb": ("https://docs.wuttaproject.org/wuttaweb/", None),
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
html_theme = 'furo'
|
||||
html_static_path = ['_static']
|
||||
html_theme = "furo"
|
||||
html_static_path = ["_static"]
|
||||
|
|
|
@ -49,8 +49,9 @@ class SideshowAppProvider(base.AppProvider):
|
|||
|
||||
:returns: Instance of :class:`~sideshow.orders.OrderHandler`.
|
||||
"""
|
||||
if 'order_handler' not in self.__dict__:
|
||||
spec = self.config.get('sideshow.orders.handler_spec',
|
||||
default='sideshow.orders:OrderHandler')
|
||||
if "order_handler" not in self.__dict__:
|
||||
spec = self.config.get(
|
||||
"sideshow.orders.handler_spec", default="sideshow.orders:OrderHandler"
|
||||
)
|
||||
self.order_handler = self.app.load_object(spec)(self.config)
|
||||
return self.order_handler
|
||||
|
|
|
@ -49,6 +49,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
After the batch has executed the :term:`order handler` takes over
|
||||
responsibility for the rest of the order lifecycle.
|
||||
"""
|
||||
|
||||
model_class = NewOrderBatch
|
||||
|
||||
def get_default_store_id(self):
|
||||
|
@ -57,7 +58,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
:attr:`~sideshow.db.model.batch.neworder.NewOrderBatch.store_id`,
|
||||
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):
|
||||
"""
|
||||
|
@ -65,8 +66,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
accounts should be used. This is true by default, but may be
|
||||
false for :term:`external customer` lookups.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.use_local_customers',
|
||||
default=True)
|
||||
return self.config.get_bool("sideshow.orders.use_local_customers", default=True)
|
||||
|
||||
def use_local_products(self):
|
||||
"""
|
||||
|
@ -74,8 +74,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
records should be used. This is true by default, but may be
|
||||
false for :term:`external product` lookups.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.use_local_products',
|
||||
default=True)
|
||||
return self.config.get_bool("sideshow.orders.use_local_products", default=True)
|
||||
|
||||
def allow_unknown_products(self):
|
||||
"""
|
||||
|
@ -86,24 +85,27 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
when creating an order. This can be disabled, to force user
|
||||
to choose existing local/external product.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.allow_unknown_products',
|
||||
default=True)
|
||||
return self.config.get_bool(
|
||||
"sideshow.orders.allow_unknown_products", default=True
|
||||
)
|
||||
|
||||
def allow_item_discounts(self):
|
||||
"""
|
||||
Returns boolean indicating whether per-item discounts are
|
||||
allowed when creating an order.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.allow_item_discounts',
|
||||
default=False)
|
||||
return self.config.get_bool(
|
||||
"sideshow.orders.allow_item_discounts", default=False
|
||||
)
|
||||
|
||||
def allow_item_discounts_if_on_sale(self):
|
||||
"""
|
||||
Returns boolean indicating whether per-item discounts are
|
||||
allowed even when the item is already on sale.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.allow_item_discounts_if_on_sale',
|
||||
default=False)
|
||||
return self.config.get_bool(
|
||||
"sideshow.orders.allow_item_discounts_if_on_sale", default=False
|
||||
)
|
||||
|
||||
def get_default_item_discount(self):
|
||||
"""
|
||||
|
@ -111,7 +113,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
|
||||
: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:
|
||||
return decimal.Decimal(discount)
|
||||
|
||||
|
@ -157,8 +159,9 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
query = session.query(model.LocalCustomer)
|
||||
|
||||
# filter query
|
||||
criteria = [model.LocalCustomer.full_name.ilike(f'%{word}%')
|
||||
for word in term.split()]
|
||||
criteria = [
|
||||
model.LocalCustomer.full_name.ilike(f"%{word}%") for word in term.split()
|
||||
]
|
||||
query = query.filter(sa.and_(*criteria))
|
||||
|
||||
# sort query
|
||||
|
@ -170,8 +173,8 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
|
||||
# get results
|
||||
def result(customer):
|
||||
return {'value': customer.uuid.hex,
|
||||
'label': customer.full_name}
|
||||
return {"value": customer.uuid.hex, "label": customer.full_name}
|
||||
|
||||
return [result(c) for c in customers]
|
||||
|
||||
def init_batch(self, batch, session=None, progress=None, **kwargs):
|
||||
|
@ -240,7 +243,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
batch.local_customer = customer
|
||||
self.refresh_batch_from_local_customer(batch)
|
||||
|
||||
else: # external customer_id
|
||||
else: # external customer_id
|
||||
batch.customer_id = customer_info
|
||||
self.refresh_batch_from_external_customer(batch)
|
||||
|
||||
|
@ -251,22 +254,25 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
batch.local_customer = None
|
||||
customer = batch.pending_customer
|
||||
if not customer:
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user or batch.created_by)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user or batch.created_by,
|
||||
)
|
||||
session.add(customer)
|
||||
batch.pending_customer = customer
|
||||
fields = [
|
||||
'full_name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
"full_name",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
]
|
||||
for key in fields:
|
||||
setattr(customer, key, customer_info.get(key))
|
||||
if 'full_name' not in customer_info:
|
||||
customer.full_name = self.app.make_full_name(customer.first_name,
|
||||
customer.last_name)
|
||||
if "full_name" not in customer_info:
|
||||
customer.full_name = self.app.make_full_name(
|
||||
customer.first_name, customer.last_name
|
||||
)
|
||||
self.refresh_batch_from_pending_customer(batch)
|
||||
|
||||
else:
|
||||
|
@ -361,14 +367,18 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
# filter query
|
||||
criteria = []
|
||||
for word in term.split():
|
||||
criteria.append(sa.or_(
|
||||
model.LocalProduct.brand_name.ilike(f'%{word}%'),
|
||||
model.LocalProduct.description.ilike(f'%{word}%')))
|
||||
criteria.append(
|
||||
sa.or_(
|
||||
model.LocalProduct.brand_name.ilike(f"%{word}%"),
|
||||
model.LocalProduct.description.ilike(f"%{word}%"),
|
||||
)
|
||||
)
|
||||
query = query.filter(sa.and_(*criteria))
|
||||
|
||||
# sort query
|
||||
query = query.order_by(model.LocalProduct.brand_name,
|
||||
model.LocalProduct.description)
|
||||
query = query.order_by(
|
||||
model.LocalProduct.brand_name, model.LocalProduct.description
|
||||
)
|
||||
|
||||
# get data
|
||||
# TODO: need max_results option
|
||||
|
@ -376,8 +386,8 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
|
||||
# get results
|
||||
def result(product):
|
||||
return {'value': product.uuid.hex,
|
||||
'label': product.full_description}
|
||||
return {"value": product.uuid.hex, "label": product.full_description}
|
||||
|
||||
return [result(c) for c in products]
|
||||
|
||||
def get_default_uom_choices(self):
|
||||
|
@ -392,8 +402,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
corresponding to the UOM code and label, respectively.
|
||||
"""
|
||||
enum = self.app.enum
|
||||
return [{'key': key, 'value': val}
|
||||
for key, val in enum.ORDER_UOM.items()]
|
||||
return [{"key": key, "value": val} for key, val in enum.ORDER_UOM.items()]
|
||||
|
||||
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
|
||||
"""
|
||||
return {
|
||||
'product_id': product.uuid.hex,
|
||||
'scancode': product.scancode,
|
||||
'brand_name': product.brand_name,
|
||||
'description': product.description,
|
||||
'size': product.size,
|
||||
'full_description': product.full_description,
|
||||
'weighed': product.weighed,
|
||||
'special_order': product.special_order,
|
||||
'department_id': product.department_id,
|
||||
'department_name': product.department_name,
|
||||
'case_size': product.case_size,
|
||||
'unit_price_reg': product.unit_price_reg,
|
||||
'vendor_name': product.vendor_name,
|
||||
'vendor_item_code': product.vendor_item_code,
|
||||
"product_id": product.uuid.hex,
|
||||
"scancode": product.scancode,
|
||||
"brand_name": product.brand_name,
|
||||
"description": product.description,
|
||||
"size": product.size,
|
||||
"full_description": product.full_description,
|
||||
"weighed": product.weighed,
|
||||
"special_order": product.special_order,
|
||||
"department_id": product.department_id,
|
||||
"department_name": product.department_name,
|
||||
"case_size": product.case_size,
|
||||
"unit_price_reg": product.unit_price_reg,
|
||||
"vendor_name": product.vendor_name,
|
||||
"vendor_item_code": product.vendor_item_code,
|
||||
}
|
||||
|
||||
def get_past_orders(self, batch):
|
||||
|
@ -605,36 +614,51 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
products[product.uuid] = self.normalize_local_product(product)
|
||||
elif item.product_id and item.product_id not in products:
|
||||
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())
|
||||
for product in products:
|
||||
|
||||
price = product['unit_price_reg']
|
||||
price = product["unit_price_reg"]
|
||||
|
||||
if 'unit_price_reg_display' not in product:
|
||||
product['unit_price_reg_display'] = self.app.render_currency(price)
|
||||
if "unit_price_reg_display" not in product:
|
||||
product["unit_price_reg_display"] = self.app.render_currency(price)
|
||||
|
||||
if 'unit_price_quoted' not in product:
|
||||
product['unit_price_quoted'] = price
|
||||
if "unit_price_quoted" not in product:
|
||||
product["unit_price_quoted"] = price
|
||||
|
||||
if 'unit_price_quoted_display' not in product:
|
||||
product['unit_price_quoted_display'] = product['unit_price_reg_display']
|
||||
if "unit_price_quoted_display" not in product:
|
||||
product["unit_price_quoted_display"] = product["unit_price_reg_display"]
|
||||
|
||||
if ('case_price_quoted' not in product
|
||||
and product.get('unit_price_quoted') is not None
|
||||
and product.get('case_size') is not None):
|
||||
product['case_price_quoted'] = product['unit_price_quoted'] * product['case_size']
|
||||
if (
|
||||
"case_price_quoted" not in product
|
||||
and product.get("unit_price_quoted") is not None
|
||||
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
|
||||
and 'case_price_quoted' in product):
|
||||
product['case_price_quoted_display'] = self.app.render_currency(
|
||||
product['case_price_quoted'])
|
||||
if (
|
||||
"case_price_quoted_display" not in product
|
||||
and "case_price_quoted" in product
|
||||
):
|
||||
product["case_price_quoted_display"] = self.app.render_currency(
|
||||
product["case_price_quoted"]
|
||||
)
|
||||
|
||||
return products
|
||||
|
||||
def add_item(self, batch, product_info, order_qty, order_uom,
|
||||
discount_percent=None, user=None):
|
||||
def add_item(
|
||||
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.
|
||||
|
||||
|
@ -686,7 +710,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
raise ValueError("local product not found")
|
||||
row.local_product = local
|
||||
|
||||
else: # external product_id
|
||||
else: # external product_id
|
||||
row.product_id = product_info
|
||||
|
||||
else:
|
||||
|
@ -695,23 +719,25 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
raise TypeError("unknown/pending product not allowed for new orders")
|
||||
row.product_id = None
|
||||
row.local_product = None
|
||||
pending = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user or batch.created_by)
|
||||
pending = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user or batch.created_by,
|
||||
)
|
||||
fields = [
|
||||
'scancode',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'weighed',
|
||||
'department_id',
|
||||
'department_name',
|
||||
'special_order',
|
||||
'vendor_name',
|
||||
'vendor_item_code',
|
||||
'case_size',
|
||||
'unit_cost',
|
||||
'unit_price_reg',
|
||||
'notes',
|
||||
"scancode",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"weighed",
|
||||
"department_id",
|
||||
"department_name",
|
||||
"special_order",
|
||||
"vendor_name",
|
||||
"vendor_item_code",
|
||||
"case_size",
|
||||
"unit_cost",
|
||||
"unit_price_reg",
|
||||
"notes",
|
||||
]
|
||||
for key in fields:
|
||||
setattr(pending, key, product_info.get(key))
|
||||
|
@ -735,8 +761,9 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
session.flush()
|
||||
return row
|
||||
|
||||
def update_item(self, row, product_info, order_qty, order_uom,
|
||||
discount_percent=None, user=None):
|
||||
def update_item(
|
||||
self, row, product_info, order_qty, order_uom, discount_percent=None, user=None
|
||||
):
|
||||
"""
|
||||
Update an item/row, per given product and quantity.
|
||||
|
||||
|
@ -783,7 +810,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
raise ValueError("local product not found")
|
||||
row.local_product = local
|
||||
|
||||
else: # external product_id
|
||||
else: # external product_id
|
||||
row.product_id = product_info
|
||||
|
||||
else:
|
||||
|
@ -794,25 +821,27 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
row.local_product = None
|
||||
pending = row.pending_product
|
||||
if not pending:
|
||||
pending = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user or row.batch.created_by)
|
||||
pending = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user or row.batch.created_by,
|
||||
)
|
||||
session.add(pending)
|
||||
row.pending_product = pending
|
||||
fields = [
|
||||
'scancode',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'weighed',
|
||||
'department_id',
|
||||
'department_name',
|
||||
'special_order',
|
||||
'vendor_name',
|
||||
'vendor_item_code',
|
||||
'case_size',
|
||||
'unit_cost',
|
||||
'unit_price_reg',
|
||||
'notes',
|
||||
"scancode",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"weighed",
|
||||
"department_id",
|
||||
"department_name",
|
||||
"special_order",
|
||||
"vendor_name",
|
||||
"vendor_item_code",
|
||||
"case_size",
|
||||
"unit_cost",
|
||||
"unit_price_reg",
|
||||
"notes",
|
||||
]
|
||||
for key in fields:
|
||||
setattr(pending, key, product_info.get(key))
|
||||
|
@ -885,8 +914,8 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
row.unit_price_quoted = None
|
||||
row.case_price_quoted = None
|
||||
if row.unit_price_sale is not None and (
|
||||
not row.sale_ends
|
||||
or row.sale_ends > datetime.datetime.now()):
|
||||
not row.sale_ends or row.sale_ends > datetime.datetime.now()
|
||||
):
|
||||
row.unit_price_quoted = row.unit_price_sale
|
||||
else:
|
||||
row.unit_price_quoted = row.unit_price_reg
|
||||
|
@ -901,22 +930,22 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
# row.total_price = row.case_price_quoted * row.order_qty
|
||||
if row.unit_price_quoted is not None and row.case_size is not None:
|
||||
row.total_price = row.unit_price_quoted * row.case_size * row.order_qty
|
||||
else: # ORDER_UOM_UNIT (or similar)
|
||||
else: # ORDER_UOM_UNIT (or similar)
|
||||
if row.unit_price_quoted is not None:
|
||||
row.total_price = row.unit_price_quoted * row.order_qty
|
||||
if row.total_price is not None:
|
||||
if row.discount_percent and self.allow_item_discounts():
|
||||
row.total_price = (float(row.total_price)
|
||||
* (100 - float(row.discount_percent))
|
||||
/ 100.0)
|
||||
row.total_price = decimal.Decimal(f'{row.total_price:0.2f}')
|
||||
row.total_price = (
|
||||
float(row.total_price) * (100 - float(row.discount_percent)) / 100.0
|
||||
)
|
||||
row.total_price = decimal.Decimal(f"{row.total_price:0.2f}")
|
||||
|
||||
# update batch if total price changed
|
||||
if row.total_price != old_total:
|
||||
batch = row.batch
|
||||
batch.total_price = ((batch.total_price or 0)
|
||||
+ (row.total_price or 0)
|
||||
- (old_total or 0))
|
||||
batch.total_price = (
|
||||
(batch.total_price or 0) + (row.total_price or 0) - (old_total or 0)
|
||||
)
|
||||
|
||||
# all 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
|
||||
be created as proper order items.
|
||||
"""
|
||||
return [row for row in batch.rows
|
||||
if row.status_code == row.STATUS_OK]
|
||||
return [row for row in batch.rows if row.status_code == row.STATUS_OK]
|
||||
|
||||
def execute(self, batch, user=None, progress=None, **kwargs):
|
||||
"""
|
||||
|
@ -1152,7 +1180,7 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
row.pending_product = None
|
||||
session.delete(pending)
|
||||
|
||||
else: # external products; pending should be marked 'ready'
|
||||
else: # external products; pending should be marked 'ready'
|
||||
for row in rows:
|
||||
pending = row.pending_product
|
||||
if pending:
|
||||
|
@ -1181,48 +1209,47 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
session = self.app.get_session(batch)
|
||||
|
||||
batch_fields = [
|
||||
'store_id',
|
||||
'customer_id',
|
||||
'local_customer',
|
||||
'pending_customer',
|
||||
'customer_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'total_price',
|
||||
"store_id",
|
||||
"customer_id",
|
||||
"local_customer",
|
||||
"pending_customer",
|
||||
"customer_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"total_price",
|
||||
]
|
||||
|
||||
row_fields = [
|
||||
'product_id',
|
||||
'local_product',
|
||||
'pending_product',
|
||||
'product_scancode',
|
||||
'product_brand',
|
||||
'product_description',
|
||||
'product_size',
|
||||
'product_weighed',
|
||||
'department_id',
|
||||
'department_name',
|
||||
'vendor_name',
|
||||
'vendor_item_code',
|
||||
'case_size',
|
||||
'order_qty',
|
||||
'order_uom',
|
||||
'unit_cost',
|
||||
'unit_price_quoted',
|
||||
'case_price_quoted',
|
||||
'unit_price_reg',
|
||||
'unit_price_sale',
|
||||
'sale_ends',
|
||||
'discount_percent',
|
||||
'total_price',
|
||||
'special_order',
|
||||
"product_id",
|
||||
"local_product",
|
||||
"pending_product",
|
||||
"product_scancode",
|
||||
"product_brand",
|
||||
"product_description",
|
||||
"product_size",
|
||||
"product_weighed",
|
||||
"department_id",
|
||||
"department_name",
|
||||
"vendor_name",
|
||||
"vendor_item_code",
|
||||
"case_size",
|
||||
"order_qty",
|
||||
"order_uom",
|
||||
"unit_cost",
|
||||
"unit_price_quoted",
|
||||
"case_price_quoted",
|
||||
"unit_price_reg",
|
||||
"unit_price_sale",
|
||||
"sale_ends",
|
||||
"discount_percent",
|
||||
"total_price",
|
||||
"special_order",
|
||||
]
|
||||
|
||||
# make order
|
||||
kw = dict([(field, getattr(batch, field))
|
||||
for field in batch_fields])
|
||||
kw['order_id'] = batch.id
|
||||
kw['created_by'] = user
|
||||
kw = dict([(field, getattr(batch, field)) for field in batch_fields])
|
||||
kw["order_id"] = batch.id
|
||||
kw["created_by"] = user
|
||||
order = model.Order(**kw)
|
||||
session.add(order)
|
||||
session.flush()
|
||||
|
@ -1230,16 +1257,16 @@ class NewOrderBatchHandler(BatchHandler):
|
|||
def convert(row, i):
|
||||
|
||||
# make order item
|
||||
kw = dict([(field, getattr(row, field))
|
||||
for field in row_fields])
|
||||
kw = dict([(field, getattr(row, field)) for field in row_fields])
|
||||
item = model.OrderItem(**kw)
|
||||
order.items.append(item)
|
||||
|
||||
# set item status
|
||||
self.set_initial_item_status(item, user)
|
||||
|
||||
self.app.progress_loop(convert, rows, progress,
|
||||
message="Converting batch rows to order items")
|
||||
self.app.progress_loop(
|
||||
convert, rows, progress, message="Converting batch rows to order items"
|
||||
)
|
||||
session.flush()
|
||||
return order
|
||||
|
||||
|
|
|
@ -35,6 +35,5 @@ from wuttjamaican.cli import make_typer
|
|||
|
||||
|
||||
sideshow_typer = make_typer(
|
||||
name='sideshow',
|
||||
help="Sideshow -- Case/Special Order Tracker"
|
||||
name="sideshow", help="Sideshow -- Case/Special Order Tracker"
|
||||
)
|
||||
|
|
|
@ -31,15 +31,17 @@ from .base import sideshow_typer
|
|||
|
||||
@sideshow_typer.command()
|
||||
def install(
|
||||
ctx: typer.Context,
|
||||
ctx: typer.Context,
|
||||
):
|
||||
"""
|
||||
Install the Sideshow app
|
||||
"""
|
||||
config = ctx.parent.wutta_config
|
||||
app = config.get_app()
|
||||
install = app.get_install_handler(pkg_name='sideshow',
|
||||
app_title="Sideshow",
|
||||
pypi_name='Sideshow',
|
||||
egg_name='Sideshow')
|
||||
install = app.get_install_handler(
|
||||
pkg_name="sideshow",
|
||||
app_title="Sideshow",
|
||||
pypi_name="Sideshow",
|
||||
egg_name="Sideshow",
|
||||
)
|
||||
install.run()
|
||||
|
|
|
@ -33,26 +33,31 @@ class SideshowConfig(WuttaConfigExtension):
|
|||
|
||||
This establishes some config defaults specific to Sideshow.
|
||||
"""
|
||||
key = 'sideshow'
|
||||
|
||||
key = "sideshow"
|
||||
|
||||
def configure(self, config):
|
||||
""" """
|
||||
|
||||
# app info
|
||||
config.setdefault(f'{config.appname}.app_title', "Sideshow")
|
||||
config.setdefault(f'{config.appname}.app_dist', "Sideshow")
|
||||
config.setdefault(f"{config.appname}.app_title", "Sideshow")
|
||||
config.setdefault(f"{config.appname}.app_dist", "Sideshow")
|
||||
|
||||
# app model, enum
|
||||
config.setdefault(f'{config.appname}.model_spec', 'sideshow.db.model')
|
||||
config.setdefault(f'{config.appname}.enum_spec', 'sideshow.enum')
|
||||
config.setdefault(f"{config.appname}.model_spec", "sideshow.db.model")
|
||||
config.setdefault(f"{config.appname}.enum_spec", "sideshow.enum")
|
||||
|
||||
# batch handlers
|
||||
config.setdefault(f'{config.appname}.batch.neworder.handler.default_spec',
|
||||
'sideshow.batch.neworder:NewOrderBatchHandler')
|
||||
config.setdefault(
|
||||
f"{config.appname}.batch.neworder.handler.default_spec",
|
||||
"sideshow.batch.neworder:NewOrderBatchHandler",
|
||||
)
|
||||
|
||||
# web app menu
|
||||
config.setdefault(f'{config.appname}.web.menus.handler.default_spec',
|
||||
'sideshow.web.menus:SideshowMenuHandler')
|
||||
config.setdefault(
|
||||
f"{config.appname}.web.menus.handler.default_spec",
|
||||
"sideshow.web.menus:SideshowMenuHandler",
|
||||
)
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '13af2ffbc0e0'
|
||||
down_revision: Union[str, None] = 'a4273360d379'
|
||||
revision: str = "13af2ffbc0e0"
|
||||
down_revision: Union[str, None] = "a4273360d379"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
@ -22,20 +23,32 @@ depends_on: Union[str, Sequence[str], None] = None
|
|||
def upgrade() -> None:
|
||||
|
||||
# sideshow_batch_neworder_row
|
||||
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
||||
op.add_column('sideshow_batch_neworder_row', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
||||
op.add_column(
|
||||
"sideshow_batch_neworder_row",
|
||||
sa.Column("vendor_name", sa.String(length=50), nullable=True),
|
||||
)
|
||||
op.add_column(
|
||||
"sideshow_batch_neworder_row",
|
||||
sa.Column("vendor_item_code", sa.String(length=20), nullable=True),
|
||||
)
|
||||
|
||||
# sideshow_order_item
|
||||
op.add_column('sideshow_order_item', sa.Column('vendor_name', sa.String(length=50), nullable=True))
|
||||
op.add_column('sideshow_order_item', sa.Column('vendor_item_code', sa.String(length=20), nullable=True))
|
||||
op.add_column(
|
||||
"sideshow_order_item",
|
||||
sa.Column("vendor_name", sa.String(length=50), nullable=True),
|
||||
)
|
||||
op.add_column(
|
||||
"sideshow_order_item",
|
||||
sa.Column("vendor_item_code", sa.String(length=20), nullable=True),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
|
||||
# sideshow_order_item
|
||||
op.drop_column('sideshow_order_item', 'vendor_item_code')
|
||||
op.drop_column('sideshow_order_item', 'vendor_name')
|
||||
op.drop_column("sideshow_order_item", "vendor_item_code")
|
||||
op.drop_column("sideshow_order_item", "vendor_name")
|
||||
|
||||
# sideshow_batch_neworder_row
|
||||
op.drop_column('sideshow_batch_neworder_row', 'vendor_item_code')
|
||||
op.drop_column('sideshow_batch_neworder_row', 'vendor_name')
|
||||
op.drop_column("sideshow_batch_neworder_row", "vendor_item_code")
|
||||
op.drop_column("sideshow_batch_neworder_row", "vendor_name")
|
||||
|
|
|
@ -5,6 +5,7 @@ Revises:
|
|||
Create Date: 2024-12-30 18:53:51.358163
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
@ -14,253 +15,364 @@ import wuttjamaican.db.util
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '7a6df83afbd4'
|
||||
revision: str = "7a6df83afbd4"
|
||||
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
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
|
||||
# enums
|
||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingcustomerstatus').create(op.get_bind())
|
||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingproductstatus').create(op.get_bind())
|
||||
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingcustomerstatus").create(
|
||||
op.get_bind()
|
||||
)
|
||||
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingproductstatus").create(
|
||||
op.get_bind()
|
||||
)
|
||||
|
||||
# sideshow_customer_pending
|
||||
op.create_table('sideshow_customer_pending',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('full_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('first_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('last_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
||||
sa.Column('status', postgresql.ENUM('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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_customer_pending",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("full_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("first_name", sa.String(length=50), nullable=True),
|
||||
sa.Column("last_name", sa.String(length=50), nullable=True),
|
||||
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||
sa.Column(
|
||||
"status",
|
||||
postgresql.ENUM(
|
||||
"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
|
||||
op.create_table('sideshow_customer_local',
|
||||
sa.Column('full_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('first_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('last_name', sa.String(length=50), nullable=True),
|
||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('external_id', sa.String(length=20), nullable=True),
|
||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_customer_local'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_customer_local",
|
||||
sa.Column("full_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("first_name", sa.String(length=50), nullable=True),
|
||||
sa.Column("last_name", sa.String(length=50), nullable=True),
|
||||
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("external_id", sa.String(length=20), nullable=True),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_customer_local")),
|
||||
)
|
||||
|
||||
# sideshow_product_pending
|
||||
op.create_table('sideshow_product_pending',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('scancode', sa.String(length=14), nullable=True),
|
||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('brand_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('size', sa.String(length=30), nullable=True),
|
||||
sa.Column('weighed', sa.Boolean(), nullable=True),
|
||||
sa.Column('vendor_name', sa.String(length=50), 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('special_order', sa.Boolean(), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('status', postgresql.ENUM('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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_product_pending",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("scancode", sa.String(length=14), nullable=True),
|
||||
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||
sa.Column("brand_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("description", sa.String(length=255), nullable=True),
|
||||
sa.Column("size", sa.String(length=30), nullable=True),
|
||||
sa.Column("weighed", sa.Boolean(), nullable=True),
|
||||
sa.Column("vendor_name", sa.String(length=50), 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("special_order", sa.Boolean(), nullable=True),
|
||||
sa.Column("notes", sa.Text(), nullable=True),
|
||||
sa.Column(
|
||||
"status",
|
||||
postgresql.ENUM(
|
||||
"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
|
||||
op.create_table('sideshow_product_local',
|
||||
sa.Column('scancode', sa.String(length=14), nullable=True),
|
||||
sa.Column('brand_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('size', sa.String(length=30), nullable=True),
|
||||
sa.Column('weighed', sa.Boolean(), nullable=True),
|
||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
||||
sa.Column('vendor_name', sa.String(length=50), 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('notes', sa.Text(), nullable=True),
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('external_id', sa.String(length=20), nullable=True),
|
||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_product_local'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_product_local",
|
||||
sa.Column("scancode", sa.String(length=14), nullable=True),
|
||||
sa.Column("brand_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("description", sa.String(length=255), nullable=True),
|
||||
sa.Column("size", sa.String(length=30), nullable=True),
|
||||
sa.Column("weighed", sa.Boolean(), nullable=True),
|
||||
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||
sa.Column("vendor_name", sa.String(length=50), 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("notes", sa.Text(), nullable=True),
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("external_id", sa.String(length=20), nullable=True),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_product_local")),
|
||||
)
|
||||
|
||||
# sideshow_order
|
||||
op.create_table('sideshow_order',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('order_id', sa.Integer(), nullable=False),
|
||||
sa.Column('store_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('local_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('pending_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('customer_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
||||
sa.Column('total_price', sa.Numeric(precision=10, scale=3), nullable=True),
|
||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['local_customer_uuid'], ['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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_order",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("order_id", sa.Integer(), nullable=False),
|
||||
sa.Column("store_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("local_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("pending_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("customer_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||
sa.Column("total_price", sa.Numeric(precision=10, scale=3), nullable=True),
|
||||
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["local_customer_uuid"],
|
||||
["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
|
||||
op.create_table('sideshow_order_item',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('order_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('local_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('pending_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('product_scancode', sa.String(length=14), nullable=True),
|
||||
sa.Column('product_brand', sa.String(length=100), nullable=True),
|
||||
sa.Column('product_description', sa.String(length=255), nullable=True),
|
||||
sa.Column('product_size', sa.String(length=30), nullable=True),
|
||||
sa.Column('product_weighed', sa.Boolean(), nullable=True),
|
||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
||||
sa.Column('case_size', sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column('order_qty', sa.Numeric(precision=10, scale=4), nullable=False),
|
||||
sa.Column('order_uom', sa.String(length=10), nullable=False),
|
||||
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('unit_price_sale', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('sale_ends', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('unit_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('case_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('discount_percent', sa.Numeric(precision=5, scale=3), nullable=True),
|
||||
sa.Column('total_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('status_code', sa.Integer(), nullable=False),
|
||||
sa.Column('paid_amount', sa.Numeric(precision=8, scale=3), nullable=False),
|
||||
sa.Column('payment_transaction_number', sa.String(length=20), nullable=True),
|
||||
sa.ForeignKeyConstraint(['order_uuid'], ['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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_order_item",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("order_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("local_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("pending_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("product_scancode", sa.String(length=14), nullable=True),
|
||||
sa.Column("product_brand", sa.String(length=100), nullable=True),
|
||||
sa.Column("product_description", sa.String(length=255), nullable=True),
|
||||
sa.Column("product_size", sa.String(length=30), nullable=True),
|
||||
sa.Column("product_weighed", sa.Boolean(), nullable=True),
|
||||
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||
sa.Column("case_size", sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column("order_qty", sa.Numeric(precision=10, scale=4), nullable=False),
|
||||
sa.Column("order_uom", sa.String(length=10), nullable=False),
|
||||
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("unit_price_sale", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("sale_ends", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("unit_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("case_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("discount_percent", sa.Numeric(precision=5, scale=3), nullable=True),
|
||||
sa.Column("total_price", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("status_code", sa.Integer(), nullable=False),
|
||||
sa.Column("paid_amount", sa.Numeric(precision=8, scale=3), nullable=False),
|
||||
sa.Column("payment_transaction_number", sa.String(length=20), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["order_uuid"],
|
||||
["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
|
||||
op.create_table('sideshow_order_item_event',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('item_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('type_code', sa.Integer(), nullable=False),
|
||||
sa.Column('occurred', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column('actor_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('note', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_order_item_event",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("item_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("type_code", sa.Integer(), nullable=False),
|
||||
sa.Column("occurred", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("actor_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("note", sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["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
|
||||
op.create_table('sideshow_batch_neworder',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('notes', sa.Text(), nullable=True),
|
||||
sa.Column('row_count', sa.Integer(), nullable=True),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('created', sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column('created_by_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('executed', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('executed_by_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('store_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('customer_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('local_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('pending_customer_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('customer_name', sa.String(length=100), nullable=True),
|
||||
sa.Column('phone_number', sa.String(length=20), nullable=True),
|
||||
sa.Column('email_address', sa.String(length=255), nullable=True),
|
||||
sa.Column('total_price', sa.Numeric(precision=10, scale=3), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by_uuid'], ['user.uuid'], 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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_batch_neworder",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("id", sa.Integer(), nullable=False),
|
||||
sa.Column("description", sa.String(length=255), nullable=True),
|
||||
sa.Column("notes", sa.Text(), nullable=True),
|
||||
sa.Column("row_count", sa.Integer(), nullable=True),
|
||||
sa.Column("status_code", sa.Integer(), nullable=True),
|
||||
sa.Column("status_text", sa.String(length=255), nullable=True),
|
||||
sa.Column("created", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("created_by_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("executed", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("executed_by_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("store_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("customer_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("local_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("pending_customer_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("customer_name", sa.String(length=100), nullable=True),
|
||||
sa.Column("phone_number", sa.String(length=20), nullable=True),
|
||||
sa.Column("email_address", sa.String(length=255), nullable=True),
|
||||
sa.Column("total_price", sa.Numeric(precision=10, scale=3), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["created_by_uuid"],
|
||||
["user.uuid"],
|
||||
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
|
||||
op.create_table('sideshow_batch_neworder_row',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('batch_uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('sequence', sa.Integer(), nullable=False),
|
||||
sa.Column('status_text', sa.String(length=255), nullable=True),
|
||||
sa.Column('modified', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('product_id', sa.String(length=20), nullable=True),
|
||||
sa.Column('local_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('pending_product_uuid', wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column('product_scancode', sa.String(length=14), nullable=True),
|
||||
sa.Column('product_brand', sa.String(length=100), nullable=True),
|
||||
sa.Column('product_description', sa.String(length=255), nullable=True),
|
||||
sa.Column('product_size', sa.String(length=30), nullable=True),
|
||||
sa.Column('product_weighed', sa.Boolean(), nullable=True),
|
||||
sa.Column('department_id', sa.String(length=10), nullable=True),
|
||||
sa.Column('department_name', sa.String(length=30), nullable=True),
|
||||
sa.Column('special_order', sa.Boolean(), nullable=True),
|
||||
sa.Column('case_size', sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column('order_qty', sa.Numeric(precision=10, scale=4), nullable=False),
|
||||
sa.Column('order_uom', sa.String(length=10), nullable=False),
|
||||
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('unit_price_sale', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('sale_ends', sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column('unit_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('case_price_quoted', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('discount_percent', sa.Numeric(precision=5, scale=3), nullable=True),
|
||||
sa.Column('total_price', sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column('status_code', sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['batch_uuid'], ['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'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_batch_neworder_row",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("batch_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||
sa.Column("status_text", sa.String(length=255), nullable=True),
|
||||
sa.Column("modified", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("product_id", sa.String(length=20), nullable=True),
|
||||
sa.Column("local_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("pending_product_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("product_scancode", sa.String(length=14), nullable=True),
|
||||
sa.Column("product_brand", sa.String(length=100), nullable=True),
|
||||
sa.Column("product_description", sa.String(length=255), nullable=True),
|
||||
sa.Column("product_size", sa.String(length=30), nullable=True),
|
||||
sa.Column("product_weighed", sa.Boolean(), nullable=True),
|
||||
sa.Column("department_id", sa.String(length=10), nullable=True),
|
||||
sa.Column("department_name", sa.String(length=30), nullable=True),
|
||||
sa.Column("special_order", sa.Boolean(), nullable=True),
|
||||
sa.Column("case_size", sa.Numeric(precision=10, scale=4), nullable=True),
|
||||
sa.Column("order_qty", sa.Numeric(precision=10, scale=4), nullable=False),
|
||||
sa.Column("order_uom", sa.String(length=10), nullable=False),
|
||||
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("unit_price_sale", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("sale_ends", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("unit_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("case_price_quoted", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("discount_percent", sa.Numeric(precision=5, scale=3), nullable=True),
|
||||
sa.Column("total_price", sa.Numeric(precision=8, scale=3), nullable=True),
|
||||
sa.Column("status_code", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["batch_uuid"],
|
||||
["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:
|
||||
|
||||
# sideshow_batch_neworder*
|
||||
op.drop_table('sideshow_batch_neworder_row')
|
||||
op.drop_table('sideshow_batch_neworder')
|
||||
op.drop_table("sideshow_batch_neworder_row")
|
||||
op.drop_table("sideshow_batch_neworder")
|
||||
|
||||
# sideshow_order_item_event
|
||||
op.drop_table('sideshow_order_item_event')
|
||||
op.drop_table("sideshow_order_item_event")
|
||||
|
||||
# sideshow_order_item
|
||||
op.drop_table('sideshow_order_item')
|
||||
op.drop_table("sideshow_order_item")
|
||||
|
||||
# sideshow_order
|
||||
op.drop_table('sideshow_order')
|
||||
op.drop_table("sideshow_order")
|
||||
|
||||
# sideshow_product_local
|
||||
op.drop_table('sideshow_product_local')
|
||||
op.drop_table("sideshow_product_local")
|
||||
|
||||
# sideshow_product_pending
|
||||
op.drop_table('sideshow_product_pending')
|
||||
op.drop_table("sideshow_product_pending")
|
||||
|
||||
# sideshow_customer_local
|
||||
op.drop_table('sideshow_customer_local')
|
||||
op.drop_table("sideshow_customer_local")
|
||||
|
||||
# sideshow_customer_pending
|
||||
op.drop_table('sideshow_customer_pending')
|
||||
op.drop_table("sideshow_customer_pending")
|
||||
|
||||
# enums
|
||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingproductstatus').drop(op.get_bind())
|
||||
sa.Enum('PENDING', 'READY', 'RESOLVED', name='pendingcustomerstatus').drop(op.get_bind())
|
||||
sa.Enum("PENDING", "READY", "RESOLVED", name="pendingproductstatus").drop(
|
||||
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
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
|||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'a4273360d379'
|
||||
down_revision: Union[str, None] = '7a6df83afbd4'
|
||||
revision: str = "a4273360d379"
|
||||
down_revision: Union[str, None] = "7a6df83afbd4"
|
||||
branch_labels: 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:
|
||||
|
||||
# sideshow_store
|
||||
op.create_table('sideshow_store',
|
||||
sa.Column('uuid', wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column('store_id', sa.String(length=10), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('archived', sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint('uuid', name=op.f('pk_sideshow_store')),
|
||||
sa.UniqueConstraint('store_id', name=op.f('uq_sideshow_store_store_id')),
|
||||
sa.UniqueConstraint('name', name=op.f('uq_sideshow_store_name'))
|
||||
)
|
||||
op.create_table(
|
||||
"sideshow_store",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("store_id", sa.String(length=10), nullable=False),
|
||||
sa.Column("name", sa.String(length=100), nullable=False),
|
||||
sa.Column("archived", sa.Boolean(), nullable=False),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_sideshow_store")),
|
||||
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:
|
||||
|
||||
# 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
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
@ -13,8 +14,8 @@ import wuttjamaican.db.util
|
|||
from alembic_postgresql_enum import TableReference
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = 'fd8a2527bd30'
|
||||
down_revision: Union[str, None] = '13af2ffbc0e0'
|
||||
revision: str = "fd8a2527bd30"
|
||||
down_revision: Union[str, None] = "13af2ffbc0e0"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
@ -23,19 +24,31 @@ def upgrade() -> None:
|
|||
|
||||
# pendingcustomerstatus
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='pendingcustomerstatus',
|
||||
new_values=['PENDING', 'READY', 'RESOLVED', 'IGNORED'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_customer_pending', column_name='status')],
|
||||
enum_schema="public",
|
||||
enum_name="pendingcustomerstatus",
|
||||
new_values=["PENDING", "READY", "RESOLVED", "IGNORED"],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public",
|
||||
table_name="sideshow_customer_pending",
|
||||
column_name="status",
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
|
||||
# pendingproductstatus
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='pendingproductstatus',
|
||||
new_values=['PENDING', 'READY', 'RESOLVED', 'IGNORED'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_product_pending', column_name='status')],
|
||||
enum_schema="public",
|
||||
enum_name="pendingproductstatus",
|
||||
new_values=["PENDING", "READY", "RESOLVED", "IGNORED"],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public",
|
||||
table_name="sideshow_product_pending",
|
||||
column_name="status",
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
|
||||
|
@ -44,18 +57,30 @@ def downgrade() -> None:
|
|||
|
||||
# pendingproductstatus
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='pendingproductstatus',
|
||||
new_values=['PENDING', 'READY', 'RESOLVED'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_product_pending', column_name='status')],
|
||||
enum_schema="public",
|
||||
enum_name="pendingproductstatus",
|
||||
new_values=["PENDING", "READY", "RESOLVED"],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public",
|
||||
table_name="sideshow_product_pending",
|
||||
column_name="status",
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
|
||||
# pendingcustomerstatus
|
||||
op.sync_enum_values(
|
||||
enum_schema='public',
|
||||
enum_name='pendingcustomerstatus',
|
||||
new_values=['PENDING', 'READY', 'RESOLVED'],
|
||||
affected_columns=[TableReference(table_schema='public', table_name='sideshow_customer_pending', column_name='status')],
|
||||
enum_schema="public",
|
||||
enum_name="pendingcustomerstatus",
|
||||
new_values=["PENDING", "READY", "RESOLVED"],
|
||||
affected_columns=[
|
||||
TableReference(
|
||||
table_schema="public",
|
||||
table_name="sideshow_customer_pending",
|
||||
column_name="status",
|
||||
)
|
||||
],
|
||||
enum_values_to_rename=[],
|
||||
)
|
||||
|
|
|
@ -47,10 +47,11 @@ class NewOrderBatch(model.BatchMixin, model.Base):
|
|||
Generic batch attributes (undocumented below) are inherited from
|
||||
: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.
|
||||
"""
|
||||
|
@ -58,72 +59,102 @@ class NewOrderBatch(model.BatchMixin, model.Base):
|
|||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__default_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['local_customer_uuid'], ['sideshow_customer_local.uuid']),
|
||||
sa.ForeignKeyConstraint(['pending_customer_uuid'], ['sideshow_customer_pending.uuid']),
|
||||
sa.ForeignKeyConstraint(
|
||||
["local_customer_uuid"], ["sideshow_customer_local.uuid"]
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["pending_customer_uuid"], ["sideshow_customer_pending.uuid"]
|
||||
),
|
||||
)
|
||||
|
||||
STATUS_OK = 1
|
||||
STATUS_OK = 1
|
||||
|
||||
STATUS = {
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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
|
||||
order pertains, if applicable.
|
||||
|
||||
See also :attr:`local_customer` and :attr:`pending_customer`.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
local_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
def local_customer(cls):
|
||||
return orm.relationship(
|
||||
'LocalCustomer',
|
||||
back_populates='new_order_batches',
|
||||
"LocalCustomer",
|
||||
back_populates="new_order_batches",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
||||
for the order, if applicable.
|
||||
|
||||
See also :attr:`customer_id` and :attr:`pending_customer`.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
pending_customer_uuid = sa.Column(model.UUID(), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
def pending_customer(cls):
|
||||
return orm.relationship(
|
||||
'PendingCustomer',
|
||||
back_populates='new_order_batches',
|
||||
"PendingCustomer",
|
||||
back_populates="new_order_batches",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.customers.PendingCustomer`
|
||||
record for the order, if applicable.
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
||||
|
@ -134,82 +165,96 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
|||
Generic row attributes (undocumented below) are inherited from
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.batch.BatchRowMixin`.
|
||||
"""
|
||||
__tablename__ = 'sideshow_batch_neworder_row'
|
||||
|
||||
__tablename__ = "sideshow_batch_neworder_row"
|
||||
__batch_class__ = NewOrderBatch
|
||||
|
||||
@declared_attr
|
||||
def __table_args__(cls):
|
||||
return cls.__default_table_args__() + (
|
||||
sa.ForeignKeyConstraint(['local_product_uuid'], ['sideshow_product_local.uuid']),
|
||||
sa.ForeignKeyConstraint(['pending_product_uuid'], ['sideshow_product_pending.uuid']),
|
||||
sa.ForeignKeyConstraint(
|
||||
["local_product_uuid"], ["sideshow_product_local.uuid"]
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["pending_product_uuid"], ["sideshow_product_pending.uuid"]
|
||||
),
|
||||
)
|
||||
|
||||
STATUS_OK = 1
|
||||
STATUS_OK = 1
|
||||
"""
|
||||
This is the default value for :attr:`status_code`. All rows are
|
||||
considered "OK" if they have either a :attr:`product_id` or
|
||||
:attr:`pending_product`.
|
||||
"""
|
||||
|
||||
STATUS_MISSING_PRODUCT = 2
|
||||
STATUS_MISSING_PRODUCT = 2
|
||||
"""
|
||||
Status code indicating the row has no :attr:`product_id` or
|
||||
:attr:`pending_product` set.
|
||||
"""
|
||||
|
||||
STATUS_MISSING_ORDER_QTY = 3
|
||||
STATUS_MISSING_ORDER_QTY = 3
|
||||
"""
|
||||
Status code indicating the row has no :attr:`order_qty` and/or
|
||||
:attr:`order_uom` set.
|
||||
"""
|
||||
|
||||
STATUS = {
|
||||
STATUS_OK : "ok",
|
||||
STATUS_MISSING_PRODUCT : "missing product",
|
||||
STATUS_MISSING_ORDER_QTY : "missing order qty/uom",
|
||||
STATUS_OK: "ok",
|
||||
STATUS_MISSING_PRODUCT: "missing product",
|
||||
STATUS_MISSING_ORDER_QTY: "missing order qty/uom",
|
||||
}
|
||||
"""
|
||||
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
|
||||
represents, if applicable.
|
||||
|
||||
See also :attr:`local_product` and :attr:`pending_product`.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
local_product_uuid = sa.Column(model.UUID(), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
def local_product(cls):
|
||||
return orm.relationship(
|
||||
'LocalProduct',
|
||||
back_populates='new_order_batch_rows',
|
||||
"LocalProduct",
|
||||
back_populates="new_order_batch_rows",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.products.LocalProduct` record
|
||||
for the order item, if applicable.
|
||||
|
||||
See also :attr:`product_id` and :attr:`pending_product`.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
pending_product_uuid = sa.Column(model.UUID(), nullable=True)
|
||||
|
||||
@declared_attr
|
||||
def pending_product(cls):
|
||||
return orm.relationship(
|
||||
'PendingProduct',
|
||||
back_populates='new_order_batch_rows',
|
||||
"PendingProduct",
|
||||
back_populates="new_order_batch_rows",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.products.PendingProduct` record
|
||||
for the order item, if applicable.
|
||||
|
||||
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.
|
||||
|
||||
.. note::
|
||||
|
@ -221,61 +266,109 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
|||
That may change eventually, depending on POS integration
|
||||
scenarios that come up. Maybe a config option to declare
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
This must be interpreted along with :attr:`order_uom` to determine
|
||||
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.
|
||||
|
||||
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`
|
||||
differently but :data:`~sideshow.enum.ORDER_UOM_UNIT` and others
|
||||
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,
|
||||
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,
|
||||
: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
|
||||
:attr:`unit_price_quoted` will typically match this value. See
|
||||
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.
|
||||
|
||||
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
|
||||
price, which is used to calculate :attr:`total_price`.
|
||||
|
||||
|
@ -317,21 +430,33 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
|||
:attr:`unit_price_sale`.
|
||||
|
||||
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.
|
||||
|
||||
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
||||
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
|
||||
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
|
||||
for the order item.
|
||||
|
||||
|
@ -342,7 +467,8 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base):
|
|||
* :attr:`order_uom`
|
||||
* :attr:`case_size`
|
||||
* :attr:`discount_percent`
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.pending_product or self.product_description or "")
|
||||
|
|
|
@ -42,25 +42,45 @@ class CustomerMixin:
|
|||
* :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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
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
|
||||
this local customers table, for lookup next time.
|
||||
"""
|
||||
__tablename__ = 'sideshow_customer_local'
|
||||
|
||||
__tablename__ = "sideshow_customer_local"
|
||||
|
||||
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
|
||||
applicable.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
orders = orm.relationship(
|
||||
'Order',
|
||||
order_by='Order.order_id.desc()',
|
||||
back_populates='local_customer',
|
||||
"Order",
|
||||
order_by="Order.order_id.desc()",
|
||||
back_populates="local_customer",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of :class:`~sideshow.db.model.orders.Order` records
|
||||
associated with this customer.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
new_order_batches = orm.relationship(
|
||||
'NewOrderBatch',
|
||||
order_by='NewOrderBatch.id.desc()',
|
||||
back_populates='local_customer',
|
||||
"NewOrderBatch",
|
||||
order_by="NewOrderBatch.id.desc()",
|
||||
back_populates="local_customer",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of
|
||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
||||
records associated with this customer.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
<local customer>` table, for lookup next time.
|
||||
"""
|
||||
__tablename__ = 'sideshow_customer_pending'
|
||||
|
||||
__tablename__ = "sideshow_customer_pending"
|
||||
|
||||
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
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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 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(
|
||||
model.User,
|
||||
cascade_backrefs=False,
|
||||
|
@ -147,25 +187,28 @@ class PendingCustomer(CustomerMixin, model.Base):
|
|||
Reference to the
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||
created the customer record.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
orders = orm.relationship(
|
||||
'Order',
|
||||
order_by='Order.order_id.desc()',
|
||||
"Order",
|
||||
order_by="Order.order_id.desc()",
|
||||
cascade_backrefs=False,
|
||||
back_populates='pending_customer',
|
||||
back_populates="pending_customer",
|
||||
doc="""
|
||||
List of :class:`~sideshow.db.model.orders.Order` records
|
||||
associated with this customer.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
new_order_batches = orm.relationship(
|
||||
'NewOrderBatch',
|
||||
order_by='NewOrderBatch.id.desc()',
|
||||
"NewOrderBatch",
|
||||
order_by="NewOrderBatch.id.desc()",
|
||||
cascade_backrefs=False,
|
||||
back_populates='pending_customer',
|
||||
back_populates="pending_customer",
|
||||
doc="""
|
||||
List of
|
||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatch`
|
||||
records associated with this customer.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
|
|
@ -41,93 +41,134 @@ class Order(model.Base):
|
|||
Usually, orders are created by way of a
|
||||
: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
|
||||
# showing the Orders grid for a PendingCustomer
|
||||
__colanderalchemy_config__ = {
|
||||
'excludes': ['items'],
|
||||
"excludes": ["items"],
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
When the order is created from New Order Batch, this order ID will
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
store = orm.relationship(
|
||||
'Store',
|
||||
primaryjoin='Store.store_id == Order.store_id',
|
||||
foreign_keys='Order.store_id',
|
||||
"Store",
|
||||
primaryjoin="Store.store_id == Order.store_id",
|
||||
foreign_keys="Order.store_id",
|
||||
doc="""
|
||||
Reference to the :class:`~sideshow.db.model.stores.Store`
|
||||
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
|
||||
order pertains, if applicable.
|
||||
|
||||
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(
|
||||
'LocalCustomer',
|
||||
"LocalCustomer",
|
||||
cascade_backrefs=False,
|
||||
back_populates='orders',
|
||||
back_populates="orders",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.customers.LocalCustomer` record
|
||||
for the order, if applicable.
|
||||
|
||||
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(
|
||||
'PendingCustomer',
|
||||
"PendingCustomer",
|
||||
cascade_backrefs=False,
|
||||
back_populates='orders',
|
||||
back_populates="orders",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.customers.PendingCustomer` record
|
||||
for the order, if applicable.
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
|
||||
If the order is created via New Order Batch, this will match the
|
||||
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(
|
||||
model.User,
|
||||
cascade_backrefs=False,
|
||||
|
@ -135,17 +176,19 @@ class Order(model.Base):
|
|||
Reference to the
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||
created the order.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
items = orm.relationship(
|
||||
'OrderItem',
|
||||
collection_class=ordering_list('sequence', count_from=1),
|
||||
cascade='all, delete-orphan',
|
||||
"OrderItem",
|
||||
collection_class=ordering_list("sequence", count_from=1),
|
||||
cascade="all, delete-orphan",
|
||||
cascade_backrefs=False,
|
||||
back_populates='order',
|
||||
back_populates="order",
|
||||
doc="""
|
||||
List of :class:`OrderItem` records belonging to the order.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.order_id)
|
||||
|
@ -159,58 +202,77 @@ class OrderItem(model.Base):
|
|||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||
records.
|
||||
"""
|
||||
__tablename__ = 'sideshow_order_item'
|
||||
|
||||
__tablename__ = "sideshow_order_item"
|
||||
|
||||
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,
|
||||
cascade_backrefs=False,
|
||||
back_populates='items',
|
||||
back_populates="items",
|
||||
doc="""
|
||||
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
|
||||
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
|
||||
represents, if applicable.
|
||||
|
||||
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(
|
||||
'LocalProduct',
|
||||
"LocalProduct",
|
||||
cascade_backrefs=False,
|
||||
back_populates='order_items',
|
||||
back_populates="order_items",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.products.LocalProduct` record for
|
||||
the order item, if applicable.
|
||||
|
||||
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(
|
||||
'PendingProduct',
|
||||
"PendingProduct",
|
||||
cascade_backrefs=False,
|
||||
back_populates='order_items',
|
||||
back_populates="order_items",
|
||||
doc="""
|
||||
Reference to the
|
||||
:class:`~sideshow.db.model.products.PendingProduct` record for
|
||||
the order item, if applicable.
|
||||
|
||||
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.
|
||||
|
||||
.. note::
|
||||
|
@ -222,109 +284,189 @@ class OrderItem(model.Base):
|
|||
That may change eventually, depending on POS integration
|
||||
scenarios that come up. Maybe a config option to declare
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
|
||||
This must be interpreted along with :attr:`order_uom` to determine
|
||||
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.
|
||||
|
||||
This should be one of the codes from
|
||||
: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,
|
||||
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,
|
||||
: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
|
||||
:attr:`unit_price_quoted` will typically match this value. See
|
||||
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.
|
||||
|
||||
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
|
||||
price, which is used to calculate :attr:`total_price`.
|
||||
|
||||
This price does *not* reflect the :attr:`discount_percent`. It
|
||||
normally should match either :attr:`unit_price_reg` or
|
||||
: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.
|
||||
|
||||
This is mostly for display purposes; :attr:`unit_price_quoted` is
|
||||
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
|
||||
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
|
||||
for the order item.
|
||||
|
||||
|
@ -335,41 +477,57 @@ class OrderItem(model.Base):
|
|||
* :attr:`order_uom`
|
||||
* :attr:`case_size`
|
||||
* :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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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`
|
||||
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
|
||||
applicable/known.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
events = orm.relationship(
|
||||
'OrderItemEvent',
|
||||
order_by='OrderItemEvent.occurred, OrderItemEvent.uuid',
|
||||
cascade='all, delete-orphan',
|
||||
"OrderItemEvent",
|
||||
order_by="OrderItemEvent.occurred, OrderItemEvent.uuid",
|
||||
cascade="all, delete-orphan",
|
||||
cascade_backrefs=False,
|
||||
back_populates='item',
|
||||
back_populates="item",
|
||||
doc="""
|
||||
List of :class:`OrderItemEvent` records for the item.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
@property
|
||||
def full_description(self):
|
||||
""" """
|
||||
fields = [
|
||||
self.product_brand or '',
|
||||
self.product_description or '',
|
||||
self.product_size or '']
|
||||
self.product_brand or "",
|
||||
self.product_description or "",
|
||||
self.product_size or "",
|
||||
]
|
||||
fields = [f.strip() for f in fields if f.strip()]
|
||||
return ' '.join(fields)
|
||||
return " ".join(fields)
|
||||
|
||||
def __str__(self):
|
||||
return self.full_description
|
||||
|
@ -379,8 +537,8 @@ class OrderItem(model.Base):
|
|||
Convenience method to add a new :class:`OrderItemEvent` for
|
||||
the item.
|
||||
"""
|
||||
kwargs['type_code'] = type_code
|
||||
kwargs['actor'] = user
|
||||
kwargs["type_code"] = type_code
|
||||
kwargs["actor"] = user
|
||||
self.events.append(OrderItemEvent(**kwargs))
|
||||
|
||||
|
||||
|
@ -388,37 +546,53 @@ class OrderItemEvent(model.Base):
|
|||
"""
|
||||
An event in the life of an :term:`order item`.
|
||||
"""
|
||||
__tablename__ = 'sideshow_order_item_event'
|
||||
|
||||
__tablename__ = "sideshow_order_item_event"
|
||||
|
||||
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(
|
||||
OrderItem,
|
||||
cascade_backrefs=False,
|
||||
back_populates='events',
|
||||
back_populates="events",
|
||||
doc="""
|
||||
Reference to the :class:`OrderItem` to which the event
|
||||
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
|
||||
: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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
actor_uuid = model.uuid_fk_column('user.uuid', nullable=False)
|
||||
actor_uuid = model.uuid_fk_column("user.uuid", nullable=False)
|
||||
actor = orm.relationship(
|
||||
model.User,
|
||||
doc="""
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
|
|
@ -42,7 +42,10 @@ class ProductMixin:
|
|||
* :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.
|
||||
|
||||
.. note::
|
||||
|
@ -54,73 +57,123 @@ class ProductMixin:
|
|||
That may change eventually, depending on POS integration
|
||||
scenarios that come up. Maybe a config option to declare
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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,
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
notes = sa.Column(sa.Text(), nullable=True, doc="""
|
||||
notes = sa.Column(
|
||||
sa.Text(),
|
||||
nullable=True,
|
||||
doc="""
|
||||
Arbitrary notes regarding the product, if applicable.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
@property
|
||||
def full_description(self):
|
||||
""" """
|
||||
fields = [
|
||||
self.brand_name or '',
|
||||
self.description or '',
|
||||
self.size or '']
|
||||
fields = [self.brand_name or "", self.description or "", self.size or ""]
|
||||
fields = [f.strip() for f in fields if f.strip()]
|
||||
return ' '.join(fields)
|
||||
return " ".join(fields)
|
||||
|
||||
def __str__(self):
|
||||
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
|
||||
next time.
|
||||
"""
|
||||
__tablename__ = 'sideshow_product_local'
|
||||
|
||||
__tablename__ = "sideshow_product_local"
|
||||
|
||||
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
|
||||
applicable.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
order_items = orm.relationship(
|
||||
'OrderItem',
|
||||
back_populates='local_product',
|
||||
"OrderItem",
|
||||
back_populates="local_product",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
||||
associated with this product.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
new_order_batch_rows = orm.relationship(
|
||||
'NewOrderBatchRow',
|
||||
back_populates='local_product',
|
||||
"NewOrderBatchRow",
|
||||
back_populates="local_product",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of
|
||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||
records associated with this product.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
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
|
||||
products <local product>` table, for lookup next time.
|
||||
"""
|
||||
__tablename__ = 'sideshow_product_pending'
|
||||
|
||||
__tablename__ = "sideshow_product_pending"
|
||||
|
||||
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
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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 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(
|
||||
model.User,
|
||||
cascade_backrefs=False,
|
||||
|
@ -206,23 +279,26 @@ class PendingProduct(ProductMixin, model.Base):
|
|||
Reference to the
|
||||
:class:`~wuttjamaican:wuttjamaican.db.model.auth.User` who
|
||||
created the product record.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
order_items = orm.relationship(
|
||||
'OrderItem',
|
||||
back_populates='pending_product',
|
||||
"OrderItem",
|
||||
back_populates="pending_product",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of :class:`~sideshow.db.model.orders.OrderItem` records
|
||||
associated with this product.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
new_order_batch_rows = orm.relationship(
|
||||
'NewOrderBatchRow',
|
||||
back_populates='pending_product',
|
||||
"NewOrderBatchRow",
|
||||
back_populates="pending_product",
|
||||
cascade_backrefs=False,
|
||||
doc="""
|
||||
List of
|
||||
:class:`~sideshow.db.model.batch.neworder.NewOrderBatchRow`
|
||||
records associated with this product.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
|
|
@ -33,22 +33,38 @@ class Store(model.Base):
|
|||
"""
|
||||
Represents a physical location for the business.
|
||||
"""
|
||||
__tablename__ = 'sideshow_store'
|
||||
|
||||
__tablename__ = "sideshow_store"
|
||||
|
||||
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.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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!).
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
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
|
||||
hidden from view.
|
||||
""")
|
||||
""",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.get_display()
|
||||
|
@ -57,6 +73,6 @@ class Store(model.Base):
|
|||
"""
|
||||
Returns the display string for the store, e.g. "001 Acme Goods".
|
||||
"""
|
||||
return ' '.join([(self.store_id or '').strip(),
|
||||
(self.name or '').strip()])\
|
||||
.strip()
|
||||
return " ".join(
|
||||
[(self.store_id or "").strip(), (self.name or "").strip()]
|
||||
).strip()
|
||||
|
|
|
@ -30,7 +30,7 @@ from collections import OrderedDict
|
|||
from wuttjamaican.enum import *
|
||||
|
||||
|
||||
ORDER_UOM_CASE = 'CS'
|
||||
ORDER_UOM_CASE = "CS"
|
||||
"""
|
||||
UOM code for ordering a "case" of product.
|
||||
|
||||
|
@ -38,7 +38,7 @@ Sideshow will treat "case" orders somewhat differently as compared to
|
|||
"unit" orders.
|
||||
"""
|
||||
|
||||
ORDER_UOM_UNIT = 'EA'
|
||||
ORDER_UOM_UNIT = "EA"
|
||||
"""
|
||||
UOM code for ordering a "unit" of product.
|
||||
|
||||
|
@ -47,7 +47,7 @@ the same by Sideshow, whereas "case" orders are treated somewhat
|
|||
differently.
|
||||
"""
|
||||
|
||||
ORDER_UOM_KILOGRAM = 'KG'
|
||||
ORDER_UOM_KILOGRAM = "KG"
|
||||
"""
|
||||
UOM code for ordering a "kilogram" of product.
|
||||
|
||||
|
@ -57,7 +57,7 @@ e.g. :attr:`~sideshow.db.model.orders.OrderItem.product_weighed` is
|
|||
true.
|
||||
"""
|
||||
|
||||
ORDER_UOM_POUND = 'LB'
|
||||
ORDER_UOM_POUND = "LB"
|
||||
"""
|
||||
UOM code for ordering a "pound" of product.
|
||||
|
||||
|
@ -67,12 +67,14 @@ e.g. :attr:`~sideshow.db.model.orders.OrderItem.product_weighed` is
|
|||
true.
|
||||
"""
|
||||
|
||||
ORDER_UOM = OrderedDict([
|
||||
(ORDER_UOM_CASE, "Cases"),
|
||||
(ORDER_UOM_UNIT, "Units"),
|
||||
(ORDER_UOM_KILOGRAM, "Kilograms"),
|
||||
(ORDER_UOM_POUND, "Pounds"),
|
||||
])
|
||||
ORDER_UOM = OrderedDict(
|
||||
[
|
||||
(ORDER_UOM_CASE, "Cases"),
|
||||
(ORDER_UOM_UNIT, "Units"),
|
||||
(ORDER_UOM_KILOGRAM, "Kilograms"),
|
||||
(ORDER_UOM_POUND, "Pounds"),
|
||||
]
|
||||
)
|
||||
"""
|
||||
Dict of possible code -> label options for ordering unit of measure.
|
||||
|
||||
|
@ -88,10 +90,11 @@ class PendingCustomerStatus(Enum):
|
|||
Enum values for
|
||||
:attr:`sideshow.db.model.customers.PendingCustomer.status`.
|
||||
"""
|
||||
PENDING = 'pending'
|
||||
READY = 'ready'
|
||||
RESOLVED = 'resolved'
|
||||
IGNORED = 'ignored'
|
||||
|
||||
PENDING = "pending"
|
||||
READY = "ready"
|
||||
RESOLVED = "resolved"
|
||||
IGNORED = "ignored"
|
||||
|
||||
|
||||
class PendingProductStatus(Enum):
|
||||
|
@ -99,29 +102,30 @@ class PendingProductStatus(Enum):
|
|||
Enum values for
|
||||
:attr:`sideshow.db.model.products.PendingProduct.status`.
|
||||
"""
|
||||
PENDING = 'pending'
|
||||
READY = 'ready'
|
||||
RESOLVED = 'resolved'
|
||||
IGNORED = 'ignored'
|
||||
|
||||
PENDING = "pending"
|
||||
READY = "ready"
|
||||
RESOLVED = "resolved"
|
||||
IGNORED = "ignored"
|
||||
|
||||
|
||||
########################################
|
||||
# Order Item Status
|
||||
########################################
|
||||
|
||||
ORDER_ITEM_STATUS_UNINITIATED = 1
|
||||
ORDER_ITEM_STATUS_UNINITIATED = 1
|
||||
"""
|
||||
Indicates the item is "not yet initiated" - this probably is not
|
||||
useful but exists as a possibility just in case.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_INITIATED = 10
|
||||
ORDER_ITEM_STATUS_INITIATED = 10
|
||||
"""
|
||||
Indicates the item is "initiated" (aka. created) but not yet "ready"
|
||||
for buyer/PO. This may imply the price needs confirmation etc.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_PAID_BEFORE = 50
|
||||
ORDER_ITEM_STATUS_PAID_BEFORE = 50
|
||||
"""
|
||||
Indicates the customer has fully paid for the item, up-front before
|
||||
the buyer places PO etc. It implies the item is not yet "ready" for
|
||||
|
@ -129,101 +133,103 @@ some reason.
|
|||
"""
|
||||
|
||||
# TODO: deprecate / remove this one
|
||||
ORDER_ITEM_STATUS_PAID = ORDER_ITEM_STATUS_PAID_BEFORE
|
||||
ORDER_ITEM_STATUS_PAID = ORDER_ITEM_STATUS_PAID_BEFORE
|
||||
|
||||
ORDER_ITEM_STATUS_READY = 100
|
||||
ORDER_ITEM_STATUS_READY = 100
|
||||
"""
|
||||
Indicates the item is "ready" for buyer to include it on a vendor
|
||||
purchase order.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_PLACED = 200
|
||||
ORDER_ITEM_STATUS_PLACED = 200
|
||||
"""
|
||||
Indicates the buyer has placed a vendor purchase order which includes
|
||||
this item. The item is thereby "on order" until the truck arrives.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_RECEIVED = 300
|
||||
ORDER_ITEM_STATUS_RECEIVED = 300
|
||||
"""
|
||||
Indicates the item has been received as part of a vendor delivery.
|
||||
The item is thereby "on hand" until customer comes in for pickup.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_CONTACTED = 350
|
||||
ORDER_ITEM_STATUS_CONTACTED = 350
|
||||
"""
|
||||
Indicates the customer has been notified that the item is "on hand"
|
||||
and awaiting their pickup.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_CONTACT_FAILED = 375
|
||||
ORDER_ITEM_STATUS_CONTACT_FAILED = 375
|
||||
"""
|
||||
Indicates the attempt(s) to notify customer have failed. The item is
|
||||
on hand but the customer does not know to pickup.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_DELIVERED = 500
|
||||
ORDER_ITEM_STATUS_DELIVERED = 500
|
||||
"""
|
||||
Indicates the customer has picked up the item.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_PAID_AFTER = 550
|
||||
ORDER_ITEM_STATUS_PAID_AFTER = 550
|
||||
"""
|
||||
Indicates the customer has fully paid for the item, as part of their
|
||||
pickup. This completes the cycle for orders which require payment on
|
||||
the tail end.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_CANCELED = 900
|
||||
ORDER_ITEM_STATUS_CANCELED = 900
|
||||
"""
|
||||
Indicates the order item has been canceled.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_REFUND_PENDING = 910
|
||||
ORDER_ITEM_STATUS_REFUND_PENDING = 910
|
||||
"""
|
||||
Indicates the order item has been canceled, and the customer is due a
|
||||
(pending) refund.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_REFUNDED = 920
|
||||
ORDER_ITEM_STATUS_REFUNDED = 920
|
||||
"""
|
||||
Indicates the order item has been canceled, and the customer has been
|
||||
given a refund.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_RESTOCKED = 930
|
||||
ORDER_ITEM_STATUS_RESTOCKED = 930
|
||||
"""
|
||||
Indicates the product has been restocked, e.g. after the order item
|
||||
was canceled.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_EXPIRED = 940
|
||||
ORDER_ITEM_STATUS_EXPIRED = 940
|
||||
"""
|
||||
Indicates the order item and/or product has expired.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS_INACTIVE = 950
|
||||
ORDER_ITEM_STATUS_INACTIVE = 950
|
||||
"""
|
||||
Indicates the order item has become inactive.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_STATUS = OrderedDict([
|
||||
(ORDER_ITEM_STATUS_UNINITIATED, "uninitiated"),
|
||||
(ORDER_ITEM_STATUS_INITIATED, "initiated"),
|
||||
(ORDER_ITEM_STATUS_PAID_BEFORE, "paid"),
|
||||
(ORDER_ITEM_STATUS_READY, "ready"),
|
||||
(ORDER_ITEM_STATUS_PLACED, "placed"),
|
||||
(ORDER_ITEM_STATUS_RECEIVED, "received"),
|
||||
(ORDER_ITEM_STATUS_CONTACTED, "contacted"),
|
||||
(ORDER_ITEM_STATUS_CONTACT_FAILED, "contact failed"),
|
||||
(ORDER_ITEM_STATUS_DELIVERED, "delivered"),
|
||||
(ORDER_ITEM_STATUS_PAID_AFTER, "paid"),
|
||||
(ORDER_ITEM_STATUS_CANCELED, "canceled"),
|
||||
(ORDER_ITEM_STATUS_REFUND_PENDING, "refund pending"),
|
||||
(ORDER_ITEM_STATUS_REFUNDED, "refunded"),
|
||||
(ORDER_ITEM_STATUS_RESTOCKED, "restocked"),
|
||||
(ORDER_ITEM_STATUS_EXPIRED, "expired"),
|
||||
(ORDER_ITEM_STATUS_INACTIVE, "inactive"),
|
||||
])
|
||||
ORDER_ITEM_STATUS = OrderedDict(
|
||||
[
|
||||
(ORDER_ITEM_STATUS_UNINITIATED, "uninitiated"),
|
||||
(ORDER_ITEM_STATUS_INITIATED, "initiated"),
|
||||
(ORDER_ITEM_STATUS_PAID_BEFORE, "paid"),
|
||||
(ORDER_ITEM_STATUS_READY, "ready"),
|
||||
(ORDER_ITEM_STATUS_PLACED, "placed"),
|
||||
(ORDER_ITEM_STATUS_RECEIVED, "received"),
|
||||
(ORDER_ITEM_STATUS_CONTACTED, "contacted"),
|
||||
(ORDER_ITEM_STATUS_CONTACT_FAILED, "contact failed"),
|
||||
(ORDER_ITEM_STATUS_DELIVERED, "delivered"),
|
||||
(ORDER_ITEM_STATUS_PAID_AFTER, "paid"),
|
||||
(ORDER_ITEM_STATUS_CANCELED, "canceled"),
|
||||
(ORDER_ITEM_STATUS_REFUND_PENDING, "refund pending"),
|
||||
(ORDER_ITEM_STATUS_REFUNDED, "refunded"),
|
||||
(ORDER_ITEM_STATUS_RESTOCKED, "restocked"),
|
||||
(ORDER_ITEM_STATUS_EXPIRED, "expired"),
|
||||
(ORDER_ITEM_STATUS_INACTIVE, "inactive"),
|
||||
]
|
||||
)
|
||||
"""
|
||||
Dict of possible code -> label options for :term:`order item` status.
|
||||
|
||||
|
@ -237,19 +243,19 @@ These codes are referenced by:
|
|||
# Order Item Event Type
|
||||
########################################
|
||||
|
||||
ORDER_ITEM_EVENT_INITIATED = 10
|
||||
ORDER_ITEM_EVENT_INITIATED = 10
|
||||
"""
|
||||
Indicates the item was "initiated" - this occurs when the
|
||||
:term:`order` is first created.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_PRICE_CONFIRMED = 20
|
||||
ORDER_ITEM_EVENT_PRICE_CONFIRMED = 20
|
||||
"""
|
||||
Indicates the item's price was confirmed by a user who is authorized
|
||||
to do that.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_PAYMENT_RECEIVED = 50
|
||||
ORDER_ITEM_EVENT_PAYMENT_RECEIVED = 50
|
||||
"""
|
||||
Indicates payment was received for the item. This may occur toward
|
||||
the beginning, or toward the end, of the item's life cycle depending
|
||||
|
@ -257,9 +263,9 @@ on app configuration etc.
|
|||
"""
|
||||
|
||||
# TODO: deprecate / remove this
|
||||
ORDER_ITEM_EVENT_PAID = ORDER_ITEM_EVENT_PAYMENT_RECEIVED
|
||||
ORDER_ITEM_EVENT_PAID = ORDER_ITEM_EVENT_PAYMENT_RECEIVED
|
||||
|
||||
ORDER_ITEM_EVENT_READY = 100
|
||||
ORDER_ITEM_EVENT_READY = 100
|
||||
"""
|
||||
Indicates the item has become "ready" for buyer placement on a new
|
||||
vendor purchase order. Often this will occur when the :term:`order`
|
||||
|
@ -267,128 +273,130 @@ is first created, if the data is suitable. However this may be
|
|||
delayed if e.g. the price needs confirmation.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_CUSTOMER_RESOLVED = 120
|
||||
ORDER_ITEM_EVENT_CUSTOMER_RESOLVED = 120
|
||||
"""
|
||||
Indicates the customer for the :term:`order` has been assigned to a
|
||||
"proper" (existing) account. This may happen (after the fact) if the
|
||||
order was first created with a new/unknown customer.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_PRODUCT_RESOLVED = 140
|
||||
ORDER_ITEM_EVENT_PRODUCT_RESOLVED = 140
|
||||
"""
|
||||
Indicates the product for the :term:`order item` has been assigned to
|
||||
a "proper" (existing) product record. This may happen (after the
|
||||
fact) if the order was first created with a new/unknown product.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_PLACED = 200
|
||||
ORDER_ITEM_EVENT_PLACED = 200
|
||||
"""
|
||||
Indicates the buyer has placed a vendor purchase order which includes
|
||||
this item. So the item is "on order" until the truck arrives.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_REORDER = 210
|
||||
ORDER_ITEM_EVENT_REORDER = 210
|
||||
"""
|
||||
Indicates the item was not received with the delivery on which it was
|
||||
expected, and must be re-ordered from vendor.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_RECEIVED = 300
|
||||
ORDER_ITEM_EVENT_RECEIVED = 300
|
||||
"""
|
||||
Indicates the receiver has found the item while receiving a vendor
|
||||
delivery. The item is set aside and is "on hand" until customer comes
|
||||
in to pick it up.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_CONTACTED = 350
|
||||
ORDER_ITEM_EVENT_CONTACTED = 350
|
||||
"""
|
||||
Indicates the customer has been contacted, to notify them of the item
|
||||
being on hand and ready for pickup.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_CONTACT_FAILED = 375
|
||||
ORDER_ITEM_EVENT_CONTACT_FAILED = 375
|
||||
"""
|
||||
Indicates an attempt was made to contact the customer, to notify them
|
||||
of item being on hand, but the attempt failed, e.g. due to bad phone
|
||||
or email on file.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_DELIVERED = 500
|
||||
ORDER_ITEM_EVENT_DELIVERED = 500
|
||||
"""
|
||||
Indicates the customer has picked up the item.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_STATUS_CHANGE = 700
|
||||
ORDER_ITEM_EVENT_STATUS_CHANGE = 700
|
||||
"""
|
||||
Indicates a manual status change was made. Such an event should
|
||||
ideally contain a note with further explanation.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_NOTE_ADDED = 750
|
||||
ORDER_ITEM_EVENT_NOTE_ADDED = 750
|
||||
"""
|
||||
Indicates an arbitrary note was added.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_CANCELED = 900
|
||||
ORDER_ITEM_EVENT_CANCELED = 900
|
||||
"""
|
||||
Indicates the :term:`order item` was canceled.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_REFUND_PENDING = 910
|
||||
ORDER_ITEM_EVENT_REFUND_PENDING = 910
|
||||
"""
|
||||
Indicates the customer is due a (pending) refund for the item.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_REFUNDED = 920
|
||||
ORDER_ITEM_EVENT_REFUNDED = 920
|
||||
"""
|
||||
Indicates the customer has been refunded for the item.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_RESTOCKED = 930
|
||||
ORDER_ITEM_EVENT_RESTOCKED = 930
|
||||
"""
|
||||
Indicates the product has been restocked, e.g. due to the order item
|
||||
being canceled.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_EXPIRED = 940
|
||||
ORDER_ITEM_EVENT_EXPIRED = 940
|
||||
"""
|
||||
Indicates the order item (or its product) has expired.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_INACTIVE = 950
|
||||
ORDER_ITEM_EVENT_INACTIVE = 950
|
||||
"""
|
||||
Indicates the order item has become inactive.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT_OTHER = 999
|
||||
ORDER_ITEM_EVENT_OTHER = 999
|
||||
"""
|
||||
Arbitrary event type which does not signify anything in particular.
|
||||
If used, the event should be given an explanatory note.
|
||||
"""
|
||||
|
||||
ORDER_ITEM_EVENT = OrderedDict([
|
||||
(ORDER_ITEM_EVENT_INITIATED, "initiated"),
|
||||
(ORDER_ITEM_EVENT_PRICE_CONFIRMED, "price confirmed"),
|
||||
(ORDER_ITEM_EVENT_PAYMENT_RECEIVED, "payment received"),
|
||||
(ORDER_ITEM_EVENT_READY, "ready to proceed"),
|
||||
(ORDER_ITEM_EVENT_CUSTOMER_RESOLVED, "customer resolved"),
|
||||
(ORDER_ITEM_EVENT_PRODUCT_RESOLVED, "product resolved"),
|
||||
(ORDER_ITEM_EVENT_PLACED, "placed with vendor"),
|
||||
(ORDER_ITEM_EVENT_REORDER, "marked for re-order"),
|
||||
(ORDER_ITEM_EVENT_RECEIVED, "received from vendor"),
|
||||
(ORDER_ITEM_EVENT_CONTACTED, "customer contacted"),
|
||||
(ORDER_ITEM_EVENT_CONTACT_FAILED, "contact failed"),
|
||||
(ORDER_ITEM_EVENT_DELIVERED, "delivered"),
|
||||
(ORDER_ITEM_EVENT_STATUS_CHANGE, "changed status"),
|
||||
(ORDER_ITEM_EVENT_NOTE_ADDED, "added note"),
|
||||
(ORDER_ITEM_EVENT_CANCELED, "canceled"),
|
||||
(ORDER_ITEM_EVENT_REFUND_PENDING, "refund pending"),
|
||||
(ORDER_ITEM_EVENT_REFUNDED, "refunded"),
|
||||
(ORDER_ITEM_EVENT_RESTOCKED, "restocked"),
|
||||
(ORDER_ITEM_EVENT_EXPIRED, "expired"),
|
||||
(ORDER_ITEM_EVENT_INACTIVE, "inactive"),
|
||||
(ORDER_ITEM_EVENT_OTHER, "other"),
|
||||
])
|
||||
ORDER_ITEM_EVENT = OrderedDict(
|
||||
[
|
||||
(ORDER_ITEM_EVENT_INITIATED, "initiated"),
|
||||
(ORDER_ITEM_EVENT_PRICE_CONFIRMED, "price confirmed"),
|
||||
(ORDER_ITEM_EVENT_PAYMENT_RECEIVED, "payment received"),
|
||||
(ORDER_ITEM_EVENT_READY, "ready to proceed"),
|
||||
(ORDER_ITEM_EVENT_CUSTOMER_RESOLVED, "customer resolved"),
|
||||
(ORDER_ITEM_EVENT_PRODUCT_RESOLVED, "product resolved"),
|
||||
(ORDER_ITEM_EVENT_PLACED, "placed with vendor"),
|
||||
(ORDER_ITEM_EVENT_REORDER, "marked for re-order"),
|
||||
(ORDER_ITEM_EVENT_RECEIVED, "received from vendor"),
|
||||
(ORDER_ITEM_EVENT_CONTACTED, "customer contacted"),
|
||||
(ORDER_ITEM_EVENT_CONTACT_FAILED, "contact failed"),
|
||||
(ORDER_ITEM_EVENT_DELIVERED, "delivered"),
|
||||
(ORDER_ITEM_EVENT_STATUS_CHANGE, "changed status"),
|
||||
(ORDER_ITEM_EVENT_NOTE_ADDED, "added note"),
|
||||
(ORDER_ITEM_EVENT_CANCELED, "canceled"),
|
||||
(ORDER_ITEM_EVENT_REFUND_PENDING, "refund pending"),
|
||||
(ORDER_ITEM_EVENT_REFUNDED, "refunded"),
|
||||
(ORDER_ITEM_EVENT_RESTOCKED, "restocked"),
|
||||
(ORDER_ITEM_EVENT_EXPIRED, "expired"),
|
||||
(ORDER_ITEM_EVENT_INACTIVE, "inactive"),
|
||||
(ORDER_ITEM_EVENT_OTHER, "other"),
|
||||
]
|
||||
)
|
||||
"""
|
||||
Dict of possible code -> label options for :term:`order item` event
|
||||
types.
|
||||
|
|
|
@ -42,8 +42,7 @@ class OrderHandler(GenericHandler):
|
|||
Returns boolean indicating whether the ``store_id`` field
|
||||
should be exposed at all. This is false by default.
|
||||
"""
|
||||
return self.config.get_bool('sideshow.orders.expose_store_id',
|
||||
default=False)
|
||||
return self.config.get_bool("sideshow.orders.expose_store_id", default=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 case_size is None:
|
||||
case_qty = unit_qty = '??'
|
||||
case_qty = unit_qty = "??"
|
||||
else:
|
||||
case_qty = self.app.render_quantity(case_size)
|
||||
unit_qty = self.app.render_quantity(order_qty * case_size)
|
||||
CS = enum.ORDER_UOM[enum.ORDER_UOM_CASE]
|
||||
EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT]
|
||||
order_qty = self.app.render_quantity(order_qty)
|
||||
times = '×' if html else 'x'
|
||||
return (f"{order_qty} {CS} ({times} {case_qty} = {unit_qty} {EA})")
|
||||
times = "×" if html else "x"
|
||||
return f"{order_qty} {CS} ({times} {case_qty} = {unit_qty} {EA})"
|
||||
|
||||
# units
|
||||
unit_qty = self.app.render_quantity(order_qty)
|
||||
|
@ -97,13 +96,15 @@ class OrderHandler(GenericHandler):
|
|||
``None``.
|
||||
"""
|
||||
enum = self.app.enum
|
||||
if status_code in (enum.ORDER_ITEM_STATUS_CANCELED,
|
||||
enum.ORDER_ITEM_STATUS_REFUND_PENDING,
|
||||
enum.ORDER_ITEM_STATUS_REFUNDED,
|
||||
enum.ORDER_ITEM_STATUS_RESTOCKED,
|
||||
enum.ORDER_ITEM_STATUS_EXPIRED,
|
||||
enum.ORDER_ITEM_STATUS_INACTIVE):
|
||||
return 'warning'
|
||||
if status_code in (
|
||||
enum.ORDER_ITEM_STATUS_CANCELED,
|
||||
enum.ORDER_ITEM_STATUS_REFUND_PENDING,
|
||||
enum.ORDER_ITEM_STATUS_REFUNDED,
|
||||
enum.ORDER_ITEM_STATUS_RESTOCKED,
|
||||
enum.ORDER_ITEM_STATUS_EXPIRED,
|
||||
enum.ORDER_ITEM_STATUS_INACTIVE,
|
||||
):
|
||||
return "warning"
|
||||
|
||||
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")
|
||||
|
||||
info = product_info
|
||||
pending_product.product_id = info['product_id']
|
||||
pending_product.product_id = info["product_id"]
|
||||
pending_product.status = enum.PendingProductStatus.RESOLVED
|
||||
|
||||
items = session.query(model.OrderItem)\
|
||||
.filter(model.OrderItem.pending_product == pending_product)\
|
||||
.filter(model.OrderItem.product_id == None)\
|
||||
.all()
|
||||
items = (
|
||||
session.query(model.OrderItem)
|
||||
.filter(model.OrderItem.pending_product == pending_product)
|
||||
.filter(model.OrderItem.product_id == None)
|
||||
.all()
|
||||
)
|
||||
|
||||
for item in items:
|
||||
item.product_id = info['product_id']
|
||||
item.product_scancode = info['scancode']
|
||||
item.product_brand = info['brand_name']
|
||||
item.product_description = info['description']
|
||||
item.product_size = info['size']
|
||||
item.product_weighed = info['weighed']
|
||||
item.department_id = info['department_id']
|
||||
item.department_name = info['department_name']
|
||||
item.special_order = info['special_order']
|
||||
item.vendor_name = info['vendor_name']
|
||||
item.vendor_item_code = info['vendor_item_code']
|
||||
item.case_size = info['case_size']
|
||||
item.unit_cost = info['unit_cost']
|
||||
item.unit_price_reg = info['unit_price_reg']
|
||||
item.product_id = info["product_id"]
|
||||
item.product_scancode = info["scancode"]
|
||||
item.product_brand = info["brand_name"]
|
||||
item.product_description = info["description"]
|
||||
item.product_size = info["size"]
|
||||
item.product_weighed = info["weighed"]
|
||||
item.department_id = info["department_id"]
|
||||
item.department_name = info["department_name"]
|
||||
item.special_order = info["special_order"]
|
||||
item.vendor_name = info["vendor_name"]
|
||||
item.vendor_item_code = info["vendor_item_code"]
|
||||
item.case_size = info["case_size"]
|
||||
item.unit_cost = info["unit_cost"]
|
||||
item.unit_price_reg = info["unit_price_reg"]
|
||||
|
||||
item.add_event(enum.ORDER_ITEM_EVENT_PRODUCT_RESOLVED, user)
|
||||
if 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.
|
||||
|
||||
|
@ -221,8 +226,15 @@ class OrderHandler(GenericHandler):
|
|||
item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note)
|
||||
item.status_code = enum.ORDER_ITEM_STATUS_PLACED
|
||||
|
||||
def process_receiving(self, items, user, vendor_name=None,
|
||||
invoice_number=None, po_number=None, note=None):
|
||||
def process_receiving(
|
||||
self,
|
||||
items,
|
||||
user,
|
||||
vendor_name=None,
|
||||
invoice_number=None,
|
||||
po_number=None,
|
||||
note=None,
|
||||
):
|
||||
"""
|
||||
Process the "receiving" step for the given order items.
|
||||
|
||||
|
@ -252,7 +264,9 @@ class OrderHandler(GenericHandler):
|
|||
|
||||
received = None
|
||||
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:
|
||||
received = f"invoice {invoice_number} from vendor {vendor_name}"
|
||||
elif po_number and vendor_name:
|
||||
|
|
|
@ -31,8 +31,10 @@ class WebTestCase(base.WebTestCase):
|
|||
|
||||
def make_config(self, **kwargs):
|
||||
config = super().make_config(**kwargs)
|
||||
config.setdefault('wutta.model_spec', 'sideshow.db.model')
|
||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
||||
config.setdefault(f'{config.appname}.batch.neworder.handler.default_spec',
|
||||
'sideshow.batch.neworder:NewOrderBatchHandler')
|
||||
config.setdefault("wutta.model_spec", "sideshow.db.model")
|
||||
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||
config.setdefault(
|
||||
f"{config.appname}.batch.neworder.handler.default_spec",
|
||||
"sideshow.batch.neworder:NewOrderBatchHandler",
|
||||
)
|
||||
return config
|
||||
|
|
|
@ -26,6 +26,6 @@ Sideshow web app
|
|||
|
||||
|
||||
def includeme(config):
|
||||
config.include('sideshow.web.static')
|
||||
config.include('wuttaweb.subscribers')
|
||||
config.include('sideshow.web.views')
|
||||
config.include("sideshow.web.static")
|
||||
config.include("wuttaweb.subscribers")
|
||||
config.include("sideshow.web.views")
|
||||
|
|
|
@ -32,17 +32,20 @@ def main(global_config, **settings):
|
|||
Make and return the WSGI app (Paste entry point).
|
||||
"""
|
||||
# prefer Sideshow templates over wuttaweb
|
||||
settings.setdefault('mako.directories', [
|
||||
'sideshow.web:templates',
|
||||
'wuttaweb:templates',
|
||||
])
|
||||
settings.setdefault(
|
||||
"mako.directories",
|
||||
[
|
||||
"sideshow.web:templates",
|
||||
"wuttaweb:templates",
|
||||
],
|
||||
)
|
||||
|
||||
# make config objects
|
||||
wutta_config = base.make_wutta_config(settings)
|
||||
pyramid_config = base.make_pyramid_config(settings)
|
||||
|
||||
# bring in the rest of Sideshow
|
||||
pyramid_config.include('sideshow.web')
|
||||
pyramid_config.include("sideshow.web")
|
||||
|
||||
return pyramid_config.make_wsgi_app()
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class OrderRef(ObjectRef):
|
|||
|
||||
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):
|
||||
|
@ -73,7 +73,7 @@ class LocalCustomerRef(ObjectRef):
|
|||
|
||||
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):
|
||||
|
@ -98,7 +98,7 @@ class PendingCustomerRef(ObjectRef):
|
|||
|
||||
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):
|
||||
|
@ -122,7 +122,7 @@ class LocalProductRef(ObjectRef):
|
|||
|
||||
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):
|
||||
|
@ -147,4 +147,4 @@ class PendingProductRef(ObjectRef):
|
|||
|
||||
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.
|
||||
"""
|
||||
return {
|
||||
'title': "Orders",
|
||||
'type': 'menu',
|
||||
'items': [
|
||||
"title": "Orders",
|
||||
"type": "menu",
|
||||
"items": [
|
||||
{
|
||||
'title': "Create New Order",
|
||||
'route': 'orders.create',
|
||||
'perm': 'orders.create',
|
||||
"title": "Create New Order",
|
||||
"route": "orders.create",
|
||||
"perm": "orders.create",
|
||||
},
|
||||
{'type': 'sep'},
|
||||
{"type": "sep"},
|
||||
{
|
||||
'title': "Placement",
|
||||
'route': 'order_items_placement',
|
||||
'perm': 'order_items_placement.list',
|
||||
"title": "Placement",
|
||||
"route": "order_items_placement",
|
||||
"perm": "order_items_placement.list",
|
||||
},
|
||||
{
|
||||
'title': "Receiving",
|
||||
'route': 'order_items_receiving',
|
||||
'perm': 'order_items_receiving.list',
|
||||
"title": "Receiving",
|
||||
"route": "order_items_receiving",
|
||||
"perm": "order_items_receiving.list",
|
||||
},
|
||||
{
|
||||
'title': "Contact",
|
||||
'route': 'order_items_contact',
|
||||
'perm': 'order_items_contact.list',
|
||||
"title": "Contact",
|
||||
"route": "order_items_contact",
|
||||
"perm": "order_items_contact.list",
|
||||
},
|
||||
{
|
||||
'title': "Delivery",
|
||||
'route': 'order_items_delivery',
|
||||
'perm': 'order_items_delivery.list',
|
||||
"title": "Delivery",
|
||||
"route": "order_items_delivery",
|
||||
"perm": "order_items_delivery.list",
|
||||
},
|
||||
{'type': 'sep'},
|
||||
{"type": "sep"},
|
||||
{
|
||||
'title': "All Order Items",
|
||||
'route': 'order_items',
|
||||
'perm': 'order_items.list',
|
||||
"title": "All Order Items",
|
||||
"route": "order_items",
|
||||
"perm": "order_items.list",
|
||||
},
|
||||
{
|
||||
'title': "All Orders",
|
||||
'route': 'orders',
|
||||
'perm': 'orders.list',
|
||||
"title": "All Orders",
|
||||
"route": "orders",
|
||||
"perm": "orders.list",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -96,18 +96,18 @@ class SideshowMenuHandler(base.MenuHandler):
|
|||
Generate the Customers menu.
|
||||
"""
|
||||
return {
|
||||
'title': "Customers",
|
||||
'type': 'menu',
|
||||
'items': [
|
||||
"title": "Customers",
|
||||
"type": "menu",
|
||||
"items": [
|
||||
{
|
||||
'title': "Local Customers",
|
||||
'route': 'local_customers',
|
||||
'perm': 'local_customers.list',
|
||||
"title": "Local Customers",
|
||||
"route": "local_customers",
|
||||
"perm": "local_customers.list",
|
||||
},
|
||||
{
|
||||
'title': "Pending Customers",
|
||||
'route': 'pending_customers',
|
||||
'perm': 'pending_customers.list',
|
||||
"title": "Pending Customers",
|
||||
"route": "pending_customers",
|
||||
"perm": "pending_customers.list",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -117,18 +117,18 @@ class SideshowMenuHandler(base.MenuHandler):
|
|||
Generate the Products menu.
|
||||
"""
|
||||
return {
|
||||
'title': "Products",
|
||||
'type': 'menu',
|
||||
'items': [
|
||||
"title": "Products",
|
||||
"type": "menu",
|
||||
"items": [
|
||||
{
|
||||
'title': "Local Products",
|
||||
'route': 'local_products',
|
||||
'perm': 'local_products.list',
|
||||
"title": "Local Products",
|
||||
"route": "local_products",
|
||||
"perm": "local_products.list",
|
||||
},
|
||||
{
|
||||
'title': "Pending Products",
|
||||
'route': 'pending_products',
|
||||
'perm': 'pending_products.list',
|
||||
"title": "Pending Products",
|
||||
"route": "pending_products",
|
||||
"perm": "pending_products.list",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -138,13 +138,13 @@ class SideshowMenuHandler(base.MenuHandler):
|
|||
Generate the Batch menu.
|
||||
"""
|
||||
return {
|
||||
'title': "Batches",
|
||||
'type': 'menu',
|
||||
'items': [
|
||||
"title": "Batches",
|
||||
"type": "menu",
|
||||
"items": [
|
||||
{
|
||||
'title': "New Orders",
|
||||
'route': 'neworder_batches',
|
||||
'perm': 'neworder_batches.list',
|
||||
"title": "New Orders",
|
||||
"route": "neworder_batches",
|
||||
"perm": "neworder_batches.list",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -154,20 +154,23 @@ class SideshowMenuHandler(base.MenuHandler):
|
|||
Generate the "Other" menu.
|
||||
"""
|
||||
return {
|
||||
'title': "Other",
|
||||
'type': 'menu',
|
||||
'items': [],
|
||||
"title": "Other",
|
||||
"type": "menu",
|
||||
"items": [],
|
||||
}
|
||||
|
||||
def make_admin_menu(self, request, **kwargs):
|
||||
""" """
|
||||
kwargs['include_people'] = True
|
||||
kwargs["include_people"] = True
|
||||
menu = super().make_admin_menu(request, **kwargs)
|
||||
|
||||
menu['items'].insert(0, {
|
||||
'title': "Stores",
|
||||
'route': 'stores',
|
||||
'perm': 'stores.list',
|
||||
})
|
||||
menu["items"].insert(
|
||||
0,
|
||||
{
|
||||
"title": "Stores",
|
||||
"route": "stores",
|
||||
"perm": "stores.list",
|
||||
},
|
||||
)
|
||||
|
||||
return menu
|
||||
|
|
|
@ -28,12 +28,12 @@ from fanstatic import Library, Resource
|
|||
|
||||
|
||||
# # libcache
|
||||
libcache = Library('sideshow_libcache', 'libcache')
|
||||
vue_js = Resource(libcache, 'vue-2.6.14.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_css = Resource(libcache, 'buefy-0.9.25.min.css')
|
||||
fontawesome_js = Resource(libcache, 'fontawesome-5.3.1-all.min.js')
|
||||
libcache = Library("sideshow_libcache", "libcache")
|
||||
vue_js = Resource(libcache, "vue-2.6.14.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_css = Resource(libcache, "buefy-0.9.25.min.css")
|
||||
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_oruga_js = Resource(libcache, 'oruga-0.8.10.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):
|
||||
config.include('wuttaweb.static')
|
||||
config.add_static_view('sideshow', 'sideshow.web:static', cache_max_age=3600)
|
||||
config.include("wuttaweb.static")
|
||||
config.add_static_view("sideshow", "sideshow.web:static", cache_max_age=3600)
|
||||
|
|
|
@ -30,15 +30,18 @@ from wuttaweb.views import essential
|
|||
def includeme(config):
|
||||
|
||||
# core views for wuttaweb
|
||||
essential.defaults(config, **{
|
||||
'wuttaweb.views.common': 'sideshow.web.views.common',
|
||||
})
|
||||
essential.defaults(
|
||||
config,
|
||||
**{
|
||||
"wuttaweb.views.common": "sideshow.web.views.common",
|
||||
},
|
||||
)
|
||||
|
||||
# sideshow views
|
||||
config.include('sideshow.web.views.stores')
|
||||
config.include('sideshow.web.views.customers')
|
||||
config.include('sideshow.web.views.products')
|
||||
config.include('sideshow.web.views.orders')
|
||||
config.include("sideshow.web.views.stores")
|
||||
config.include("sideshow.web.views.customers")
|
||||
config.include("sideshow.web.views.products")
|
||||
config.include("sideshow.web.views.orders")
|
||||
|
||||
# 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
|
||||
:class:`~sideshow.web.views.orders.OrderView` instead.
|
||||
"""
|
||||
|
||||
model_class = NewOrderBatch
|
||||
model_title = "New Order Batch"
|
||||
model_title_plural = "New Order Batches"
|
||||
route_prefix = 'neworder_batches'
|
||||
url_prefix = '/batch/neworder'
|
||||
route_prefix = "neworder_batches"
|
||||
url_prefix = "/batch/neworder"
|
||||
creatable = False
|
||||
editable = False
|
||||
|
||||
labels = {
|
||||
'store_id': "Store ID",
|
||||
'customer_id': "Customer ID",
|
||||
"store_id": "Store ID",
|
||||
"customer_id": "Customer ID",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'id',
|
||||
'store_id',
|
||||
'customer_id',
|
||||
'customer_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'total_price',
|
||||
'row_count',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
"id",
|
||||
"store_id",
|
||||
"customer_id",
|
||||
"customer_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"total_price",
|
||||
"row_count",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
]
|
||||
|
||||
filter_defaults = {
|
||||
'executed': {'active': True, 'verb': 'is_null'},
|
||||
"executed": {"active": True, "verb": "is_null"},
|
||||
}
|
||||
|
||||
form_fields = [
|
||||
'id',
|
||||
'store_id',
|
||||
'customer_id',
|
||||
'local_customer',
|
||||
'pending_customer',
|
||||
'customer_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'total_price',
|
||||
'row_count',
|
||||
'status_code',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
'executed_by',
|
||||
"id",
|
||||
"store_id",
|
||||
"customer_id",
|
||||
"local_customer",
|
||||
"pending_customer",
|
||||
"customer_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"total_price",
|
||||
"row_count",
|
||||
"status_code",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
"executed_by",
|
||||
]
|
||||
|
||||
row_labels = {
|
||||
'product_scancode': "Scancode",
|
||||
'product_brand': "Brand",
|
||||
'product_description': "Description",
|
||||
'product_size': "Size",
|
||||
'order_uom': "Order UOM",
|
||||
"product_scancode": "Scancode",
|
||||
"product_brand": "Brand",
|
||||
"product_description": "Description",
|
||||
"product_size": "Size",
|
||||
"order_uom": "Order UOM",
|
||||
}
|
||||
|
||||
row_grid_columns = [
|
||||
'sequence',
|
||||
'product_scancode',
|
||||
'product_brand',
|
||||
'product_description',
|
||||
'product_size',
|
||||
'special_order',
|
||||
'unit_price_quoted',
|
||||
'case_size',
|
||||
'case_price_quoted',
|
||||
'order_qty',
|
||||
'order_uom',
|
||||
'discount_percent',
|
||||
'total_price',
|
||||
'status_code',
|
||||
"sequence",
|
||||
"product_scancode",
|
||||
"product_brand",
|
||||
"product_description",
|
||||
"product_size",
|
||||
"special_order",
|
||||
"unit_price_quoted",
|
||||
"case_size",
|
||||
"case_price_quoted",
|
||||
"order_qty",
|
||||
"order_uom",
|
||||
"discount_percent",
|
||||
"total_price",
|
||||
"status_code",
|
||||
]
|
||||
|
||||
def __init__(self, request, context=None):
|
||||
|
@ -141,10 +142,10 @@ class NewOrderBatchView(BatchMasterView):
|
|||
|
||||
# store_id
|
||||
if not self.order_handler.expose_store_id():
|
||||
g.remove('store_id')
|
||||
g.remove("store_id")
|
||||
|
||||
# total_price
|
||||
g.set_renderer('total_price', 'currency')
|
||||
g.set_renderer("total_price", "currency")
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
|
@ -152,16 +153,16 @@ class NewOrderBatchView(BatchMasterView):
|
|||
|
||||
# store_id
|
||||
if not self.order_handler.expose_store_id():
|
||||
f.remove('store_id')
|
||||
f.remove("store_id")
|
||||
|
||||
# local_customer
|
||||
f.set_node('local_customer', LocalCustomerRef(self.request))
|
||||
f.set_node("local_customer", LocalCustomerRef(self.request))
|
||||
|
||||
# pending_customer
|
||||
f.set_node('pending_customer', PendingCustomerRef(self.request))
|
||||
f.set_node("pending_customer", PendingCustomerRef(self.request))
|
||||
|
||||
# total_price
|
||||
f.set_node('total_price', WuttaMoney(self.request))
|
||||
f.set_node("total_price", WuttaMoney(self.request))
|
||||
|
||||
def configure_row_grid(self, g):
|
||||
""" """
|
||||
|
@ -170,22 +171,22 @@ class NewOrderBatchView(BatchMasterView):
|
|||
|
||||
# TODO
|
||||
# order_uom
|
||||
#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
|
||||
g.set_label('unit_price_quoted', "Unit Price", column_only=True)
|
||||
g.set_renderer('unit_price_quoted', 'currency')
|
||||
g.set_label("unit_price_quoted", "Unit Price", column_only=True)
|
||||
g.set_renderer("unit_price_quoted", "currency")
|
||||
|
||||
# case_price_quoted
|
||||
g.set_label('case_price_quoted', "Case Price", column_only=True)
|
||||
g.set_renderer('case_price_quoted', 'currency')
|
||||
g.set_label("case_price_quoted", "Case Price", column_only=True)
|
||||
g.set_renderer("case_price_quoted", "currency")
|
||||
|
||||
# discount_percent
|
||||
g.set_renderer('discount_percent', 'percent')
|
||||
g.set_label('discount_percent', "Disc. %", column_only=True)
|
||||
g.set_renderer("discount_percent", "percent")
|
||||
g.set_label("discount_percent", "Disc. %", column_only=True)
|
||||
|
||||
# total_price
|
||||
g.set_renderer('total_price', 'currency')
|
||||
g.set_renderer("total_price", "currency")
|
||||
|
||||
def get_xref_buttons(self, batch):
|
||||
"""
|
||||
|
@ -197,14 +198,19 @@ class NewOrderBatchView(BatchMasterView):
|
|||
model = self.app.model
|
||||
session = self.Session()
|
||||
|
||||
if batch.executed and self.request.has_perm('orders.view'):
|
||||
order = session.query(model.Order)\
|
||||
.filter(model.Order.order_id == batch.id)\
|
||||
.first()
|
||||
if batch.executed and self.request.has_perm("orders.view"):
|
||||
order = (
|
||||
session.query(model.Order)
|
||||
.filter(model.Order.order_id == batch.id)
|
||||
.first()
|
||||
)
|
||||
if order:
|
||||
url = self.request.route_url('orders.view', uuid=order.uuid)
|
||||
url = self.request.route_url("orders.view", uuid=order.uuid)
|
||||
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
|
||||
|
||||
|
@ -212,7 +218,7 @@ class NewOrderBatchView(BatchMasterView):
|
|||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
NewOrderBatchView = kwargs.get('NewOrderBatchView', base['NewOrderBatchView'])
|
||||
NewOrderBatchView = kwargs.get("NewOrderBatchView", base["NewOrderBatchView"])
|
||||
NewOrderBatchView.defaults(config)
|
||||
|
||||
|
||||
|
|
|
@ -46,54 +46,55 @@ class CommonView(base.CommonView):
|
|||
auth = self.app.get_auth_handler()
|
||||
|
||||
admin = model.Role(name="Order Admin")
|
||||
admin.notes = ("this role was auto-created; "
|
||||
"you can change or remove it as needed.")
|
||||
admin.notes = (
|
||||
"this role was auto-created; " "you can change or remove it as needed."
|
||||
)
|
||||
|
||||
session.add(admin)
|
||||
user.roles.append(admin)
|
||||
|
||||
order_admin_perms = [
|
||||
'local_customers.list',
|
||||
'local_customers.view',
|
||||
'local_products.list',
|
||||
'local_products.view',
|
||||
'neworder_batches.list',
|
||||
'neworder_batches.view',
|
||||
'order_items.add_note',
|
||||
'order_items.change_status',
|
||||
'order_items.list',
|
||||
'order_items.view',
|
||||
'order_items_contact.add_note',
|
||||
'order_items_contact.change_status',
|
||||
'order_items_contact.list',
|
||||
'order_items_contact.process_contact',
|
||||
'order_items_contact.view',
|
||||
'order_items_delivery.add_note',
|
||||
'order_items_delivery.change_status',
|
||||
'order_items_delivery.list',
|
||||
'order_items_delivery.process_delivery',
|
||||
'order_items_delivery.process_restock',
|
||||
'order_items_delivery.view',
|
||||
'order_items_placement.add_note',
|
||||
'order_items_placement.change_status',
|
||||
'order_items_placement.list',
|
||||
'order_items_placement.process_placement',
|
||||
'order_items_placement.view',
|
||||
'order_items_receiving.add_note',
|
||||
'order_items_receiving.change_status',
|
||||
'order_items_receiving.list',
|
||||
'order_items_receiving.process_receiving',
|
||||
'order_items_receiving.process_reorder',
|
||||
'order_items_receiving.view',
|
||||
'orders.configure',
|
||||
'orders.create',
|
||||
'orders.create_unknown_product',
|
||||
'orders.list',
|
||||
'orders.view',
|
||||
'pending_customers.list',
|
||||
'pending_customers.view',
|
||||
'pending_products.list',
|
||||
'pending_products.view',
|
||||
"local_customers.list",
|
||||
"local_customers.view",
|
||||
"local_products.list",
|
||||
"local_products.view",
|
||||
"neworder_batches.list",
|
||||
"neworder_batches.view",
|
||||
"order_items.add_note",
|
||||
"order_items.change_status",
|
||||
"order_items.list",
|
||||
"order_items.view",
|
||||
"order_items_contact.add_note",
|
||||
"order_items_contact.change_status",
|
||||
"order_items_contact.list",
|
||||
"order_items_contact.process_contact",
|
||||
"order_items_contact.view",
|
||||
"order_items_delivery.add_note",
|
||||
"order_items_delivery.change_status",
|
||||
"order_items_delivery.list",
|
||||
"order_items_delivery.process_delivery",
|
||||
"order_items_delivery.process_restock",
|
||||
"order_items_delivery.view",
|
||||
"order_items_placement.add_note",
|
||||
"order_items_placement.change_status",
|
||||
"order_items_placement.list",
|
||||
"order_items_placement.process_placement",
|
||||
"order_items_placement.view",
|
||||
"order_items_receiving.add_note",
|
||||
"order_items_receiving.change_status",
|
||||
"order_items_receiving.list",
|
||||
"order_items_receiving.process_receiving",
|
||||
"order_items_receiving.process_reorder",
|
||||
"order_items_receiving.view",
|
||||
"orders.configure",
|
||||
"orders.create",
|
||||
"orders.create_unknown_product",
|
||||
"orders.list",
|
||||
"orders.view",
|
||||
"pending_customers.list",
|
||||
"pending_customers.view",
|
||||
"pending_products.list",
|
||||
"pending_products.view",
|
||||
]
|
||||
|
||||
for perm in order_admin_perms:
|
||||
|
@ -101,4 +102,4 @@ class CommonView(base.CommonView):
|
|||
|
||||
|
||||
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/delete``
|
||||
"""
|
||||
|
||||
model_class = LocalCustomer
|
||||
model_title = "Local Customer"
|
||||
route_prefix = 'local_customers'
|
||||
url_prefix = '/local/customers'
|
||||
route_prefix = "local_customers"
|
||||
url_prefix = "/local/customers"
|
||||
|
||||
labels = {
|
||||
'external_id': "External ID",
|
||||
"external_id": "External ID",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'external_id',
|
||||
'full_name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
"external_id",
|
||||
"full_name",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
]
|
||||
|
||||
sort_defaults = 'full_name'
|
||||
sort_defaults = "full_name"
|
||||
|
||||
form_fields = [
|
||||
'external_id',
|
||||
'full_name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'orders',
|
||||
'new_order_batches',
|
||||
"external_id",
|
||||
"full_name",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"orders",
|
||||
"new_order_batches",
|
||||
]
|
||||
|
||||
def configure_grid(self, g):
|
||||
|
@ -80,11 +81,11 @@ class LocalCustomerView(MasterView):
|
|||
super().configure_grid(g)
|
||||
|
||||
# links
|
||||
g.set_link('full_name')
|
||||
g.set_link('first_name')
|
||||
g.set_link('last_name')
|
||||
g.set_link('phone_number')
|
||||
g.set_link('email_address')
|
||||
g.set_link("full_name")
|
||||
g.set_link("first_name")
|
||||
g.set_link("last_name")
|
||||
g.set_link("phone_number")
|
||||
g.set_link("email_address")
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
|
@ -93,25 +94,25 @@ class LocalCustomerView(MasterView):
|
|||
|
||||
# external_id
|
||||
if self.creating:
|
||||
f.remove('external_id')
|
||||
f.remove("external_id")
|
||||
else:
|
||||
f.set_readonly('external_id')
|
||||
f.set_readonly("external_id")
|
||||
|
||||
# full_name
|
||||
if self.creating or self.editing:
|
||||
f.remove('full_name')
|
||||
f.remove("full_name")
|
||||
|
||||
# orders
|
||||
if self.creating or self.editing:
|
||||
f.remove('orders')
|
||||
f.remove("orders")
|
||||
else:
|
||||
f.set_grid('orders', self.make_orders_grid(customer))
|
||||
f.set_grid("orders", self.make_orders_grid(customer))
|
||||
|
||||
# new_order_batches
|
||||
if self.creating or self.editing:
|
||||
f.remove('new_order_batches')
|
||||
f.remove("new_order_batches")
|
||||
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):
|
||||
"""
|
||||
|
@ -120,24 +121,28 @@ class LocalCustomerView(MasterView):
|
|||
model = self.app.model
|
||||
route_prefix = self.get_route_prefix()
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
||||
model_class=model.Order,
|
||||
data=customer.orders,
|
||||
columns=[
|
||||
'order_id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
],
|
||||
labels={
|
||||
'order_id': "Order ID",
|
||||
})
|
||||
grid.set_renderer('total_price', grid.render_currency)
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.orders",
|
||||
model_class=model.Order,
|
||||
data=customer.orders,
|
||||
columns=[
|
||||
"order_id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
],
|
||||
labels={
|
||||
"order_id": "Order ID",
|
||||
},
|
||||
)
|
||||
grid.set_renderer("total_price", grid.render_currency)
|
||||
|
||||
if self.request.has_perm('orders.view'):
|
||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('order_id')
|
||||
if self.request.has_perm("orders.view"):
|
||||
url = lambda order, i: self.request.route_url(
|
||||
"orders.view", uuid=order.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("order_id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -148,28 +153,32 @@ class LocalCustomerView(MasterView):
|
|||
model = self.app.model
|
||||
route_prefix = self.get_route_prefix()
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
||||
model_class=model.NewOrderBatch,
|
||||
data=customer.new_order_batches,
|
||||
columns=[
|
||||
'id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
],
|
||||
labels={
|
||||
'id': "Batch ID",
|
||||
},
|
||||
renderers={
|
||||
'id': 'batch_id',
|
||||
'total_price': 'currency',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.new_order_batches",
|
||||
model_class=model.NewOrderBatch,
|
||||
data=customer.new_order_batches,
|
||||
columns=[
|
||||
"id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
],
|
||||
labels={
|
||||
"id": "Batch ID",
|
||||
},
|
||||
renderers={
|
||||
"id": "batch_id",
|
||||
"total_price": "currency",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('neworder_batches.view'):
|
||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('id')
|
||||
if self.request.has_perm("neworder_batches.view"):
|
||||
url = lambda batch, i: self.request.route_url(
|
||||
"neworder_batches.view", uuid=batch.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -178,8 +187,9 @@ class LocalCustomerView(MasterView):
|
|||
enum = self.app.enum
|
||||
customer = super().objectify(form)
|
||||
|
||||
customer.full_name = self.app.make_full_name(customer.first_name,
|
||||
customer.last_name)
|
||||
customer.full_name = self.app.make_full_name(
|
||||
customer.first_name, customer.last_name
|
||||
)
|
||||
|
||||
return customer
|
||||
|
||||
|
@ -198,41 +208,42 @@ class PendingCustomerView(MasterView):
|
|||
* ``/pending/customers/XXX/edit``
|
||||
* ``/pending/customers/XXX/delete``
|
||||
"""
|
||||
|
||||
model_class = PendingCustomer
|
||||
model_title = "Pending Customer"
|
||||
route_prefix = 'pending_customers'
|
||||
url_prefix = '/pending/customers'
|
||||
route_prefix = "pending_customers"
|
||||
url_prefix = "/pending/customers"
|
||||
|
||||
labels = {
|
||||
'customer_id': "Customer ID",
|
||||
"customer_id": "Customer ID",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'full_name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'customer_id',
|
||||
'status',
|
||||
'created',
|
||||
'created_by',
|
||||
"full_name",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"customer_id",
|
||||
"status",
|
||||
"created",
|
||||
"created_by",
|
||||
]
|
||||
|
||||
sort_defaults = 'full_name'
|
||||
sort_defaults = "full_name"
|
||||
|
||||
form_fields = [
|
||||
'customer_id',
|
||||
'full_name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone_number',
|
||||
'email_address',
|
||||
'status',
|
||||
'created',
|
||||
'created_by',
|
||||
'orders',
|
||||
'new_order_batches',
|
||||
"customer_id",
|
||||
"full_name",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"phone_number",
|
||||
"email_address",
|
||||
"status",
|
||||
"created",
|
||||
"created_by",
|
||||
"orders",
|
||||
"new_order_batches",
|
||||
]
|
||||
|
||||
def configure_grid(self, g):
|
||||
|
@ -241,14 +252,14 @@ class PendingCustomerView(MasterView):
|
|||
enum = self.app.enum
|
||||
|
||||
# status
|
||||
g.set_renderer('status', self.grid_render_enum, enum=enum.PendingCustomerStatus)
|
||||
g.set_renderer("status", self.grid_render_enum, enum=enum.PendingCustomerStatus)
|
||||
|
||||
# links
|
||||
g.set_link('full_name')
|
||||
g.set_link('first_name')
|
||||
g.set_link('last_name')
|
||||
g.set_link('phone_number')
|
||||
g.set_link('email_address')
|
||||
g.set_link("full_name")
|
||||
g.set_link("first_name")
|
||||
g.set_link("last_name")
|
||||
g.set_link("phone_number")
|
||||
g.set_link("email_address")
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
|
@ -258,41 +269,41 @@ class PendingCustomerView(MasterView):
|
|||
|
||||
# customer_id
|
||||
if self.creating:
|
||||
f.remove('customer_id')
|
||||
f.remove("customer_id")
|
||||
else:
|
||||
f.set_readonly('customer_id')
|
||||
f.set_readonly("customer_id")
|
||||
|
||||
# status
|
||||
if self.creating:
|
||||
f.remove('status')
|
||||
f.remove("status")
|
||||
else:
|
||||
f.set_node('status', WuttaEnum(self.request, enum.PendingCustomerStatus))
|
||||
f.set_readonly('status')
|
||||
f.set_node("status", WuttaEnum(self.request, enum.PendingCustomerStatus))
|
||||
f.set_readonly("status")
|
||||
|
||||
# created
|
||||
if self.creating:
|
||||
f.remove('created')
|
||||
f.remove("created")
|
||||
else:
|
||||
f.set_readonly('created')
|
||||
f.set_readonly("created")
|
||||
|
||||
# created_by
|
||||
if self.creating:
|
||||
f.remove('created_by')
|
||||
f.remove("created_by")
|
||||
else:
|
||||
f.set_node('created_by', UserRef(self.request))
|
||||
f.set_readonly('created_by')
|
||||
f.set_node("created_by", UserRef(self.request))
|
||||
f.set_readonly("created_by")
|
||||
|
||||
# orders
|
||||
if self.creating or self.editing:
|
||||
f.remove('orders')
|
||||
f.remove("orders")
|
||||
else:
|
||||
f.set_grid('orders', self.make_orders_grid(customer))
|
||||
f.set_grid("orders", self.make_orders_grid(customer))
|
||||
|
||||
# new_order_batches
|
||||
if self.creating or self.editing:
|
||||
f.remove('new_order_batches')
|
||||
f.remove("new_order_batches")
|
||||
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):
|
||||
"""
|
||||
|
@ -301,24 +312,28 @@ class PendingCustomerView(MasterView):
|
|||
model = self.app.model
|
||||
route_prefix = self.get_route_prefix()
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
||||
model_class=model.Order,
|
||||
data=customer.orders,
|
||||
columns=[
|
||||
'order_id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
],
|
||||
labels={
|
||||
'order_id': "Order ID",
|
||||
})
|
||||
grid.set_renderer('total_price', grid.render_currency)
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.orders",
|
||||
model_class=model.Order,
|
||||
data=customer.orders,
|
||||
columns=[
|
||||
"order_id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
],
|
||||
labels={
|
||||
"order_id": "Order ID",
|
||||
},
|
||||
)
|
||||
grid.set_renderer("total_price", grid.render_currency)
|
||||
|
||||
if self.request.has_perm('orders.view'):
|
||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('order_id')
|
||||
if self.request.has_perm("orders.view"):
|
||||
url = lambda order, i: self.request.route_url(
|
||||
"orders.view", uuid=order.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("order_id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -329,28 +344,32 @@ class PendingCustomerView(MasterView):
|
|||
model = self.app.model
|
||||
route_prefix = self.get_route_prefix()
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
||||
model_class=model.NewOrderBatch,
|
||||
data=customer.new_order_batches,
|
||||
columns=[
|
||||
'id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
],
|
||||
labels={
|
||||
'id': "Batch ID",
|
||||
},
|
||||
renderers={
|
||||
'id': 'batch_id',
|
||||
'total_price': 'currency',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.new_order_batches",
|
||||
model_class=model.NewOrderBatch,
|
||||
data=customer.new_order_batches,
|
||||
columns=[
|
||||
"id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
],
|
||||
labels={
|
||||
"id": "Batch ID",
|
||||
},
|
||||
renderers={
|
||||
"id": "batch_id",
|
||||
"total_price": "currency",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('neworder_batches.view'):
|
||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('id')
|
||||
if self.request.has_perm("neworder_batches.view"):
|
||||
url = lambda batch, i: self.request.route_url(
|
||||
"neworder_batches.view", uuid=batch.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -371,16 +390,20 @@ class PendingCustomerView(MasterView):
|
|||
|
||||
# avoid deleting if still referenced by order(s)
|
||||
for order in customer.orders:
|
||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
||||
"to Order(s)", 'warning')
|
||||
raise self.redirect(self.get_action_url('view', customer))
|
||||
self.request.session.flash(
|
||||
f"Cannot delete {model_title} still attached " "to Order(s)", "warning"
|
||||
)
|
||||
raise self.redirect(self.get_action_url("view", customer))
|
||||
|
||||
# avoid deleting if still referenced by new order batch(es)
|
||||
for batch in customer.new_order_batches:
|
||||
if not batch.executed:
|
||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
||||
"to New Order Batch(es)", 'warning')
|
||||
raise self.redirect(self.get_action_url('view', customer))
|
||||
self.request.session.flash(
|
||||
f"Cannot delete {model_title} still attached "
|
||||
"to New Order Batch(es)",
|
||||
"warning",
|
||||
)
|
||||
raise self.redirect(self.get_action_url("view", customer))
|
||||
|
||||
# go ahead and delete per usual
|
||||
super().delete_instance(customer)
|
||||
|
@ -389,10 +412,10 @@ class PendingCustomerView(MasterView):
|
|||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
LocalCustomerView = kwargs.get('LocalCustomerView', base['LocalCustomerView'])
|
||||
LocalCustomerView = kwargs.get("LocalCustomerView", base["LocalCustomerView"])
|
||||
LocalCustomerView.defaults(config)
|
||||
|
||||
PendingCustomerView = kwargs.get('PendingCustomerView', base['PendingCustomerView'])
|
||||
PendingCustomerView = kwargs.get("PendingCustomerView", base["PendingCustomerView"])
|
||||
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/delete``
|
||||
"""
|
||||
|
||||
model_class = LocalProduct
|
||||
model_title = "Local Product"
|
||||
route_prefix = 'local_products'
|
||||
url_prefix = '/local/products'
|
||||
route_prefix = "local_products"
|
||||
url_prefix = "/local/products"
|
||||
|
||||
labels = {
|
||||
'external_id': "External ID",
|
||||
'department_id': "Department ID",
|
||||
"external_id": "External ID",
|
||||
"department_id": "Department ID",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'scancode',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'department_name',
|
||||
'special_order',
|
||||
'case_size',
|
||||
'unit_cost',
|
||||
'unit_price_reg',
|
||||
"scancode",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"department_name",
|
||||
"special_order",
|
||||
"case_size",
|
||||
"unit_cost",
|
||||
"unit_price_reg",
|
||||
]
|
||||
|
||||
sort_defaults = 'scancode'
|
||||
sort_defaults = "scancode"
|
||||
|
||||
form_fields = [
|
||||
'external_id',
|
||||
'scancode',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'department_id',
|
||||
'department_name',
|
||||
'special_order',
|
||||
'vendor_name',
|
||||
'vendor_item_code',
|
||||
'case_size',
|
||||
'unit_cost',
|
||||
'unit_price_reg',
|
||||
'notes',
|
||||
'orders',
|
||||
'new_order_batches',
|
||||
"external_id",
|
||||
"scancode",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"department_id",
|
||||
"department_name",
|
||||
"special_order",
|
||||
"vendor_name",
|
||||
"vendor_item_code",
|
||||
"case_size",
|
||||
"unit_cost",
|
||||
"unit_price_reg",
|
||||
"notes",
|
||||
"orders",
|
||||
"new_order_batches",
|
||||
]
|
||||
|
||||
def configure_grid(self, g):
|
||||
|
@ -92,17 +93,17 @@ class LocalProductView(MasterView):
|
|||
super().configure_grid(g)
|
||||
|
||||
# unit_cost
|
||||
g.set_renderer('unit_cost', 'currency', scale=4)
|
||||
g.set_renderer("unit_cost", "currency", scale=4)
|
||||
|
||||
# unit_price_reg
|
||||
g.set_label('unit_price_reg', "Reg. Price", column_only=True)
|
||||
g.set_renderer('unit_price_reg', 'currency')
|
||||
g.set_label("unit_price_reg", "Reg. Price", column_only=True)
|
||||
g.set_renderer("unit_price_reg", "currency")
|
||||
|
||||
# links
|
||||
g.set_link('scancode')
|
||||
g.set_link('brand_name')
|
||||
g.set_link('description')
|
||||
g.set_link('size')
|
||||
g.set_link("scancode")
|
||||
g.set_link("brand_name")
|
||||
g.set_link("description")
|
||||
g.set_link("size")
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
|
@ -112,40 +113,40 @@ class LocalProductView(MasterView):
|
|||
|
||||
# external_id
|
||||
if self.creating:
|
||||
f.remove('external_id')
|
||||
f.remove("external_id")
|
||||
else:
|
||||
f.set_readonly('external_id')
|
||||
f.set_readonly("external_id")
|
||||
|
||||
# TODO: should not have to explicitly mark these nodes
|
||||
# as required=False.. i guess i do for now b/c i am
|
||||
# totally overriding the node from colanderlachemy
|
||||
|
||||
# case_size
|
||||
f.set_node('case_size', WuttaQuantity(self.request))
|
||||
f.set_required('case_size', False)
|
||||
f.set_node("case_size", WuttaQuantity(self.request))
|
||||
f.set_required("case_size", False)
|
||||
|
||||
# unit_cost
|
||||
f.set_node('unit_cost', WuttaMoney(self.request, scale=4))
|
||||
f.set_required('unit_cost', False)
|
||||
f.set_node("unit_cost", WuttaMoney(self.request, scale=4))
|
||||
f.set_required("unit_cost", False)
|
||||
|
||||
# unit_price_reg
|
||||
f.set_node('unit_price_reg', WuttaMoney(self.request))
|
||||
f.set_required('unit_price_reg', False)
|
||||
f.set_node("unit_price_reg", WuttaMoney(self.request))
|
||||
f.set_required("unit_price_reg", False)
|
||||
|
||||
# notes
|
||||
f.set_widget('notes', 'notes')
|
||||
f.set_widget("notes", "notes")
|
||||
|
||||
# orders
|
||||
if self.creating or self.editing:
|
||||
f.remove('orders')
|
||||
f.remove("orders")
|
||||
else:
|
||||
f.set_grid('orders', self.make_orders_grid(product))
|
||||
f.set_grid("orders", self.make_orders_grid(product))
|
||||
|
||||
# new_order_batches
|
||||
if self.creating or self.editing:
|
||||
f.remove('new_order_batches')
|
||||
f.remove("new_order_batches")
|
||||
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):
|
||||
"""
|
||||
|
@ -157,26 +158,30 @@ class LocalProductView(MasterView):
|
|||
orders = set([item.order for item in product.order_items])
|
||||
orders = sorted(orders, key=lambda order: order.order_id)
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
||||
model_class=model.Order,
|
||||
data=orders,
|
||||
columns=[
|
||||
'order_id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
],
|
||||
labels={
|
||||
'order_id': "Order ID",
|
||||
},
|
||||
renderers={
|
||||
'total_price': 'currency',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.orders",
|
||||
model_class=model.Order,
|
||||
data=orders,
|
||||
columns=[
|
||||
"order_id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
],
|
||||
labels={
|
||||
"order_id": "Order ID",
|
||||
},
|
||||
renderers={
|
||||
"total_price": "currency",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('orders.view'):
|
||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('order_id')
|
||||
if self.request.has_perm("orders.view"):
|
||||
url = lambda order, i: self.request.route_url(
|
||||
"orders.view", uuid=order.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("order_id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -190,28 +195,32 @@ class LocalProductView(MasterView):
|
|||
batches = set([row.batch for row in product.new_order_batch_rows])
|
||||
batches = sorted(batches, key=lambda batch: batch.id)
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
||||
model_class=model.NewOrderBatch,
|
||||
data=batches,
|
||||
columns=[
|
||||
'id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
],
|
||||
labels={
|
||||
'id': "Batch ID",
|
||||
'status_code': "Status",
|
||||
},
|
||||
renderers={
|
||||
'id': 'batch_id',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.new_order_batches",
|
||||
model_class=model.NewOrderBatch,
|
||||
data=batches,
|
||||
columns=[
|
||||
"id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
],
|
||||
labels={
|
||||
"id": "Batch ID",
|
||||
"status_code": "Status",
|
||||
},
|
||||
renderers={
|
||||
"id": "batch_id",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('neworder_batches.view'):
|
||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('id')
|
||||
if self.request.has_perm("neworder_batches.view"):
|
||||
url = lambda batch, i: self.request.route_url(
|
||||
"neworder_batches.view", uuid=batch.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -230,57 +239,57 @@ class PendingProductView(MasterView):
|
|||
* ``/pending/products/XXX/edit``
|
||||
* ``/pending/products/XXX/delete``
|
||||
"""
|
||||
|
||||
model_class = PendingProduct
|
||||
model_title = "Pending Product"
|
||||
route_prefix = 'pending_products'
|
||||
url_prefix = '/pending/products'
|
||||
route_prefix = "pending_products"
|
||||
url_prefix = "/pending/products"
|
||||
|
||||
labels = {
|
||||
'department_id': "Department ID",
|
||||
'product_id': "Product ID",
|
||||
"department_id": "Department ID",
|
||||
"product_id": "Product ID",
|
||||
}
|
||||
|
||||
grid_columns = [
|
||||
'scancode',
|
||||
'department_name',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'unit_cost',
|
||||
'case_size',
|
||||
'unit_price_reg',
|
||||
'special_order',
|
||||
'status',
|
||||
'created',
|
||||
'created_by',
|
||||
"scancode",
|
||||
"department_name",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"unit_cost",
|
||||
"case_size",
|
||||
"unit_price_reg",
|
||||
"special_order",
|
||||
"status",
|
||||
"created",
|
||||
"created_by",
|
||||
]
|
||||
|
||||
sort_defaults = ('created', 'desc')
|
||||
sort_defaults = ("created", "desc")
|
||||
|
||||
filter_defaults = {
|
||||
'status': {'active': True,
|
||||
'value': PendingProductStatus.READY.name},
|
||||
"status": {"active": True, "value": PendingProductStatus.READY.name},
|
||||
}
|
||||
|
||||
form_fields = [
|
||||
'product_id',
|
||||
'scancode',
|
||||
'department_id',
|
||||
'department_name',
|
||||
'brand_name',
|
||||
'description',
|
||||
'size',
|
||||
'vendor_name',
|
||||
'vendor_item_code',
|
||||
'unit_cost',
|
||||
'case_size',
|
||||
'unit_price_reg',
|
||||
'special_order',
|
||||
'notes',
|
||||
'created',
|
||||
'created_by',
|
||||
'orders',
|
||||
'new_order_batches',
|
||||
"product_id",
|
||||
"scancode",
|
||||
"department_id",
|
||||
"department_name",
|
||||
"brand_name",
|
||||
"description",
|
||||
"size",
|
||||
"vendor_name",
|
||||
"vendor_item_code",
|
||||
"unit_cost",
|
||||
"case_size",
|
||||
"unit_price_reg",
|
||||
"special_order",
|
||||
"notes",
|
||||
"created",
|
||||
"created_by",
|
||||
"orders",
|
||||
"new_order_batches",
|
||||
]
|
||||
|
||||
def configure_grid(self, g):
|
||||
|
@ -289,26 +298,26 @@ class PendingProductView(MasterView):
|
|||
enum = self.app.enum
|
||||
|
||||
# unit_cost
|
||||
g.set_renderer('unit_cost', 'currency', scale=4)
|
||||
g.set_renderer("unit_cost", "currency", scale=4)
|
||||
|
||||
# unit_price_reg
|
||||
g.set_label('unit_price_reg', "Reg. Price", column_only=True)
|
||||
g.set_renderer('unit_price_reg', 'currency')
|
||||
g.set_label("unit_price_reg", "Reg. Price", column_only=True)
|
||||
g.set_renderer("unit_price_reg", "currency")
|
||||
|
||||
# status
|
||||
g.set_enum('status', enum.PendingProductStatus)
|
||||
g.set_enum("status", enum.PendingProductStatus)
|
||||
|
||||
# links
|
||||
g.set_link('scancode')
|
||||
g.set_link('brand_name')
|
||||
g.set_link('description')
|
||||
g.set_link('size')
|
||||
g.set_link("scancode")
|
||||
g.set_link("brand_name")
|
||||
g.set_link("description")
|
||||
g.set_link("size")
|
||||
|
||||
def grid_row_class(self, product, data, i):
|
||||
""" """
|
||||
enum = self.app.enum
|
||||
if product.status == enum.PendingProductStatus.IGNORED:
|
||||
return 'has-background-warning'
|
||||
return "has-background-warning"
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
|
@ -318,40 +327,40 @@ class PendingProductView(MasterView):
|
|||
|
||||
# product_id
|
||||
if self.creating:
|
||||
f.remove('product_id')
|
||||
f.remove("product_id")
|
||||
else:
|
||||
f.set_readonly('product_id')
|
||||
f.set_readonly("product_id")
|
||||
|
||||
# unit_price_reg
|
||||
f.set_node('unit_price_reg', WuttaMoney(self.request))
|
||||
f.set_node("unit_price_reg", WuttaMoney(self.request))
|
||||
|
||||
# notes
|
||||
f.set_widget('notes', 'notes')
|
||||
f.set_widget("notes", "notes")
|
||||
|
||||
# created
|
||||
if self.creating:
|
||||
f.remove('created')
|
||||
f.remove("created")
|
||||
else:
|
||||
f.set_readonly('created')
|
||||
f.set_readonly("created")
|
||||
|
||||
# created_by
|
||||
if self.creating:
|
||||
f.remove('created_by')
|
||||
f.remove("created_by")
|
||||
else:
|
||||
f.set_node('created_by', UserRef(self.request))
|
||||
f.set_readonly('created_by')
|
||||
f.set_node("created_by", UserRef(self.request))
|
||||
f.set_readonly("created_by")
|
||||
|
||||
# orders
|
||||
if self.creating or self.editing:
|
||||
f.remove('orders')
|
||||
f.remove("orders")
|
||||
else:
|
||||
f.set_grid('orders', self.make_orders_grid(product))
|
||||
f.set_grid("orders", self.make_orders_grid(product))
|
||||
|
||||
# new_order_batches
|
||||
if self.creating or self.editing:
|
||||
f.remove('new_order_batches')
|
||||
f.remove("new_order_batches")
|
||||
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):
|
||||
"""
|
||||
|
@ -363,26 +372,30 @@ class PendingProductView(MasterView):
|
|||
orders = set([item.order for item in product.order_items])
|
||||
orders = sorted(orders, key=lambda order: order.order_id)
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.orders',
|
||||
model_class=model.Order,
|
||||
data=orders,
|
||||
columns=[
|
||||
'order_id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
],
|
||||
labels={
|
||||
'order_id': "Order ID",
|
||||
},
|
||||
renderers={
|
||||
'total_price': 'currency',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.orders",
|
||||
model_class=model.Order,
|
||||
data=orders,
|
||||
columns=[
|
||||
"order_id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
],
|
||||
labels={
|
||||
"order_id": "Order ID",
|
||||
},
|
||||
renderers={
|
||||
"total_price": "currency",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('orders.view'):
|
||||
url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('order_id')
|
||||
if self.request.has_perm("orders.view"):
|
||||
url = lambda order, i: self.request.route_url(
|
||||
"orders.view", uuid=order.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("order_id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -396,28 +409,32 @@ class PendingProductView(MasterView):
|
|||
batches = set([row.batch for row in product.new_order_batch_rows])
|
||||
batches = sorted(batches, key=lambda batch: batch.id)
|
||||
|
||||
grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
|
||||
model_class=model.NewOrderBatch,
|
||||
data=batches,
|
||||
columns=[
|
||||
'id',
|
||||
'total_price',
|
||||
'created',
|
||||
'created_by',
|
||||
'executed',
|
||||
],
|
||||
labels={
|
||||
'id': "Batch ID",
|
||||
'status_code': "Status",
|
||||
},
|
||||
renderers={
|
||||
'id': 'batch_id',
|
||||
})
|
||||
grid = self.make_grid(
|
||||
key=f"{route_prefix}.view.new_order_batches",
|
||||
model_class=model.NewOrderBatch,
|
||||
data=batches,
|
||||
columns=[
|
||||
"id",
|
||||
"total_price",
|
||||
"created",
|
||||
"created_by",
|
||||
"executed",
|
||||
],
|
||||
labels={
|
||||
"id": "Batch ID",
|
||||
"status_code": "Status",
|
||||
},
|
||||
renderers={
|
||||
"id": "batch_id",
|
||||
},
|
||||
)
|
||||
|
||||
if self.request.has_perm('neworder_batches.view'):
|
||||
url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
|
||||
grid.add_action('view', icon='eye', url=url)
|
||||
grid.set_link('id')
|
||||
if self.request.has_perm("neworder_batches.view"):
|
||||
url = lambda batch, i: self.request.route_url(
|
||||
"neworder_batches.view", uuid=batch.uuid
|
||||
)
|
||||
grid.add_action("view", icon="eye", url=url)
|
||||
grid.set_link("id")
|
||||
|
||||
return grid
|
||||
|
||||
|
@ -426,11 +443,12 @@ class PendingProductView(MasterView):
|
|||
enum = self.app.enum
|
||||
|
||||
if self.viewing:
|
||||
product = context['instance']
|
||||
if (product.status == enum.PendingProductStatus.READY
|
||||
and self.has_any_perm('resolve', 'ignore')):
|
||||
handler = self.app.get_batch_handler('neworder')
|
||||
context['use_local_products'] = handler.use_local_products()
|
||||
product = context["instance"]
|
||||
if product.status == enum.PendingProductStatus.READY and self.has_any_perm(
|
||||
"resolve", "ignore"
|
||||
):
|
||||
handler = self.app.get_batch_handler("neworder")
|
||||
context["use_local_products"] = handler.use_local_products()
|
||||
|
||||
return context
|
||||
|
||||
|
@ -441,9 +459,12 @@ class PendingProductView(MasterView):
|
|||
for row in product.new_order_batch_rows:
|
||||
if not row.batch.executed:
|
||||
model_title = self.get_model_title()
|
||||
self.request.session.flash(f"Cannot delete {model_title} still attached "
|
||||
"to New Order Batch(es)", 'warning')
|
||||
raise self.redirect(self.get_action_url('view', product))
|
||||
self.request.session.flash(
|
||||
f"Cannot delete {model_title} still attached "
|
||||
"to New Order Batch(es)",
|
||||
"warning",
|
||||
)
|
||||
raise self.redirect(self.get_action_url("view", product))
|
||||
|
||||
# go ahead and delete per usual
|
||||
super().delete_instance(product)
|
||||
|
@ -469,21 +490,23 @@ class PendingProductView(MasterView):
|
|||
product = self.get_instance()
|
||||
|
||||
if product.status != enum.PendingProductStatus.READY:
|
||||
self.request.session.flash("pending product does not have 'ready' status!", 'error')
|
||||
return self.redirect(self.get_action_url('view', product))
|
||||
self.request.session.flash(
|
||||
"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:
|
||||
self.request.session.flash("must specify valid product_id", 'error')
|
||||
return self.redirect(self.get_action_url('view', product))
|
||||
self.request.session.flash("must specify valid product_id", "error")
|
||||
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()
|
||||
|
||||
info = batch_handler.get_product_info_external(session, product_id)
|
||||
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):
|
||||
"""
|
||||
|
@ -499,11 +522,13 @@ class PendingProductView(MasterView):
|
|||
product = self.get_instance()
|
||||
|
||||
if product.status != enum.PendingProductStatus.READY:
|
||||
self.request.session.flash("pending product does not have 'ready' status!", 'error')
|
||||
return self.redirect(self.get_action_url('view', product))
|
||||
self.request.session.flash(
|
||||
"pending product does not have 'ready' status!", "error"
|
||||
)
|
||||
return self.redirect(self.get_action_url("view", product))
|
||||
|
||||
product.status = enum.PendingProductStatus.IGNORED
|
||||
return self.redirect(self.get_action_url('view', product))
|
||||
return self.redirect(self.get_action_url("view", product))
|
||||
|
||||
@classmethod
|
||||
def defaults(cls, config):
|
||||
|
@ -519,35 +544,45 @@ class PendingProductView(MasterView):
|
|||
model_title = cls.get_model_title()
|
||||
|
||||
# resolve
|
||||
config.add_wutta_permission(permission_prefix,
|
||||
f'{permission_prefix}.resolve',
|
||||
f"Resolve {model_title}")
|
||||
config.add_route(f'{route_prefix}.resolve',
|
||||
f'{instance_url_prefix}/resolve',
|
||||
request_method='POST')
|
||||
config.add_view(cls, attr='resolve',
|
||||
route_name=f'{route_prefix}.resolve',
|
||||
permission=f'{permission_prefix}.resolve')
|
||||
config.add_wutta_permission(
|
||||
permission_prefix, f"{permission_prefix}.resolve", f"Resolve {model_title}"
|
||||
)
|
||||
config.add_route(
|
||||
f"{route_prefix}.resolve",
|
||||
f"{instance_url_prefix}/resolve",
|
||||
request_method="POST",
|
||||
)
|
||||
config.add_view(
|
||||
cls,
|
||||
attr="resolve",
|
||||
route_name=f"{route_prefix}.resolve",
|
||||
permission=f"{permission_prefix}.resolve",
|
||||
)
|
||||
|
||||
# ignore
|
||||
config.add_wutta_permission(permission_prefix,
|
||||
f'{permission_prefix}.ignore',
|
||||
f"Ignore {model_title}")
|
||||
config.add_route(f'{route_prefix}.ignore',
|
||||
f'{instance_url_prefix}/ignore',
|
||||
request_method='POST')
|
||||
config.add_view(cls, attr='ignore',
|
||||
route_name=f'{route_prefix}.ignore',
|
||||
permission=f'{permission_prefix}.ignore')
|
||||
config.add_wutta_permission(
|
||||
permission_prefix, f"{permission_prefix}.ignore", f"Ignore {model_title}"
|
||||
)
|
||||
config.add_route(
|
||||
f"{route_prefix}.ignore",
|
||||
f"{instance_url_prefix}/ignore",
|
||||
request_method="POST",
|
||||
)
|
||||
config.add_view(
|
||||
cls,
|
||||
attr="ignore",
|
||||
route_name=f"{route_prefix}.ignore",
|
||||
permission=f"{permission_prefix}.ignore",
|
||||
)
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
LocalProductView = kwargs.get('LocalProductView', base['LocalProductView'])
|
||||
LocalProductView = kwargs.get("LocalProductView", base["LocalProductView"])
|
||||
LocalProductView.defaults(config)
|
||||
|
||||
PendingProductView = kwargs.get('PendingProductView', base['PendingProductView'])
|
||||
PendingProductView = kwargs.get("PendingProductView", base["PendingProductView"])
|
||||
PendingProductView.defaults(config)
|
||||
|
||||
|
||||
|
|
|
@ -43,51 +43,51 @@ class StoreView(MasterView):
|
|||
* ``/stores/XXX/edit``
|
||||
* ``/stores/XXX/delete``
|
||||
"""
|
||||
|
||||
model_class = Store
|
||||
|
||||
labels = {
|
||||
'store_id': "Store ID",
|
||||
"store_id": "Store ID",
|
||||
}
|
||||
|
||||
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):
|
||||
""" """
|
||||
super().configure_grid(g)
|
||||
|
||||
# links
|
||||
g.set_link('store_id')
|
||||
g.set_link('name')
|
||||
g.set_link("store_id")
|
||||
g.set_link("name")
|
||||
|
||||
def grid_row_class(self, store, data, i):
|
||||
""" """
|
||||
if store.archived:
|
||||
return 'has-background-warning'
|
||||
return "has-background-warning"
|
||||
|
||||
def configure_form(self, f):
|
||||
""" """
|
||||
super().configure_form(f)
|
||||
|
||||
# store_id
|
||||
f.set_validator('store_id', self.unique_store_id)
|
||||
f.set_validator("store_id", self.unique_store_id)
|
||||
|
||||
# name
|
||||
f.set_validator('name', self.unique_name)
|
||||
f.set_validator("name", self.unique_name)
|
||||
|
||||
def unique_store_id(self, node, value):
|
||||
""" """
|
||||
model = self.app.model
|
||||
session = self.Session()
|
||||
|
||||
query = session.query(model.Store)\
|
||||
.filter(model.Store.store_id == value)
|
||||
query = session.query(model.Store).filter(model.Store.store_id == value)
|
||||
|
||||
if self.editing:
|
||||
uuid = self.request.matchdict['uuid']
|
||||
uuid = self.request.matchdict["uuid"]
|
||||
query = query.filter(model.Store.uuid != uuid)
|
||||
|
||||
if query.count():
|
||||
|
@ -98,11 +98,10 @@ class StoreView(MasterView):
|
|||
model = self.app.model
|
||||
session = self.Session()
|
||||
|
||||
query = session.query(model.Store)\
|
||||
.filter(model.Store.name == value)
|
||||
query = session.query(model.Store).filter(model.Store.name == value)
|
||||
|
||||
if self.editing:
|
||||
uuid = self.request.matchdict['uuid']
|
||||
uuid = self.request.matchdict["uuid"]
|
||||
query = query.filter(model.Store.uuid != uuid)
|
||||
|
||||
if query.count():
|
||||
|
@ -112,7 +111,7 @@ class StoreView(MasterView):
|
|||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
StoreView = kwargs.get('StoreView', base['StoreView'])
|
||||
StoreView = kwargs.get("StoreView", base["StoreView"])
|
||||
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
|
||||
"""
|
||||
if not skip_tests:
|
||||
c.run('pytest')
|
||||
c.run("pytest")
|
||||
|
||||
# rebuild pkg
|
||||
if os.path.exists('dist'):
|
||||
shutil.rmtree('dist')
|
||||
if os.path.exists('Sideshow.egg-info'):
|
||||
shutil.rmtree('Sideshow.egg-info')
|
||||
c.run('python -m build --sdist')
|
||||
if os.path.exists("dist"):
|
||||
shutil.rmtree("dist")
|
||||
if os.path.exists("Sideshow.egg-info"):
|
||||
shutil.rmtree("Sideshow.egg-info")
|
||||
c.run("python -m build --sdist")
|
||||
|
||||
# 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):
|
||||
ctx = MagicMock(params={})
|
||||
ctx.parent.wutta_config = self.config
|
||||
with patch.object(InstallHandler, 'run') as run:
|
||||
with patch.object(InstallHandler, "run") as run:
|
||||
mod.install(ctx)
|
||||
run.assert_called_once_with()
|
||||
|
|
|
@ -16,8 +16,6 @@ class TestNewOrderBatchRow(DataTestCase):
|
|||
row = mod.NewOrderBatchRow(product_description="Vinegar")
|
||||
self.assertEqual(str(row), "Vinegar")
|
||||
|
||||
product = PendingProduct(brand_name="Bragg",
|
||||
description="Vinegar",
|
||||
size="32oz")
|
||||
product = PendingProduct(brand_name="Bragg", description="Vinegar", size="32oz")
|
||||
row = mod.NewOrderBatchRow(pending_product=product)
|
||||
self.assertEqual(str(row), "Bragg Vinegar 32oz")
|
||||
|
|
|
@ -21,7 +21,7 @@ class TestOrderItem(DataTestCase):
|
|||
|
||||
def make_config(self, **kw):
|
||||
config = super().make_config(**kw)
|
||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
||||
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||
return config
|
||||
|
||||
def test_full_description(self):
|
||||
|
@ -32,9 +32,9 @@ class TestOrderItem(DataTestCase):
|
|||
item = mod.OrderItem(product_description="Vinegar")
|
||||
self.assertEqual(item.full_description, "Vinegar")
|
||||
|
||||
item = mod.OrderItem(product_brand='Bragg',
|
||||
product_description='Vinegar',
|
||||
product_size='32oz')
|
||||
item = mod.OrderItem(
|
||||
product_brand="Bragg", product_description="Vinegar", product_size="32oz"
|
||||
)
|
||||
self.assertEqual(item.full_description, "Bragg Vinegar 32oz")
|
||||
|
||||
def test_str(self):
|
||||
|
@ -45,15 +45,15 @@ class TestOrderItem(DataTestCase):
|
|||
item = mod.OrderItem(product_description="Vinegar")
|
||||
self.assertEqual(str(item), "Vinegar")
|
||||
|
||||
item = mod.OrderItem(product_brand='Bragg',
|
||||
product_description='Vinegar',
|
||||
product_size='32oz')
|
||||
item = mod.OrderItem(
|
||||
product_brand="Bragg", product_description="Vinegar", product_size="32oz"
|
||||
)
|
||||
self.assertEqual(str(item), "Bragg Vinegar 32oz")
|
||||
|
||||
def test_add_event(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
item = mod.OrderItem()
|
||||
self.assertEqual(item.events, [])
|
||||
item.add_event(enum.ORDER_ITEM_EVENT_INITIATED, user)
|
||||
|
|
|
@ -20,9 +20,9 @@ class TestPendingProduct(DataTestCase):
|
|||
product = mod.PendingProduct(size="32oz")
|
||||
self.assertEqual(str(product), "32oz")
|
||||
|
||||
product = mod.PendingProduct(brand_name="Bragg",
|
||||
description="Vinegar",
|
||||
size="32oz")
|
||||
product = mod.PendingProduct(
|
||||
brand_name="Bragg", description="Vinegar", size="32oz"
|
||||
)
|
||||
self.assertEqual(str(product), "Bragg Vinegar 32oz")
|
||||
|
||||
def test_full_description(self):
|
||||
|
@ -38,7 +38,7 @@ class TestPendingProduct(DataTestCase):
|
|||
product = mod.PendingProduct(size="32oz")
|
||||
self.assertEqual(product.full_description, "32oz")
|
||||
|
||||
product = mod.PendingProduct(brand_name="Bragg",
|
||||
description="Vinegar",
|
||||
size="32oz")
|
||||
product = mod.PendingProduct(
|
||||
brand_name="Bragg", description="Vinegar", size="32oz"
|
||||
)
|
||||
self.assertEqual(product.full_description, "Bragg Vinegar 32oz")
|
||||
|
|
|
@ -13,5 +13,5 @@ class TestSideshowConfig(TestCase):
|
|||
config = WuttaConfig(files=[])
|
||||
ext = mod.SideshowConfig()
|
||||
ext.configure(config)
|
||||
self.assertEqual(config.get('wutta.app_title'), "Sideshow")
|
||||
self.assertEqual(config.get('wutta.app_dist'), "Sideshow")
|
||||
self.assertEqual(config.get("wutta.app_title"), "Sideshow")
|
||||
self.assertEqual(config.get("wutta.app_dist"), "Sideshow")
|
||||
|
|
|
@ -9,8 +9,8 @@ class TestOrderHandler(DataTestCase):
|
|||
|
||||
def make_config(self, **kwargs):
|
||||
config = super().make_config(**kwargs)
|
||||
config.setdefault('wutta.model_spec', 'sideshow.db.model')
|
||||
config.setdefault('wutta.enum_spec', 'sideshow.enum')
|
||||
config.setdefault("wutta.model_spec", "sideshow.db.model")
|
||||
config.setdefault("wutta.enum_spec", "sideshow.enum")
|
||||
return config
|
||||
|
||||
def make_handler(self):
|
||||
|
@ -23,7 +23,7 @@ class TestOrderHandler(DataTestCase):
|
|||
self.assertFalse(handler.expose_store_id())
|
||||
|
||||
# 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())
|
||||
|
||||
def test_get_order_qty_uom_text(self):
|
||||
|
@ -35,7 +35,9 @@ class TestOrderHandler(DataTestCase):
|
|||
self.assertEqual(text, "2 Cases (x 12 = 24 Units)")
|
||||
|
||||
# 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)")
|
||||
|
||||
# unknown case size
|
||||
|
@ -55,20 +57,39 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# 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_PLACED))
|
||||
self.assertIsNone(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_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))
|
||||
|
||||
# warning
|
||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CANCELED), 'warning')
|
||||
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUND_PENDING), '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')
|
||||
self.assertEqual(
|
||||
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_CANCELED), "warning"
|
||||
)
|
||||
self.assertEqual(
|
||||
handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_REFUND_PENDING),
|
||||
"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):
|
||||
model = self.app.model
|
||||
|
@ -76,65 +97,87 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
pending = model.PendingProduct(description='vinegar', unit_price_reg=5.99,
|
||||
status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
pending = model.PendingProduct(
|
||||
description="vinegar",
|
||||
unit_price_reg=5.99,
|
||||
status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user,
|
||||
)
|
||||
self.session.add(pending)
|
||||
order = model.Order(order_id=100, customer_name="Fred Flintstone", created_by=user)
|
||||
item = model.OrderItem(pending_product=pending,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
order = model.Order(
|
||||
order_id=100, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
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)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
||||
info = {
|
||||
'product_id': '07430500132',
|
||||
'scancode': '07430500132',
|
||||
'brand_name': "Bragg's",
|
||||
'description': "Apple Cider Vinegar",
|
||||
'size': "32oz",
|
||||
'weighed': False,
|
||||
'department_id': None,
|
||||
'department_name': None,
|
||||
'special_order': False,
|
||||
'vendor_name': None,
|
||||
'vendor_item_code': None,
|
||||
'case_size': 12,
|
||||
'unit_cost': 2.99,
|
||||
'unit_price_reg': 5.99,
|
||||
"product_id": "07430500132",
|
||||
"scancode": "07430500132",
|
||||
"brand_name": "Bragg's",
|
||||
"description": "Apple Cider Vinegar",
|
||||
"size": "32oz",
|
||||
"weighed": False,
|
||||
"department_id": None,
|
||||
"department_name": None,
|
||||
"special_order": False,
|
||||
"vendor_name": None,
|
||||
"vendor_item_code": None,
|
||||
"case_size": 12,
|
||||
"unit_cost": 2.99,
|
||||
"unit_price_reg": 5.99,
|
||||
}
|
||||
|
||||
# first try fails b/c pending status
|
||||
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
|
||||
pending.status = enum.PendingProductStatus.READY
|
||||
handler.resolve_pending_product(pending, info, user)
|
||||
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)
|
||||
|
||||
# more sample data
|
||||
pending2 = model.PendingProduct(description='vinegar', unit_price_reg=5.99,
|
||||
status=enum.PendingProductStatus.READY,
|
||||
created_by=user)
|
||||
pending2 = model.PendingProduct(
|
||||
description="vinegar",
|
||||
unit_price_reg=5.99,
|
||||
status=enum.PendingProductStatus.READY,
|
||||
created_by=user,
|
||||
)
|
||||
self.session.add(pending2)
|
||||
order2 = model.Order(order_id=101, customer_name="Wilma Flintstone", created_by=user)
|
||||
item2 = model.OrderItem(pending_product=pending2,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
order2 = model.Order(
|
||||
order_id=101, customer_name="Wilma Flintstone", created_by=user
|
||||
)
|
||||
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)
|
||||
self.session.add(order2)
|
||||
self.session.flush()
|
||||
|
||||
# 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(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.assertEqual(item2.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
|
||||
self.assertEqual(item2.events[1].note, "hello world")
|
||||
|
@ -145,17 +188,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -165,8 +219,9 @@ class TestOrderHandler(DataTestCase):
|
|||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
|
||||
self.assertEqual(len(item1.events), 0)
|
||||
self.assertEqual(len(item2.events), 0)
|
||||
handler.process_placement([item1, item2], user,
|
||||
vendor_name="Acme Dist", po_number='ACME123')
|
||||
handler.process_placement(
|
||||
[item1, item2], user, vendor_name="Acme Dist", po_number="ACME123"
|
||||
)
|
||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||
self.assertEqual(len(item1.events), 1)
|
||||
|
@ -193,23 +248,40 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
item4 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item4 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item4)
|
||||
item5 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item5 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item5)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -217,17 +289,26 @@ class TestOrderHandler(DataTestCase):
|
|||
# all info provided
|
||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||
self.assertEqual(len(item1.events), 0)
|
||||
handler.process_receiving([item1], user, vendor_name="Acme Dist",
|
||||
invoice_number='INV123', po_number='123')
|
||||
handler.process_receiving(
|
||||
[item1],
|
||||
user,
|
||||
vendor_name="Acme Dist",
|
||||
invoice_number="INV123",
|
||||
po_number="123",
|
||||
)
|
||||
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
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)
|
||||
|
||||
# missing PO number
|
||||
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||
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(len(item2.events), 1)
|
||||
self.assertEqual(item2.events[0].note, "invoice INV123 from vendor Acme Dist")
|
||||
|
@ -236,7 +317,9 @@ class TestOrderHandler(DataTestCase):
|
|||
# missing invoice number
|
||||
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
|
||||
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(len(item3.events), 1)
|
||||
self.assertEqual(item3.events[0].note, "PO 123 from vendor Acme Dist")
|
||||
|
@ -268,17 +351,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_PLACED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -315,17 +409,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -362,17 +467,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -389,8 +505,12 @@ class TestOrderHandler(DataTestCase):
|
|||
self.assertEqual(len(item2.events), 1)
|
||||
self.assertIsNone(item1.events[0].note)
|
||||
self.assertIsNone(item2.events[0].note)
|
||||
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
|
||||
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
|
||||
self.assertEqual(
|
||||
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
|
||||
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
|
@ -400,7 +520,9 @@ class TestOrderHandler(DataTestCase):
|
|||
self.assertEqual(len(item3.events), 2)
|
||||
self.assertIsNone(item3.events[0].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)
|
||||
|
||||
def test_process_delivery(self):
|
||||
|
@ -409,17 +531,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
@ -456,17 +589,28 @@ class TestOrderHandler(DataTestCase):
|
|||
handler = self.make_handler()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
||||
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
order = model.Order(
|
||||
order_id=42, customer_name="Fred Flintstone", created_by=user
|
||||
)
|
||||
item1 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item1)
|
||||
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item2 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item2)
|
||||
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
|
||||
item3 = model.OrderItem(
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_RECEIVED,
|
||||
)
|
||||
order.items.append(item3)
|
||||
self.session.add(order)
|
||||
self.session.flush()
|
||||
|
|
|
@ -17,10 +17,10 @@ class TestOrderRef(WebTestCase):
|
|||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
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
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, created_by=user)
|
||||
self.session.add(order)
|
||||
|
@ -29,7 +29,7 @@ class TestOrderRef(WebTestCase):
|
|||
typ = mod.OrderRef(self.request, session=self.session)
|
||||
url = typ.get_object_url(order)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/orders/{order.uuid}', url)
|
||||
self.assertIn(f"/orders/{order.uuid}", url)
|
||||
|
||||
|
||||
class TestLocalCustomerRef(WebTestCase):
|
||||
|
@ -43,7 +43,7 @@ class TestLocalCustomerRef(WebTestCase):
|
|||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
|
||||
|
@ -54,7 +54,7 @@ class TestLocalCustomerRef(WebTestCase):
|
|||
typ = mod.LocalCustomerRef(self.request, session=self.session)
|
||||
url = typ.get_object_url(customer)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/local/customers/{customer.uuid}', url)
|
||||
self.assertIn(f"/local/customers/{customer.uuid}", url)
|
||||
|
||||
|
||||
class TestPendingCustomerRef(WebTestCase):
|
||||
|
@ -68,21 +68,24 @@ class TestPendingCustomerRef(WebTestCase):
|
|||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
self.session.commit()
|
||||
|
||||
typ = mod.PendingCustomerRef(self.request, session=self.session)
|
||||
url = typ.get_object_url(customer)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/pending/customers/{customer.uuid}', url)
|
||||
self.assertIn(f"/pending/customers/{customer.uuid}", url)
|
||||
|
||||
|
||||
class TestLocalProductRef(WebTestCase):
|
||||
|
@ -96,7 +99,7 @@ class TestLocalProductRef(WebTestCase):
|
|||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
|
||||
|
@ -107,7 +110,7 @@ class TestLocalProductRef(WebTestCase):
|
|||
typ = mod.LocalProductRef(self.request, session=self.session)
|
||||
url = typ.get_object_url(product)
|
||||
self.assertIsNotNone(url)
|
||||
self.assertIn(f'/local/products/{product.uuid}', url)
|
||||
self.assertIn(f"/local/products/{product.uuid}", url)
|
||||
|
||||
|
||||
class TestPendingProductRef(WebTestCase):
|
||||
|
@ -121,18 +124,21 @@ class TestPendingProductRef(WebTestCase):
|
|||
self.assertIsNot(sorted_query, query)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
self.session.commit()
|
||||
|
||||
typ = mod.PendingProductRef(self.request, session=self.session)
|
||||
url = typ.get_object_url(product)
|
||||
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):
|
||||
|
||||
def test_coverage(self):
|
||||
app = mod.main({}, **{'wutta_config': self.config})
|
||||
app = mod.main({}, **{"wutta_config": self.config})
|
||||
self.assertIsInstance(app, Router)
|
||||
|
||||
|
||||
|
|
|
@ -9,12 +9,15 @@ class TestSideshowMenuHandler(WebTestCase):
|
|||
def test_make_menus(self):
|
||||
handler = mod.SideshowMenuHandler(self.config)
|
||||
menus = handler.make_menus(self.request)
|
||||
titles = [menu['title'] for menu in menus]
|
||||
self.assertEqual(titles, [
|
||||
'Orders',
|
||||
'Customers',
|
||||
'Products',
|
||||
'Batches',
|
||||
'Other',
|
||||
'Admin',
|
||||
])
|
||||
titles = [menu["title"] for menu in menus]
|
||||
self.assertEqual(
|
||||
titles,
|
||||
[
|
||||
"Orders",
|
||||
"Customers",
|
||||
"Products",
|
||||
"Batches",
|
||||
"Other",
|
||||
"Admin",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -33,16 +33,16 @@ class TestNewOrderBatchView(WebTestCase):
|
|||
|
||||
# store_id not exposed by default
|
||||
grid = view.make_grid(model_class=model.NewOrderBatch)
|
||||
self.assertIn('store_id', grid.columns)
|
||||
self.assertIn("store_id", grid.columns)
|
||||
view.configure_grid(grid)
|
||||
self.assertNotIn('store_id', grid.columns)
|
||||
self.assertNotIn("store_id", grid.columns)
|
||||
|
||||
# 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)
|
||||
self.assertIn('store_id', grid.columns)
|
||||
self.assertIn("store_id", grid.columns)
|
||||
view.configure_grid(grid)
|
||||
self.assertIn('store_id', grid.columns)
|
||||
self.assertIn("store_id", grid.columns)
|
||||
|
||||
def test_configure_form(self):
|
||||
model = self.app.model
|
||||
|
@ -50,74 +50,85 @@ class TestNewOrderBatchView(WebTestCase):
|
|||
view = self.make_view()
|
||||
handler = view.batch_handler
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
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.commit()
|
||||
|
||||
# viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
with patch.object(view, "viewing", new=True):
|
||||
form = view.make_form(model_instance=batch)
|
||||
view.configure_form(form)
|
||||
schema = form.get_schema()
|
||||
self.assertIsInstance(schema['pending_customer'].typ, PendingCustomerRef)
|
||||
self.assertIsInstance(schema['total_price'].typ, WuttaMoney)
|
||||
self.assertIsInstance(schema["pending_customer"].typ, PendingCustomerRef)
|
||||
self.assertIsInstance(schema["total_price"].typ, WuttaMoney)
|
||||
|
||||
# store_id not exposed by default
|
||||
form = view.make_form(model_instance=batch)
|
||||
self.assertIn('store_id', form)
|
||||
self.assertIn("store_id", form)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('store_id', form)
|
||||
self.assertNotIn("store_id", form)
|
||||
|
||||
# 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)
|
||||
self.assertIn('store_id', form)
|
||||
self.assertIn("store_id", form)
|
||||
view.configure_form(form)
|
||||
self.assertIn('store_id', form)
|
||||
self.assertIn("store_id", form)
|
||||
|
||||
def test_configure_row_grid(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
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)
|
||||
self.assertIn('total_price', grid.renderers)
|
||||
self.assertIn("total_price", grid.renderers)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
handler = view.batch_handler
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
|
||||
# 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.flush()
|
||||
buttons = view.get_xref_buttons(batch)
|
||||
self.assertEqual(len(buttons), 0)
|
||||
|
||||
# 2nd batch is executed; has order
|
||||
batch = handler.make_batch(self.session, pending_customer=customer, created_by=user,
|
||||
executed=datetime.datetime.now(), executed_by=user)
|
||||
batch = handler.make_batch(
|
||||
self.session,
|
||||
pending_customer=customer,
|
||||
created_by=user,
|
||||
executed=datetime.datetime.now(),
|
||||
executed_by=user,
|
||||
)
|
||||
self.session.add(batch)
|
||||
self.session.flush()
|
||||
order = model.Order(order_id=batch.id, created_by=user)
|
||||
self.session.add(order)
|
||||
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
|
||||
with patch.object(self.request, 'is_root', new=True):
|
||||
with patch.object(self.request, "is_root", new=True):
|
||||
buttons = view.get_xref_buttons(batch)
|
||||
self.assertEqual(len(buttons), 1)
|
||||
|
|
|
@ -19,11 +19,11 @@ class TestCommonView(WebTestCase):
|
|||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
self.session.flush()
|
||||
|
||||
self.assertEqual(len(user.roles), 0)
|
||||
view.setup_enhance_admin_user(user)
|
||||
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
|
||||
view = self.make_view()
|
||||
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)
|
||||
self.assertIn('full_name', grid.linked_columns)
|
||||
self.assertIn("full_name", grid.linked_columns)
|
||||
|
||||
def test_configure_form(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# creating
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(view, "creating", new=True):
|
||||
form = view.make_form(model_class=model.LocalCustomer)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('external_id', form)
|
||||
self.assertNotIn('full_name', form)
|
||||
self.assertNotIn('orders', form)
|
||||
self.assertNotIn('new_order_batches', form)
|
||||
self.assertNotIn("external_id", form)
|
||||
self.assertNotIn("full_name", form)
|
||||
self.assertNotIn("orders", form)
|
||||
self.assertNotIn("new_order_batches", form)
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.LocalCustomer()
|
||||
self.session.add(customer)
|
||||
self.session.commit()
|
||||
|
||||
# viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
with patch.object(view, "viewing", new=True):
|
||||
form = view.make_form(model_instance=customer)
|
||||
view.configure_form(form)
|
||||
self.assertIn('external_id', form)
|
||||
self.assertIn('full_name', form)
|
||||
self.assertIn('orders', form)
|
||||
self.assertIn('new_order_batches', form)
|
||||
self.assertIn("external_id", form)
|
||||
self.assertIn("full_name", form)
|
||||
self.assertIn("orders", form)
|
||||
self.assertIn("new_order_batches", form)
|
||||
|
||||
def test_make_orders_grid(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.LocalCustomer()
|
||||
self.session.add(customer)
|
||||
|
@ -74,21 +74,23 @@ class TestLocalCustomerView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
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):
|
||||
model = self.app.model
|
||||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.LocalCustomer()
|
||||
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.commit()
|
||||
|
||||
|
@ -97,31 +99,36 @@ class TestLocalCustomerView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
self.assertEqual(len(grid.actions), 1)
|
||||
self.assertEqual(grid.actions[0].key, 'view')
|
||||
self.assertEqual(grid.actions[0].key, "view")
|
||||
|
||||
def test_objectify(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(self.request, 'user', new=user):
|
||||
with patch.object(view, "creating", new=True):
|
||||
with patch.object(self.request, "user", new=user):
|
||||
form = view.make_model_form()
|
||||
with patch.object(form, 'validated', create=True, new={
|
||||
'first_name': 'Chuck',
|
||||
'last_name': 'Norris',
|
||||
}):
|
||||
with patch.object(
|
||||
form,
|
||||
"validated",
|
||||
create=True,
|
||||
new={
|
||||
"first_name": "Chuck",
|
||||
"last_name": "Norris",
|
||||
},
|
||||
):
|
||||
customer = view.objectify(form)
|
||||
self.assertIsInstance(customer, model.LocalCustomer)
|
||||
self.assertEqual(customer.first_name, 'Chuck')
|
||||
self.assertEqual(customer.last_name, 'Norris')
|
||||
self.assertEqual(customer.full_name, 'Chuck Norris')
|
||||
self.assertEqual(customer.first_name, "Chuck")
|
||||
self.assertEqual(customer.last_name, "Norris")
|
||||
self.assertEqual(customer.full_name, "Chuck Norris")
|
||||
|
||||
|
||||
class TestPendingCustomerView(WebTestCase):
|
||||
|
@ -135,7 +142,7 @@ class TestPendingCustomerView(WebTestCase):
|
|||
# nb. mostly just getting coverage here
|
||||
grid = view.make_grid(model_class=model.PendingCustomer)
|
||||
view.configure_grid(grid)
|
||||
self.assertIn('full_name', grid.linked_columns)
|
||||
self.assertIn("full_name", grid.linked_columns)
|
||||
|
||||
def test_configure_form(self):
|
||||
model = self.app.model
|
||||
|
@ -143,41 +150,43 @@ class TestPendingCustomerView(WebTestCase):
|
|||
view = self.make_view()
|
||||
|
||||
# creating
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(view, "creating", new=True):
|
||||
form = view.make_form(model_class=model.PendingCustomer)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('status', form)
|
||||
self.assertNotIn('created', form)
|
||||
self.assertNotIn('created_by', form)
|
||||
self.assertNotIn('orders', form)
|
||||
self.assertNotIn('new_order_batches', form)
|
||||
self.assertNotIn("status", form)
|
||||
self.assertNotIn("created", form)
|
||||
self.assertNotIn("created_by", form)
|
||||
self.assertNotIn("orders", form)
|
||||
self.assertNotIn("new_order_batches", form)
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
self.session.commit()
|
||||
|
||||
# viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
with patch.object(view, "viewing", new=True):
|
||||
form = view.make_form(model_instance=customer)
|
||||
view.configure_form(form)
|
||||
self.assertIn('status', form)
|
||||
self.assertIn('created', form)
|
||||
self.assertIn('created_by', form)
|
||||
self.assertIn('orders', form)
|
||||
self.assertIn('new_order_batches', form)
|
||||
self.assertIn("status", form)
|
||||
self.assertIn("created", form)
|
||||
self.assertIn("created_by", form)
|
||||
self.assertIn("orders", form)
|
||||
self.assertIn("new_order_batches", form)
|
||||
|
||||
def test_make_orders_grid(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
order = model.Order(order_id=42, pending_customer=customer, created_by=user)
|
||||
self.session.add(order)
|
||||
|
@ -188,10 +197,10 @@ class TestPendingCustomerView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
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):
|
||||
model = self.app.model
|
||||
|
@ -199,12 +208,15 @@ class TestPendingCustomerView(WebTestCase):
|
|||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
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.commit()
|
||||
|
||||
|
@ -213,44 +225,54 @@ class TestPendingCustomerView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
self.assertEqual(len(grid.actions), 1)
|
||||
self.assertEqual(grid.actions[0].key, 'view')
|
||||
self.assertEqual(grid.actions[0].key, "view")
|
||||
|
||||
def test_objectify(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(self.request, 'user', new=user):
|
||||
with patch.object(view, "creating", new=True):
|
||||
with patch.object(self.request, "user", new=user):
|
||||
form = view.make_model_form()
|
||||
with patch.object(form, 'validated', create=True, new={
|
||||
'full_name': "Fred Flinstone",
|
||||
}):
|
||||
with patch.object(
|
||||
form,
|
||||
"validated",
|
||||
create=True,
|
||||
new={
|
||||
"full_name": "Fred Flinstone",
|
||||
},
|
||||
):
|
||||
customer = view.objectify(form)
|
||||
self.assertIsInstance(customer, model.PendingCustomer)
|
||||
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):
|
||||
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
|
||||
enum = self.app.enum
|
||||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
|
||||
# 1st customer is standalone, will be deleted
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
self.session.flush()
|
||||
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)
|
||||
|
||||
# 2nd customer is attached to new order batch, will not be deleted
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
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.flush()
|
||||
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)
|
||||
|
||||
# 3rd customer is attached to order, will not be deleted
|
||||
customer = model.PendingCustomer(status=enum.PendingCustomerStatus.PENDING,
|
||||
created_by=user)
|
||||
customer = model.PendingCustomer(
|
||||
status=enum.PendingCustomerStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(customer)
|
||||
order = model.Order(order_id=42, created_by=user, pending_customer=customer)
|
||||
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
|
||||
view = self.make_view()
|
||||
grid = view.make_grid(model_class=model.LocalProduct)
|
||||
self.assertNotIn('scancode', grid.linked_columns)
|
||||
self.assertNotIn('brand_name', grid.linked_columns)
|
||||
self.assertNotIn('description', grid.linked_columns)
|
||||
self.assertNotIn("scancode", grid.linked_columns)
|
||||
self.assertNotIn("brand_name", grid.linked_columns)
|
||||
self.assertNotIn("description", grid.linked_columns)
|
||||
view.configure_grid(grid)
|
||||
self.assertIn('scancode', grid.linked_columns)
|
||||
self.assertIn('brand_name', grid.linked_columns)
|
||||
self.assertIn('description', grid.linked_columns)
|
||||
self.assertIn("scancode", grid.linked_columns)
|
||||
self.assertIn("brand_name", grid.linked_columns)
|
||||
self.assertIn("description", grid.linked_columns)
|
||||
|
||||
def test_configure_form(self):
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
|
||||
# creating
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(view, "creating", new=True):
|
||||
form = view.make_form(model_class=model.LocalProduct)
|
||||
self.assertIn('external_id', form)
|
||||
self.assertIn("external_id", 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)
|
||||
product = model.LocalProduct()
|
||||
self.session.add(product)
|
||||
self.session.commit()
|
||||
|
||||
# viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
with patch.object(view, "viewing", new=True):
|
||||
form = view.make_form(model_instance=product)
|
||||
self.assertNotIn('external_id', form.readonly_fields)
|
||||
self.assertNotIn('local_products.view.orders', form.grid_vue_context)
|
||||
self.assertNotIn("external_id", form.readonly_fields)
|
||||
self.assertNotIn("local_products.view.orders", form.grid_vue_context)
|
||||
view.configure_form(form)
|
||||
self.assertIn('external_id', form.readonly_fields)
|
||||
self.assertIn('local_products.view.orders', form.grid_vue_context)
|
||||
self.assertIn("external_id", form.readonly_fields)
|
||||
self.assertIn("local_products.view.orders", form.grid_vue_context)
|
||||
|
||||
def test_make_orders_grid(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
||||
product = model.LocalProduct()
|
||||
self.session.add(product)
|
||||
item = model.OrderItem(local_product=product,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
||||
item = model.OrderItem(
|
||||
local_product=product,
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED,
|
||||
)
|
||||
order.items.append(item)
|
||||
self.session.add(order)
|
||||
self.session.commit()
|
||||
|
@ -81,10 +84,10 @@ class TestLocalProductView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
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):
|
||||
model = self.app.model
|
||||
|
@ -92,14 +95,15 @@ class TestLocalProductView(WebTestCase):
|
|||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
batch = handler.make_batch(self.session, created_by=user)
|
||||
self.session.add(batch)
|
||||
product = model.LocalProduct()
|
||||
self.session.add(product)
|
||||
row = handler.make_row(local_product=product,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
||||
row = handler.make_row(
|
||||
local_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||
)
|
||||
handler.add_row(batch, row)
|
||||
self.session.commit()
|
||||
|
||||
|
@ -108,10 +112,10 @@ class TestLocalProductView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
self.assertEqual(len(grid.actions), 1)
|
||||
self.assertEqual(grid.actions[0].key, 'view')
|
||||
self.assertEqual(grid.actions[0].key, "view")
|
||||
|
||||
|
||||
class TestPendingProductView(WebTestCase):
|
||||
|
@ -124,13 +128,13 @@ class TestPendingProductView(WebTestCase):
|
|||
view = self.make_view()
|
||||
# nb. mostly just getting coverage here
|
||||
grid = view.make_grid(model_class=model.PendingProduct)
|
||||
self.assertNotIn('scancode', grid.linked_columns)
|
||||
self.assertNotIn('brand_name', grid.linked_columns)
|
||||
self.assertNotIn('description', grid.linked_columns)
|
||||
self.assertNotIn("scancode", grid.linked_columns)
|
||||
self.assertNotIn("brand_name", grid.linked_columns)
|
||||
self.assertNotIn("description", grid.linked_columns)
|
||||
view.configure_grid(grid)
|
||||
self.assertIn('scancode', grid.linked_columns)
|
||||
self.assertIn('brand_name', grid.linked_columns)
|
||||
self.assertIn('description', grid.linked_columns)
|
||||
self.assertIn("scancode", grid.linked_columns)
|
||||
self.assertIn("brand_name", grid.linked_columns)
|
||||
self.assertIn("description", grid.linked_columns)
|
||||
|
||||
def test_grid_row_class(self):
|
||||
enum = self.app.enum
|
||||
|
@ -143,7 +147,7 @@ class TestPendingProductView(WebTestCase):
|
|||
|
||||
# warning for 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):
|
||||
model = self.app.model
|
||||
|
@ -151,41 +155,46 @@ class TestPendingProductView(WebTestCase):
|
|||
view = self.make_view()
|
||||
|
||||
# creating
|
||||
with patch.object(view, 'creating', new=True):
|
||||
with patch.object(view, "creating", new=True):
|
||||
form = view.make_form(model_class=model.PendingProduct)
|
||||
view.configure_form(form)
|
||||
self.assertNotIn('created', form)
|
||||
self.assertNotIn('created_by', form)
|
||||
self.assertNotIn("created", form)
|
||||
self.assertNotIn("created_by", form)
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
self.session.commit()
|
||||
|
||||
# viewing
|
||||
with patch.object(view, 'viewing', new=True):
|
||||
with patch.object(view, "viewing", new=True):
|
||||
form = view.make_form(model_instance=product)
|
||||
view.configure_form(form)
|
||||
self.assertIn('status', form)
|
||||
self.assertIn('created', form)
|
||||
self.assertIn('created_by', form)
|
||||
self.assertIn("status", form)
|
||||
self.assertIn("created", form)
|
||||
self.assertIn("created_by", form)
|
||||
|
||||
def test_make_orders_grid(self):
|
||||
model = self.app.model
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
order = model.Order(order_id=42, customer_id=42, created_by=user)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
item = model.OrderItem(pending_product=product,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
||||
item = model.OrderItem(
|
||||
pending_product=product,
|
||||
order_qty=1,
|
||||
order_uom=enum.ORDER_UOM_UNIT,
|
||||
status_code=enum.ORDER_ITEM_STATUS_INITIATED,
|
||||
)
|
||||
order.items.append(item)
|
||||
self.session.add(order)
|
||||
self.session.commit()
|
||||
|
@ -195,10 +204,10 @@ class TestPendingProductView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
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):
|
||||
model = self.app.model
|
||||
|
@ -206,15 +215,17 @@ class TestPendingProductView(WebTestCase):
|
|||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
batch = handler.make_batch(self.session, created_by=user)
|
||||
self.session.add(batch)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
row = handler.make_row(pending_product=product,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
||||
row = handler.make_row(
|
||||
pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||
)
|
||||
handler.add_row(batch, row)
|
||||
self.session.commit()
|
||||
|
||||
|
@ -223,57 +234,60 @@ class TestPendingProductView(WebTestCase):
|
|||
self.assertEqual(len(grid.actions), 0)
|
||||
|
||||
# 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)
|
||||
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):
|
||||
enum = self.app.enum
|
||||
model = self.app.model
|
||||
view = self.make_view()
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING)
|
||||
orig_context = {'instance': product}
|
||||
orig_context = {"instance": product}
|
||||
|
||||
# local setting omitted by default
|
||||
context = view.get_template_context(orig_context)
|
||||
self.assertNotIn('use_local_products', context)
|
||||
self.assertNotIn("use_local_products", context)
|
||||
|
||||
# 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)
|
||||
self.assertNotIn('use_local_products', context)
|
||||
self.assertNotIn("use_local_products", context)
|
||||
|
||||
# still omitted even though correct status
|
||||
product.status = enum.PendingProductStatus.READY
|
||||
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
|
||||
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)
|
||||
self.assertIn('use_local_products', context)
|
||||
self.assertIn("use_local_products", context)
|
||||
# nb. true by default
|
||||
self.assertTrue(context['use_local_products'])
|
||||
self.assertTrue(context["use_local_products"])
|
||||
|
||||
# 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)
|
||||
self.assertFalse(context['use_local_products'])
|
||||
self.assertFalse(context["use_local_products"])
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
handler = NewOrderBatchHandler(self.config)
|
||||
view = self.make_view()
|
||||
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
|
||||
# 1st product is standalone, will be deleted
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
self.session.flush()
|
||||
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
|
||||
batch = handler.make_batch(self.session, created_by=user)
|
||||
self.session.add(batch)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
row = handler.make_row(pending_product=product,
|
||||
order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
||||
row = handler.make_row(
|
||||
pending_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT
|
||||
)
|
||||
handler.add_row(batch, row)
|
||||
self.session.flush()
|
||||
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)
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
self.session.flush()
|
||||
|
||||
info = {
|
||||
'product_id': '07430500132',
|
||||
'scancode': '07430500132',
|
||||
'brand_name': "Bragg's",
|
||||
'description': "Apple Cider Vinegar",
|
||||
'size': "32oz",
|
||||
'weighed': False,
|
||||
'department_id': None,
|
||||
'department_name': None,
|
||||
'special_order': False,
|
||||
'vendor_name': None,
|
||||
'vendor_item_code': None,
|
||||
'case_size': 12,
|
||||
'unit_cost': 2.99,
|
||||
'unit_price_reg': 5.99,
|
||||
"product_id": "07430500132",
|
||||
"scancode": "07430500132",
|
||||
"brand_name": "Bragg's",
|
||||
"description": "Apple Cider Vinegar",
|
||||
"size": "32oz",
|
||||
"weighed": False,
|
||||
"department_id": None,
|
||||
"department_name": None,
|
||||
"special_order": False,
|
||||
"vendor_name": None,
|
||||
"vendor_item_code": None,
|
||||
"case_size": 12,
|
||||
"unit_cost": 2.99,
|
||||
"unit_price_reg": 5.99,
|
||||
}
|
||||
|
||||
with patch.object(view, 'Session', return_value=self.session):
|
||||
with patch.object(self.request, 'user', new=user):
|
||||
with patch.object(self.request, 'matchdict', new={'uuid': product.uuid}):
|
||||
with patch.object(view, "Session", return_value=self.session):
|
||||
with patch.object(self.request, "user", new=user):
|
||||
with patch.object(
|
||||
self.request, "matchdict", new={"uuid": product.uuid}
|
||||
):
|
||||
|
||||
# flash error if wrong status
|
||||
result = view.resolve()
|
||||
self.assertIsInstance(result, HTTPFound)
|
||||
self.assertTrue(self.request.session.peek_flash('error'))
|
||||
self.assertEqual(self.request.session.pop_flash('error'),
|
||||
["pending product does not have 'ready' status!"])
|
||||
self.assertTrue(self.request.session.peek_flash("error"))
|
||||
self.assertEqual(
|
||||
self.request.session.pop_flash("error"),
|
||||
["pending product does not have 'ready' status!"],
|
||||
)
|
||||
|
||||
# flash error if product_id not specified
|
||||
product.status = enum.PendingProductStatus.READY
|
||||
result = view.resolve()
|
||||
self.assertIsInstance(result, HTTPFound)
|
||||
self.assertTrue(self.request.session.peek_flash('error'))
|
||||
self.assertEqual(self.request.session.pop_flash('error'),
|
||||
["must specify valid product_id"])
|
||||
self.assertTrue(self.request.session.peek_flash("error"))
|
||||
self.assertEqual(
|
||||
self.request.session.pop_flash("error"),
|
||||
["must specify valid product_id"],
|
||||
)
|
||||
|
||||
# more sample data
|
||||
order = model.Order(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,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY)
|
||||
order = model.Order(
|
||||
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,
|
||||
status_code=enum.ORDER_ITEM_STATUS_READY,
|
||||
)
|
||||
order.items.append(item)
|
||||
self.session.add(order)
|
||||
|
||||
|
@ -369,45 +398,58 @@ class TestPendingProductView(WebTestCase):
|
|||
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
||||
self.assertIsNone(item.product_id)
|
||||
batch_handler = NewOrderBatchHandler(self.config)
|
||||
with patch.object(batch_handler, 'get_product_info_external',
|
||||
return_value=info):
|
||||
with patch.object(self.app, 'get_batch_handler',
|
||||
return_value=batch_handler):
|
||||
with patch.object(self.request, 'POST',
|
||||
new={'product_id': '07430500132'}):
|
||||
with patch.object(batch_handler, 'get_product_info_external',
|
||||
return_value=info):
|
||||
with patch.object(
|
||||
batch_handler, "get_product_info_external", return_value=info
|
||||
):
|
||||
with patch.object(
|
||||
self.app, "get_batch_handler", return_value=batch_handler
|
||||
):
|
||||
with patch.object(
|
||||
self.request, "POST", new={"product_id": "07430500132"}
|
||||
):
|
||||
with patch.object(
|
||||
batch_handler,
|
||||
"get_product_info_external",
|
||||
return_value=info,
|
||||
):
|
||||
result = view.resolve()
|
||||
self.assertIsInstance(result, HTTPFound)
|
||||
self.assertFalse(self.request.session.peek_flash('error'))
|
||||
self.assertEqual(product.product_id, '07430500132')
|
||||
self.assertFalse(self.request.session.peek_flash("error"))
|
||||
self.assertEqual(product.product_id, "07430500132")
|
||||
self.assertEqual(product.status, enum.PendingProductStatus.RESOLVED)
|
||||
self.assertEqual(item.product_id, '07430500132')
|
||||
self.assertEqual(item.product_id, "07430500132")
|
||||
|
||||
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
|
||||
enum = self.app.enum
|
||||
view = self.make_view()
|
||||
|
||||
# sample data
|
||||
user = model.User(username='barney')
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
product = model.PendingProduct(status=enum.PendingProductStatus.PENDING,
|
||||
created_by=user)
|
||||
product = model.PendingProduct(
|
||||
status=enum.PendingProductStatus.PENDING, created_by=user
|
||||
)
|
||||
self.session.add(product)
|
||||
self.session.flush()
|
||||
|
||||
with patch.object(view, 'Session', return_value=self.session):
|
||||
with patch.object(self.request, 'user', new=user):
|
||||
with patch.object(self.request, 'matchdict', new={'uuid': product.uuid}):
|
||||
with patch.object(view, "Session", return_value=self.session):
|
||||
with patch.object(self.request, "user", new=user):
|
||||
with patch.object(
|
||||
self.request, "matchdict", new={"uuid": product.uuid}
|
||||
):
|
||||
|
||||
# flash error if wrong status
|
||||
result = view.ignore()
|
||||
self.assertIsInstance(result, HTTPFound)
|
||||
self.assertTrue(self.request.session.peek_flash('error'))
|
||||
self.assertEqual(self.request.session.pop_flash('error'),
|
||||
["pending product does not have 'ready' status!"])
|
||||
self.assertTrue(self.request.session.peek_flash("error"))
|
||||
self.assertEqual(
|
||||
self.request.session.pop_flash("error"),
|
||||
["pending product does not have 'ready' status!"],
|
||||
)
|
||||
|
||||
# product updated
|
||||
product.status = enum.PendingProductStatus.READY
|
||||
|
@ -415,6 +457,6 @@ class TestPendingProductView(WebTestCase):
|
|||
self.assertEqual(product.status, enum.PendingProductStatus.READY)
|
||||
result = view.ignore()
|
||||
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.assertEqual(product.status, enum.PendingProductStatus.IGNORED)
|
||||
|
|
|
@ -23,11 +23,11 @@ class TestStoreView(WebTestCase):
|
|||
model = self.app.model
|
||||
view = self.make_view()
|
||||
grid = view.make_grid(model_class=model.Store)
|
||||
self.assertNotIn('store_id', grid.linked_columns)
|
||||
self.assertNotIn('name', grid.linked_columns)
|
||||
self.assertNotIn("store_id", grid.linked_columns)
|
||||
self.assertNotIn("name", grid.linked_columns)
|
||||
view.configure_grid(grid)
|
||||
self.assertIn('store_id', grid.linked_columns)
|
||||
self.assertIn('name', grid.linked_columns)
|
||||
self.assertIn("store_id", grid.linked_columns)
|
||||
self.assertIn("name", grid.linked_columns)
|
||||
|
||||
def test_grid_row_class(self):
|
||||
model = self.app.model
|
||||
|
@ -39,7 +39,7 @@ class TestStoreView(WebTestCase):
|
|||
|
||||
store = model.Store(archived=True)
|
||||
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):
|
||||
model = self.app.model
|
||||
|
@ -47,48 +47,48 @@ class TestStoreView(WebTestCase):
|
|||
|
||||
# unique validators are set
|
||||
form = view.make_form(model_class=model.Store)
|
||||
self.assertNotIn('store_id', form.validators)
|
||||
self.assertNotIn('name', form.validators)
|
||||
self.assertNotIn("store_id", form.validators)
|
||||
self.assertNotIn("name", form.validators)
|
||||
view.configure_form(form)
|
||||
self.assertIn('store_id', form.validators)
|
||||
self.assertIn('name', form.validators)
|
||||
self.assertIn("store_id", form.validators)
|
||||
self.assertIn("name", form.validators)
|
||||
|
||||
def test_unique_store_id(self):
|
||||
model = self.app.model
|
||||
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.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
|
||||
node = colander.SchemaNode(colander.String(), name='store_id')
|
||||
self.assertRaises(colander.Invalid, view.unique_store_id, node, '001')
|
||||
node = colander.SchemaNode(colander.String(), name="store_id")
|
||||
self.assertRaises(colander.Invalid, view.unique_store_id, node, "001")
|
||||
|
||||
# but not if store_id belongs to current store
|
||||
with patch.object(self.request, 'matchdict', new={'uuid': store.uuid}):
|
||||
with patch.object(view, 'editing', new=True):
|
||||
node = colander.SchemaNode(colander.String(), name='store_id')
|
||||
self.assertIsNone(view.unique_store_id(node, '001'))
|
||||
with patch.object(self.request, "matchdict", new={"uuid": store.uuid}):
|
||||
with patch.object(view, "editing", new=True):
|
||||
node = colander.SchemaNode(colander.String(), name="store_id")
|
||||
self.assertIsNone(view.unique_store_id(node, "001"))
|
||||
|
||||
def test_unique_name(self):
|
||||
model = self.app.model
|
||||
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.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
|
||||
node = colander.SchemaNode(colander.String(), name='name')
|
||||
self.assertRaises(colander.Invalid, view.unique_name, node, 'Acme Goods')
|
||||
node = colander.SchemaNode(colander.String(), name="name")
|
||||
self.assertRaises(colander.Invalid, view.unique_name, node, "Acme Goods")
|
||||
|
||||
# but not if name belongs to current store
|
||||
with patch.object(self.request, 'matchdict', new={'uuid': store.uuid}):
|
||||
with patch.object(view, 'editing', new=True):
|
||||
node = colander.SchemaNode(colander.String(), name='name')
|
||||
self.assertIsNone(view.unique_name(node, 'Acme Goods'))
|
||||
with patch.object(self.request, "matchdict", new={"uuid": store.uuid}):
|
||||
with patch.object(view, "editing", new=True):
|
||||
node = colander.SchemaNode(colander.String(), name="name")
|
||||
self.assertIsNone(view.unique_name(node, "Acme Goods"))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue