Add support for 'department' field in purchases / batches

Also fix logic for deleting a purchase (delete its batches first)
This commit is contained in:
Lance Edgar 2016-12-09 14:01:06 -06:00
parent 6c3d221e98
commit c73ba56505
6 changed files with 62 additions and 13 deletions

View file

@ -43,8 +43,8 @@ from .users import UserFieldRenderer, PermissionsFieldRenderer
from .employees import EmployeeFieldRenderer
from .products import (ProductFieldRenderer, GPCFieldRenderer, BrandFieldRenderer,
PriceFieldRenderer, PriceWithExpirationFieldRenderer)
from .products import (GPCFieldRenderer, DepartmentFieldRenderer, BrandFieldRenderer,
ProductFieldRenderer, PriceFieldRenderer, PriceWithExpirationFieldRenderer)
from .stores import StoreFieldRenderer

View file

@ -83,11 +83,16 @@ class DepartmentFieldRenderer(SelectFieldRenderer):
"""
Shows the department number as well as the name.
"""
def render_readonly(self, **kwargs):
dept = self.raw_value
if dept:
return "{0} - {1}".format(dept.number, dept.name)
return ""
department = self.raw_value
if not department:
return ''
if department.number:
text = '{} {}'.format(department.number, department.name)
else:
text = department.name
return tags.link_to(text, self.request.route_url('departments.view', uuid=department.uuid))
class SubdepartmentFieldRenderer(SelectFieldRenderer):

View file

@ -9,6 +9,7 @@
if (mode == ${enum.PURCHASE_BATCH_MODE_NEW}) {
$('.field-wrapper.store_uuid').show();
$('.field-wrapper.purchase_uuid').hide();
$('.field-wrapper.department_uuid').show();
$('.field-wrapper.buyer_uuid').show();
$('.field-wrapper.date_ordered').show();
$('.field-wrapper.date_received').hide();
@ -17,6 +18,7 @@
} else if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING}) {
$('.field-wrapper.store_uuid').hide();
$('.field-wrapper.purchase_uuid').show();
$('.field-wrapper.department_uuid').hide();
$('.field-wrapper.buyer_uuid').hide();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').show();
@ -25,6 +27,7 @@
} else if (mode == ${enum.PURCHASE_BATCH_MODE_COSTING}) {
$('.field-wrapper.store_uuid').hide();
$('.field-wrapper.purchase_uuid').show();
$('.field-wrapper.department_uuid').hide();
$('.field-wrapper.buyer_uuid').hide();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').hide();
@ -76,6 +79,7 @@
});
$('.field-wrapper.purchase_uuid select').selectmenu();
$('.field-wrapper.department_uuid select').selectmenu();
show_mode(${form.fieldset.model.mode or enum.PURCHASE_BATCH_MODE_NEW});

View file

@ -526,7 +526,12 @@ class MasterView(View):
Return a "humanized" (and plural) version of the model name, for
display in templates.
"""
return getattr(cls, 'model_title_plural', '{0}s'.format(cls.get_model_title()))
if hasattr(cls, 'model_title_plural'):
return cls.model_title_plural
try:
return cls.get_model_class().get_model_title_plural()
except (NotImplementedError, AttributeError):
return '{}s'.format(cls.get_model_title())
@classmethod
def get_route_prefix(cls):

View file

@ -31,7 +31,7 @@ import logging
from sqlalchemy import orm
from rattail import enum, pod
from rattail import pod
from rattail.db import model, api
from rattail.gpc import GPC
from rattail.time import localtime
@ -67,7 +67,6 @@ class PurchaseBatchView(BatchMasterView):
Master view for purchase order batches.
"""
model_class = model.PurchaseBatch
model_title_plural = "Purchase Batches"
model_row_class = model.PurchaseBatchRow
default_handler_spec = 'rattail.batch.purchase:PurchaseBatchHandler'
route_prefix = 'purchases.batch'
@ -87,6 +86,10 @@ class PurchaseBatchView(BatchMasterView):
default_active=True, default_verb='contains')
g.sorters['vendor'] = g.make_sorter(model.Vendor.name)
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)
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')
@ -106,6 +109,7 @@ class PurchaseBatchView(BatchMasterView):
g.id,
g.mode,
g.vendor,
g.department,
g.buyer,
g.date_ordered,
g.created,
@ -121,6 +125,8 @@ class PurchaseBatchView(BatchMasterView):
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer,
attrs={'selected': 'vendor_selected',
'cleared': 'vendor_cleared'})
fs.department.set(renderer=forms.renderers.DepartmentFieldRenderer,
options=self.get_department_options())
fs.buyer.set(renderer=forms.renderers.EmployeeFieldRenderer)
fs.po_number.set(label="PO Number")
fs.po_total.set(label="PO Total", readonly=True, renderer=forms.renderers.CurrencyFieldRenderer)
@ -135,6 +141,10 @@ class PurchaseBatchView(BatchMasterView):
fs.append(fa.Field('vendor_phone', readonly=True,
value=self.get_vendor_phone_number))
def get_department_options(self):
departments = Session.query(model.Department).order_by(model.Department.number)
return [('{} {}'.format(d.number, d.name), d.uuid) for d in departments]
def get_vendor_phone_number(self, batch):
for phone in batch.vendor.phones:
if phone.type == 'Voice':
@ -152,6 +162,7 @@ class PurchaseBatchView(BatchMasterView):
fs.mode,
fs.store,
fs.vendor,
fs.department,
fs.purchase,
fs.vendor_email,
fs.vendor_fax,
@ -208,6 +219,7 @@ class PurchaseBatchView(BatchMasterView):
fs.mode.set(readonly=True)
fs.store.set(readonly=True)
fs.vendor.set(readonly=True)
fs.department.set(readonly=True)
fs.purchase.set(readonly=True)
def eligible_purchases(self):
@ -223,10 +235,10 @@ class PurchaseBatchView(BatchMasterView):
purchases = Session.query(model.Purchase)\
.filter(model.Purchase.vendor == vendor)
if mode == enum.PURCHASE_BATCH_MODE_RECEIVING:
if mode == self.enum.PURCHASE_BATCH_MODE_RECEIVING:
purchases = purchases.filter(model.Purchase.status == self.enum.PURCHASE_STATUS_ORDERED)\
.order_by(model.Purchase.date_ordered, model.Purchase.created)
elif mode == enum.PURCHASE_BATCH_MODE_COSTING:
elif mode == self.enum.PURCHASE_BATCH_MODE_COSTING:
purchases = purchases.filter(model.Purchase.status == self.enum.PURCHASE_STATUS_RECEIVED)\
.order_by(model.Purchase.date_received, model.Purchase.created)
@ -240,7 +252,7 @@ class PurchaseBatchView(BatchMasterView):
elif purchase.status == self.enum.PURCHASE_STATUS_RECEIVED:
date = purchase.date_received
total = purchase.invoice_total
return '{} for ${:0,.2f} ({})'.format(date, total, purchase.buyer)
return '{} for ${:0,.2f} ({})'.format(date, total, purchase.department or purchase.buyer)
def get_batch_kwargs(self, batch):
kwargs = super(PurchaseBatchView, self).get_batch_kwargs(batch)
@ -253,6 +265,10 @@ class PurchaseBatchView(BatchMasterView):
kwargs['vendor'] = batch.vendor
elif batch.vendor_uuid:
kwargs['vendor_uuid'] = batch.vendor_uuid
if batch.department:
kwargs['department'] = batch.department
elif batch.department_uuid:
kwargs['department_uuid'] = batch.department_uuid
if batch.buyer:
kwargs['buyer'] = batch.buyer
elif batch.buyer_uuid:
@ -274,6 +290,8 @@ class PurchaseBatchView(BatchMasterView):
purchase = Session.query(model.Purchase).get(batch.purchase_uuid)
assert purchase
kwargs['purchase'] = purchase
kwargs['buyer'] = purchase.buyer
kwargs['buyer_uuid'] = purchase.buyer_uuid
kwargs['date_ordered'] = purchase.date_ordered
kwargs['po_total'] = purchase.po_total
@ -510,7 +528,7 @@ class PurchaseBatchView(BatchMasterView):
history = OrderedDict()
purchases = Session.query(model.Purchase)\
.filter(model.Purchase.vendor == batch.vendor)\
.filter(model.Purchase.status >= enum.PURCHASE_STATUS_ORDERED)\
.filter(model.Purchase.status >= self.enum.PURCHASE_STATUS_ORDERED)\
.order_by(model.Purchase.date_ordered.desc(), model.Purchase.created.desc())\
.options(orm.joinedload(model.Purchase.items))[:6]
for purchase in purchases[:6]:

View file

@ -100,6 +100,10 @@ class PurchaseView(MasterView):
default_active=True, default_verb='contains')
g.sorters['vendor'] = g.make_sorter(model.Vendor.name)
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)
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')
@ -121,6 +125,7 @@ class PurchaseView(MasterView):
include=[
g.store,
g.vendor,
g.department,
g.buyer,
g.date_ordered,
g.date_received,
@ -130,6 +135,7 @@ class PurchaseView(MasterView):
def _preconfigure_fieldset(self, fs):
fs.vendor.set(renderer=forms.renderers.VendorFieldRenderer)
fs.department.set(renderer=forms.renderers.DepartmentFieldRenderer)
fs.status.set(renderer=forms.renderers.EnumFieldRenderer(self.enum.PURCHASE_STATUS),
readonly=True)
fs.po_number.set(label="PO Number")
@ -142,6 +148,7 @@ class PurchaseView(MasterView):
include=[
fs.store,
fs.vendor,
fs.department,
fs.status,
fs.buyer,
fs.date_ordered,
@ -162,6 +169,16 @@ class PurchaseView(MasterView):
del fs.invoice_number
del fs.invoice_total
def delete_instance(self, purchase):
"""
Delete all batches for the purchase, then delete the purchase.
"""
for batch in list(purchase.batches):
self.Session.delete(batch)
self.Session.flush()
self.Session.delete(purchase)
self.Session.flush()
def get_parent(self, item):
return item.purchase