Coverage for .tox/coverage/lib/python3.11/site-packages/sideshow/web/views/customers.py: 100%
143 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-09 12:58 -0600
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-09 12:58 -0600
1# -*- coding: utf-8; -*-
2################################################################################
3#
4# Sideshow -- Case/Special Order Tracker
5# Copyright © 2024 Lance Edgar
6#
7# This file is part of Sideshow.
8#
9# Sideshow is free software: you can redistribute it and/or modify it
10# under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# Sideshow is distributed in the hope that it will be useful, but
15# WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17# General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with Sideshow. If not, see <http://www.gnu.org/licenses/>.
21#
22################################################################################
23"""
24Views for Customers
25"""
27from wuttaweb.views import MasterView
28from wuttaweb.forms.schema import UserRef, WuttaEnum
30from sideshow.db.model import LocalCustomer, PendingCustomer
33class LocalCustomerView(MasterView):
34 """
35 Master view for
36 :class:`~sideshow.db.model.customers.LocalCustomer`; route prefix
37 is ``local_customers``.
39 Notable URLs provided by this class:
41 * ``/local/customers/``
42 * ``/local/customers/new``
43 * ``/local/customers/XXX``
44 * ``/local/customers/XXX/edit``
45 * ``/local/customers/XXX/delete``
46 """
47 model_class = LocalCustomer
48 model_title = "Local Customer"
49 route_prefix = 'local_customers'
50 url_prefix = '/local/customers'
52 labels = {
53 'external_id': "External ID",
54 }
56 grid_columns = [
57 'external_id',
58 'full_name',
59 'first_name',
60 'last_name',
61 'phone_number',
62 'email_address',
63 ]
65 sort_defaults = 'full_name'
67 form_fields = [
68 'external_id',
69 'full_name',
70 'first_name',
71 'last_name',
72 'phone_number',
73 'email_address',
74 'orders',
75 'new_order_batches',
76 ]
78 def configure_grid(self, g):
79 """ """
80 super().configure_grid(g)
82 # links
83 g.set_link('full_name')
84 g.set_link('first_name')
85 g.set_link('last_name')
86 g.set_link('phone_number')
87 g.set_link('email_address')
89 def configure_form(self, f):
90 """ """
91 super().configure_form(f)
92 customer = f.model_instance
94 # external_id
95 if self.creating:
96 f.remove('external_id')
97 else:
98 f.set_readonly('external_id')
100 # full_name
101 if self.creating or self.editing:
102 f.remove('full_name')
104 # orders
105 if self.creating or self.editing:
106 f.remove('orders')
107 else:
108 f.set_grid('orders', self.make_orders_grid(customer))
110 # new_order_batches
111 if self.creating or self.editing:
112 f.remove('new_order_batches')
113 else:
114 f.set_grid('new_order_batches', self.make_new_order_batches_grid(customer))
116 def make_orders_grid(self, customer):
117 """
118 Make and return the grid for the Orders field.
119 """
120 model = self.app.model
121 route_prefix = self.get_route_prefix()
123 grid = self.make_grid(key=f'{route_prefix}.view.orders',
124 model_class=model.Order,
125 data=customer.orders,
126 columns=[
127 'order_id',
128 'total_price',
129 'created',
130 'created_by',
131 ],
132 labels={
133 'order_id': "Order ID",
134 })
135 grid.set_renderer('total_price', grid.render_currency)
137 if self.request.has_perm('orders.view'):
138 url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
139 grid.add_action('view', icon='eye', url=url)
140 grid.set_link('order_id')
142 return grid
144 def make_new_order_batches_grid(self, customer):
145 """
146 Make and return the grid for the New Order Batches field.
147 """
148 model = self.app.model
149 route_prefix = self.get_route_prefix()
151 grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
152 model_class=model.NewOrderBatch,
153 data=customer.new_order_batches,
154 columns=[
155 'id',
156 'total_price',
157 'created',
158 'created_by',
159 'executed',
160 ],
161 labels={
162 'id': "Batch ID",
163 },
164 renderers={
165 'id': 'batch_id',
166 'total_price': 'currency',
167 })
169 if self.request.has_perm('neworder_batches.view'):
170 url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
171 grid.add_action('view', icon='eye', url=url)
172 grid.set_link('id')
174 return grid
176 def objectify(self, form):
177 """ """
178 enum = self.app.enum
179 customer = super().objectify(form)
181 customer.full_name = self.app.make_full_name(customer.first_name,
182 customer.last_name)
184 return customer
187class PendingCustomerView(MasterView):
188 """
189 Master view for
190 :class:`~sideshow.db.model.customers.PendingCustomer`; route
191 prefix is ``pending_customers``.
193 Notable URLs provided by this class:
195 * ``/pending/customers/``
196 * ``/pending/customers/new``
197 * ``/pending/customers/XXX``
198 * ``/pending/customers/XXX/edit``
199 * ``/pending/customers/XXX/delete``
200 """
201 model_class = PendingCustomer
202 model_title = "Pending Customer"
203 route_prefix = 'pending_customers'
204 url_prefix = '/pending/customers'
206 labels = {
207 'customer_id': "Customer ID",
208 }
210 grid_columns = [
211 'full_name',
212 'first_name',
213 'last_name',
214 'phone_number',
215 'email_address',
216 'customer_id',
217 'status',
218 'created',
219 'created_by',
220 ]
222 sort_defaults = 'full_name'
224 form_fields = [
225 'customer_id',
226 'full_name',
227 'first_name',
228 'last_name',
229 'phone_number',
230 'email_address',
231 'status',
232 'created',
233 'created_by',
234 'orders',
235 'new_order_batches',
236 ]
238 def configure_grid(self, g):
239 """ """
240 super().configure_grid(g)
241 enum = self.app.enum
243 # status
244 g.set_renderer('status', self.grid_render_enum, enum=enum.PendingCustomerStatus)
246 # links
247 g.set_link('full_name')
248 g.set_link('first_name')
249 g.set_link('last_name')
250 g.set_link('phone_number')
251 g.set_link('email_address')
253 def configure_form(self, f):
254 """ """
255 super().configure_form(f)
256 enum = self.app.enum
257 customer = f.model_instance
259 # customer_id
260 if self.creating:
261 f.remove('customer_id')
262 else:
263 f.set_readonly('customer_id')
265 # status
266 if self.creating:
267 f.remove('status')
268 else:
269 f.set_node('status', WuttaEnum(self.request, enum.PendingCustomerStatus))
270 f.set_readonly('status')
272 # created
273 if self.creating:
274 f.remove('created')
275 else:
276 f.set_readonly('created')
278 # created_by
279 if self.creating:
280 f.remove('created_by')
281 else:
282 f.set_node('created_by', UserRef(self.request))
283 f.set_readonly('created_by')
285 # orders
286 if self.creating or self.editing:
287 f.remove('orders')
288 else:
289 f.set_grid('orders', self.make_orders_grid(customer))
291 # new_order_batches
292 if self.creating or self.editing:
293 f.remove('new_order_batches')
294 else:
295 f.set_grid('new_order_batches', self.make_new_order_batches_grid(customer))
297 def make_orders_grid(self, customer):
298 """
299 Make and return the grid for the Orders field.
300 """
301 model = self.app.model
302 route_prefix = self.get_route_prefix()
304 grid = self.make_grid(key=f'{route_prefix}.view.orders',
305 model_class=model.Order,
306 data=customer.orders,
307 columns=[
308 'order_id',
309 'total_price',
310 'created',
311 'created_by',
312 ],
313 labels={
314 'order_id': "Order ID",
315 })
316 grid.set_renderer('total_price', grid.render_currency)
318 if self.request.has_perm('orders.view'):
319 url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid)
320 grid.add_action('view', icon='eye', url=url)
321 grid.set_link('order_id')
323 return grid
325 def make_new_order_batches_grid(self, customer):
326 """
327 Make and return the grid for the New Order Batches field.
328 """
329 model = self.app.model
330 route_prefix = self.get_route_prefix()
332 grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches',
333 model_class=model.NewOrderBatch,
334 data=customer.new_order_batches,
335 columns=[
336 'id',
337 'total_price',
338 'created',
339 'created_by',
340 'executed',
341 ],
342 labels={
343 'id': "Batch ID",
344 },
345 renderers={
346 'id': 'batch_id',
347 'total_price': 'currency',
348 })
350 if self.request.has_perm('neworder_batches.view'):
351 url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid)
352 grid.add_action('view', icon='eye', url=url)
353 grid.set_link('id')
355 return grid
357 def objectify(self, form):
358 """ """
359 enum = self.app.enum
360 customer = super().objectify(form)
362 if self.creating:
363 customer.status = enum.PendingCustomerStatus.PENDING
364 customer.created_by = self.request.user
366 return customer
368 def delete_instance(self, customer):
369 """ """
370 model_title = self.get_model_title()
372 # avoid deleting if still referenced by order(s)
373 for order in customer.orders:
374 self.request.session.flash(f"Cannot delete {model_title} still attached "
375 "to Order(s)", 'warning')
376 raise self.redirect(self.get_action_url('view', customer))
378 # avoid deleting if still referenced by new order batch(es)
379 for batch in customer.new_order_batches:
380 if not batch.executed:
381 self.request.session.flash(f"Cannot delete {model_title} still attached "
382 "to New Order Batch(es)", 'warning')
383 raise self.redirect(self.get_action_url('view', customer))
385 # go ahead and delete per usual
386 super().delete_instance(customer)
389def defaults(config, **kwargs):
390 base = globals()
392 LocalCustomerView = kwargs.get('LocalCustomerView', base['LocalCustomerView'])
393 LocalCustomerView.defaults(config)
395 PendingCustomerView = kwargs.get('PendingCustomerView', base['PendingCustomerView'])
396 PendingCustomerView.defaults(config)
399def includeme(config):
400 defaults(config)