Refactor "receive row" and "declare credit" tools per buefy theme
This commit is contained in:
parent
ae76ceea04
commit
10e34b83ed
|
@ -118,11 +118,7 @@ class ReceivingBatchViews(APIBatchView):
|
||||||
return {'purchases': purchases}
|
return {'purchases': purchases}
|
||||||
|
|
||||||
def normalize_eligible_purchase(self, purchase):
|
def normalize_eligible_purchase(self, purchase):
|
||||||
return {
|
return self.handler.normalize_eligible_purchase(purchase)
|
||||||
'key': purchase.uuid,
|
|
||||||
'department_uuid': purchase.department_uuid,
|
|
||||||
'display': self.render_eligible_purchase(purchase),
|
|
||||||
}
|
|
||||||
|
|
||||||
def render_eligible_purchase(self, purchase):
|
def render_eligible_purchase(self, purchase):
|
||||||
return self.handler.render_eligible_purchase(purchase)
|
return self.handler.render_eligible_purchase(purchase)
|
||||||
|
|
|
@ -343,8 +343,9 @@ class Form(object):
|
||||||
model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={},
|
model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={},
|
||||||
assume_local_times=False, renderers=None,
|
assume_local_times=False, renderers=None,
|
||||||
hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None,
|
hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None,
|
||||||
action_url=None, cancel_url=None, use_buefy=None, component='tailbone-form'):
|
action_url=None, cancel_url=None, use_buefy=None, component='tailbone-form',
|
||||||
|
vuejs_field_converters={},
|
||||||
|
):
|
||||||
self.fields = None
|
self.fields = None
|
||||||
if fields is not None:
|
if fields is not None:
|
||||||
self.set_fields(fields)
|
self.set_fields(fields)
|
||||||
|
@ -380,6 +381,7 @@ class Form(object):
|
||||||
self.cancel_url = cancel_url
|
self.cancel_url = cancel_url
|
||||||
self.use_buefy = use_buefy
|
self.use_buefy = use_buefy
|
||||||
self.component = component
|
self.component = component
|
||||||
|
self.vuejs_field_converters = vuejs_field_converters or {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def component_studly(self):
|
def component_studly(self):
|
||||||
|
@ -702,6 +704,9 @@ class Form(object):
|
||||||
"""
|
"""
|
||||||
return self.helptext[key]
|
return self.helptext[key]
|
||||||
|
|
||||||
|
def set_vuejs_field_converter(self, field, converter):
|
||||||
|
self.vuejs_field_converters[field] = converter
|
||||||
|
|
||||||
def render(self, template=None, **kwargs):
|
def render(self, template=None, **kwargs):
|
||||||
if not template:
|
if not template:
|
||||||
if self.readonly and not self.use_buefy:
|
if self.readonly and not self.use_buefy:
|
||||||
|
@ -788,6 +793,11 @@ class Form(object):
|
||||||
model value for the given field. This JS will be written as part of
|
model value for the given field. This JS will be written as part of
|
||||||
the overall response, to be interpreted on the client side.
|
the overall response, to be interpreted on the client side.
|
||||||
"""
|
"""
|
||||||
|
if field.name in self.vuejs_field_converters:
|
||||||
|
convert = self.vuejs_field_converters[field.name]
|
||||||
|
value = convert(field.cstruct)
|
||||||
|
return json.dumps(value)
|
||||||
|
|
||||||
if isinstance(field.schema.typ, deform.FileData):
|
if isinstance(field.schema.typ, deform.FileData):
|
||||||
# TODO: we used to always/only return 'null' here but hopefully
|
# TODO: we used to always/only return 'null' here but hopefully
|
||||||
# this also works, to show existing filename when present
|
# this also works, to show existing filename when present
|
||||||
|
@ -807,6 +817,16 @@ class Form(object):
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
raise TailboneJSONFieldError(field.name, error)
|
raise TailboneJSONFieldError(field.name, error)
|
||||||
|
|
||||||
|
def get_error_messages(self, field):
|
||||||
|
if field.error:
|
||||||
|
return field.error.messages()
|
||||||
|
|
||||||
|
error = self.make_deform_form().error
|
||||||
|
if error:
|
||||||
|
if isinstance(error, colander.Invalid):
|
||||||
|
if error.node.name == field.name:
|
||||||
|
return error.messages()
|
||||||
|
|
||||||
def messages_json(self, messages):
|
def messages_json(self, messages):
|
||||||
dump = json.dumps(messages)
|
dump = json.dumps(messages)
|
||||||
dump = dump.replace("'", ''')
|
dump = dump.replace("'", ''')
|
||||||
|
|
|
@ -1,29 +1,58 @@
|
||||||
<!--! -*- mode: html; -*- -->
|
<!--! -*- mode: html; -*- -->
|
||||||
<div tal:define="oid oid|field.oid;
|
<div tal:define="oid oid|field.oid;
|
||||||
|
name name|field.name;
|
||||||
css_class css_class|field.widget.css_class;
|
css_class css_class|field.widget.css_class;
|
||||||
style style|field.widget.style;"
|
style style|field.widget.style;
|
||||||
|
use_buefy use_buefy|0;"
|
||||||
i18n:domain="deform"
|
i18n:domain="deform"
|
||||||
tal:omit-tag="">
|
tal:omit-tag="">
|
||||||
${field.start_mapping()}
|
|
||||||
<div>
|
<div tal:condition="not use_buefy" tal:omit-tag="">
|
||||||
<input type="text" name="cases" value="${cases}"
|
${field.start_mapping()}
|
||||||
tal:attributes="style style;
|
<div>
|
||||||
class string: form-control ${css_class or ''};
|
<input type="text" name="cases" value="${cases}"
|
||||||
cases_attributes|field.widget.cases_attributes|{};"
|
tal:attributes="style style;
|
||||||
placeholder="cases"
|
class string: form-control ${css_class or ''};
|
||||||
autocomplete="off"
|
cases_attributes|field.widget.cases_attributes|{};"
|
||||||
id="${oid}-cases"/>
|
placeholder="cases"
|
||||||
Cases
|
autocomplete="off"
|
||||||
|
id="${oid}-cases"/>
|
||||||
|
Cases
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input type="text" name="units" value="${units}"
|
||||||
|
tal:attributes="class string: form-control ${css_class or ''};
|
||||||
|
style style;
|
||||||
|
units_attributes|field.widget.units_attributes|{};"
|
||||||
|
placeholder="units"
|
||||||
|
autocomplete="off"
|
||||||
|
id="${oid}-units"/>
|
||||||
|
Units
|
||||||
|
</div>
|
||||||
|
${field.end_mapping()}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<input type="text" name="units" value="${units}"
|
<div tal:condition="use_buefy"
|
||||||
tal:attributes="class string: form-control ${css_class or ''};
|
tal:define="vmodel vmodel|'field_model_' + name;"
|
||||||
style style;
|
tal:omit-tag="">
|
||||||
units_attributes|field.widget.units_attributes|{};"
|
|
||||||
placeholder="units"
|
${field.start_mapping()}
|
||||||
autocomplete="off"
|
|
||||||
id="${oid}-units"/>
|
<b-field label="Cases">
|
||||||
Units
|
<b-input name="cases" autocomplete="off"
|
||||||
|
tal:attributes="v-model string: ${vmodel + '.cases'};
|
||||||
|
cases_attributes|field.widget.cases_attributes|{};">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units">
|
||||||
|
<b-input name="units" autocomplete="off"
|
||||||
|
tal:attributes="v-model string: ${vmodel + '.units'};
|
||||||
|
units_attributes|field.widget.units_attributes|{};">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
${field.end_mapping()}
|
||||||
</div>
|
</div>
|
||||||
${field.end_mapping()}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
|
<%namespace file="/forms/util.mako" import="render_buefy_field" />
|
||||||
|
|
||||||
<script type="text/x-template" id="${form.component}-template">
|
<script type="text/x-template" id="${form.component}-template">
|
||||||
|
|
||||||
|
@ -9,6 +10,9 @@
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
% if form_body is not Undefined and form_body:
|
||||||
|
${form_body|n}
|
||||||
|
% else:
|
||||||
% for field in form.fields:
|
% for field in form.fields:
|
||||||
% if form.readonly or (field not in dform and field in form.readonly_fields):
|
% if form.readonly or (field not in dform and field in form.readonly_fields):
|
||||||
<b-field horizontal
|
<b-field horizontal
|
||||||
|
@ -17,29 +21,11 @@
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
% elif field in dform:
|
% elif field in dform:
|
||||||
<% field = dform[field] %>
|
${render_buefy_field(dform[field])}
|
||||||
|
|
||||||
% if form.field_visible(field.name):
|
|
||||||
<b-field horizontal
|
|
||||||
label="${form.get_label(field.name)}"
|
|
||||||
## TODO: is this class="file" really needed?
|
|
||||||
% if isinstance(field.schema.typ, deform.FileData):
|
|
||||||
class="file"
|
|
||||||
% endif
|
|
||||||
% if field.error:
|
|
||||||
type="is-danger"
|
|
||||||
:message='${form.messages_json(field.error.messages())|n}'
|
|
||||||
% endif
|
|
||||||
>
|
|
||||||
${field.serialize(use_buefy=True)|n}
|
|
||||||
</b-field>
|
|
||||||
% else:
|
|
||||||
## hidden field
|
|
||||||
${field.serialize()|n}
|
|
||||||
% endif
|
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% endfor
|
% endfor
|
||||||
|
% endif
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
% if buttons:
|
% if buttons:
|
||||||
|
@ -48,6 +34,20 @@
|
||||||
% elif not form.readonly and (buttons is Undefined or (buttons is not None and buttons is not False)):
|
% elif not form.readonly and (buttons is Undefined or (buttons is not None and buttons is not False)):
|
||||||
<br />
|
<br />
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
% if getattr(form, 'show_cancel', True):
|
||||||
|
% if form.auto_disable_cancel:
|
||||||
|
<once-button tag="a" href="${form.cancel_url or request.get_referrer()}"
|
||||||
|
text="Cancel">
|
||||||
|
</once-button>
|
||||||
|
% else:
|
||||||
|
<b-button tag="a" href="${form.cancel_url or request.get_referrer()}">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
% if getattr(form, 'show_reset', False):
|
||||||
|
<input type="reset" value="Reset" class="button" />
|
||||||
|
% endif
|
||||||
## TODO: deprecate / remove the latter option here
|
## TODO: deprecate / remove the latter option here
|
||||||
% if form.auto_disable_save or form.auto_disable:
|
% if form.auto_disable_save or form.auto_disable:
|
||||||
<b-button type="is-primary"
|
<b-button type="is-primary"
|
||||||
|
@ -61,20 +61,6 @@
|
||||||
${getattr(form, 'submit_label', getattr(form, 'save_label', "Submit"))}
|
${getattr(form, 'submit_label', getattr(form, 'save_label', "Submit"))}
|
||||||
</b-button>
|
</b-button>
|
||||||
% endif
|
% endif
|
||||||
% if getattr(form, 'show_reset', False):
|
|
||||||
<input type="reset" value="Reset" class="button" />
|
|
||||||
% endif
|
|
||||||
% if getattr(form, 'show_cancel', True):
|
|
||||||
% if form.auto_disable_cancel:
|
|
||||||
<once-button tag="a" href="${form.cancel_url or request.get_referrer()}"
|
|
||||||
text="Cancel">
|
|
||||||
</once-button>
|
|
||||||
% else:
|
|
||||||
<b-button tag="a" href="${form.cancel_url or request.get_referrer()}">
|
|
||||||
Cancel
|
|
||||||
</b-button>
|
|
||||||
% endif
|
|
||||||
% endif
|
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
|
24
tailbone/templates/forms/util.mako
Normal file
24
tailbone/templates/forms/util.mako
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
## -*- coding: utf-8; -*-
|
||||||
|
|
||||||
|
<%def name="render_buefy_field(field, bfield_kwargs={})">
|
||||||
|
% if form.field_visible(field.name):
|
||||||
|
<% error_messages = form.get_error_messages(field) %>
|
||||||
|
<b-field horizontal
|
||||||
|
label="${form.get_label(field.name)}"
|
||||||
|
## TODO: is this class="file" really needed?
|
||||||
|
% if isinstance(field.schema.typ, deform.FileData):
|
||||||
|
class="file"
|
||||||
|
% endif
|
||||||
|
% if error_messages:
|
||||||
|
type="is-danger"
|
||||||
|
:message='${form.messages_json(error_messages)|n}'
|
||||||
|
% endif
|
||||||
|
${h.HTML.render_attrs(bfield_kwargs)}
|
||||||
|
>
|
||||||
|
${field.serialize(use_buefy=True)|n}
|
||||||
|
</b-field>
|
||||||
|
% else:
|
||||||
|
## hidden field
|
||||||
|
${field.serialize()|n}
|
||||||
|
% endif
|
||||||
|
</%def>
|
|
@ -1,16 +1,19 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/base.mako" />
|
<%inherit file="/form.mako" />
|
||||||
|
<%namespace file="/forms/util.mako" import="render_buefy_field" />
|
||||||
|
|
||||||
<%def name="title()">Declare Credit for Row #${row.sequence}</%def>
|
<%def name="title()">Declare Credit for Row #${row.sequence}</%def>
|
||||||
|
|
||||||
<%def name="context_menu_items()">
|
<%def name="context_menu_items()">
|
||||||
% if master.rows_viewable and request.has_perm('{}.view'.format(permission_prefix)):
|
${parent.context_menu_items()}
|
||||||
|
% if master.rows_viewable and master.has_perm('view'):
|
||||||
<li>${h.link_to("View this {}".format(row_model_title), row_action_url('view', row))}</li>
|
<li>${h.link_to("View this {}".format(row_model_title), row_action_url('view', row))}</li>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="extra_javascript()">
|
<%def name="extra_javascript()">
|
||||||
${parent.extra_javascript()}
|
${parent.extra_javascript()}
|
||||||
|
% if not use_buefy:
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function toggleFields(creditType) {
|
function toggleFields(creditType) {
|
||||||
|
@ -34,11 +37,49 @@
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<div style="display: flex; justify-content: space-between;">
|
<%def name="render_buefy_form()">
|
||||||
|
|
||||||
<div class="form-wrapper">
|
<p class="block">
|
||||||
|
Please select the "state" of the product, and enter the
|
||||||
|
appropriate quantity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Note that this tool will
|
||||||
|
<span class="has-text-weight-bold">deduct</span> from the
|
||||||
|
"received" quantity, and
|
||||||
|
<span class="has-text-weight-bold">add</span> to the
|
||||||
|
corresponding credit quantity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Please see ${h.link_to("Receive Row", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
|
||||||
|
if you need to "receive" instead of "convert" the product.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
${parent.render_buefy_form()}
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="buefy_form_body()">
|
||||||
|
|
||||||
|
${render_buefy_field(dform['credit_type'])}
|
||||||
|
|
||||||
|
${render_buefy_field(dform['quantity'])}
|
||||||
|
|
||||||
|
${render_buefy_field(dform['expiration_date'], bfield_kwargs={'v-show': "field_model_credit_type == 'expired'"})}
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="render_form()">
|
||||||
|
% if use_buefy:
|
||||||
|
|
||||||
|
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
|
||||||
|
|
||||||
|
% else:
|
||||||
|
|
||||||
<p style="padding: 1em;">
|
<p style="padding: 1em;">
|
||||||
Please select the "state" of the product, and enter the appropriate
|
Please select the "state" of the product, and enter the appropriate
|
||||||
|
@ -55,11 +96,10 @@
|
||||||
if you need to "receive" instead of "convert" the product.
|
if you need to "receive" instead of "convert" the product.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
${form.render()|n}
|
${parent.render_form()}
|
||||||
</div><!-- form-wrapper -->
|
|
||||||
|
|
||||||
<ul id="context-menu">
|
% endif
|
||||||
${self.context_menu_items()}
|
</%def>
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
${parent.body()}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/base.mako" />
|
<%inherit file="/form.mako" />
|
||||||
|
<%namespace file="/forms/util.mako" import="render_buefy_field" />
|
||||||
|
|
||||||
<%def name="title()">Receive for Row #${row.sequence}</%def>
|
<%def name="title()">Receive for Row #${row.sequence}</%def>
|
||||||
|
|
||||||
<%def name="context_menu_items()">
|
<%def name="context_menu_items()">
|
||||||
% if master.rows_viewable and request.has_perm('{}.view'.format(permission_prefix)):
|
${parent.context_menu_items()}
|
||||||
|
% if master.rows_viewable and master.has_perm('view'):
|
||||||
<li>${h.link_to("View this {}".format(row_model_title), row_action_url('view', row))}</li>
|
<li>${h.link_to("View this {}".format(row_model_title), row_action_url('view', row))}</li>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="extra_javascript()">
|
<%def name="extra_javascript()">
|
||||||
${parent.extra_javascript()}
|
${parent.extra_javascript()}
|
||||||
|
% if not use_buefy:
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function toggleFields(mode) {
|
function toggleFields(mode) {
|
||||||
|
@ -34,11 +37,46 @@
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<div style="display: flex; justify-content: space-between;">
|
<%def name="render_buefy_form()">
|
||||||
|
|
||||||
<div class="form-wrapper">
|
<p class="block">
|
||||||
|
Please select the "state" of the product, and enter the appropriate
|
||||||
|
quantity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Note that this tool will <span class="has-text-weight-bold">add</span>
|
||||||
|
the corresponding quantities for the row.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Please see ${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
|
||||||
|
if you need to "convert" some already-received amount, into a credit.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
${parent.render_buefy_form()}
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="buefy_form_body()">
|
||||||
|
|
||||||
|
${render_buefy_field(dform['mode'])}
|
||||||
|
|
||||||
|
${render_buefy_field(dform['quantity'])}
|
||||||
|
|
||||||
|
${render_buefy_field(dform['expiration_date'], bfield_kwargs={'v-show': "field_model_mode == 'expired'"})}
|
||||||
|
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="render_form()">
|
||||||
|
% if use_buefy:
|
||||||
|
|
||||||
|
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
|
||||||
|
|
||||||
|
% else:
|
||||||
|
|
||||||
<p style="padding: 1em;">
|
<p style="padding: 1em;">
|
||||||
Please select the "state" of the product, and enter the appropriate
|
Please select the "state" of the product, and enter the appropriate
|
||||||
|
@ -55,11 +93,10 @@
|
||||||
if you need to "convert" some already-received amount, into a credit.
|
if you need to "convert" some already-received amount, into a credit.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
${form.render()|n}
|
${parent.render_form()}
|
||||||
</div><!-- form-wrapper -->
|
|
||||||
|
|
||||||
<ul id="context-menu">
|
% endif
|
||||||
${self.context_menu_items()}
|
</%def>
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
${parent.body()}
|
||||||
|
|
|
@ -8,8 +8,19 @@
|
||||||
<h3>Receiving Tools</h3>
|
<h3>Receiving Tools</h3>
|
||||||
<div class="object-helper-content">
|
<div class="object-helper-content">
|
||||||
<div style="white-space: nowrap;">
|
<div style="white-space: nowrap;">
|
||||||
|
% if use_buefy:
|
||||||
|
<once-button type="is-primary"
|
||||||
|
tag="a" href="${url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid)}"
|
||||||
|
text="Receive Product">
|
||||||
|
</once-button>
|
||||||
|
<once-button type="is-primary"
|
||||||
|
tag="a" href="${url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid)}"
|
||||||
|
text="Declare Credit">
|
||||||
|
</once-button>
|
||||||
|
% else:
|
||||||
${h.link_to("Receive Product", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
|
${h.link_to("Receive Product", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
|
||||||
${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
|
${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
|
||||||
|
% endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -637,6 +637,11 @@ class PurchasingBatchView(BatchMasterView):
|
||||||
g.set_label('catalog_unit_cost', "Catalog Cost")
|
g.set_label('catalog_unit_cost', "Catalog Cost")
|
||||||
g.filters['catalog_unit_cost'].label = "Catalog Unit Cost"
|
g.filters['catalog_unit_cost'].label = "Catalog Unit Cost"
|
||||||
|
|
||||||
|
# po_unit_cost
|
||||||
|
g.set_renderer('po_unit_cost', self.render_row_grid_cost)
|
||||||
|
g.set_label('po_unit_cost', "PO Cost")
|
||||||
|
g.filters['po_unit_cost'].label = "PO Unit Cost"
|
||||||
|
|
||||||
# invoice_unit_cost
|
# invoice_unit_cost
|
||||||
g.set_renderer('invoice_unit_cost', self.render_row_grid_cost)
|
g.set_renderer('invoice_unit_cost', self.render_row_grid_cost)
|
||||||
g.set_label('invoice_unit_cost', "Invoice Cost")
|
g.set_label('invoice_unit_cost', "Invoice Cost")
|
||||||
|
|
|
@ -144,6 +144,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
'cases_received',
|
'cases_received',
|
||||||
'units_received',
|
'units_received',
|
||||||
'catalog_unit_cost',
|
'catalog_unit_cost',
|
||||||
|
'po_unit_cost',
|
||||||
'invoice_unit_cost',
|
'invoice_unit_cost',
|
||||||
'invoice_total_calculated',
|
'invoice_total_calculated',
|
||||||
'credits',
|
'credits',
|
||||||
|
@ -152,6 +153,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
]
|
]
|
||||||
|
|
||||||
row_form_fields = [
|
row_form_fields = [
|
||||||
|
'sequence',
|
||||||
'item_entry',
|
'item_entry',
|
||||||
'upc',
|
'upc',
|
||||||
'item_id',
|
'item_id',
|
||||||
|
@ -487,6 +489,14 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('invoice_total_calculated')
|
f.remove('invoice_total_calculated')
|
||||||
|
|
||||||
|
# hide all invoice fields if batch does not have invoice file
|
||||||
|
if not self.creating and not self.handler.has_invoice_file(batch):
|
||||||
|
f.remove('invoice_file',
|
||||||
|
'invoice_date',
|
||||||
|
'invoice_number',
|
||||||
|
'invoice_total',
|
||||||
|
'invoice_total_calculated')
|
||||||
|
|
||||||
# receiving_complete
|
# receiving_complete
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.remove('receiving_complete')
|
f.remove('receiving_complete')
|
||||||
|
@ -506,8 +516,12 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
|
|
||||||
elif workflow == 'from_po':
|
elif workflow == 'from_po':
|
||||||
f.remove('truck_dump_batch_uuid',
|
f.remove('truck_dump_batch_uuid',
|
||||||
|
'date_ordered',
|
||||||
|
'po_number',
|
||||||
'invoice_file',
|
'invoice_file',
|
||||||
'invoice_parser_key')
|
'invoice_parser_key',
|
||||||
|
'invoice_date',
|
||||||
|
'invoice_number')
|
||||||
|
|
||||||
elif workflow == 'from_po_with_invoice':
|
elif workflow == 'from_po_with_invoice':
|
||||||
f.remove('truck_dump_batch_uuid')
|
f.remove('truck_dump_batch_uuid')
|
||||||
|
@ -736,11 +750,25 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(ReceivingBatchView, self).configure_row_grid(g)
|
super(ReceivingBatchView, self).configure_row_grid(g)
|
||||||
|
batch = self.get_instance()
|
||||||
|
|
||||||
# vendor_code
|
# vendor_code
|
||||||
g.filters['vendor_code'].default_active = True
|
g.filters['vendor_code'].default_active = True
|
||||||
g.filters['vendor_code'].default_verb = 'contains'
|
g.filters['vendor_code'].default_verb = 'contains'
|
||||||
|
|
||||||
|
# catalog_unit_cost
|
||||||
|
if (self.handler.has_purchase_order(batch)
|
||||||
|
or self.handler.has_invoice_file(batch)):
|
||||||
|
g.remove('catalog_unit_cost')
|
||||||
|
|
||||||
|
# po_unit_cost
|
||||||
|
if self.handler.has_invoice_file(batch):
|
||||||
|
g.remove('po_unit_cost')
|
||||||
|
|
||||||
|
# invoice_unit_cost
|
||||||
|
if not self.handler.has_invoice_file(batch):
|
||||||
|
g.remove('invoice_unit_cost')
|
||||||
|
|
||||||
# credits
|
# credits
|
||||||
# note that sorting by credits involves a subquery with group by clause.
|
# note that sorting by credits involves a subquery with group by clause.
|
||||||
# seems likely there may be a better way? but this seems to work fine
|
# seems likely there may be a better way? but this seems to work fine
|
||||||
|
@ -753,7 +781,6 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
|
|
||||||
# hide 'ordered' columns for truck dump parent, if its "children first"
|
# hide 'ordered' columns for truck dump parent, if its "children first"
|
||||||
# flag is set, since that batch type is only concerned with receiving
|
# flag is set, since that batch type is only concerned with receiving
|
||||||
batch = self.get_instance()
|
|
||||||
if batch.is_truck_dump_parent() and not batch.truck_dump_children_first:
|
if batch.is_truck_dump_parent() and not batch.truck_dump_children_first:
|
||||||
g.remove('cases_ordered',
|
g.remove('cases_ordered',
|
||||||
'units_ordered')
|
'units_ordered')
|
||||||
|
@ -788,6 +815,11 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
|
|
||||||
return css_class
|
return css_class
|
||||||
|
|
||||||
|
def get_row_instance_title(self, row):
|
||||||
|
if row.upc:
|
||||||
|
return row.upc.pretty()
|
||||||
|
return super(ReceivingBatchView, self).get_row_instance_title(row)
|
||||||
|
|
||||||
def transform_unit_url(self, row, i):
|
def transform_unit_url(self, row, i):
|
||||||
# grid action is shown only when we return a URL here
|
# grid action is shown only when we return a URL here
|
||||||
if self.row_editable(row):
|
if self.row_editable(row):
|
||||||
|
@ -795,6 +827,18 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
if row.product and row.product.is_pack_item():
|
if row.product and row.product.is_pack_item():
|
||||||
return self.get_row_action_url('transform_unit', row)
|
return self.get_row_action_url('transform_unit', row)
|
||||||
|
|
||||||
|
def vuejs_convert_quantity(self, cstruct):
|
||||||
|
result = dict(cstruct)
|
||||||
|
if result['cases'] is colander.null:
|
||||||
|
result['cases'] = None
|
||||||
|
elif isinstance(result['cases'], decimal.Decimal):
|
||||||
|
result['cases'] = float(result['cases'])
|
||||||
|
if result['units'] is colander.null:
|
||||||
|
result['units'] = None
|
||||||
|
elif isinstance(result['units'], decimal.Decimal):
|
||||||
|
result['units'] = float(result['units'])
|
||||||
|
return result
|
||||||
|
|
||||||
def receive_row(self, **kwargs):
|
def receive_row(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Primary desktop view for row-level receiving.
|
Primary desktop view for row-level receiving.
|
||||||
|
@ -830,14 +874,24 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
schema = ReceiveRowForm().bind(session=self.Session())
|
schema = ReceiveRowForm().bind(session=self.Session())
|
||||||
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
|
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
|
||||||
form.cancel_url = self.get_row_action_url('view', row)
|
form.cancel_url = self.get_row_action_url('view', row)
|
||||||
|
|
||||||
|
# mode
|
||||||
mode_values = [(mode, mode) for mode in possible_modes]
|
mode_values = [(mode, mode) for mode in possible_modes]
|
||||||
if use_buefy:
|
if use_buefy:
|
||||||
form.set_widget('mode', dfwidget.SelectWidget(values=mode_values))
|
mode_widget = dfwidget.SelectWidget(values=mode_values)
|
||||||
else:
|
else:
|
||||||
form.set_widget('mode', forms.widgets.JQuerySelectWidget(values=mode_values))
|
mode_widget = forms.widgets.JQuerySelectWidget(values=mode_values)
|
||||||
|
form.set_widget('mode', mode_widget)
|
||||||
|
|
||||||
|
# quantity
|
||||||
form.set_widget('quantity', forms.widgets.CasesUnitsWidget(amount_required=True,
|
form.set_widget('quantity', forms.widgets.CasesUnitsWidget(amount_required=True,
|
||||||
one_amount_only=True))
|
one_amount_only=True))
|
||||||
|
form.set_vuejs_field_converter('quantity', self.vuejs_convert_quantity)
|
||||||
|
|
||||||
|
# expiration_date
|
||||||
form.set_type('expiration_date', 'date_jquery')
|
form.set_type('expiration_date', 'date_jquery')
|
||||||
|
|
||||||
|
# TODO: what is this one about again?
|
||||||
form.remove_field('quick_receive')
|
form.remove_field('quick_receive')
|
||||||
|
|
||||||
if form.validate(newstyle=True):
|
if form.validate(newstyle=True):
|
||||||
|
@ -946,6 +1000,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
View for declaring a credit, i.e. converting some "received" or similar
|
View for declaring a credit, i.e. converting some "received" or similar
|
||||||
quantity, to a credit of some sort.
|
quantity, to a credit of some sort.
|
||||||
"""
|
"""
|
||||||
|
use_buefy = self.get_use_buefy()
|
||||||
row = self.get_row_instance()
|
row = self.get_row_instance()
|
||||||
batch = row.batch
|
batch = row.batch
|
||||||
possible_credit_types = [
|
possible_credit_types = [
|
||||||
|
@ -965,11 +1020,23 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
}
|
}
|
||||||
|
|
||||||
schema = DeclareCreditForm()
|
schema = DeclareCreditForm()
|
||||||
form = forms.Form(schema=schema, request=self.request)
|
form = forms.Form(schema=schema, request=self.request,
|
||||||
form.set_widget('credit_type', forms.widgets.JQuerySelectWidget(
|
use_buefy=use_buefy)
|
||||||
values=[(m, m) for m in possible_credit_types]))
|
|
||||||
|
# credit_type
|
||||||
|
values = [(m, m) for m in possible_credit_types]
|
||||||
|
if use_buefy:
|
||||||
|
widget = dfwidget.SelectWidget(values=values)
|
||||||
|
else:
|
||||||
|
widget = forms.widgets.JQuerySelectWidget(values=values)
|
||||||
|
form.set_widget('credit_type', widget)
|
||||||
|
|
||||||
|
# quantity
|
||||||
form.set_widget('quantity', forms.widgets.CasesUnitsWidget(
|
form.set_widget('quantity', forms.widgets.CasesUnitsWidget(
|
||||||
amount_required=True, one_amount_only=True))
|
amount_required=True, one_amount_only=True))
|
||||||
|
form.set_vuejs_field_converter('quantity', self.vuejs_convert_quantity)
|
||||||
|
|
||||||
|
# expiration_date
|
||||||
form.set_type('expiration_date', 'date_jquery')
|
form.set_type('expiration_date', 'date_jquery')
|
||||||
|
|
||||||
if form.validate(newstyle=True):
|
if form.validate(newstyle=True):
|
||||||
|
@ -1554,6 +1621,15 @@ class ReceiveRowForm(colander.MappingSchema):
|
||||||
|
|
||||||
quick_receive = colander.SchemaNode(colander.Boolean())
|
quick_receive = colander.SchemaNode(colander.Boolean())
|
||||||
|
|
||||||
|
def deserialize(self, *args):
|
||||||
|
result = super(ReceiveRowForm, self).deserialize(*args)
|
||||||
|
|
||||||
|
if result['mode'] == 'expired' and not result['expiration_date']:
|
||||||
|
msg = "Expiration date is required for items with 'expired' mode."
|
||||||
|
self.raise_invalid(msg, node=self.get('expiration_date'))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class DeclareCreditForm(colander.MappingSchema):
|
class DeclareCreditForm(colander.MappingSchema):
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue