From 919d8d109fa9c30a3686f1af2786cafa205755f9 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 18 Oct 2023 18:18:55 -0500 Subject: [PATCH] Use `Grid.make_sorter()` instead of legacy code b/c multi-column sorting relies on this --- tailbone/views/bouncer.py | 16 +++++--- tailbone/views/customers.py | 16 ++++---- tailbone/views/employees.py | 41 ++++++++++----------- tailbone/views/members.py | 8 ++-- tailbone/views/messages.py | 31 ++++++++++------ tailbone/views/people.py | 51 ++++++++++++++------------ tailbone/views/products.py | 40 ++++++++++---------- tailbone/views/purchases/core.py | 51 ++++++++++++++------------ tailbone/views/purchasing/batch.py | 17 +++++---- tailbone/views/purchasing/receiving.py | 32 ++++++++-------- tailbone/views/shifts/core.py | 29 ++++++++------- tailbone/views/tempmon/probes.py | 5 ++- tailbone/views/tempmon/readings.py | 31 ++++++++-------- tailbone/views/views.py | 6 +-- 14 files changed, 198 insertions(+), 176 deletions(-) diff --git a/tailbone/views/bouncer.py b/tailbone/views/bouncer.py index 3416bbed..7afcc567 100644 --- a/tailbone/views/bouncer.py +++ b/tailbone/views/bouncer.py @@ -61,7 +61,7 @@ class EmailBounceView(MasterView): ] def __init__(self, request): - super(EmailBounceView, self).__init__(request) + super().__init__(request) self.handler_options = sorted(get_profile_keys(self.rattail_config)) def get_handler(self, bounce): @@ -69,17 +69,21 @@ class EmailBounceView(MasterView): return app.get_bounce_handler(bounce.config_key) def configure_grid(self, g): - super(EmailBounceView, self).configure_grid(g) + super().configure_grid(g) + model = self.model g.filters['config_key'].set_choices(self.handler_options) g.filters['config_key'].default_active = True g.filters['config_key'].default_verb = 'equal' - g.joiners['processed_by'] = lambda q: q.outerjoin(model.User) g.filters['processed'].default_active = True g.filters['processed'].default_verb = 'is_null' - g.filters['processed_by'] = g.make_filter('processed_by', model.User.username) - g.sorters['processed_by'] = g.make_sorter(model.User.username) + + # processed_by + g.set_joiner('processed_by', lambda q: q.outerjoin(model.User)) + g.set_sorter('processed_by', model.User.username) + g.set_filter('processed_by', model.User.username) + g.set_sort_defaults('bounced', 'desc') g.set_label('bounce_recipient_address', "Bounced To") @@ -89,7 +93,7 @@ class EmailBounceView(MasterView): g.set_link('intended_recipient_address') def configure_form(self, f): - super(EmailBounceView, self).configure_form(f) + super().configure_form(f) bounce = f.model_instance f.set_renderer('message', self.render_message_file) f.set_renderer('links', self.render_links) diff --git a/tailbone/views/customers.py b/tailbone/views/customers.py index dd8923e6..668f4a2b 100644 --- a/tailbone/views/customers.py +++ b/tailbone/views/customers.py @@ -168,22 +168,22 @@ class CustomerView(MasterView): g.filters['name'].default_verb = 'contains' # phone + g.set_label('phone', "Phone Number") g.set_joiner('phone', lambda q: q.outerjoin(model.CustomerPhoneNumber, sa.and_( model.CustomerPhoneNumber.parent_uuid == model.Customer.uuid, model.CustomerPhoneNumber.preference == 1))) - g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.CustomerPhoneNumber.number, d)()) + g.set_sorter('phone', model.CustomerPhoneNumber.number) g.set_filter('phone', model.CustomerPhoneNumber.number, # label="Phone Number", factory=grids.filters.AlchemyPhoneNumberFilter) - g.set_label('phone', "Phone Number") # email + g.set_label('email', "Email Address") g.set_joiner('email', lambda q: q.outerjoin(model.CustomerEmailAddress, sa.and_( model.CustomerEmailAddress.parent_uuid == model.Customer.uuid, model.CustomerEmailAddress.preference == 1))) - g.sorters['email'] = lambda q, d: q.order_by(getattr(model.CustomerEmailAddress.address, d)()) + g.set_sorter('email', model.CustomerEmailAddress.address) g.set_filter('email', model.CustomerEmailAddress.address)#, label="Email Address") - g.set_label('email', "Email Address") # email_preference g.set_enum('email_preference', self.enum.EMAIL_PREFERENCE) @@ -244,7 +244,7 @@ class CustomerView(MasterView): def get_instance(self): try: - instance = super(CustomerView, self).get_instance() + instance = super().get_instance() except HTTPNotFound: pass else: @@ -273,7 +273,7 @@ class CustomerView(MasterView): raise HTTPNotFound def configure_form(self, f): - super(CustomerView, self).configure_form(f) + super().configure_form(f) customer = f.model_instance permission_prefix = self.get_permission_prefix() @@ -802,7 +802,7 @@ class PendingCustomerView(MasterView): ] def configure_grid(self, g): - super(PendingCustomerView, self).configure_grid(g) + super().configure_grid(g) g.set_enum('status_code', self.enum.PENDING_CUSTOMER_STATUS) g.filters['status_code'].default_active = True @@ -814,7 +814,7 @@ class PendingCustomerView(MasterView): g.set_link('display_name') def configure_form(self, f): - super(PendingCustomerView, self).configure_form(f) + super().configure_form(f) f.set_enum('status_code', self.enum.PENDING_CUSTOMER_STATUS) diff --git a/tailbone/views/employees.py b/tailbone/views/employees.py index 973075b6..f4f99058 100644 --- a/tailbone/views/employees.py +++ b/tailbone/views/employees.py @@ -96,7 +96,7 @@ class EmployeeView(MasterView): return app.get_people_handler().get_quickie_search_placeholder() def configure_grid(self, g): - super(EmployeeView, self).configure_grid(g) + super().configure_grid(g) route_prefix = self.get_route_prefix() # phone @@ -115,9 +115,20 @@ class EmployeeView(MasterView): g.filters['email'] = g.make_filter('email', model.EmployeeEmailAddress.address, label="Email Address") - # first/last name - g.filters['first_name'] = g.make_filter('first_name', model.Person.first_name) - g.filters['last_name'] = g.make_filter('last_name', model.Person.last_name) + # first_name + g.set_link('first_name') + g.set_sorter('first_name', model.Person.first_name) + g.set_sort_defaults('first_name') + g.set_filter('first_name', model.Person.first_name, + default_active=True, + default_verb='contains') + + # last_name + g.set_link('last_name') + g.set_sorter('last_name', model.Person.last_name) + g.set_filter('last_name', model.Person.last_name, + default_active=True, + default_verb='contains') # username if self.request.has_perm('users.view'): @@ -145,18 +156,7 @@ class EmployeeView(MasterView): g.remove('status') del g.filters['status'] - g.filters['first_name'].default_active = True - g.filters['first_name'].default_verb = 'contains' - - g.filters['last_name'].default_active = True - g.filters['last_name'].default_verb = 'contains' - - g.sorters['first_name'] = lambda q, d: q.order_by(getattr(model.Person.first_name, d)()) - g.sorters['last_name'] = lambda q, d: q.order_by(getattr(model.Person.last_name, d)()) - - g.sorters['email'] = lambda q, d: q.order_by(getattr(model.EmployeeEmailAddress.address, d)()) - - g.set_sort_defaults('first_name') + g.set_sorter('email', model.EmployeeEmailAddress.address) g.set_label('email', "Email Address") @@ -170,9 +170,6 @@ class EmployeeView(MasterView): g.main_actions.insert(1, self.make_action( 'view_raw', url=url, icon='eye')) - g.set_link('first_name') - g.set_link('last_name') - def default_view_url(self): if (self.request.has_perm('people.view_profile') and self.should_link_straight_to_profile()): @@ -196,7 +193,7 @@ class EmployeeView(MasterView): default=False) def query(self, session): - query = super(EmployeeView, self).query(session) + query = super().query(session) query = query.join(model.Person) if not self.has_perm('view_all'): query = query.filter(model.Employee.status == self.enum.EMPLOYEE_STATUS_CURRENT) @@ -229,7 +226,7 @@ class EmployeeView(MasterView): return not self.is_employee_protected(employee) def configure_form(self, f): - super(EmployeeView, self).configure_form(f) + super().configure_form(f) employee = f.model_instance f.set_renderer('person', self.render_person) @@ -283,7 +280,7 @@ class EmployeeView(MasterView): def objectify(self, form, data=None): if data is None: data = form.validated - employee = super(EmployeeView, self).objectify(form, data) + employee = super().objectify(form, data) self.update_stores(employee, data) self.update_departments(employee, data) return employee diff --git a/tailbone/views/members.py b/tailbone/views/members.py index 74b15512..3a4ff0a1 100644 --- a/tailbone/views/members.py +++ b/tailbone/views/members.py @@ -196,21 +196,21 @@ class MemberView(MasterView): g.filters['active'].default_verb = 'is_true' # phone + g.set_label('phone', "Phone Number") g.set_joiner('phone', lambda q: q.outerjoin(model.MemberPhoneNumber, sa.and_( model.MemberPhoneNumber.parent_uuid == model.Member.uuid, model.MemberPhoneNumber.preference == 1))) - g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.MemberPhoneNumber.number, d)()) + g.set_sorter('phone', model.MemberPhoneNumber.number) g.set_filter('phone', model.MemberPhoneNumber.number, factory=grids.filters.AlchemyPhoneNumberFilter) - g.set_label('phone', "Phone Number") # email + g.set_label('email', "Email Address") g.set_joiner('email', lambda q: q.outerjoin(model.MemberEmailAddress, sa.and_( model.MemberEmailAddress.parent_uuid == model.Member.uuid, model.MemberEmailAddress.preference == 1))) - g.sorters['email'] = lambda q, d: q.order_by(getattr(model.MemberEmailAddress.address, d)()) + g.set_sorter('email', model.MemberEmailAddress.address) g.set_filter('email', model.MemberEmailAddress.address) - g.set_label('email', "Email Address") # membership_type g.set_joiner('membership_type', lambda q: q.outerjoin(model.MembershipType)) diff --git a/tailbone/views/messages.py b/tailbone/views/messages.py index 4c83da34..d1509163 100644 --- a/tailbone/views/messages.py +++ b/tailbone/views/messages.py @@ -84,12 +84,12 @@ class MessageView(MasterView): def index(self): if not self.request.user: raise httpexceptions.HTTPForbidden - return super(MessageView, self).index() + return super().index() def get_instance(self): if not self.request.user: raise httpexceptions.HTTPForbidden - message = super(MessageView, self).get_instance() + message = super().get_instance() if not self.associated_with(message): raise httpexceptions.HTTPForbidden return message @@ -108,11 +108,18 @@ class MessageView(MasterView): .filter(model.MessageRecipient.recipient == self.request.user) def configure_grid(self, g): - - g.joiners['sender'] = lambda q: q.join(model.User, model.User.uuid == model.Message.sender_uuid).outerjoin(model.Person) - g.filters['sender'] = g.make_filter('sender', model.Person.display_name, - default_active=True, default_verb='contains') - g.sorters['sender'] = g.make_sorter(model.Person.display_name) + super().configure_grid(g) + model = self.model + + # sender + g.set_joiner('sender', + lambda q: q.join(model.User, + model.User.uuid == model.Message.sender_uuid)\ + .outerjoin(model.Person)) + g.set_sorter('sender', model.Person.display_name) + g.set_filter('sender', model.Person.display_name, + default_active=True, + default_verb='contains') g.filters['subject'].default_active = True g.filters['subject'].default_verb = 'contains' @@ -201,7 +208,7 @@ class MessageView(MasterView): # return form def configure_form(self, f): - super(MessageView, self).configure_form(f) + super().configure_form(f) f.submit_label = "Send Message" @@ -274,7 +281,7 @@ class MessageView(MasterView): def objectify(self, form, data=None): if data is None: data = form.validated - message = super(MessageView, self).objectify(form, data) + message = super().objectify(form, data) if self.creating: if self.request.user: @@ -463,7 +470,7 @@ class InboxView(MessageView): return self.request.route_url('messages.inbox') def query(self, session): - q = super(InboxView, self).query(session) + q = super().query(session) return q.filter(model.MessageRecipient.status == self.enum.MESSAGE_STATUS_INBOX) @@ -479,7 +486,7 @@ class ArchiveView(MessageView): return self.request.route_url('messages.archive') def query(self, session): - q = super(ArchiveView, self).query(session) + q = super().query(session) return q.filter(model.MessageRecipient.status == self.enum.MESSAGE_STATUS_ARCHIVE) @@ -500,7 +507,7 @@ class SentView(MessageView): .filter(model.Message.sender == self.request.user) def configure_grid(self, g): - super(SentView, self).configure_grid(g) + super().configure_grid(g) g.filters['sender'].default_active = False g.joiners['recipients'] = lambda q: q.join(model.MessageRecipient)\ .join(model.User, model.User.uuid == model.MessageRecipient.recipient_uuid)\ diff --git a/tailbone/views/people.py b/tailbone/views/people.py index 31760d2a..7f786ace 100644 --- a/tailbone/views/people.py +++ b/tailbone/views/people.py @@ -95,7 +95,7 @@ class PersonView(MasterView): mergeable = True def __init__(self, request): - super(PersonView, self).__init__(request) + super().__init__(request) app = self.get_rattail_app() # always get a reference to the People Handler @@ -105,7 +105,7 @@ class PersonView(MasterView): self.handler = self.people_handler def make_grid_kwargs(self, **kwargs): - kwargs = super(PersonView, self).make_grid_kwargs(**kwargs) + kwargs = super().make_grid_kwargs(**kwargs) # turn on checkboxes if user can create a merge reqeust if self.mergeable and self.has_perm('request_merge'): @@ -114,18 +114,28 @@ class PersonView(MasterView): return kwargs def configure_grid(self, g): - super(PersonView, self).configure_grid(g) + super().configure_grid(g) route_prefix = self.get_route_prefix() model = self.model - g.joiners['email'] = lambda q: q.outerjoin(model.PersonEmailAddress, sa.and_( - model.PersonEmailAddress.parent_uuid == model.Person.uuid, - model.PersonEmailAddress.preference == 1)) - g.joiners['phone'] = lambda q: q.outerjoin(model.PersonPhoneNumber, sa.and_( - model.PersonPhoneNumber.parent_uuid == model.Person.uuid, - model.PersonPhoneNumber.preference == 1)) + # email + g.set_label('email', "Email Address") + g.set_joiner('email', lambda q: q.outerjoin( + model.PersonEmailAddress, + sa.and_( + model.PersonEmailAddress.parent_uuid == model.Person.uuid, + model.PersonEmailAddress.preference == 1))) + g.set_sorter('email', model.PersonEmailAddress.address) + g.set_filter('email', model.PersonEmailAddress.address) - g.filters['email'] = g.make_filter('email', model.PersonEmailAddress.address) + # phone + g.set_label('phone', "Phone Number") + g.set_joiner('phone', lambda q: q.outerjoin( + model.PersonPhoneNumber, + sa.and_( + model.PersonPhoneNumber.parent_uuid == model.Person.uuid, + model.PersonPhoneNumber.preference == 1))) + g.set_sorter('phone', model.PersonPhoneNumber.number) g.set_filter('phone', model.PersonPhoneNumber.number, factory=grids.filters.AlchemyPhoneNumberFilter) @@ -151,17 +161,12 @@ class PersonView(MasterView): g.set_filter('employee_status', model.Employee.status, value_enum=self.enum.EMPLOYEE_STATUS) - g.sorters['email'] = lambda q, d: q.order_by(getattr(model.PersonEmailAddress.address, d)()) - g.sorters['phone'] = lambda q, d: q.order_by(getattr(model.PersonPhoneNumber.number, d)()) - g.set_label('merge_requested', "MR") g.set_renderer('merge_requested', self.render_merge_requested) g.set_sort_defaults('display_name') g.set_label('display_name', "Full Name") - g.set_label('phone', "Phone Number") - g.set_label('email', "Email Address") g.set_label('customer_id', "Customer ID") if (self.has_perm('view_profile') @@ -237,7 +242,7 @@ class PersonView(MasterView): data = form.validated # do normal create/update - person = super(PersonView, self).objectify(form, data) + person = super().objectify(form, data) # collect data from all name fields names = {} @@ -278,7 +283,7 @@ class PersonView(MasterView): customer._people.reorder() # continue with normal logic - super(PersonView, self).delete_instance(person) + super().delete_instance(person) def touch_instance(self, person): """ @@ -288,7 +293,7 @@ class PersonView(MasterView): contact info record associated with them. """ # touch person, as per usual - super(PersonView, self).touch_instance(person) + super().touch_instance(person) def touch(obj): change = model.Change() @@ -310,7 +315,7 @@ class PersonView(MasterView): touch(address) def configure_common_form(self, f): - super(PersonView, self).configure_common_form(f) + super().configure_common_form(f) person = f.model_instance f.set_label('display_name', "Full Name") @@ -1836,7 +1841,7 @@ class PersonNoteView(MasterView): return note.subject or "(no subject)" def configure_grid(self, g): - super(PersonNoteView, self).configure_grid(g) + super().configure_grid(g) # person g.set_joiner('person', lambda q: q.join(model.Person, @@ -1857,7 +1862,7 @@ class PersonNoteView(MasterView): g.set_link('created') def configure_form(self, f): - super(PersonNoteView, self).configure_form(f) + super().configure_form(f) # person f.set_readonly('person') @@ -1931,7 +1936,7 @@ class MergePeopleRequestView(MasterView): ] def configure_grid(self, g): - super(MergePeopleRequestView, self).configure_grid(g) + super().configure_grid(g) g.set_renderer('removing_uuid', self.render_referenced_person_name) g.set_renderer('keeping_uuid', self.render_referenced_person_name) @@ -1960,7 +1965,7 @@ class MergePeopleRequestView(MasterView): keeping or "(not found)") def configure_form(self, f): - super(MergePeopleRequestView, self).configure_form(f) + super().configure_form(f) f.set_renderer('removing_uuid', self.render_referenced_person) f.set_renderer('keeping_uuid', self.render_referenced_person) diff --git a/tailbone/views/products.py b/tailbone/views/products.py index 327b6366..1ddf6ae0 100644 --- a/tailbone/views/products.py +++ b/tailbone/views/products.py @@ -167,7 +167,7 @@ class ProductView(MasterView): TPRPrice = orm.aliased(model.ProductPrice) def __init__(self, request): - super(ProductView, self).__init__(request) + super().__init__(request) self.expose_label_printing = self.rattail_config.getbool( 'tailbone', 'products.print_labels', default=False) @@ -224,7 +224,10 @@ class ProductView(MasterView): g.set_link(field) # brand - g.joiners['brand'] = lambda q: q.outerjoin(model.Brand) + g.set_joiner('brand', lambda q: q.outerjoin(model.Brand)) + g.set_sorter('brand', model.Brand.name) + g.set_filter('brand', model.Brand.name, + default_active=True, default_verb='contains') # department g.set_joiner('department', lambda q: q.outerjoin(model.Department)) @@ -237,12 +240,14 @@ class ProductView(MasterView): verbs=['equal', 'not_equal', 'is_null', 'is_not_null', 'is_any'], default_active=True, default_verb='equal') - g.joiners['subdepartment'] = lambda q: q.outerjoin(model.Subdepartment, - model.Subdepartment.uuid == model.Product.subdepartment_uuid) - g.joiners['code'] = lambda q: q.outerjoin(model.ProductCode) + # subdepartment + g.set_joiner('subdepartment', lambda q: q.outerjoin( + model.Subdepartment, + model.Subdepartment.uuid == model.Product.subdepartment_uuid)) + g.set_sorter('subdepartment', model.Subdepartment.name) + g.set_filter('subdepartment', model.Subdepartment.name) - g.sorters['brand'] = g.make_sorter(model.Brand.name) - g.sorters['subdepartment'] = g.make_sorter(model.Subdepartment.name) + g.joiners['code'] = lambda q: q.outerjoin(model.ProductCode) # vendor ProductVendorCost = orm.aliased(model.ProductCost) @@ -296,9 +301,6 @@ class ProductView(MasterView): g.filters['description'].default_active = True g.filters['description'].default_verb = 'contains' - g.filters['brand'] = g.make_filter('brand', model.Brand.name, - default_active=True, default_verb='contains') - g.filters['subdepartment'] = g.make_filter('subdepartment', model.Subdepartment.name) g.filters['code'] = g.make_filter('code', model.ProductCode.code) # g.joiners['vendor_code_any'] = join_vendor_code_any @@ -392,7 +394,7 @@ class ProductView(MasterView): g.set_link('description') def configure_common_form(self, f): - super(ProductView, self).configure_common_form(f) + super().configure_common_form(f) product = f.model_instance # unit_size @@ -687,7 +689,7 @@ class ProductView(MasterView): return ' '.join(classes) def get_xlsx_fields(self): - fields = super(ProductView, self).get_xlsx_fields() + fields = super().get_xlsx_fields() i = fields.index('department_uuid') fields.insert(i + 1, 'department_number') @@ -734,7 +736,7 @@ class ProductView(MasterView): return fields def get_xlsx_row(self, product, fields): - row = super(ProductView, self).get_xlsx_row(product, fields) + row = super().get_xlsx_row(product, fields) if 'upc' in fields and isinstance(row['upc'], GPC): row['upc'] = row['upc'].pretty() @@ -799,7 +801,7 @@ class ProductView(MasterView): return row def download_results_normalize(self, product, fields, **kwargs): - data = super(ProductView, self).download_results_normalize( + data = super().download_results_normalize( product, fields, **kwargs) if 'upc' in data: @@ -988,7 +990,7 @@ class ProductView(MasterView): def objectify(self, form, data=None): if data is None: data = form.validated - product = super(ProductView, self).objectify(form, data=data) + product = super().objectify(form, data=data) # regular_price_amount if (self.creating or self.editing) and 'regular_price_amount' in form.fields: @@ -1163,7 +1165,7 @@ class ProductView(MasterView): return jsdata def template_kwargs_view(self, **kwargs): - kwargs = super(ProductView, self).template_kwargs_view(**kwargs) + kwargs = super().template_kwargs_view(**kwargs) product = kwargs['instance'] kwargs['image_url'] = self.products_handler.get_image_url(product) @@ -2287,7 +2289,7 @@ class PendingProductView(MasterView): ] def configure_grid(self, g): - super(PendingProductView, self).configure_grid(g) + super().configure_grid(g) g.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS) g.filters['status_code'].default_active = True @@ -2299,7 +2301,7 @@ class PendingProductView(MasterView): g.set_link('description') def configure_form(self, f): - super(PendingProductView, self).configure_form(f) + super().configure_form(f) model = self.model pending = f.model_instance @@ -2417,7 +2419,7 @@ class PendingProductView(MasterView): if data is None: data = form.validated - pending = super(PendingProductView, self).objectify(form, data) + pending = super().objectify(form, data) if not pending.user: pending.user = self.request.user diff --git a/tailbone/views/purchases/core.py b/tailbone/views/purchases/core.py index 77b02501..e7bebdff 100644 --- a/tailbone/views/purchases/core.py +++ b/tailbone/views/purchases/core.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,10 +24,6 @@ Views for "true" purchase orders """ -from __future__ import unicode_literals, absolute_import - -import six - from rattail.db import model from webhelpers2.html import HTML, tags @@ -143,28 +139,35 @@ class PurchaseView(MasterView): if purchase.date_ordered: return "{} (ordered {})".format(purchase.vendor, purchase.date_ordered.strftime('%Y-%m-%d')) return "{} (ordered)".format(purchase.vendor) - return six.text_type(purchase) + return str(purchase) def configure_grid(self, g): - super(PurchaseView, self).configure_grid(g) + super().configure_grid(g) + model = self.model - g.joiners['store'] = lambda q: q.join(model.Store) - g.filters['store'] = g.make_filter('store', model.Store.name) - g.sorters['store'] = g.make_sorter(model.Store.name) + # store + g.set_joiner('store', lambda q: q.join(model.Store)) + g.set_sorter('store', model.Store.name) + g.set_filter('store', model.Store.name) - g.joiners['vendor'] = lambda q: q.join(model.Vendor) - g.filters['vendor'] = g.make_filter('vendor', model.Vendor.name, - default_active=True, default_verb='contains') - g.sorters['vendor'] = g.make_sorter(model.Vendor.name) + # vendor + g.set_joiner('vendor', lambda q: q.join(model.Vendor)) + g.set_sorter('vendor', model.Vendor.name) + g.set_filter('vendor', model.Vendor.name, + default_active=True, + default_verb='contains') - g.joiners['department'] = lambda q: q.join(model.Department) - g.filters['department'] = g.make_filter('department', model.Department.name) - g.sorters['department'] = g.make_sorter(model.Department.name) + # department + g.set_joiner('department', lambda q: q.join(model.Department)) + g.set_sorter('department', model.Department.name) + g.set_filter('department', model.Department.name) - g.joiners['buyer'] = lambda q: q.join(model.Employee).join(model.Person) - g.filters['buyer'] = g.make_filter('buyer', model.Person.display_name, - default_active=True, default_verb='contains') - g.sorters['buyer'] = g.make_sorter(model.Person.display_name) + # buyer + g.set_joiner('buyer', lambda q: q.join(model.Employee).join(model.Person)) + g.set_sorter('buyer', model.Person.display_name) + g.set_filter('buyer', model.Person.display_name, + default_active=True, + default_verb='contains') # id g.set_renderer('id', self.render_id_str) @@ -198,7 +201,7 @@ class PurchaseView(MasterView): g.set_link('invoice_total') def configure_form(self, f): - super(PurchaseView, self).configure_form(f) + super().configure_form(f) # id f.set_renderer('id', self.render_id_str) @@ -322,7 +325,7 @@ class PurchaseView(MasterView): .filter(model.PurchaseItem.purchase == purchase) def configure_row_grid(self, g): - super(PurchaseView, self).configure_row_grid(g) + super().configure_row_grid(g) g.set_sort_defaults('sequence') @@ -353,7 +356,7 @@ class PurchaseView(MasterView): g.remove('po_total') def configure_row_form(self, f): - super(PurchaseView, self).configure_row_form(f) + super().configure_row_form(f) # quantity fields f.set_type('case_quantity', 'quantity') diff --git a/tailbone/views/purchasing/batch.py b/tailbone/views/purchasing/batch.py index 96557d55..e49a5dea 100644 --- a/tailbone/views/purchasing/batch.py +++ b/tailbone/views/purchasing/batch.py @@ -175,9 +175,10 @@ class PurchasingBatchView(BatchMasterView): g.set_filter('vendor', model.Vendor.name, default_active=True, default_verb='contains') - g.joiners['department'] = lambda q: q.join(model.Department) - g.filters['department'] = g.make_filter('department', model.Department.name) - g.sorters['department'] = g.make_sorter(model.Department.name) + # department + g.set_joiner('department', lambda q: q.join(model.Department)) + g.set_filter('department', model.Department.name) + g.set_sorter('department', model.Department.name) g.set_joiner('buyer', lambda q: q.join(model.Employee).join(model.Person)) g.set_filter('buyer', model.Person.display_name) @@ -212,7 +213,7 @@ class PurchasingBatchView(BatchMasterView): # return form def configure_common_form(self, f): - super(PurchasingBatchView, self).configure_common_form(f) + super().configure_common_form(f) # po_total if self.creating: @@ -225,7 +226,7 @@ class PurchasingBatchView(BatchMasterView): f.set_type('po_total_calculated', 'currency') def configure_form(self, f): - super(PurchasingBatchView, self).configure_form(f) + super().configure_form(f) model = self.model batch = f.model_instance app = self.get_rattail_app() @@ -598,7 +599,7 @@ class PurchasingBatchView(BatchMasterView): # return query.options(orm.joinedload(model.PurchaseBatchRow.credits)) def configure_row_grid(self, g): - super(PurchasingBatchView, self).configure_row_grid(g) + super().configure_row_grid(g) g.set_type('upc', 'gpc') g.set_type('cases_ordered', 'quantity') @@ -685,7 +686,7 @@ class PurchasingBatchView(BatchMasterView): return 'notice' def configure_row_form(self, f): - super(PurchasingBatchView, self).configure_row_form(f) + super().configure_row_form(f) row = f.model_instance if self.creating: batch = self.get_instance() @@ -894,7 +895,7 @@ class PurchasingBatchView(BatchMasterView): batch.invoice_total -= row.invoice_total # do the "normal" save logic... - row = super(PurchasingBatchView, self).save_edit_row_form(form) + row = super().save_edit_row_form(form) # TODO: is this needed? # self.handler.refresh_row(row) diff --git a/tailbone/views/purchasing/receiving.py b/tailbone/views/purchasing/receiving.py index 0cef3a37..3e78dfea 100644 --- a/tailbone/views/purchasing/receiving.py +++ b/tailbone/views/purchasing/receiving.py @@ -233,7 +233,7 @@ class ReceivingBatchView(PurchasingBatchView): return self.enum.PURCHASE_BATCH_MODE_RECEIVING def configure_grid(self, g): - super(ReceivingBatchView, self).configure_grid(g) + super().configure_grid(g) if not self.handler.allow_truck_dump_receiving(): g.remove('truck_dump') @@ -285,14 +285,14 @@ class ReceivingBatchView(PurchasingBatchView): raise redirect # okay now do the normal thing, per workflow - return super(ReceivingBatchView, self).create(**kwargs) + return super().create(**kwargs) # on the other hand, if caller provided a form, that means we are in # the middle of some other custom workflow, e.g. "add child to truck # dump parent" or some such. in which case we also defer to the normal # logic, so as to not interfere with that. if form: - return super(ReceivingBatchView, self).create(form=form, **kwargs) + return super().create(form=form, **kwargs) # okay, at this point we need the user to select a vendor and workflow self.creating = True @@ -372,14 +372,14 @@ class ReceivingBatchView(PurchasingBatchView): # first run it through the normal logic, if that doesn't like # it then we won't either - if not super(ReceivingBatchView, self).row_deletable(row): + if not super().row_deletable(row): return False # otherwise let handler decide return self.batch_handler.is_row_deletable(row) def get_instance_title(self, batch): - title = super(ReceivingBatchView, self).get_instance_title(batch) + title = super().get_instance_title(batch) if batch.is_truck_dump_parent(): title = "{} (TRUCK DUMP PARENT)".format(title) elif batch.is_truck_dump_child(): @@ -633,7 +633,7 @@ class ReceivingBatchView(PurchasingBatchView): return info['display'] def get_visible_params(self, batch): - params = super(ReceivingBatchView, self).get_visible_params(batch) + params = super().get_visible_params(batch) # remove this since we show it separately params.pop('invoice_files', None) @@ -655,7 +655,7 @@ class ReceivingBatchView(PurchasingBatchView): return kwargs def get_batch_kwargs(self, batch, **kwargs): - kwargs = super(ReceivingBatchView, self).get_batch_kwargs(batch, **kwargs) + kwargs = super().get_batch_kwargs(batch, **kwargs) batch_type = self.request.POST['batch_type'] # must pull vendor from URL if it was not in form data @@ -769,7 +769,7 @@ class ReceivingBatchView(PurchasingBatchView): return True def template_kwargs_view(self, **kwargs): - kwargs = super(ReceivingBatchView, self).template_kwargs_view(**kwargs) + kwargs = super().template_kwargs_view(**kwargs) batch = kwargs['instance'] if self.handler.has_purchase_order(batch) and self.handler.has_invoice_file(batch): @@ -810,7 +810,7 @@ class ReceivingBatchView(PurchasingBatchView): return credits_data def template_kwargs_view_row(self, **kwargs): - kwargs = super(ReceivingBatchView, self).template_kwargs_view_row(**kwargs) + kwargs = super().template_kwargs_view_row(**kwargs) app = self.get_rattail_app() products_handler = app.get_products_handler() row = kwargs['instance'] @@ -847,7 +847,7 @@ class ReceivingBatchView(PurchasingBatchView): if batch.is_truck_dump_parent(): for child in batch.truck_dump_children: self.delete_instance(child) - super(ReceivingBatchView, self).delete_instance(batch) + super().delete_instance(batch) if truck_dump: self.handler.refresh(truck_dump) @@ -1010,7 +1010,7 @@ class ReceivingBatchView(PurchasingBatchView): .group_by(model.PurchaseBatchCredit.row_uuid)\ .subquery() g.set_joiner('credits', lambda q: q.outerjoin(Credits)) - g.sorters['credits'] = lambda q, d: q.order_by(getattr(Credits.c.credit_count, d)()) + g.set_sorter('credits', Credits.c.credit_count) show_ordered = self.rattail_config.getbool( 'rattail.batch', 'purchase.receiving.show_ordered_column_in_grid', @@ -1083,7 +1083,7 @@ class ReceivingBatchView(PurchasingBatchView): }) def row_grid_extra_class(self, row, i): - css_class = super(ReceivingBatchView, self).row_grid_extra_class(row, i) + css_class = super().row_grid_extra_class(row, i) if row.catalog_cost_confirmed: css_class = '{} catalog_cost_confirmed'.format(css_class or '') @@ -1098,7 +1098,7 @@ class ReceivingBatchView(PurchasingBatchView): return str(row.product) if row.upc: return row.upc.pretty() - return super(ReceivingBatchView, self).get_row_instance_title(row) + return super().get_row_instance_title(row) def transform_unit_url(self, row, i): # grid action is shown only when we return a URL here @@ -1110,7 +1110,7 @@ class ReceivingBatchView(PurchasingBatchView): def make_row_credits_grid(self, row): # first make grid like normal - g = super(ReceivingBatchView, self).make_row_credits_grid(row) + g = super().make_row_credits_grid(row) if (self.has_perm('edit_row') and self.row_editable(row)): @@ -1616,7 +1616,7 @@ class ReceivingBatchView(PurchasingBatchView): def validate_row_form(self, form): # if normal validation fails, stop there - if not super(ReceivingBatchView, self).validate_row_form(form): + if not super().validate_row_form(form): return False # if user is editing row from truck dump child, then we must further @@ -2097,7 +2097,7 @@ class ReceiveRowForm(colander.MappingSchema): quick_receive = colander.SchemaNode(colander.Boolean()) def deserialize(self, *args): - result = super(ReceiveRowForm, self).deserialize(*args) + result = super().deserialize(*args) if result['mode'] == 'expired' and not result['expiration_date']: msg = "Expiration date is required for items with 'expired' mode." diff --git a/tailbone/views/shifts/core.py b/tailbone/views/shifts/core.py index 8fa934ea..53bfc446 100644 --- a/tailbone/views/shifts/core.py +++ b/tailbone/views/shifts/core.py @@ -84,7 +84,7 @@ class ScheduledShiftView(MasterView, ShiftViewMixin): g.set_label('employee', "Employee Name") def configure_form(self, f): - super(ScheduledShiftView, self).configure_form(f) + super().configure_form(f) f.set_renderer('length', self.render_shift_length) @@ -118,19 +118,22 @@ class WorkedShiftView(MasterView, ShiftViewMixin): ] def configure_grid(self, g): - super(WorkedShiftView, self).configure_grid(g) + super().configure_grid(g) + model = self.model - g.joiners['employee'] = lambda q: q.join(model.Employee).join(model.Person) - g.filters['employee'] = g.make_filter('employee', model.Person.display_name) - g.sorters['employee'] = g.make_sorter(model.Person.display_name) + # employee + g.set_joiner('employee', lambda q: q.join(model.Employee).join(model.Person)) + g.set_sorter('employee', model.Person.display_name) + g.set_filter('employee', model.Person.display_name) - g.joiners['store'] = lambda q: q.join(model.Store) - g.filters['store'] = g.make_filter('store', model.Store.name) - g.sorters['store'] = g.make_sorter(model.Store.name) + # store + g.set_joiner('store', lambda q: q.join(model.Store)) + g.set_sorter('store', model.Store.name) + g.set_filter('store', model.Store.name) # TODO: these sorters should be automatic once we fix the schema - g.sorters['start_time'] = g.make_sorter(model.WorkedShift.punch_in) - g.sorters['end_time'] = g.make_sorter(model.WorkedShift.punch_out) + g.set_sorter('start_time', model.WorkedShift.punch_in) + g.set_sorter('end_time', model.WorkedShift.punch_out) # TODO: same goes for these renderers g.set_type('start_time', 'datetime') g.set_type('end_time', 'datetime') @@ -150,7 +153,7 @@ class WorkedShiftView(MasterView, ShiftViewMixin): return "WorkedShift: {}, {}".format(shift.employee, date) def configure_form(self, f): - super(WorkedShiftView, self).configure_form(f) + super().configure_form(f) f.set_readonly('employee') f.set_renderer('employee', self.render_employee) @@ -168,7 +171,7 @@ class WorkedShiftView(MasterView, ShiftViewMixin): return tags.link_to(text, url) def get_xlsx_fields(self): - fields = super(WorkedShiftView, self).get_xlsx_fields() + fields = super().get_xlsx_fields() # add employee name i = fields.index('employee_uuid') @@ -180,7 +183,7 @@ class WorkedShiftView(MasterView, ShiftViewMixin): return fields def get_xlsx_row(self, shift, fields): - row = super(WorkedShiftView, self).get_xlsx_row(shift, fields) + row = super().get_xlsx_row(shift, fields) # localize start and end times (Excel requires time with no zone) if shift.punch_in: diff --git a/tailbone/views/tempmon/probes.py b/tailbone/views/tempmon/probes.py index dbf15dd1..573f9a2d 100644 --- a/tailbone/views/tempmon/probes.py +++ b/tailbone/views/tempmon/probes.py @@ -101,8 +101,9 @@ class TempmonProbeView(MasterView): def configure_grid(self, g): super().configure_grid(g) - g.joiners['client'] = lambda q: q.join(tempmon.Client) - g.sorters['client'] = g.make_sorter(tempmon.Client.config_key) + # client + g.set_joiner('client', lambda q: q.join(tempmon.Client)) + g.set_sorter('client', tempmon.Client.config_key) g.set_sort_defaults('client') g.set_enum('appliance_type', self.enum.TEMPMON_APPLIANCE_TYPE) diff --git a/tailbone/views/tempmon/readings.py b/tailbone/views/tempmon/readings.py index a8223dd2..02e3fc51 100644 --- a/tailbone/views/tempmon/readings.py +++ b/tailbone/views/tempmon/readings.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,9 +24,6 @@ Views for tempmon readings """ -from __future__ import unicode_literals, absolute_import - -import six from sqlalchemy import orm from rattail_tempmon.db import model as tempmon @@ -70,17 +67,21 @@ class TempmonReadingView(MasterView): .options(orm.joinedload(tempmon.Reading.client)) def configure_grid(self, g): - super(TempmonReadingView, self).configure_grid(g) + super().configure_grid(g) - g.sorters['client_key'] = g.make_sorter(tempmon.Client.config_key) - g.filters['client_key'] = g.make_filter('client_key', tempmon.Client.config_key) + # client_key + g.set_sorter('client_key', tempmon.Client.config_key) + g.set_filter('client_key', tempmon.Client.config_key) - g.sorters['client_host'] = g.make_sorter(tempmon.Client.hostname) - g.filters['client_host'] = g.make_filter('client_host', tempmon.Client.hostname) + # client_host + g.set_sorter('client_host', tempmon.Client.hostname) + g.set_filter('client_host', tempmon.Client.hostname) - g.joiners['probe'] = lambda q: q.join(tempmon.Probe, tempmon.Probe.uuid == tempmon.Reading.probe_uuid) - g.sorters['probe'] = g.make_sorter(tempmon.Probe.description) - g.filters['probe'] = g.make_filter('probe', tempmon.Probe.description) + # probe + g.set_joiner('probe', lambda q: q.join(tempmon.Probe, + tempmon.Probe.uuid == tempmon.Reading.probe_uuid)) + g.set_sorter('probe', tempmon.Probe.description) + g.set_filter('probe', tempmon.Probe.description) g.set_sort_defaults('taken', 'desc') g.set_type('taken', 'datetime') @@ -98,7 +99,7 @@ class TempmonReadingView(MasterView): return reading.client.hostname def configure_form(self, f): - super(TempmonReadingView, self).configure_form(f) + super().configure_form(f) # client f.set_renderer('client', self.render_client) @@ -112,7 +113,7 @@ class TempmonReadingView(MasterView): client = reading.client if not client: return "" - text = six.text_type(client) + text = str(client) url = self.request.route_url('tempmon.clients.view', uuid=client.uuid) return tags.link_to(text, url) @@ -120,7 +121,7 @@ class TempmonReadingView(MasterView): probe = reading.probe if not probe: return "" - text = six.text_type(probe) + text = str(probe) url = self.request.route_url('tempmon.probes.view', uuid=probe.uuid) return tags.link_to(text, url) diff --git a/tailbone/views/views.py b/tailbone/views/views.py index 25828cde..67cba2e2 100644 --- a/tailbone/views/views.py +++ b/tailbone/views/views.py @@ -24,8 +24,6 @@ Views for views """ -from __future__ import unicode_literals, absolute_import - import os import sys @@ -80,7 +78,7 @@ class ModelViewView(MasterView): return data def configure_grid(self, g): - super(ModelViewView, self).configure_grid(g) + super().configure_grid(g) # label g.sorters['label'] = g.make_simple_sorter('label') @@ -107,7 +105,7 @@ class ModelViewView(MasterView): return ModelViewSchema() def template_kwargs_create(self, **kwargs): - kwargs = super(ModelViewView, self).template_kwargs_create(**kwargs) + kwargs = super().template_kwargs_create(**kwargs) app = self.get_rattail_app() db_handler = app.get_db_handler()