diff --git a/.pylintrc b/.pylintrc index 55fbabc..527cc44 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,35 +3,3 @@ [MESSAGES CONTROL] disable=fixme, duplicate-code, - abstract-method, - arguments-differ, - arguments-renamed, - attribute-defined-outside-init, - broad-exception-caught, - consider-using-dict-comprehension, - consider-using-f-string, - consider-using-set-comprehension, - empty-docstring, - implicit-str-concat, - inconsistent-return-statements, - invalid-name, - missing-class-docstring, - missing-function-docstring, - no-else-return, - no-member, - no-self-argument, - redefined-outer-name, - singleton-comparison, - too-few-public-methods, - too-many-arguments, - too-many-branches, - too-many-lines, - too-many-locals, - too-many-positional-arguments, - too-many-public-methods, - unnecessary-lambda-assignment, - unused-argument, - unused-import, - unused-variable, - unused-wildcard-import, - wildcard-import, diff --git a/docs/index.rst b/docs/index.rst index f067448..3bb4efc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,6 +10,9 @@ project. .. _test coverage: https://buildbot.rattailproject.org/coverage/sideshow/ +.. image:: https://img.shields.io/badge/linting-pylint-yellowgreen + :target: https://github.com/pylint-dev/pylint + .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black diff --git a/src/sideshow/app.py b/src/sideshow/app.py index ec2f85a..02363ec 100644 --- a/src/sideshow/app.py +++ b/src/sideshow/app.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -35,7 +35,7 @@ class SideshowAppProvider(base.AppProvider): handler`. """ - def get_order_handler(self, **kwargs): + def get_order_handler(self): """ Get the configured :term:`order handler` for the app. @@ -49,9 +49,9 @@ class SideshowAppProvider(base.AppProvider): :returns: Instance of :class:`~sideshow.orders.OrderHandler`. """ - if "order_handler" not in self.__dict__: + if "orders" not in self.app.handlers: 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 + self.app.handlers["orders"] = self.app.load_object(spec)(self.config) + return self.app.handlers["orders"] diff --git a/src/sideshow/batch/neworder.py b/src/sideshow/batch/neworder.py index fd0a05e..599ad73 100644 --- a/src/sideshow/batch/neworder.py +++ b/src/sideshow/batch/neworder.py @@ -23,6 +23,7 @@ """ New Order Batch Handler """ +# pylint: disable=too-many-lines import datetime import decimal @@ -35,7 +36,7 @@ from wuttjamaican.batch import BatchHandler from sideshow.db.model import NewOrderBatch -class NewOrderBatchHandler(BatchHandler): +class NewOrderBatchHandler(BatchHandler): # pylint: disable=too-many-public-methods """ The :term:`batch handler` for :term:`new order batches `. @@ -116,6 +117,7 @@ class NewOrderBatchHandler(BatchHandler): discount = self.config.get("sideshow.orders.default_item_discount") if discount: return decimal.Decimal(discount) + return None def autocomplete_customers_external(self, session, term, user=None): """ @@ -137,7 +139,9 @@ class NewOrderBatchHandler(BatchHandler): """ raise NotImplementedError - def autocomplete_customers_local(self, session, term, user=None): + def autocomplete_customers_local( # pylint: disable=unused-argument + self, session, term, user=None + ): """ Return autocomplete search results for :class:`~sideshow.db.model.customers.LocalCustomer` records. @@ -343,7 +347,9 @@ class NewOrderBatchHandler(BatchHandler): """ raise NotImplementedError - def autocomplete_products_local(self, session, term, user=None): + def autocomplete_products_local( # pylint: disable=unused-argument + self, session, term, user=None + ): """ Return autocomplete search results for :class:`~sideshow.db.model.products.LocalProduct` records. @@ -468,7 +474,9 @@ class NewOrderBatchHandler(BatchHandler): """ raise NotImplementedError - def get_product_info_local(self, session, uuid, user=None): + def get_product_info_local( # pylint: disable=unused-argument + self, session, uuid, user=None + ): """ Returns basic info for a :term:`local product` as pertains to ordering. @@ -597,7 +605,6 @@ class NewOrderBatchHandler(BatchHandler): :returns: List of product info dicts. """ - model = self.app.model session = self.app.get_session(batch) use_local = self.use_local_products() user = user or batch.created_by @@ -650,7 +657,7 @@ class NewOrderBatchHandler(BatchHandler): return products - def add_item( + def add_item( # pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals self, batch, product_info, @@ -761,7 +768,7 @@ class NewOrderBatchHandler(BatchHandler): session.flush() return row - def update_item( + def update_item( # pylint: disable=too-many-arguments,too-many-positional-arguments self, row, product_info, order_qty, order_uom, discount_percent=None, user=None ): """ @@ -865,7 +872,7 @@ class NewOrderBatchHandler(BatchHandler): # refresh per new info self.refresh_row(row) - def refresh_row(self, row): + def refresh_row(self, row): # pylint: disable=too-many-branches """ Refresh data for the row. This is called when adding a new row to the batch, or anytime the row is updated (e.g. when @@ -1023,7 +1030,7 @@ class NewOrderBatchHandler(BatchHandler): super().remove_row(row) - def do_delete(self, batch, user, **kwargs): + def do_delete(self, batch, user, **kwargs): # pylint: disable=arguments-differ """ Delete a batch completely. @@ -1047,7 +1054,7 @@ class NewOrderBatchHandler(BatchHandler): # continue with normal deletion super().do_delete(batch, user, **kwargs) - def why_not_execute(self, batch, **kwargs): + def why_not_execute(self, batch, **kwargs): # pylint: disable=arguments-differ """ By default this checks to ensure the batch has a customer with phone number, and at least one item. It also may check to @@ -1068,6 +1075,8 @@ class NewOrderBatchHandler(BatchHandler): if not rows: return "Must add at least one valid item" + return None + def get_effective_rows(self, batch): """ Only rows with @@ -1188,7 +1197,7 @@ class NewOrderBatchHandler(BatchHandler): session.flush() - def make_new_order(self, batch, rows, user=None, progress=None, **kwargs): + def make_new_order(self, batch, rows, user=None, progress=None): """ Create a new :term:`order` from the batch data. @@ -1205,7 +1214,6 @@ class NewOrderBatchHandler(BatchHandler): :returns: :class:`~sideshow.db.model.orders.Order` instance. """ model = self.app.model - enum = self.app.enum session = self.app.get_session(batch) batch_fields = [ @@ -1247,17 +1255,17 @@ class NewOrderBatchHandler(BatchHandler): ] # make order - kw = dict([(field, getattr(batch, field)) for field in batch_fields]) + kw = {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() - def convert(row, i): + def convert(row, i): # pylint: disable=unused-argument # make order item - kw = dict([(field, getattr(row, field)) for field in row_fields]) + kw = {field: getattr(row, field) for field in row_fields} item = model.OrderItem(**kw) order.items.append(item) @@ -1270,7 +1278,7 @@ class NewOrderBatchHandler(BatchHandler): session.flush() return order - def set_initial_item_status(self, item, user, **kwargs): + def set_initial_item_status(self, item, user): """ Set the initial status and attach event(s) for the given item. diff --git a/src/sideshow/cli/install.py b/src/sideshow/cli/install.py index 06231f6..38ebc25 100644 --- a/src/sideshow/cli/install.py +++ b/src/sideshow/cli/install.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -38,10 +38,10 @@ def install( """ config = ctx.parent.wutta_config app = config.get_app() - install = app.get_install_handler( + handler = app.get_install_handler( pkg_name="sideshow", app_title="Sideshow", pypi_name="Sideshow", egg_name="Sideshow", ) - install.run() + handler.run() diff --git a/src/sideshow/config.py b/src/sideshow/config.py index e58c368..eb97479 100644 --- a/src/sideshow/config.py +++ b/src/sideshow/config.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -36,7 +36,7 @@ class SideshowConfig(WuttaConfigExtension): key = "sideshow" - def configure(self, config): + def configure(self, config): # pylint: disable=empty-docstring """ """ # app info diff --git a/src/sideshow/db/model/batch/neworder.py b/src/sideshow/db/model/batch/neworder.py index bae0a79..c5dfb94 100644 --- a/src/sideshow/db/model/batch/neworder.py +++ b/src/sideshow/db/model/batch/neworder.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -57,7 +57,7 @@ class NewOrderBatch(model.BatchMixin, model.Base): """ @declared_attr - def __table_args__(cls): + def __table_args__(cls): # pylint: disable=no-self-argument return cls.__default_table_args__() + ( sa.ForeignKeyConstraint( ["local_customer_uuid"], ["sideshow_customer_local.uuid"] @@ -95,7 +95,9 @@ class NewOrderBatch(model.BatchMixin, model.Base): local_customer_uuid = sa.Column(model.UUID(), nullable=True) @declared_attr - def local_customer(cls): + def local_customer( # pylint: disable=no-self-argument,missing-function-docstring + cls, + ): return orm.relationship( "LocalCustomer", back_populates="new_order_batches", @@ -111,7 +113,9 @@ class NewOrderBatch(model.BatchMixin, model.Base): pending_customer_uuid = sa.Column(model.UUID(), nullable=True) @declared_attr - def pending_customer(cls): + def pending_customer( # pylint: disable=no-self-argument,missing-function-docstring + cls, + ): return orm.relationship( "PendingCustomer", back_populates="new_order_batches", @@ -170,7 +174,7 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base): __batch_class__ = NewOrderBatch @declared_attr - def __table_args__(cls): + def __table_args__(cls): # pylint: disable=no-self-argument return cls.__default_table_args__() + ( sa.ForeignKeyConstraint( ["local_product_uuid"], ["sideshow_product_local.uuid"] @@ -222,7 +226,9 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base): local_product_uuid = sa.Column(model.UUID(), nullable=True) @declared_attr - def local_product(cls): + def local_product( # pylint: disable=no-self-argument,missing-function-docstring + cls, + ): return orm.relationship( "LocalProduct", back_populates="new_order_batch_rows", @@ -238,7 +244,9 @@ class NewOrderBatchRow(model.BatchRowMixin, model.Base): pending_product_uuid = sa.Column(model.UUID(), nullable=True) @declared_attr - def pending_product(cls): + def pending_product( # pylint: disable=no-self-argument,missing-function-docstring + cls, + ): return orm.relationship( "PendingProduct", back_populates="new_order_batch_rows", diff --git a/src/sideshow/db/model/customers.py b/src/sideshow/db/model/customers.py index b106a13..deb081c 100644 --- a/src/sideshow/db/model/customers.py +++ b/src/sideshow/db/model/customers.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -34,7 +34,7 @@ from wuttjamaican.db import model from sideshow.enum import PendingCustomerStatus -class CustomerMixin: +class CustomerMixin: # pylint: disable=too-few-public-methods """ Base class for customer tables. This has shared columns, used by e.g.: @@ -86,7 +86,9 @@ class CustomerMixin: return self.full_name or "" -class LocalCustomer(CustomerMixin, model.Base): +class LocalCustomer( # pylint: disable=too-few-public-methods + CustomerMixin, model.Base +): """ This table contains the :term:`local customer` records. @@ -136,7 +138,9 @@ class LocalCustomer(CustomerMixin, model.Base): ) -class PendingCustomer(CustomerMixin, model.Base): +class PendingCustomer( # pylint: disable=too-few-public-methods + CustomerMixin, model.Base +): """ This table contains the :term:`pending customer` records, used when creating an :term:`order` for new/unknown customer. diff --git a/src/sideshow/db/model/orders.py b/src/sideshow/db/model/orders.py index c5c9218..b0d7f08 100644 --- a/src/sideshow/db/model/orders.py +++ b/src/sideshow/db/model/orders.py @@ -33,7 +33,7 @@ from sqlalchemy.ext.orderinglist import ordering_list from wuttjamaican.db import model -class Order(model.Base): +class Order(model.Base): # pylint: disable=too-few-public-methods """ Represents an :term:`order` for a customer. Each order has one or more :attr:`items`. @@ -519,7 +519,7 @@ class OrderItem(model.Base): ) @property - def full_description(self): + def full_description(self): # pylint: disable=empty-docstring """ """ fields = [ self.product_brand or "", @@ -542,7 +542,7 @@ class OrderItem(model.Base): self.events.append(OrderItemEvent(**kwargs)) -class OrderItemEvent(model.Base): +class OrderItemEvent(model.Base): # pylint: disable=too-few-public-methods """ An event in the life of an :term:`order item`. """ diff --git a/src/sideshow/db/model/products.py b/src/sideshow/db/model/products.py index 6842104..0b11308 100644 --- a/src/sideshow/db/model/products.py +++ b/src/sideshow/db/model/products.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -169,7 +169,7 @@ class ProductMixin: ) @property - def full_description(self): + def full_description(self): # pylint: disable=empty-docstring """ """ fields = [self.brand_name or "", self.description or "", self.size or ""] fields = [f.strip() for f in fields if f.strip()] @@ -179,7 +179,7 @@ class ProductMixin: return self.full_description -class LocalProduct(ProductMixin, model.Base): +class LocalProduct(ProductMixin, model.Base): # pylint: disable=too-few-public-methods """ This table contains the :term:`local product` records. @@ -228,7 +228,9 @@ class LocalProduct(ProductMixin, model.Base): ) -class PendingProduct(ProductMixin, model.Base): +class PendingProduct( # pylint: disable=too-few-public-methods + ProductMixin, model.Base +): """ This table contains the :term:`pending product` records, used when creating an :term:`order` for new/unknown product(s). diff --git a/src/sideshow/enum.py b/src/sideshow/enum.py index e9abd8a..34d953c 100644 --- a/src/sideshow/enum.py +++ b/src/sideshow/enum.py @@ -27,7 +27,7 @@ Enum Values from enum import Enum from collections import OrderedDict -from wuttjamaican.enum import * +from wuttjamaican.enum import * # pylint: disable=wildcard-import,unused-wildcard-import ORDER_UOM_CASE = "CS" diff --git a/src/sideshow/orders.py b/src/sideshow/orders.py index b0e639e..0222f30 100644 --- a/src/sideshow/orders.py +++ b/src/sideshow/orders.py @@ -72,15 +72,15 @@ class OrderHandler(GenericHandler): 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] + CS = enum.ORDER_UOM[enum.ORDER_UOM_CASE] # pylint: disable=invalid-name + EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT] # pylint: disable=invalid-name order_qty = self.app.render_quantity(order_qty) 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) - EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT] + EA = enum.ORDER_UOM[enum.ORDER_UOM_UNIT] # pylint: disable=invalid-name return f"{unit_qty} {EA}" def item_status_to_variant(self, status_code): @@ -105,6 +105,7 @@ class OrderHandler(GenericHandler): enum.ORDER_ITEM_STATUS_INACTIVE, ): return "warning" + return None def resolve_pending_product(self, pending_product, product_info, user, note=None): """ @@ -159,7 +160,10 @@ class OrderHandler(GenericHandler): items = ( session.query(model.OrderItem) .filter(model.OrderItem.pending_product == pending_product) - .filter(model.OrderItem.product_id == None) + .filter( + model.OrderItem.product_id # pylint: disable=singleton-comparison + == None + ) .all() ) @@ -183,7 +187,7 @@ class OrderHandler(GenericHandler): if note: item.add_event(enum.ORDER_ITEM_EVENT_NOTE_ADDED, user, note=note) - def process_placement( + def process_placement( # pylint: disable=too-many-arguments,too-many-positional-arguments self, items, user, vendor_name=None, po_number=None, note=None ): """ @@ -226,7 +230,7 @@ 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( + def process_receiving( # pylint: disable=too-many-arguments,too-many-positional-arguments self, items, user, diff --git a/src/sideshow/testing.py b/src/sideshow/testing.py index f1fccfd..667df18 100644 --- a/src/sideshow/testing.py +++ b/src/sideshow/testing.py @@ -28,6 +28,10 @@ from wuttaweb import testing as base class WebTestCase(base.WebTestCase): + """ + Custom class for web tests; it configures defaults specific to + Sideshow. + """ def make_config(self, **kwargs): config = super().make_config(**kwargs) diff --git a/src/sideshow/web/__init__.py b/src/sideshow/web/__init__.py index 34f0b6f..61135e5 100644 --- a/src/sideshow/web/__init__.py +++ b/src/sideshow/web/__init__.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -25,7 +25,7 @@ Sideshow web app """ -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring config.include("sideshow.web.static") config.include("wuttaweb.subscribers") config.include("sideshow.web.views") diff --git a/src/sideshow/web/app.py b/src/sideshow/web/app.py index 8d10424..11e29db 100644 --- a/src/sideshow/web/app.py +++ b/src/sideshow/web/app.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -27,7 +27,7 @@ Sideshow web app from wuttaweb import app as base -def main(global_config, **settings): +def main(global_config, **settings): # pylint: disable=unused-argument """ Make and return the WSGI app (Paste entry point). """ @@ -41,7 +41,7 @@ def main(global_config, **settings): ) # make config objects - wutta_config = base.make_wutta_config(settings) + wutta_config = base.make_wutta_config(settings) # pylint: disable=unused-variable pyramid_config = base.make_pyramid_config(settings) # bring in the rest of Sideshow diff --git a/src/sideshow/web/forms/schema.py b/src/sideshow/web/forms/schema.py index c990523..b1b0a0c 100644 --- a/src/sideshow/web/forms/schema.py +++ b/src/sideshow/web/forms/schema.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -37,17 +37,18 @@ class OrderRef(ObjectRef): """ @property - def model_class(self): + def model_class(self): # pylint: disable=empty-docstring """ """ model = self.app.model return model.Order - def sort_query(self, query): + def sort_query(self, query): # pylint: disable=empty-docstring """ """ return query.order_by(self.model_class.order_id) - def get_object_url(self, order): + def get_object_url(self, obj): # pylint: disable=empty-docstring """ """ + order = obj return self.request.route_url("orders.view", uuid=order.uuid) @@ -62,17 +63,18 @@ class LocalCustomerRef(ObjectRef): """ @property - def model_class(self): + def model_class(self): # pylint: disable=empty-docstring """ """ model = self.app.model return model.LocalCustomer - def sort_query(self, query): + def sort_query(self, query): # pylint: disable=empty-docstring """ """ return query.order_by(self.model_class.full_name) - def get_object_url(self, customer): + def get_object_url(self, obj): # pylint: disable=empty-docstring """ """ + customer = obj return self.request.route_url("local_customers.view", uuid=customer.uuid) @@ -87,17 +89,18 @@ class PendingCustomerRef(ObjectRef): """ @property - def model_class(self): + def model_class(self): # pylint: disable=empty-docstring """ """ model = self.app.model return model.PendingCustomer - def sort_query(self, query): + def sort_query(self, query): # pylint: disable=empty-docstring """ """ return query.order_by(self.model_class.full_name) - def get_object_url(self, customer): + def get_object_url(self, obj): # pylint: disable=empty-docstring """ """ + customer = obj return self.request.route_url("pending_customers.view", uuid=customer.uuid) @@ -111,17 +114,18 @@ class LocalProductRef(ObjectRef): """ @property - def model_class(self): + def model_class(self): # pylint: disable=empty-docstring """ """ model = self.app.model return model.LocalProduct - def sort_query(self, query): + def sort_query(self, query): # pylint: disable=empty-docstring """ """ return query.order_by(self.model_class.scancode) - def get_object_url(self, product): + def get_object_url(self, obj): # pylint: disable=empty-docstring """ """ + product = obj return self.request.route_url("local_products.view", uuid=product.uuid) @@ -136,15 +140,16 @@ class PendingProductRef(ObjectRef): """ @property - def model_class(self): + def model_class(self): # pylint: disable=empty-docstring """ """ model = self.app.model return model.PendingProduct - def sort_query(self, query): + def sort_query(self, query): # pylint: disable=empty-docstring """ """ return query.order_by(self.model_class.scancode) - def get_object_url(self, product): + def get_object_url(self, obj): # pylint: disable=empty-docstring """ """ + product = obj return self.request.route_url("pending_products.view", uuid=product.uuid) diff --git a/src/sideshow/web/menus.py b/src/sideshow/web/menus.py index 14fb027..18598d4 100644 --- a/src/sideshow/web/menus.py +++ b/src/sideshow/web/menus.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -32,7 +32,7 @@ class SideshowMenuHandler(base.MenuHandler): Sideshow menu handler """ - def make_menus(self, request, **kwargs): + def make_menus(self, request): # pylint: disable=empty-docstring """ """ return [ self.make_orders_menu(request), @@ -43,7 +43,7 @@ class SideshowMenuHandler(base.MenuHandler): self.make_admin_menu(request), ] - def make_orders_menu(self, request, **kwargs): + def make_orders_menu(self, request): # pylint: disable=unused-argument """ Generate the Orders menu. """ @@ -91,7 +91,7 @@ class SideshowMenuHandler(base.MenuHandler): ], } - def make_customers_menu(self, request, **kwargs): + def make_customers_menu(self, request): # pylint: disable=unused-argument """ Generate the Customers menu. """ @@ -112,7 +112,7 @@ class SideshowMenuHandler(base.MenuHandler): ], } - def make_products_menu(self, request, **kwargs): + def make_products_menu(self, request): # pylint: disable=unused-argument """ Generate the Products menu. """ @@ -133,7 +133,7 @@ class SideshowMenuHandler(base.MenuHandler): ], } - def make_batch_menu(self, request, **kwargs): + def make_batch_menu(self, request): # pylint: disable=unused-argument """ Generate the Batch menu. """ @@ -149,7 +149,7 @@ class SideshowMenuHandler(base.MenuHandler): ], } - def make_other_menu(self, request, **kwargs): + def make_other_menu(self, request): # pylint: disable=unused-argument """ Generate the "Other" menu. """ @@ -159,7 +159,7 @@ class SideshowMenuHandler(base.MenuHandler): "items": [], } - def make_admin_menu(self, request, **kwargs): + def make_admin_menu(self, request, **kwargs): # pylint: disable=empty-docstring """ """ kwargs["include_people"] = True menu = super().make_admin_menu(request, **kwargs) diff --git a/src/sideshow/web/static/__init__.py b/src/sideshow/web/static/__init__.py index 43d30aa..651042c 100644 --- a/src/sideshow/web/static/__init__.py +++ b/src/sideshow/web/static/__init__.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -43,6 +43,6 @@ fontawesome_js = Resource(libcache, "fontawesome-5.3.1-all.min.js") # bb_vue_fontawesome_js = Resource(libcache, 'vue-fontawesome-3.0.6.index.es.js') -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring config.include("wuttaweb.static") config.add_static_view("sideshow", "sideshow.web:static", cache_max_age=3600) diff --git a/src/sideshow/web/views/__init__.py b/src/sideshow/web/views/__init__.py index 3879f8c..f4550ef 100644 --- a/src/sideshow/web/views/__init__.py +++ b/src/sideshow/web/views/__init__.py @@ -27,7 +27,7 @@ Sideshow Views from wuttaweb.views import essential -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring # core views for wuttaweb essential.defaults( diff --git a/src/sideshow/web/views/batch/neworder.py b/src/sideshow/web/views/batch/neworder.py index d847a14..6b0ba60 100644 --- a/src/sideshow/web/views/batch/neworder.py +++ b/src/sideshow/web/views/batch/neworder.py @@ -32,7 +32,7 @@ from sideshow.batch.neworder import NewOrderBatchHandler from sideshow.web.forms.schema import LocalCustomerRef, PendingCustomerRef -class NewOrderBatchView(BatchMasterView): +class NewOrderBatchView(BatchMasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.batch.neworder.NewOrderBatch`. @@ -131,13 +131,14 @@ class NewOrderBatchView(BatchMasterView): super().__init__(request, context=context) self.order_handler = self.app.get_order_handler() - def get_batch_handler(self): + def get_batch_handler(self): # pylint: disable=empty-docstring """ """ # TODO: call self.app.get_batch_handler() return NewOrderBatchHandler(self.config) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # store_id @@ -147,8 +148,9 @@ class NewOrderBatchView(BatchMasterView): # total_price g.set_renderer("total_price", "currency") - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) # store_id @@ -164,10 +166,10 @@ class NewOrderBatchView(BatchMasterView): # total_price f.set_node("total_price", WuttaMoney(self.request)) - def configure_row_grid(self, g): + def configure_row_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_row_grid(g) - enum = self.app.enum # TODO # order_uom @@ -188,12 +190,13 @@ class NewOrderBatchView(BatchMasterView): # total_price g.set_renderer("total_price", "currency") - def get_xref_buttons(self, batch): + def get_xref_buttons(self, obj): """ Adds "View this Order" button, if batch has been executed and a corresponding :class:`~sideshow.db.model.orders.Order` can be located. """ + batch = obj buttons = super().get_xref_buttons(batch) model = self.app.model session = self.Session() @@ -215,12 +218,14 @@ class NewOrderBatchView(BatchMasterView): return buttons -def defaults(config, **kwargs): +def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() - NewOrderBatchView = kwargs.get("NewOrderBatchView", base["NewOrderBatchView"]) + NewOrderBatchView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "NewOrderBatchView", base["NewOrderBatchView"] + ) NewOrderBatchView.defaults(config) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring defaults(config) diff --git a/src/sideshow/web/views/common.py b/src/sideshow/web/views/common.py index c0debb0..ad52738 100644 --- a/src/sideshow/web/views/common.py +++ b/src/sideshow/web/views/common.py @@ -47,7 +47,7 @@ class CommonView(base.CommonView): admin = model.Role(name="Order Admin") admin.notes = ( - "this role was auto-created; " "you can change or remove it as needed." + "this role was auto-created; you can change or remove it as needed." ) session.add(admin) @@ -101,5 +101,5 @@ class CommonView(base.CommonView): auth.grant_permission(admin, perm) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring base.defaults(config, **{"CommonView": CommonView}) diff --git a/src/sideshow/web/views/customers.py b/src/sideshow/web/views/customers.py index eb252c3..f3999bd 100644 --- a/src/sideshow/web/views/customers.py +++ b/src/sideshow/web/views/customers.py @@ -2,7 +2,7 @@ ################################################################################ # # Sideshow -- Case/Special Order Tracker -# Copyright © 2024 Lance Edgar +# Copyright © 2024-2025 Lance Edgar # # This file is part of Sideshow. # @@ -30,7 +30,7 @@ from wuttaweb.forms.schema import UserRef, WuttaEnum from sideshow.db.model import LocalCustomer, PendingCustomer -class LocalCustomerView(MasterView): +class LocalCustomerView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.customers.LocalCustomer`; route prefix @@ -76,8 +76,9 @@ class LocalCustomerView(MasterView): "new_order_batches", ] - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # links @@ -87,8 +88,9 @@ class LocalCustomerView(MasterView): g.set_link("phone_number") g.set_link("email_address") - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) customer = f.model_instance @@ -138,10 +140,11 @@ class LocalCustomerView(MasterView): 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) + + def view_url(order, i): # pylint: disable=unused-argument + return self.request.route_url("orders.view", uuid=order.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("order_id") return grid @@ -174,17 +177,17 @@ class LocalCustomerView(MasterView): ) 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) + + def view_url(batch, i): # pylint: disable=unused-argument + return self.request.route_url("neworder_batches.view", uuid=batch.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("id") return grid - def objectify(self, form): + def objectify(self, form): # pylint: disable=empty-docstring """ """ - enum = self.app.enum customer = super().objectify(form) customer.full_name = self.app.make_full_name( @@ -194,7 +197,7 @@ class LocalCustomerView(MasterView): return customer -class PendingCustomerView(MasterView): +class PendingCustomerView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.customers.PendingCustomer`; route @@ -246,8 +249,9 @@ class PendingCustomerView(MasterView): "new_order_batches", ] - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) enum = self.app.enum @@ -261,8 +265,9 @@ class PendingCustomerView(MasterView): g.set_link("phone_number") g.set_link("email_address") - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) enum = self.app.enum customer = f.model_instance @@ -329,10 +334,11 @@ class PendingCustomerView(MasterView): 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) + + def view_url(order, i): # pylint: disable=unused-argument + return self.request.route_url("orders.view", uuid=order.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("order_id") return grid @@ -365,15 +371,16 @@ class PendingCustomerView(MasterView): ) 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) + + def view_url(batch, i): # pylint: disable=unused-argument + return self.request.route_url("neworder_batches.view", uuid=batch.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("id") return grid - def objectify(self, form): + def objectify(self, form): # pylint: disable=empty-docstring """ """ enum = self.app.enum customer = super().objectify(form) @@ -384,14 +391,15 @@ class PendingCustomerView(MasterView): return customer - def delete_instance(self, customer): + def delete_instance(self, obj): # pylint: disable=empty-docstring """ """ + customer = obj model_title = self.get_model_title() # avoid deleting if still referenced by order(s) - for order in customer.orders: + if list(customer.orders): self.request.session.flash( - f"Cannot delete {model_title} still attached " "to Order(s)", "warning" + f"Cannot delete {model_title} still attached to Order(s)", "warning" ) raise self.redirect(self.get_action_url("view", customer)) @@ -409,15 +417,19 @@ class PendingCustomerView(MasterView): super().delete_instance(customer) -def defaults(config, **kwargs): +def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() - LocalCustomerView = kwargs.get("LocalCustomerView", base["LocalCustomerView"]) + LocalCustomerView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "LocalCustomerView", base["LocalCustomerView"] + ) LocalCustomerView.defaults(config) - PendingCustomerView = kwargs.get("PendingCustomerView", base["PendingCustomerView"]) + PendingCustomerView = ( # pylint: disable=redefined-outer-name,invalid-name + kwargs.get("PendingCustomerView", base["PendingCustomerView"]) + ) PendingCustomerView.defaults(config) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring defaults(config) diff --git a/src/sideshow/web/views/orders.py b/src/sideshow/web/views/orders.py index dc5fbd8..14e16dd 100644 --- a/src/sideshow/web/views/orders.py +++ b/src/sideshow/web/views/orders.py @@ -23,30 +23,23 @@ """ Views for Orders """ +# pylint: disable=too-many-lines import decimal import json import logging import re -import colander import sqlalchemy as sa from sqlalchemy import orm from webhelpers2.html import tags, HTML from wuttaweb.views import MasterView -from wuttaweb.forms.schema import ( - UserRef, - WuttaMoney, - WuttaQuantity, - WuttaEnum, - WuttaDictEnum, -) +from wuttaweb.forms.schema import UserRef, WuttaMoney, WuttaQuantity, WuttaDictEnum from wuttaweb.util import make_json_safe from sideshow.db.model import Order, OrderItem -from sideshow.batch.neworder import NewOrderBatchHandler from sideshow.web.forms.schema import ( OrderRef, LocalCustomerRef, @@ -59,7 +52,7 @@ from sideshow.web.forms.schema import ( log = logging.getLogger(__name__) -class OrderView(MasterView): +class OrderView(MasterView): # pylint: disable=too-many-public-methods """ Master view for :class:`~sideshow.db.model.orders.Order`; route prefix is ``orders``. @@ -172,8 +165,9 @@ class OrderView(MasterView): self.order_handler = self.app.get_order_handler() self.batch_handler = self.app.get_batch_handler("neworder") - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # store_id @@ -224,7 +218,6 @@ class OrderView(MasterView): * :meth:`submit_order()` """ model = self.app.model - enum = self.app.enum session = self.Session() batch = self.get_current_batch() self.creating = True @@ -264,7 +257,7 @@ class OrderView(MasterView): if action in json_actions: try: result = getattr(self, action)(batch, data) - except Exception as error: + except Exception as error: # pylint: disable=broad-exception-caught log.warning("error calling json action for order", exc_info=True) result = {"error": self.app.render_error(error)} return self.json_response(result) @@ -292,7 +285,10 @@ class OrderView(MasterView): if context["expose_store_id"]: stores = ( session.query(model.Store) - .filter(model.Store.archived == False) + .filter( + model.Store.archived # pylint: disable=singleton-comparison + == False + ) .order_by(model.Store.store_id) .all() ) @@ -313,12 +309,10 @@ class OrderView(MasterView): context["default_item_discount"] = self.app.render_quantity( self.batch_handler.get_default_item_discount() ) - context["dept_item_discounts"] = dict( - [ - (d["department_id"], d["default_item_discount"]) - for d in self.get_dept_item_discounts() - ] - ) + context["dept_item_discounts"] = { + d["department_id"]: d["default_item_discount"] + for d in self.get_dept_item_discounts() + } return self.render_to_response("create", context) @@ -346,7 +340,10 @@ class OrderView(MasterView): batch = ( session.query(model.NewOrderBatch) .filter(model.NewOrderBatch.created_by == user) - .filter(model.NewOrderBatch.executed == None) + .filter( + model.NewOrderBatch.executed # pylint: disable=singleton-comparison + == None + ) .one() ) @@ -381,10 +378,9 @@ class OrderView(MasterView): return handler.autocomplete_customers_local( session, term, user=self.request.user ) - else: - return handler.autocomplete_customers_external( - session, term, user=self.request.user - ) + return handler.autocomplete_customers_external( + session, term, user=self.request.user + ) def product_autocomplete(self): """ @@ -409,12 +405,11 @@ class OrderView(MasterView): return handler.autocomplete_products_local( session, term, user=self.request.user ) - else: - return handler.autocomplete_products_external( - session, term, user=self.request.user - ) + return handler.autocomplete_products_external( + session, term, user=self.request.user + ) - def get_pending_product_required_fields(self): + def get_pending_product_required_fields(self): # pylint: disable=empty-docstring """ """ required = [] for field in self.PENDING_PRODUCT_ENTRY_FIELDS: @@ -488,9 +483,11 @@ class OrderView(MasterView): * :meth:`cancel_order()` * :meth:`submit_order()` """ + session = self.Session() + # drop current batch self.batch_handler.do_delete(batch, self.request.user) - self.Session.flush() + session.flush() # send back to "create order" which makes new batch route_prefix = self.get_route_prefix() @@ -508,8 +505,10 @@ class OrderView(MasterView): * :meth:`start_over()` * :meth:`submit_order()` """ + session = self.Session() + self.batch_handler.do_delete(batch, self.request.user) - self.Session.flush() + session.flush() # set flash msg just to be more obvious self.request.session.flash("New order has been deleted.") @@ -534,7 +533,7 @@ class OrderView(MasterView): batch.store_id = store_id return self.get_context_customer(batch) - def get_context_customer(self, batch): + def get_context_customer(self, batch): # pylint: disable=empty-docstring """ """ context = { "store_id": batch.store_id, @@ -599,7 +598,7 @@ class OrderView(MasterView): self.batch_handler.set_customer(batch, customer_id) return self.get_context_customer(batch) - def unassign_customer(self, batch, data): + def unassign_customer(self, batch, data): # pylint: disable=unused-argument """ Clear the customer info for a batch. @@ -633,7 +632,9 @@ class OrderView(MasterView): self.batch_handler.set_customer(batch, data, user=self.request.user) return self.get_context_customer(batch) - def get_product_info(self, batch, data): + def get_product_info( # pylint: disable=unused-argument,too-many-branches + self, batch, data + ): """ Fetch data for a specific product. @@ -707,7 +708,7 @@ class OrderView(MasterView): return data - def get_past_products(self, batch, data): + def get_past_products(self, batch, data): # pylint: disable=unused-argument """ Fetch past products for convenient re-ordering. @@ -802,7 +803,7 @@ class OrderView(MasterView): self.batch_handler.do_remove_row(row) return {"batch": self.normalize_batch(batch)} - def submit_order(self, batch, data): + def submit_order(self, batch, data): # pylint: disable=unused-argument """ This submits the user's current new order batch, hence executing the batch and creating the true order. @@ -820,7 +821,7 @@ class OrderView(MasterView): try: order = self.batch_handler.do_execute(batch, user) - except Exception as error: + except Exception as error: # pylint: disable=broad-exception-caught log.warning("failed to execute new order batch: %s", batch, exc_info=True) return {"error": self.app.render_error(error)} @@ -828,7 +829,7 @@ class OrderView(MasterView): "next_url": self.get_action_url("view", order), } - def normalize_batch(self, batch): + def normalize_batch(self, batch): # pylint: disable=empty-docstring """ """ return { "uuid": batch.uuid.hex, @@ -838,7 +839,7 @@ class OrderView(MasterView): "status_text": batch.status_text, } - def normalize_row(self, row): + def normalize_row(self, row): # pylint: disable=empty-docstring """ """ data = { "uuid": row.uuid.hex, @@ -915,7 +916,6 @@ class OrderView(MasterView): row.unit_price_sale ) if row.sale_ends: - sale_ends = row.sale_ends data["sale_ends"] = str(row.sale_ends) data["sale_ends_display"] = self.app.render_date(row.sale_ends) @@ -953,12 +953,14 @@ class OrderView(MasterView): return data - def get_instance_title(self, order): + def get_instance_title(self, instance): # pylint: disable=empty-docstring """ """ + order = instance return f"#{order.order_id} for {order.customer_name}" - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) order = f.model_instance @@ -985,8 +987,9 @@ class OrderView(MasterView): f.set_node("created_by", UserRef(self.request)) f.set_readonly("created_by") - def get_xref_buttons(self, order): + def get_xref_buttons(self, obj): # pylint: disable=empty-docstring """ """ + order = obj buttons = super().get_xref_buttons(order) model = self.app.model session = self.Session() @@ -1007,14 +1010,16 @@ class OrderView(MasterView): return buttons - def get_row_grid_data(self, order): + def get_row_grid_data(self, obj): # pylint: disable=empty-docstring """ """ + order = obj model = self.app.model session = self.Session() return session.query(model.OrderItem).filter(model.OrderItem.order == order) - def configure_row_grid(self, g): + def configure_row_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_row_grid(g) # enum = self.app.enum @@ -1051,22 +1056,28 @@ class OrderView(MasterView): # TODO: upstream should set this automatically g.row_class = self.row_grid_row_class - def row_grid_row_class(self, item, data, i): + def row_grid_row_class( # pylint: disable=unused-argument,empty-docstring + self, item, data, i + ): """ """ variant = self.order_handler.item_status_to_variant(item.status_code) if variant: return f"has-background-{variant}" + return None - def render_status_code(self, item, key, value): + def render_status_code( # pylint: disable=unused-argument,empty-docstring + self, item, key, value + ): """ """ enum = self.app.enum return enum.ORDER_ITEM_STATUS[value] - def get_row_action_url_view(self, item, i): + def get_row_action_url_view(self, row, i): # pylint: disable=empty-docstring """ """ + item = row return self.request.route_url("order_items.view", uuid=item.uuid) - def configure_get_simple_settings(self): + def configure_get_simple_settings(self): # pylint: disable=empty-docstring """ """ settings = [ # stores @@ -1111,7 +1122,9 @@ class OrderView(MasterView): return settings - def configure_get_context(self, **kwargs): + def configure_get_context( # pylint: disable=empty-docstring,arguments-differ + self, **kwargs + ): """ """ context = super().configure_get_context(**kwargs) @@ -1125,7 +1138,9 @@ class OrderView(MasterView): return context - def configure_gather_settings(self, data, simple_settings=None): + def configure_gather_settings( + self, data, simple_settings=None + ): # pylint: disable=empty-docstring """ """ settings = super().configure_gather_settings( data, simple_settings=simple_settings @@ -1148,7 +1163,9 @@ class OrderView(MasterView): return settings - def configure_remove_settings(self, **kwargs): + def configure_remove_settings( # pylint: disable=empty-docstring,arguments-differ + self, **kwargs + ): """ """ model = self.app.model session = self.Session() @@ -1224,7 +1241,7 @@ class OrderView(MasterView): ) -class OrderItemView(MasterView): +class OrderItemView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.orders.OrderItem`; route prefix is ``order_items``. @@ -1329,20 +1346,21 @@ class OrderItemView(MasterView): super().__init__(request, context=context) self.order_handler = self.app.get_order_handler() - def get_fallback_templates(self, template): + def get_fallback_templates(self, template): # pylint: disable=empty-docstring """ """ templates = super().get_fallback_templates(template) templates.insert(0, f"/order-items/{template}.mako") return templates - def get_query(self, session=None): + def get_query(self, session=None): # pylint: disable=empty-docstring """ """ query = super().get_query(session=session) model = self.app.model return query.join(model.Order) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) model = self.app.model # enum = self.app.enum @@ -1391,24 +1409,32 @@ class OrderItemView(MasterView): # status_code g.set_renderer("status_code", self.render_status_code) - def render_order_attr(self, item, key, value): + def render_order_attr( # pylint: disable=unused-argument,empty-docstring + self, item, key, value + ): """ """ order = item.order return getattr(order, key) - def render_status_code(self, item, key, value): + def render_status_code( # pylint: disable=unused-argument,empty-docstring + self, item, key, value + ): """ """ enum = self.app.enum return enum.ORDER_ITEM_STATUS[value] - def grid_row_class(self, item, data, i): + def grid_row_class( # pylint: disable=unused-argument,empty-docstring + self, item, data, i + ): """ """ variant = self.order_handler.item_status_to_variant(item.status_code) if variant: return f"has-background-{variant}" + return None - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) enum = self.app.enum item = f.model_instance @@ -1455,7 +1481,7 @@ class OrderItemView(MasterView): # paid_amount f.set_node("paid_amount", WuttaMoney(self.request)) - def get_template_context(self, context): + def get_template_context(self, context): # pylint: disable=empty-docstring """ """ if self.viewing: model = self.app.model @@ -1505,7 +1531,9 @@ class OrderItemView(MasterView): return context - def render_event_note(self, event, key, value): + def render_event_note( # pylint: disable=unused-argument,empty-docstring + self, event, key, value + ): """ """ enum = self.app.enum if event.type_code == enum.ORDER_ITEM_EVENT_NOTE_ADDED: @@ -1517,8 +1545,9 @@ class OrderItemView(MasterView): ) return value - def get_xref_buttons(self, item): + def get_xref_buttons(self, obj): # pylint: disable=empty-docstring """ """ + item = obj buttons = super().get_xref_buttons(item) if self.request.has_perm("orders.view"): @@ -1552,10 +1581,8 @@ class OrderItemView(MasterView): View which changes status for an order item. This is POST-only; will redirect back to the item view. """ - model = self.app.model enum = self.app.enum main_item = self.get_instance() - session = self.Session() redirect = self.redirect(self.get_action_url("view", main_item)) extra_note = self.request.POST.get("note") @@ -1581,8 +1608,9 @@ class OrderItemView(MasterView): if item.status_code != new_status_code: # event: change status - note = 'status changed from "{}" to "{}"'.format( - enum.ORDER_ITEM_STATUS[item.status_code], new_status_text + note = ( + f'status changed from "{enum.ORDER_ITEM_STATUS[item.status_code]}" ' + f'to "{new_status_text}"' ) item.add_event( enum.ORDER_ITEM_EVENT_STATUS_CHANGE, self.request.user, note=note @@ -1644,7 +1672,7 @@ class OrderItemView(MasterView): return items @classmethod - def defaults(cls, config): + def defaults(cls, config): # pylint: disable=empty-docstring """ """ cls._order_item_defaults(config) cls._defaults(config) @@ -1702,7 +1730,7 @@ class OrderItemView(MasterView): ) -class PlacementView(OrderItemView): +class PlacementView(OrderItemView): # pylint: disable=abstract-method """ Master view for the "placement" phase of :class:`~sideshow.db.model.orders.OrderItem`; route prefix is @@ -1744,15 +1772,16 @@ class PlacementView(OrderItemView): "vendor_name": {"active": True}, } - def get_query(self, session=None): + def get_query(self, session=None): # pylint: disable=empty-docstring """ """ query = super().get_query(session=session) model = self.app.model enum = self.app.enum return query.filter(model.OrderItem.status_code == enum.ORDER_ITEM_STATUS_READY) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # checkable @@ -1840,7 +1869,7 @@ class PlacementView(OrderItemView): ) -class ReceivingView(OrderItemView): +class ReceivingView(OrderItemView): # pylint: disable=abstract-method """ Master view for the "receiving" phase of :class:`~sideshow.db.model.orders.OrderItem`; route prefix is @@ -1882,7 +1911,7 @@ class ReceivingView(OrderItemView): "vendor_name": {"active": True}, } - def get_query(self, session=None): + def get_query(self, session=None): # pylint: disable=empty-docstring """ """ query = super().get_query(session=session) model = self.app.model @@ -1891,8 +1920,9 @@ class ReceivingView(OrderItemView): model.OrderItem.status_code == enum.ORDER_ITEM_STATUS_PLACED ) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # checkable @@ -2040,7 +2070,7 @@ class ReceivingView(OrderItemView): ) -class ContactView(OrderItemView): +class ContactView(OrderItemView): # pylint: disable=abstract-method """ Master view for the "contact" phase of :class:`~sideshow.db.model.orders.OrderItem`; route prefix is @@ -2063,7 +2093,7 @@ class ContactView(OrderItemView): route_prefix = "order_items_contact" url_prefix = "/contact" - def get_query(self, session=None): + def get_query(self, session=None): # pylint: disable=empty-docstring """ """ query = super().get_query(session=session) model = self.app.model @@ -2074,8 +2104,9 @@ class ContactView(OrderItemView): ) ) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # checkable @@ -2207,7 +2238,7 @@ class ContactView(OrderItemView): ) -class DeliveryView(OrderItemView): +class DeliveryView(OrderItemView): # pylint: disable=abstract-method """ Master view for the "delivery" phase of :class:`~sideshow.db.model.orders.OrderItem`; route prefix is @@ -2230,7 +2261,7 @@ class DeliveryView(OrderItemView): route_prefix = "order_items_delivery" url_prefix = "/delivery" - def get_query(self, session=None): + def get_query(self, session=None): # pylint: disable=empty-docstring """ """ query = super().get_query(session=session) model = self.app.model @@ -2241,8 +2272,9 @@ class DeliveryView(OrderItemView): ) ) - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # checkable @@ -2372,27 +2404,39 @@ class DeliveryView(OrderItemView): ) -def defaults(config, **kwargs): +def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() - OrderView = kwargs.get("OrderView", base["OrderView"]) + OrderView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "OrderView", base["OrderView"] + ) OrderView.defaults(config) - OrderItemView = kwargs.get("OrderItemView", base["OrderItemView"]) + OrderItemView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "OrderItemView", base["OrderItemView"] + ) OrderItemView.defaults(config) - PlacementView = kwargs.get("PlacementView", base["PlacementView"]) + PlacementView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "PlacementView", base["PlacementView"] + ) PlacementView.defaults(config) - ReceivingView = kwargs.get("ReceivingView", base["ReceivingView"]) + ReceivingView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "ReceivingView", base["ReceivingView"] + ) ReceivingView.defaults(config) - ContactView = kwargs.get("ContactView", base["ContactView"]) + ContactView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "ContactView", base["ContactView"] + ) ContactView.defaults(config) - DeliveryView = kwargs.get("DeliveryView", base["DeliveryView"]) + DeliveryView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "DeliveryView", base["DeliveryView"] + ) DeliveryView.defaults(config) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring defaults(config) diff --git a/src/sideshow/web/views/products.py b/src/sideshow/web/views/products.py index a205977..7829b5d 100644 --- a/src/sideshow/web/views/products.py +++ b/src/sideshow/web/views/products.py @@ -25,13 +25,13 @@ Views for Products """ from wuttaweb.views import MasterView -from wuttaweb.forms.schema import UserRef, WuttaEnum, WuttaMoney, WuttaQuantity +from wuttaweb.forms.schema import UserRef, WuttaMoney, WuttaQuantity from sideshow.enum import PendingProductStatus from sideshow.db.model import LocalProduct, PendingProduct -class LocalProductView(MasterView): +class LocalProductView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.products.LocalProduct`; route prefix is ``local_products``. @@ -88,8 +88,9 @@ class LocalProductView(MasterView): "new_order_batches", ] - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # unit_cost @@ -105,10 +106,10 @@ class LocalProductView(MasterView): g.set_link("description") g.set_link("size") - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) - enum = self.app.enum product = f.model_instance # external_id @@ -155,7 +156,7 @@ class LocalProductView(MasterView): model = self.app.model route_prefix = self.get_route_prefix() - orders = set([item.order for item in product.order_items]) + orders = {item.order for item in product.order_items} orders = sorted(orders, key=lambda order: order.order_id) grid = self.make_grid( @@ -177,10 +178,11 @@ class LocalProductView(MasterView): ) 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) + + def view_url(order, i): # pylint: disable=unused-argument + return self.request.route_url("orders.view", uuid=order.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("order_id") return grid @@ -192,7 +194,7 @@ class LocalProductView(MasterView): model = self.app.model route_prefix = self.get_route_prefix() - batches = set([row.batch for row in product.new_order_batch_rows]) + batches = {row.batch for row in product.new_order_batch_rows} batches = sorted(batches, key=lambda batch: batch.id) grid = self.make_grid( @@ -216,16 +218,17 @@ class LocalProductView(MasterView): ) 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) + + def view_url(batch, i): # pylint: disable=unused-argument + return self.request.route_url("neworder_batches.view", uuid=batch.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("id") return grid -class PendingProductView(MasterView): +class PendingProductView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.products.PendingProduct`; route @@ -292,8 +295,9 @@ class PendingProductView(MasterView): "new_order_batches", ] - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) enum = self.app.enum @@ -313,16 +317,19 @@ class PendingProductView(MasterView): g.set_link("description") g.set_link("size") - def grid_row_class(self, product, data, i): + def grid_row_class( # pylint: disable=unused-argument,empty-docstring + self, product, data, i + ): """ """ enum = self.app.enum if product.status == enum.PendingProductStatus.IGNORED: return "has-background-warning" + return None - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) - enum = self.app.enum product = f.model_instance # product_id @@ -369,7 +376,7 @@ class PendingProductView(MasterView): model = self.app.model route_prefix = self.get_route_prefix() - orders = set([item.order for item in product.order_items]) + orders = {item.order for item in product.order_items} orders = sorted(orders, key=lambda order: order.order_id) grid = self.make_grid( @@ -391,10 +398,11 @@ class PendingProductView(MasterView): ) 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) + + def view_url(order, i): # pylint: disable=unused-argument + return self.request.route_url("orders.view", uuid=order.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("order_id") return grid @@ -406,7 +414,7 @@ class PendingProductView(MasterView): model = self.app.model route_prefix = self.get_route_prefix() - batches = set([row.batch for row in product.new_order_batch_rows]) + batches = {row.batch for row in product.new_order_batch_rows} batches = sorted(batches, key=lambda batch: batch.id) grid = self.make_grid( @@ -430,15 +438,16 @@ class PendingProductView(MasterView): ) 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) + + def view_url(batch, i): # pylint: disable=unused-argument + return self.request.route_url("neworder_batches.view", uuid=batch.uuid) + + grid.add_action("view", icon="eye", url=view_url) grid.set_link("id") return grid - def get_template_context(self, context): + def get_template_context(self, context): # pylint: disable=empty-docstring """ """ enum = self.app.enum @@ -452,8 +461,9 @@ class PendingProductView(MasterView): return context - def delete_instance(self, product): + def delete_instance(self, obj): # pylint: disable=empty-docstring """ """ + product = obj # avoid deleting if still referenced by new order batch(es) for row in product.new_order_batch_rows: @@ -531,7 +541,7 @@ class PendingProductView(MasterView): return self.redirect(self.get_action_url("view", product)) @classmethod - def defaults(cls, config): + def defaults(cls, config): # pylint: disable=empty-docstring """ """ cls._defaults(config) cls._pending_product_defaults(config) @@ -576,15 +586,19 @@ class PendingProductView(MasterView): ) -def defaults(config, **kwargs): +def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() - LocalProductView = kwargs.get("LocalProductView", base["LocalProductView"]) + LocalProductView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "LocalProductView", base["LocalProductView"] + ) LocalProductView.defaults(config) - PendingProductView = kwargs.get("PendingProductView", base["PendingProductView"]) + PendingProductView = ( # pylint: disable=redefined-outer-name,invalid-name + kwargs.get("PendingProductView", base["PendingProductView"]) + ) PendingProductView.defaults(config) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring defaults(config) diff --git a/src/sideshow/web/views/stores.py b/src/sideshow/web/views/stores.py index 13282c9..2543d66 100644 --- a/src/sideshow/web/views/stores.py +++ b/src/sideshow/web/views/stores.py @@ -29,7 +29,7 @@ from wuttaweb.views import MasterView from sideshow.db.model import Store -class StoreView(MasterView): +class StoreView(MasterView): # pylint: disable=abstract-method """ Master view for :class:`~sideshow.db.model.stores.Store`; route prefix @@ -56,21 +56,26 @@ class StoreView(MasterView): sort_defaults = "store_id" - def configure_grid(self, g): + def configure_grid(self, grid): # pylint: disable=empty-docstring """ """ + g = grid super().configure_grid(g) # links g.set_link("store_id") g.set_link("name") - def grid_row_class(self, store, data, i): + def grid_row_class( # pylint: disable=unused-argument,empty-docstring + self, store, data, i + ): """ """ if store.archived: return "has-background-warning" + return None - def configure_form(self, f): + def configure_form(self, form): # pylint: disable=empty-docstring """ """ + f = form super().configure_form(f) # store_id @@ -79,7 +84,7 @@ class StoreView(MasterView): # name f.set_validator("name", self.unique_name) - def unique_store_id(self, node, value): + def unique_store_id(self, node, value): # pylint: disable=empty-docstring """ """ model = self.app.model session = self.Session() @@ -93,7 +98,7 @@ class StoreView(MasterView): if query.count(): node.raise_invalid("Store ID must be unique") - def unique_name(self, node, value): + def unique_name(self, node, value): # pylint: disable=empty-docstring """ """ model = self.app.model session = self.Session() @@ -108,12 +113,14 @@ class StoreView(MasterView): node.raise_invalid("Name must be unique") -def defaults(config, **kwargs): +def defaults(config, **kwargs): # pylint: disable=missing-function-docstring base = globals() - StoreView = kwargs.get("StoreView", base["StoreView"]) + StoreView = kwargs.get( # pylint: disable=redefined-outer-name,invalid-name + "StoreView", base["StoreView"] + ) StoreView.defaults(config) -def includeme(config): +def includeme(config): # pylint: disable=missing-function-docstring defaults(config) diff --git a/tests/web/views/test_customers.py b/tests/web/views/test_customers.py index e5bd05d..a2096d2 100644 --- a/tests/web/views/test_customers.py +++ b/tests/web/views/test_customers.py @@ -58,6 +58,7 @@ class TestLocalCustomerView(WebTestCase): self.assertIn("new_order_batches", form) def test_make_orders_grid(self): + self.pyramid_config.add_route("orders.view", "/orders/{uuid}/view") model = self.app.model view = self.make_view() @@ -79,7 +80,13 @@ class TestLocalCustomerView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_make_new_order_batches_grid(self): + self.pyramid_config.add_route( + "neworder_batches.view", "/batch/neworder/{uuid}/view" + ) model = self.app.model handler = NewOrderBatchHandler(self.config) view = self.make_view() @@ -104,6 +111,9 @@ class TestLocalCustomerView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_objectify(self): model = self.app.model view = self.make_view() @@ -178,6 +188,7 @@ class TestPendingCustomerView(WebTestCase): self.assertIn("new_order_batches", form) def test_make_orders_grid(self): + self.pyramid_config.add_route("orders.view", "/orders/{uuid}/view") model = self.app.model enum = self.app.enum view = self.make_view() @@ -202,7 +213,13 @@ class TestPendingCustomerView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_make_new_order_batches_grid(self): + self.pyramid_config.add_route( + "neworder_batches.view", "/batch/neworder/{uuid}/view" + ) model = self.app.model enum = self.app.enum handler = NewOrderBatchHandler(self.config) @@ -230,6 +247,9 @@ class TestPendingCustomerView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_objectify(self): model = self.app.model enum = self.app.enum diff --git a/tests/web/views/test_products.py b/tests/web/views/test_products.py index da467ec..de17a8b 100644 --- a/tests/web/views/test_products.py +++ b/tests/web/views/test_products.py @@ -60,6 +60,7 @@ class TestLocalProductView(WebTestCase): self.assertIn("local_products.view.orders", form.grid_vue_context) def test_make_orders_grid(self): + self.pyramid_config.add_route("orders.view", "/orders/{uuid}/view") model = self.app.model enum = self.app.enum view = self.make_view() @@ -89,7 +90,13 @@ class TestLocalProductView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_make_new_order_batches_grid(self): + self.pyramid_config.add_route( + "neworder_batches.view", "/batch/neworder/{uuid}/view" + ) model = self.app.model enum = self.app.enum handler = NewOrderBatchHandler(self.config) @@ -117,6 +124,9 @@ class TestLocalProductView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + class TestPendingProductView(WebTestCase): @@ -178,6 +188,7 @@ class TestPendingProductView(WebTestCase): self.assertIn("created_by", form) def test_make_orders_grid(self): + self.pyramid_config.add_route("orders.view", "/orders/{uuid}/view") model = self.app.model enum = self.app.enum view = self.make_view() @@ -209,7 +220,13 @@ class TestPendingProductView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_make_new_order_batches_grid(self): + self.pyramid_config.add_route( + "neworder_batches.view", "/batch/neworder/{uuid}/view" + ) model = self.app.model enum = self.app.enum handler = NewOrderBatchHandler(self.config) @@ -239,6 +256,9 @@ class TestPendingProductView(WebTestCase): self.assertEqual(len(grid.actions), 1) self.assertEqual(grid.actions[0].key, "view") + # render grid for coverage generating url + grid.render_vue_template() + def test_get_template_context(self): enum = self.app.enum model = self.app.model