Add support for new Purchase/Batch views, 'create row' master pattern
More refactoring here but hopefully not that important..
This commit is contained in:
parent
8fe0e96273
commit
a6e43d1658
|
@ -28,6 +28,12 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.newgrid-wrapper .grid-header td.tools p {
|
||||
line-height: 2em;
|
||||
margin: 0;
|
||||
padding: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
/******************************
|
||||
* filters
|
||||
******************************/
|
||||
|
|
10
tailbone/templates/master/create_row.mako
Normal file
10
tailbone/templates/master/create_row.mako
Normal file
|
@ -0,0 +1,10 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="/master/create.mako" />
|
||||
|
||||
<%def name="title()">New ${row_model_title}</%def>
|
||||
|
||||
<%def name="context_menu_items()">
|
||||
<li>${h.link_to("Back to {}".format(model_title), index_url)}</li>
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
|
@ -10,7 +10,7 @@
|
|||
<li>${h.link_to("Delete this {}".format(row_model_title), row_action_url('delete', instance))}</li>
|
||||
% endif
|
||||
% if master.rows_creatable and request.has_perm('{}.create'.format(row_permission_prefix)):
|
||||
<li>${h.link_to("Create a new {}".format(row_model_title), url('{}.create'.format(row_route_prefix)))}</li>
|
||||
<li>${h.link_to("Create a new {}".format(row_model_title), url('{}.create_row'.format(route_prefix), uuid=row_parent.uuid))}</li>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
|
|
11
tailbone/templates/purchases/batches/index.mako
Normal file
11
tailbone/templates/purchases/batches/index.mako
Normal file
|
@ -0,0 +1,11 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="/master/index.mako" />
|
||||
|
||||
<%def name="context_menu_items()">
|
||||
${parent.context_menu_items()}
|
||||
% if request.has_perm('purchases.batch'):
|
||||
<li>${h.link_to("Go to Purchases", url('purchases'))}</li>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
11
tailbone/templates/purchases/index.mako
Normal file
11
tailbone/templates/purchases/index.mako
Normal file
|
@ -0,0 +1,11 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="/master/index.mako" />
|
||||
|
||||
<%def name="context_menu_items()">
|
||||
${parent.context_menu_items()}
|
||||
% if request.has_perm('purchases.batch.list'):
|
||||
<li>${h.link_to("Go to Purchase Batches", url('purchases.batch'))}</li>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
${parent.body()}
|
|
@ -76,6 +76,7 @@ def includeme(config):
|
|||
config.include('tailbone.views.people')
|
||||
config.include('tailbone.views.products')
|
||||
config.include('tailbone.views.progress')
|
||||
config.include('tailbone.views.purchases')
|
||||
config.include('tailbone.views.reportcodes')
|
||||
config.include('tailbone.views.reports')
|
||||
config.include('tailbone.views.roles')
|
||||
|
|
|
@ -182,10 +182,7 @@ class BatchMasterView(MasterView):
|
|||
views are encouraged to override this method.
|
||||
"""
|
||||
if self.creating:
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.created_by.hidden(),
|
||||
])
|
||||
fs.configure()
|
||||
|
||||
else:
|
||||
batch = fs.model
|
||||
|
@ -208,21 +205,31 @@ class BatchMasterView(MasterView):
|
|||
|
||||
def _postconfigure_fieldset(self, fs):
|
||||
if self.creating:
|
||||
if 'created' in fs.render_fields:
|
||||
del fs.created
|
||||
if 'created_by' in fs.render_fields:
|
||||
del fs.created_by
|
||||
if 'executed' in fs.render_fields:
|
||||
del fs.executed
|
||||
if 'executed_by' in fs.render_fields:
|
||||
del fs.executed_by
|
||||
unwanted = [
|
||||
'id',
|
||||
'rowcount',
|
||||
'created',
|
||||
'created_by',
|
||||
'cognized',
|
||||
'cognized_by',
|
||||
'executed',
|
||||
'executed_by',
|
||||
'purge',
|
||||
'data_rows',
|
||||
]
|
||||
for field in unwanted:
|
||||
if field in fs.render_fields:
|
||||
delattr(fs, field)
|
||||
else:
|
||||
batch = fs.model
|
||||
if not batch.executed:
|
||||
if 'executed' in fs.render_fields:
|
||||
del fs.executed
|
||||
if 'executed_by' in fs.render_fields:
|
||||
del fs.executed_by
|
||||
unwanted = [
|
||||
'executed',
|
||||
'executed_by',
|
||||
]
|
||||
for field in unwanted:
|
||||
if field in fs.render_fields:
|
||||
delattr(fs, field)
|
||||
|
||||
def save_create_form(self, form):
|
||||
"""
|
||||
|
@ -325,11 +332,14 @@ class BatchMasterView(MasterView):
|
|||
|
||||
return self.render_to_response('edit', context)
|
||||
|
||||
def make_row_grid_tools(self, batch):
|
||||
def make_batch_row_grid_tools(self, batch):
|
||||
if not batch.executed:
|
||||
url = self.request.route_url('{}.delete_rows'.format(self.get_route_prefix()), uuid=batch.uuid)
|
||||
return HTML.tag('p', c=tags.link_to("Delete all rows matching current search", url))
|
||||
|
||||
def make_row_grid_tools(self, batch):
|
||||
return self.make_batch_row_grid_tools(batch)
|
||||
|
||||
def redirect_after_edit(self, batch):
|
||||
"""
|
||||
Redirect back to edit batch page after editing a batch, unless the
|
||||
|
@ -464,7 +474,7 @@ class BatchMasterView(MasterView):
|
|||
if progress:
|
||||
progress.session.load()
|
||||
progress.session['error'] = True
|
||||
progress.session['error_msg'] = "Data refresh failed: {}".format(error)
|
||||
progress.session['error_msg'] = "Data refresh failed: {} {}".format(error.__class__.__name__, error)
|
||||
progress.session.save()
|
||||
return
|
||||
|
||||
|
@ -619,7 +629,7 @@ class BatchMasterView(MasterView):
|
|||
if progress:
|
||||
progress.session.load()
|
||||
progress.session['error'] = True
|
||||
progress.session['error_msg'] = "Batch execution failed: {}".format(error)
|
||||
progress.session['error_msg'] = "Batch execution failed: {}: {}".format(type(error).__name__, error)
|
||||
progress.session.save()
|
||||
|
||||
# If no error, check result flag (false means user canceled).
|
||||
|
|
|
@ -36,6 +36,7 @@ from rattail.util import prettify
|
|||
import formalchemy
|
||||
from pyramid import httpexceptions
|
||||
from pyramid.renderers import get_renderer, render_to_response, render
|
||||
from webhelpers.html import HTML, tags
|
||||
|
||||
from tailbone import forms, newgrids as grids
|
||||
from tailbone.views import View
|
||||
|
@ -179,8 +180,14 @@ class MasterView(View):
|
|||
tools=self.make_row_grid_tools(instance))
|
||||
return self.render_to_response('view', context)
|
||||
|
||||
def make_row_grid_tools(self, instance):
|
||||
pass
|
||||
def make_default_row_grid_tools(self, obj):
|
||||
if self.rows_creatable:
|
||||
link = tags.link_to("Create a new {}".format(self.get_row_model_title()),
|
||||
self.get_action_url('create_row', obj))
|
||||
return HTML.tag('p', c=link)
|
||||
|
||||
def make_row_grid_tools(self, obj):
|
||||
return self.make_default_row_grid_tools(obj)
|
||||
|
||||
def make_row_grid(self, **kwargs):
|
||||
"""
|
||||
|
@ -296,6 +303,8 @@ class MasterView(View):
|
|||
|
||||
@classmethod
|
||||
def get_row_model_title(cls):
|
||||
if hasattr(cls, 'row_model_title'):
|
||||
return cls.row_model_title
|
||||
return "{} Row".format(cls.get_model_title())
|
||||
|
||||
@classmethod
|
||||
|
@ -1022,6 +1031,40 @@ class MasterView(View):
|
|||
# Associated Rows Stuff
|
||||
##############################
|
||||
|
||||
def create_row(self):
|
||||
"""
|
||||
View for creating a new row record.
|
||||
"""
|
||||
self.creating = True
|
||||
parent = self.get_instance()
|
||||
index_url = self.get_action_url('view', parent)
|
||||
form = self.make_row_form(self.model_row_class, cancel_url=index_url)
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
self.before_create_row(form)
|
||||
self.save_create_row_form(form)
|
||||
obj = form.fieldset.model
|
||||
self.after_create_row(obj)
|
||||
return self.redirect_after_create_row(obj)
|
||||
return self.render_to_response('create_row', {
|
||||
'index_url': index_url,
|
||||
'index_title': '{} {}'.format(
|
||||
self.get_model_title(),
|
||||
self.get_instance_title(parent)),
|
||||
'form': form})
|
||||
|
||||
def save_create_row_form(self, form):
|
||||
self.save_row_form(form)
|
||||
|
||||
def before_create_row(self, form):
|
||||
pass
|
||||
|
||||
def after_create_row(self, row_object):
|
||||
pass
|
||||
|
||||
def redirect_after_create_row(self, row):
|
||||
return self.redirect(self.get_action_url('view', self.get_parent(row)))
|
||||
|
||||
def view_row(self):
|
||||
"""
|
||||
View for viewing details of a single data row.
|
||||
|
@ -1061,6 +1104,7 @@ class MasterView(View):
|
|||
parent = self.get_parent(row)
|
||||
return self.render_to_response('edit_row', {
|
||||
'instance': row,
|
||||
'row_parent': parent,
|
||||
'instance_title': self.get_row_instance_title(row),
|
||||
'instance_deletable': self.row_deletable(row),
|
||||
'index_url': self.get_action_url('view', parent),
|
||||
|
@ -1138,10 +1182,11 @@ class MasterView(View):
|
|||
self.configure_row_fieldset(fieldset)
|
||||
|
||||
kwargs.setdefault('action_url', self.request.current_route_url(_query=None))
|
||||
if 'cancel_url' not in kwargs:
|
||||
if self.creating:
|
||||
kwargs.setdefault('cancel_url', self.get_action_url('view', self.get_parent(instance)))
|
||||
kwargs['cancel_url'] = self.get_action_url('view', self.get_parent(instance))
|
||||
else:
|
||||
kwargs.setdefault('cancel_url', self.get_row_action_url('view', instance))
|
||||
kwargs['cancel_url'] = self.get_row_action_url('view', instance)
|
||||
|
||||
form = forms.AlchemyForm(self.request, fieldset, **kwargs)
|
||||
form.readonly = self.viewing
|
||||
|
@ -1253,6 +1298,14 @@ class MasterView(View):
|
|||
|
||||
### sub-rows stuff follows
|
||||
|
||||
# create row
|
||||
if cls.has_rows and cls.rows_creatable:
|
||||
config.add_route('{}.create_row'.format(route_prefix), '{}/{{{}}}/new-row'.format(url_prefix, model_key))
|
||||
config.add_view(cls, attr='create_row', route_name='{}.create_row'.format(route_prefix),
|
||||
permission='{}.create_row'.format(permission_prefix))
|
||||
config.add_tailbone_permission(permission_prefix, '{}.create_row'.format(permission_prefix),
|
||||
"Create new {} rows".format(model_title))
|
||||
|
||||
# view row
|
||||
if cls.has_rows and cls.rows_viewable:
|
||||
config.add_route('{}.view'.format(row_route_prefix), '{}/{{uuid}}'.format(row_url_prefix))
|
||||
|
|
32
tailbone/views/purchases/__init__.py
Normal file
32
tailbone/views/purchases/__init__.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2016 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Views for purchase orders
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
|
||||
def includeme(config):
|
||||
config.include('tailbone.views.purchases.core')
|
||||
config.include('tailbone.views.purchases.batch')
|
232
tailbone/views/purchases/batch.py
Normal file
232
tailbone/views/purchases/batch.py
Normal file
|
@ -0,0 +1,232 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2016 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Views for purchase order batches
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from rattail.db import model, api
|
||||
from rattail.gpc import GPC
|
||||
from rattail.db.batch.purchase.handler import PurchaseBatchHandler
|
||||
from rattail.time import localtime
|
||||
|
||||
import formalchemy as fa
|
||||
|
||||
from tailbone import forms
|
||||
from tailbone.db import Session
|
||||
from tailbone.views.batch import BatchMasterView
|
||||
|
||||
|
||||
class PurchaseBatchView(BatchMasterView):
|
||||
"""
|
||||
Master view for purchase order batches.
|
||||
"""
|
||||
model_class = model.PurchaseBatch
|
||||
model_title_plural = "Purchase Batches"
|
||||
model_row_class = model.PurchaseBatchRow
|
||||
batch_handler_class = PurchaseBatchHandler
|
||||
route_prefix = 'purchases.batch'
|
||||
url_prefix = '/purchases/batches'
|
||||
rows_creatable = True
|
||||
rows_editable = True
|
||||
|
||||
def _preconfigure_grid(self, g):
|
||||
super(PurchaseBatchView, self)._preconfigure_grid(g)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
g.date_ordered.set(label="Ordered")
|
||||
|
||||
def configure_grid(self, g):
|
||||
g.configure(
|
||||
include=[
|
||||
g.id,
|
||||
g.vendor,
|
||||
g.buyer,
|
||||
g.date_ordered,
|
||||
g.created,
|
||||
g.created_by,
|
||||
g.executed,
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
def _preconfigure_fieldset(self, fs):
|
||||
super(PurchaseBatchView, self)._preconfigure_fieldset(fs)
|
||||
fs.po_number.set(label="PO Number")
|
||||
fs.po_total.set(label="PO Total")
|
||||
|
||||
def configure_fieldset(self, fs):
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.store,
|
||||
fs.vendor.with_renderer(forms.renderers.VendorFieldRenderer),
|
||||
fs.buyer.with_renderer(forms.renderers.EmployeeFieldRenderer),
|
||||
fs.date_ordered,
|
||||
fs.po_number,
|
||||
fs.po_total,
|
||||
fs.created,
|
||||
fs.created_by,
|
||||
fs.executed,
|
||||
fs.executed_by,
|
||||
])
|
||||
|
||||
if self.creating:
|
||||
del fs.po_total
|
||||
|
||||
# default store may be configured
|
||||
store = self.rattail_config.get('rattail', 'store')
|
||||
if store:
|
||||
store = api.get_store(Session(), store)
|
||||
if store:
|
||||
fs.model.store = store
|
||||
|
||||
# default buyer is current user
|
||||
if self.request.method != 'POST':
|
||||
buyer = self.request.user.employee
|
||||
if buyer:
|
||||
fs.model.buyer = buyer
|
||||
|
||||
# default order date is today
|
||||
fs.model.date_ordered = localtime(self.rattail_config).date()
|
||||
|
||||
def _preconfigure_row_grid(self, g):
|
||||
super(PurchaseBatchView, self)._preconfigure_row_grid(g)
|
||||
|
||||
g.filters['upc'].label = "UPC"
|
||||
g.filters['brand_name'].label = "Brand"
|
||||
|
||||
g.upc.set(label="UPC")
|
||||
g.brand_name.set(label="Brand")
|
||||
g.cases_ordered.set(label="Cases")
|
||||
g.units_ordered.set(label="Units")
|
||||
g.po_total.set(label="Total")
|
||||
|
||||
def configure_row_grid(self, g):
|
||||
g.configure(
|
||||
include=[
|
||||
g.sequence,
|
||||
g.upc,
|
||||
g.brand_name,
|
||||
g.description,
|
||||
g.size,
|
||||
g.cases_ordered,
|
||||
g.units_ordered,
|
||||
g.po_total,
|
||||
g.status_code,
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
def make_row_grid_tools(self, batch):
|
||||
return self.make_default_row_grid_tools(batch)
|
||||
|
||||
# def row_grid_row_attrs(self, row, i):
|
||||
# attrs = {}
|
||||
# if row.status_code in (row.STATUS_NOT_IN_PURCHASE,
|
||||
# row.STATUS_NOT_IN_INVOICE,
|
||||
# row.STATUS_DIFFERS_FROM_PURCHASE):
|
||||
# attrs['class_'] = 'notice'
|
||||
# if row.status_code in (row.STATUS_NOT_IN_DB,
|
||||
# row.STATUS_COST_NOT_IN_DB,
|
||||
# row.STATUS_NO_CASE_QUANTITY):
|
||||
# attrs['class_'] = 'warning'
|
||||
# return attrs
|
||||
|
||||
def _preconfigure_row_fieldset(self, fs):
|
||||
super(PurchaseBatchView, self)._preconfigure_row_fieldset(fs)
|
||||
fs.upc.set(label="UPC")
|
||||
fs.brand_name.set(label="Brand")
|
||||
fs.po_unit_cost.set(label="PO Unit Cost")
|
||||
fs.po_total.set(label="PO Total")
|
||||
fs.append(fa.Field('item_lookup', label="Item Lookup Code", required=True,
|
||||
validate=self.item_lookup))
|
||||
|
||||
def item_lookup(self, value, field=None):
|
||||
"""
|
||||
Try to locate a single product using ``value`` as a lookup code.
|
||||
"""
|
||||
batch = self.get_instance()
|
||||
product = api.get_product_by_vendor_code(Session(), value, vendor=batch.vendor)
|
||||
if product:
|
||||
return product.uuid
|
||||
if value.isdigit():
|
||||
product = api.get_product_by_upc(Session(), GPC(value))
|
||||
if not product:
|
||||
product = api.get_product_by_upc(Session(), GPC(value, calc_check_digit='upc'))
|
||||
if product:
|
||||
if not product.cost_for_vendor(batch.vendor):
|
||||
raise fa.ValidationError("Product {} exists but has no cost for vendor {}".format(
|
||||
product.upc.pretty(), batch.vendor))
|
||||
return product.uuid
|
||||
raise fa.ValidationError("Product not found")
|
||||
|
||||
def configure_row_fieldset(self, fs):
|
||||
|
||||
if self.creating:
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.item_lookup,
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
])
|
||||
|
||||
elif self.editing:
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.upc.readonly(),
|
||||
fs.product.readonly(),
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
])
|
||||
|
||||
def before_create_row(self, form):
|
||||
row = form.fieldset.model
|
||||
batch = self.get_instance()
|
||||
row.sequence = max([0] + [r.sequence for r in batch.data_rows]) + 1
|
||||
row.batch = batch
|
||||
# TODO: this seems heavy-handed but works..
|
||||
row.product_uuid = self.item_lookup(form.fieldset.item_lookup.value)
|
||||
|
||||
def after_create_row(self, row):
|
||||
self.handler.refresh_row(row)
|
||||
|
||||
def redirect_after_create_row(self, row):
|
||||
self.request.session.flash("Added item: {} {}".format(row.upc.pretty(), row.product))
|
||||
return self.redirect(self.request.current_route_url())
|
||||
|
||||
# TODO: redirect to new purchase...
|
||||
# def get_execute_success_url(self, batch, result, **kwargs):
|
||||
# # return self.get_action_url('view', batch)
|
||||
# return
|
||||
|
||||
|
||||
def includeme(config):
|
||||
PurchaseBatchView.defaults(config)
|
163
tailbone/views/purchases/core.py
Normal file
163
tailbone/views/purchases/core.py
Normal file
|
@ -0,0 +1,163 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2016 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Views for "true" purchase orders
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from rattail import enum
|
||||
from rattail.db import model
|
||||
|
||||
import formalchemy as fa
|
||||
|
||||
from tailbone import forms
|
||||
from tailbone.db import Session
|
||||
from tailbone.views import MasterView
|
||||
|
||||
|
||||
class PurchaseView(MasterView):
|
||||
"""
|
||||
Master view for purchase orders.
|
||||
"""
|
||||
model_class = model.Purchase
|
||||
creatable = False
|
||||
editable = False
|
||||
|
||||
has_rows = True
|
||||
model_row_class = model.PurchaseItem
|
||||
row_model_title = 'Purchase Item'
|
||||
|
||||
def _preconfigure_grid(self, g):
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
g.filters['date_ordered'].label = "Ordered"
|
||||
g.filters['date_ordered'].default_active = True
|
||||
g.filters['date_ordered'].default_verb = 'equal'
|
||||
|
||||
g.default_sortkey = 'date_ordered'
|
||||
g.default_sortdir = 'desc'
|
||||
|
||||
g.date_ordered.set(label="Ordered")
|
||||
g.status.set(renderer=forms.renderers.EnumFieldRenderer(enum.PURCHASE_STATUS))
|
||||
|
||||
def configure_grid(self, g):
|
||||
g.configure(
|
||||
include=[
|
||||
g.store,
|
||||
g.vendor,
|
||||
g.buyer,
|
||||
g.date_ordered,
|
||||
g.status,
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
def _preconfigure_fieldset(self, fs):
|
||||
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer)
|
||||
fs.status.set(renderer=forms.renderers.EnumFieldRenderer(enum.PURCHASE_STATUS),
|
||||
readonly=True)
|
||||
fs.po_number.set(label="PO Number")
|
||||
fs.po_total.set(label="PO Total")
|
||||
|
||||
def configure_fieldset(self, fs):
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.store,
|
||||
fs.vendor,
|
||||
fs.buyer,
|
||||
fs.date_ordered,
|
||||
fs.po_number,
|
||||
fs.po_total,
|
||||
fs.status,
|
||||
fs.created,
|
||||
fs.created_by,
|
||||
])
|
||||
|
||||
def get_parent(self, item):
|
||||
return item.purchase
|
||||
|
||||
def get_row_data(self, purchase):
|
||||
return Session.query(model.PurchaseItem)\
|
||||
.filter(model.PurchaseItem.purchase == purchase)
|
||||
|
||||
def _preconfigure_row_grid(self, g):
|
||||
g.default_sortkey = 'sequence'
|
||||
g.sequence.set(label="Seq")
|
||||
g.upc.set(label="UPC")
|
||||
g.brand_name.set(label="Brand")
|
||||
g.cases_ordered.set(label="Cases")
|
||||
g.units_ordered.set(label="Units")
|
||||
g.po_total.set(label="PO Total")
|
||||
|
||||
def configure_row_grid(self, g):
|
||||
g.configure(
|
||||
include=[
|
||||
g.sequence,
|
||||
g.upc,
|
||||
g.brand_name,
|
||||
g.description,
|
||||
g.size,
|
||||
g.cases_ordered,
|
||||
g.units_ordered,
|
||||
g.po_total,
|
||||
],
|
||||
readonly=True)
|
||||
|
||||
def _preconfigure_row_fieldset(self, fs):
|
||||
fs.vendor_code.set(label="Vendor Item Code")
|
||||
fs.upc.set(label="UPC")
|
||||
fs.po_unit_cost.set(label="PO Unit Cost")
|
||||
fs.po_total.set(label="PO Total")
|
||||
fs.append(fa.Field('department', value=lambda i: '{} {}'.format(i.department_number, i.department_name)))
|
||||
|
||||
def configure_row_fieldset(self, fs):
|
||||
|
||||
fs.configure(
|
||||
include=[
|
||||
fs.sequence,
|
||||
fs.vendor_code,
|
||||
fs.upc,
|
||||
fs.product,
|
||||
fs.department,
|
||||
fs.case_quantity,
|
||||
fs.cases_ordered,
|
||||
fs.units_ordered,
|
||||
fs.po_unit_cost,
|
||||
fs.po_total,
|
||||
])
|
||||
|
||||
|
||||
def includeme(config):
|
||||
PurchaseView.defaults(config)
|
Loading…
Reference in a new issue