diff --git a/docs/api/sideshow.app.rst b/docs/api/sideshow.app.rst new file mode 100644 index 0000000..7c738b1 --- /dev/null +++ b/docs/api/sideshow.app.rst @@ -0,0 +1,6 @@ + +``sideshow.app`` +================ + +.. automodule:: sideshow.app + :members: diff --git a/docs/index.rst b/docs/index.rst index 643578b..d91ae5e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -30,6 +30,7 @@ For an online demo see https://demo.wuttaproject.org/ :caption: Package API: api/sideshow + api/sideshow.app api/sideshow.batch api/sideshow.batch.neworder api/sideshow.cli diff --git a/pyproject.toml b/pyproject.toml index e1d42a8..ff4a4bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,9 @@ sideshow_libcache = "sideshow.web.static:libcache" [project.entry-points."paste.app_factory"] "main" = "sideshow.web.app:main" +[project.entry-points."wutta.app.providers"] +sideshow = "sideshow.app:SideshowAppProvider" + [project.entry-points."wutta.batch.neworder"] "sideshow" = "sideshow.batch.neworder:NewOrderBatchHandler" diff --git a/src/sideshow/app.py b/src/sideshow/app.py new file mode 100644 index 0000000..0fbcf2e --- /dev/null +++ b/src/sideshow/app.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8; -*- +################################################################################ +# +# Sideshow -- Case/Special Order Tracker +# Copyright © 2024 Lance Edgar +# +# This file is part of Sideshow. +# +# Sideshow is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Sideshow is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Sideshow. If not, see . +# +################################################################################ +""" +Sideshow app provider +""" + +from wuttjamaican import app as base + + +class SideshowAppProvider(base.AppProvider): + """ + The :term:`app provider` for Sideshow. + + This adds the :meth:`get_order_handler()` method to the :term:`app + handler`. + """ + + def get_order_handler(self, **kwargs): + """ + Get the configured :term:`order handler` for the app. + + You can specify a custom handler in your :term:`config file` + like: + + .. code-block:: ini + + [sideshow] + orders.handler_spec = poser.orders:PoserOrderHandler + + :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') + self.order_handler = self.app.load_object(spec)(self.config) + return self.order_handler diff --git a/src/sideshow/batch/neworder.py b/src/sideshow/batch/neworder.py index bfa04ea..e328501 100644 --- a/src/sideshow/batch/neworder.py +++ b/src/sideshow/batch/neworder.py @@ -50,6 +50,14 @@ class NewOrderBatchHandler(BatchHandler): """ model_class = NewOrderBatch + def get_default_store_id(self): + """ + Returns the configured default value for + :attr:`~sideshow.db.model.batch.neworder.NewOrderBatch.store_id`, + or ``None``. + """ + return self.config.get('sideshow.orders.default_store_id') + def use_local_customers(self): """ Returns boolean indicating whether :term:`local customer` @@ -165,6 +173,18 @@ class NewOrderBatchHandler(BatchHandler): 'label': customer.full_name} return [result(c) for c in customers] + def init_batch(self, batch, session=None, progress=None, **kwargs): + """ + Initialize a new batch. + + This sets the + :attr:`~sideshow.db.model.batch.neworder.NewOrderBatch.store_id`, + if the batch does not yet have one and a default is + configured. + """ + if not batch.store_id: + batch.store_id = self.get_default_store_id() + def set_customer(self, batch, customer_info, user=None): """ Set/update customer info for the batch. diff --git a/src/sideshow/db/model/orders.py b/src/sideshow/db/model/orders.py index 2cadeaa..5455d01 100644 --- a/src/sideshow/db/model/orders.py +++ b/src/sideshow/db/model/orders.py @@ -62,6 +62,15 @@ class Order(model.Base): 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', + doc=""" + Reference to the :class:`~sideshow.db.model.stores.Store` + record, if applicable. + """) + 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. diff --git a/src/sideshow/db/model/stores.py b/src/sideshow/db/model/stores.py index b1956c1..4b01d02 100644 --- a/src/sideshow/db/model/stores.py +++ b/src/sideshow/db/model/stores.py @@ -51,4 +51,12 @@ class Store(model.Base): """) def __str__(self): - return self.name or "" + return self.get_display() + + def get_display(self): + """ + Returns the display string for the store, e.g. "001 Acme Goods". + """ + return ' '.join([(self.store_id or '').strip(), + (self.name or '').strip()])\ + .strip() diff --git a/src/sideshow/orders.py b/src/sideshow/orders.py index 9f99e53..868cada 100644 --- a/src/sideshow/orders.py +++ b/src/sideshow/orders.py @@ -37,6 +37,14 @@ class OrderHandler(GenericHandler): handler is responsible for creation logic.) """ + def expose_store_id(self): + """ + 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) + def get_order_qty_uom_text(self, order_qty, order_uom, case_size=None, html=False): """ Return the display text for a given order quantity. diff --git a/src/sideshow/web/templates/order-items/view.mako b/src/sideshow/web/templates/order-items/view.mako index 3cd210a..21cb8b2 100644 --- a/src/sideshow/web/templates/order-items/view.mako +++ b/src/sideshow/web/templates/order-items/view.mako @@ -29,6 +29,17 @@ ${h.link_to(f"Order ID {order.order_id}", url('orders.view', uuid=order.uuid))} — Item #${item.sequence} + % if expose_store_id: + + + % if order.store: + ${h.link_to(order.store.get_display(), url('stores.view', uuid=order.store.uuid))} + % elif order.store_id: + ${order.store_id} + % endif + + + % endif ${order_qty_uom_text|n} diff --git a/src/sideshow/web/templates/orders/configure.mako b/src/sideshow/web/templates/orders/configure.mako index e247b2f..6af30b1 100644 --- a/src/sideshow/web/templates/orders/configure.mako +++ b/src/sideshow/web/templates/orders/configure.mako @@ -3,6 +3,28 @@ <%def name="form_content()"> +

Stores

+
+ + + + Show/choose the Store ID for each order + + + + + + + +
+

Customers

@@ -14,6 +36,7 @@ +

Products

diff --git a/src/sideshow/web/templates/orders/create.mako b/src/sideshow/web/templates/orders/create.mako index 2ac6f0a..7ec015a 100644 --- a/src/sideshow/web/templates/orders/create.mako +++ b/src/sideshow/web/templates/orders/create.mako @@ -42,7 +42,25 @@