Coverage for src/sideshow/web/views/customers.py: 100%

87 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-06 15:40 -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""" 

26 

27from wuttaweb.views import MasterView 

28from wuttaweb.forms.schema import UserRef, WuttaEnum 

29 

30from sideshow.db.model import PendingCustomer 

31 

32 

33class PendingCustomerView(MasterView): 

34 """ 

35 Master view for 

36 :class:`~sideshow.db.model.customers.PendingCustomer`; route 

37 prefix is ``pending_customers``. 

38 

39 Notable URLs provided by this class: 

40 

41 * ``/pending/customers/`` 

42 * ``/pending/customers/new`` 

43 * ``/pending/customers/XXX`` 

44 * ``/pending/customers/XXX/edit`` 

45 * ``/pending/customers/XXX/delete`` 

46 """ 

47 model_class = PendingCustomer 

48 model_title = "Pending Customer" 

49 route_prefix = 'pending_customers' 

50 url_prefix = '/pending/customers' 

51 

52 labels = { 

53 'customer_id': "Customer ID", 

54 } 

55 

56 grid_columns = [ 

57 'full_name', 

58 'first_name', 

59 'last_name', 

60 'phone_number', 

61 'email_address', 

62 'customer_id', 

63 'status', 

64 'created', 

65 'created_by', 

66 ] 

67 

68 sort_defaults = 'full_name' 

69 

70 form_fields = [ 

71 'customer_id', 

72 'full_name', 

73 'first_name', 

74 'middle_name', 

75 'last_name', 

76 'phone_number', 

77 'phone_type', 

78 'email_address', 

79 'email_type', 

80 'status', 

81 'created', 

82 'created_by', 

83 'orders', 

84 'new_order_batches', 

85 ] 

86 

87 def configure_grid(self, g): 

88 """ """ 

89 super().configure_grid(g) 

90 enum = self.app.enum 

91 

92 # status 

93 g.set_renderer('status', self.grid_render_enum, enum=enum.PendingCustomerStatus) 

94 

95 # links 

96 g.set_link('full_name') 

97 g.set_link('first_name') 

98 g.set_link('last_name') 

99 g.set_link('phone_number') 

100 g.set_link('email_address') 

101 

102 def configure_form(self, f): 

103 """ """ 

104 super().configure_form(f) 

105 enum = self.app.enum 

106 customer = f.model_instance 

107 

108 # customer_id 

109 if self.creating: 

110 f.remove('customer_id') 

111 else: 

112 f.set_readonly('customer_id') 

113 

114 # status 

115 if self.creating: 

116 f.remove('status') 

117 else: 

118 f.set_node('status', WuttaEnum(self.request, enum.PendingCustomerStatus)) 

119 f.set_readonly('status') 

120 

121 # created 

122 if self.creating: 

123 f.remove('created') 

124 else: 

125 f.set_readonly('created') 

126 

127 # created_by 

128 if self.creating: 

129 f.remove('created_by') 

130 else: 

131 f.set_node('created_by', UserRef(self.request)) 

132 f.set_readonly('created_by') 

133 

134 # orders 

135 if self.creating or self.editing: 

136 f.remove('orders') 

137 else: 

138 f.set_grid('orders', self.make_orders_grid(customer)) 

139 

140 # new_order_batches 

141 if self.creating or self.editing: 

142 f.remove('new_order_batches') 

143 else: 

144 f.set_grid('new_order_batches', self.make_new_order_batches_grid(customer)) 

145 

146 def make_orders_grid(self, customer): 

147 """ 

148 Make and return the grid for the Orders field. 

149 """ 

150 model = self.app.model 

151 route_prefix = self.get_route_prefix() 

152 

153 grid = self.make_grid(key=f'{route_prefix}.view.orders', 

154 model_class=model.Order, 

155 data=customer.orders, 

156 columns=[ 

157 'order_id', 

158 'total_price', 

159 'created', 

160 'created_by', 

161 ], 

162 labels={ 

163 'order_id': "Order ID", 

164 }) 

165 grid.set_renderer('total_price', grid.render_currency) 

166 

167 if self.request.has_perm('orders.view'): 

168 url = lambda order, i: self.request.route_url('orders.view', uuid=order.uuid) 

169 grid.add_action('view', icon='eye', url=url) 

170 grid.set_link('order_id') 

171 

172 return grid 

173 

174 def make_new_order_batches_grid(self, customer): 

175 """ 

176 Make and return the grid for the New Order Batches field. 

177 """ 

178 model = self.app.model 

179 route_prefix = self.get_route_prefix() 

180 

181 grid = self.make_grid(key=f'{route_prefix}.view.new_order_batches', 

182 model_class=model.NewOrderBatch, 

183 data=customer.new_order_batches, 

184 columns=[ 

185 'id', 

186 'total_price', 

187 'created', 

188 'created_by', 

189 'executed', 

190 ], 

191 labels={ 

192 'id': "Batch ID", 

193 }, 

194 renderers={ 

195 'id': 'batch_id', 

196 'total_price': 'currency', 

197 }) 

198 

199 if self.request.has_perm('neworder_batches.view'): 

200 url = lambda batch, i: self.request.route_url('neworder_batches.view', uuid=batch.uuid) 

201 grid.add_action('view', icon='eye', url=url) 

202 grid.set_link('id') 

203 

204 return grid 

205 

206 def objectify(self, form): 

207 """ """ 

208 enum = self.app.enum 

209 customer = super().objectify(form) 

210 

211 if self.creating: 

212 customer.status = enum.PendingCustomerStatus.PENDING 

213 customer.created_by = self.request.user 

214 

215 return customer 

216 

217 def delete_instance(self, customer): 

218 """ """ 

219 model_title = self.get_model_title() 

220 

221 # avoid deleting if still referenced by order(s) 

222 for order in customer.orders: 

223 self.request.session.flash(f"Cannot delete {model_title} still attached " 

224 "to Order(s)", 'warning') 

225 raise self.redirect(self.get_action_url('view', customer)) 

226 

227 # avoid deleting if still referenced by new order batch(es) 

228 for batch in customer.new_order_batches: 

229 if not batch.executed: 

230 self.request.session.flash(f"Cannot delete {model_title} still attached " 

231 "to New Order Batch(es)", 'warning') 

232 raise self.redirect(self.get_action_url('view', customer)) 

233 

234 # go ahead and delete per usual 

235 super().delete_instance(customer) 

236 

237 

238def defaults(config, **kwargs): 

239 base = globals() 

240 

241 PendingCustomerView = kwargs.get('PendingCustomerView', base['PendingCustomerView']) 

242 PendingCustomerView.defaults(config) 

243 

244 

245def includeme(config): 

246 defaults(config)