Add way to prevent "case" entries for inventory adjustment batch
This commit is contained in:
		
							parent
							
								
									57c2a7981f
								
							
						
					
					
						commit
						54bfafdbfe
					
				
					 4 changed files with 80 additions and 30 deletions
				
			
		| 
						 | 
					@ -9,14 +9,20 @@
 | 
				
			||||||
  <script type="text/javascript">
 | 
					  <script type="text/javascript">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function assert_quantity() {
 | 
					    function assert_quantity() {
 | 
				
			||||||
 | 
					        % if allow_cases:
 | 
				
			||||||
        if ($('#cases').val() && parseFloat($('#cases').val())) {
 | 
					        if ($('#cases').val() && parseFloat($('#cases').val())) {
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        % endif
 | 
				
			||||||
        if ($('#units').val() && parseFloat($('#units').val())) {
 | 
					        if ($('#units').val() && parseFloat($('#units').val())) {
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        alert("Please provide case and/or unit quantity");
 | 
					        alert("Please provide case and/or unit quantity");
 | 
				
			||||||
 | 
					        % if allow_cases:
 | 
				
			||||||
        $('#cases').select().focus();
 | 
					        $('#cases').select().focus();
 | 
				
			||||||
 | 
					        % else:
 | 
				
			||||||
 | 
					        $('#units').select().focus();
 | 
				
			||||||
 | 
					        % endif
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +30,9 @@
 | 
				
			||||||
        $('#product-info p').text(msg);
 | 
					        $('#product-info p').text(msg);
 | 
				
			||||||
        $('#product-info img').hide();
 | 
					        $('#product-info img').hide();
 | 
				
			||||||
        $('#upc').focus().select();
 | 
					        $('#upc').focus().select();
 | 
				
			||||||
 | 
					        % if allow_cases:
 | 
				
			||||||
        $('.field-wrapper.cases input').prop('disabled', true);
 | 
					        $('.field-wrapper.cases input').prop('disabled', true);
 | 
				
			||||||
 | 
					        % endif
 | 
				
			||||||
        $('.field-wrapper.units input').prop('disabled', true);
 | 
					        $('.field-wrapper.units input').prop('disabled', true);
 | 
				
			||||||
        $('.buttons button').button('disable');
 | 
					        $('.buttons button').button('disable');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -65,7 +73,9 @@
 | 
				
			||||||
                $('#product-info .warning').hide();
 | 
					                $('#product-info .warning').hide();
 | 
				
			||||||
                $('.product-fields').hide();
 | 
					                $('.product-fields').hide();
 | 
				
			||||||
                // $('.receiving-fields').hide();
 | 
					                // $('.receiving-fields').hide();
 | 
				
			||||||
 | 
					                % if allow_cases:
 | 
				
			||||||
                $('.field-wrapper.cases input').prop('disabled', true);
 | 
					                $('.field-wrapper.cases input').prop('disabled', true);
 | 
				
			||||||
 | 
					                % endif
 | 
				
			||||||
                $('.field-wrapper.units input').prop('disabled', true);
 | 
					                $('.field-wrapper.units input').prop('disabled', true);
 | 
				
			||||||
                $('.buttons button').button('disable');
 | 
					                $('.buttons button').button('disable');
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
| 
						 | 
					@ -102,13 +112,19 @@
 | 
				
			||||||
                            $('.product-fields').show();
 | 
					                            $('.product-fields').show();
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        $('#product-info .warning.notordered').show();
 | 
					                        $('#product-info .warning.notordered').show();
 | 
				
			||||||
 | 
					                        % if allow_cases:
 | 
				
			||||||
                        $('.field-wrapper.cases input').prop('disabled', false);
 | 
					                        $('.field-wrapper.cases input').prop('disabled', false);
 | 
				
			||||||
 | 
					                        % endif
 | 
				
			||||||
                        $('.field-wrapper.units input').prop('disabled', false);
 | 
					                        $('.field-wrapper.units input').prop('disabled', false);
 | 
				
			||||||
                        $('.buttons button').button('enable');
 | 
					                        $('.buttons button').button('enable');
 | 
				
			||||||
                        if (data.product.type2) {
 | 
					                        if (data.product.type2) {
 | 
				
			||||||
                            $('#units').focus().select();
 | 
					                            $('#units').focus().select();
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            % if allow_cases:
 | 
				
			||||||
                            $('#cases').focus().select();
 | 
					                            $('#cases').focus().select();
 | 
				
			||||||
 | 
					                            % else:
 | 
				
			||||||
 | 
					                            $('#units').focus().select();
 | 
				
			||||||
 | 
					                            % endif
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // TODO: this is maybe useful if "new products" may be added via inventory batch
 | 
					                    // TODO: this is maybe useful if "new products" may be added via inventory batch
 | 
				
			||||||
| 
						 | 
					@ -147,7 +163,9 @@
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $('#upc').focus();
 | 
					        $('#upc').focus();
 | 
				
			||||||
 | 
					        % if allow_cases:
 | 
				
			||||||
        $('.field-wrapper.cases input').prop('disabled', true);
 | 
					        $('.field-wrapper.cases input').prop('disabled', true);
 | 
				
			||||||
 | 
					        % endif
 | 
				
			||||||
        $('.field-wrapper.units input').prop('disabled', true);
 | 
					        $('.field-wrapper.units input').prop('disabled', true);
 | 
				
			||||||
        $('.buttons button').button('disable');
 | 
					        $('.buttons button').button('disable');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -232,10 +250,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  % if allow_cases:
 | 
				
			||||||
      <div class="field-wrapper cases">
 | 
					      <div class="field-wrapper cases">
 | 
				
			||||||
        <label for="cases">Cases</label>
 | 
					        <label for="cases">Cases</label>
 | 
				
			||||||
        <div class="field">${h.text('cases', autocomplete='off')}</div>
 | 
					        <div class="field">${h.text('cases', autocomplete='off')}</div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					  % endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="field-wrapper units">
 | 
					  <div class="field-wrapper units">
 | 
				
			||||||
    <label for="units">Units</label>
 | 
					    <label for="units">Units</label>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,22 +3,19 @@
 | 
				
			||||||
<%namespace file="/mobile/keypad.mako" import="keypad" />
 | 
					<%namespace file="/mobile/keypad.mako" import="keypad" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## TODO: this is broken for actual page (header) title
 | 
					## TODO: this is broken for actual page (header) title
 | 
				
			||||||
<%def name="title()">${h.link_to("Inventory", url('mobile.batch.inventory'))} » ${h.link_to(instance.batch.id_str, url('mobile.batch.inventory.view', uuid=instance.batch_uuid))} » ${row.upc.pretty()}</%def>
 | 
					<%def name="title()">${h.link_to("Inventory", url('mobile.batch.inventory'))} » ${h.link_to(batch.id_str, url('mobile.batch.inventory.view', uuid=batch.uuid))} » ${row.upc.pretty()}</%def>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<%
 | 
					<%
 | 
				
			||||||
   unit_uom = 'LB' if row.product and row.product.weighed else 'EA'
 | 
					   unit_uom = 'LB' if row.product and row.product.weighed else 'EA'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   if row.cases:
 | 
					   if row.cases and allow_cases:
 | 
				
			||||||
       uom = 'CS'
 | 
					       uom = 'CS'
 | 
				
			||||||
   elif row.units:
 | 
					   elif row.units:
 | 
				
			||||||
       if row.product and row.product.weighed:
 | 
					       uom = unit_uom
 | 
				
			||||||
           uom = 'LB'
 | 
					   elif row.case_quantity and allow_cases:
 | 
				
			||||||
       else:
 | 
					 | 
				
			||||||
           uom = 'EA'
 | 
					 | 
				
			||||||
   elif row.case_quantity:
 | 
					 | 
				
			||||||
       uom = 'CS'
 | 
					       uom = 'CS'
 | 
				
			||||||
   else:
 | 
					   else:
 | 
				
			||||||
       uom = 'EA'
 | 
					       uom = unit_uom
 | 
				
			||||||
%>
 | 
					%>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="ui-grid-a">
 | 
					<div class="ui-grid-a">
 | 
				
			||||||
| 
						 | 
					@ -46,20 +43,22 @@
 | 
				
			||||||
  ${uom}
 | 
					  ${uom}
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
% if not row.batch.executed and not row.batch.complete:
 | 
					% if not batch.executed and not batch.complete:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ${h.form(request.current_route_url())}
 | 
					    ${h.form(request.current_route_url())}
 | 
				
			||||||
    ${h.csrf_token(request)}
 | 
					    ${h.csrf_token(request)}
 | 
				
			||||||
    ${h.hidden('row', value=row.uuid)}
 | 
					    ${h.hidden('row', value=row.uuid)}
 | 
				
			||||||
 | 
					    % if allow_cases:
 | 
				
			||||||
    ${h.hidden('cases')}
 | 
					    ${h.hidden('cases')}
 | 
				
			||||||
 | 
					    % endif
 | 
				
			||||||
    ${h.hidden('units')}
 | 
					    ${h.hidden('units')}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ${keypad(unit_uom, uom, quantity=row.cases or row.units or 1)}
 | 
					    ${keypad(unit_uom, uom, quantity=(row.cases or row.units or 1) if allow_cases else (row.units or 1), allow_cases=allow_cases)}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <fieldset data-role="controlgroup" data-type="horizontal" class="inventory-actions">
 | 
					    <fieldset data-role="controlgroup" data-type="horizontal" class="inventory-actions">
 | 
				
			||||||
      <button type="button" class="ui-btn-inline ui-corner-all save">Save</button>
 | 
					      <button type="button" class="ui-btn-inline ui-corner-all save">Save</button>
 | 
				
			||||||
      <button type="button" class="ui-btn-inline ui-corner-all delete" disabled="disabled">Delete</button>
 | 
					      <button type="button" class="ui-btn-inline ui-corner-all delete" disabled="disabled">Delete</button>
 | 
				
			||||||
      ${h.link_to("Cancel", url('mobile.batch.inventory.view', uuid=row.batch.uuid), class_='ui-btn ui-btn-inline ui-corner-all')}
 | 
					      ${h.link_to("Cancel", url('mobile.batch.inventory.view', uuid=batch.uuid), class_='ui-btn ui-btn-inline ui-corner-all')}
 | 
				
			||||||
    </fieldset>
 | 
					    </fieldset>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ${h.end_form()}
 | 
					    ${h.end_form()}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
## -*- coding: utf-8; -*-
 | 
					## -*- coding: utf-8; -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<%def name="keypad(unit_uom, selected_uom, quantity=1)">
 | 
					<%def name="keypad(unit_uom, selected_uom, quantity=1, allow_cases=True)">
 | 
				
			||||||
  <div class="quantity-keypad-thingy" data-changed="false">
 | 
					  <div class="quantity-keypad-thingy" data-changed="false">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <table>
 | 
					    <table>
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,9 @@
 | 
				
			||||||
    <fieldset data-role="controlgroup" data-type="horizontal">
 | 
					    <fieldset data-role="controlgroup" data-type="horizontal">
 | 
				
			||||||
      <button type="button" class="ui-btn-active keypad-quantity">${h.pretty_quantity(quantity or 1)}</button>
 | 
					      <button type="button" class="ui-btn-active keypad-quantity">${h.pretty_quantity(quantity or 1)}</button>
 | 
				
			||||||
      <button type="button" disabled="disabled"> </button>
 | 
					      <button type="button" disabled="disabled"> </button>
 | 
				
			||||||
 | 
					      % if allow_cases:
 | 
				
			||||||
      ${h.radio('keypad-uom', value='CS', checked=selected_uom == 'CS', label="CS")}
 | 
					      ${h.radio('keypad-uom', value='CS', checked=selected_uom == 'CS', label="CS")}
 | 
				
			||||||
 | 
					      % endif
 | 
				
			||||||
      ${h.radio('keypad-uom', value=unit_uom, checked=selected_uom == unit_uom, label=unit_uom)}
 | 
					      ${h.radio('keypad-uom', value=unit_uom, checked=selected_uom == unit_uom, label=unit_uom)}
 | 
				
			||||||
    </fieldset>
 | 
					    </fieldset>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +97,10 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
    # set to False to disable "zero all" batch count mode
 | 
					    # set to False to disable "zero all" batch count mode
 | 
				
			||||||
    allow_zero_all = True
 | 
					    allow_zero_all = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # set to False to prevent exposing case fields for user input,
 | 
				
			||||||
 | 
					    # when the batch count mode is "adjust only"
 | 
				
			||||||
 | 
					    allow_adjustment_cases = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    labels = {
 | 
					    labels = {
 | 
				
			||||||
        'mode': "Count Mode",
 | 
					        'mode': "Count Mode",
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -310,8 +314,16 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
            'index_url': self.get_action_url('view', batch),
 | 
					            'index_url': self.get_action_url('view', batch),
 | 
				
			||||||
            'form': form,
 | 
					            'form': form,
 | 
				
			||||||
            'dform': form.make_deform_form(),
 | 
					            'dform': form.make_deform_form(),
 | 
				
			||||||
 | 
					            'allow_cases': self.allow_cases(batch),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def allow_cases(self, batch):
 | 
				
			||||||
 | 
					        if batch.mode == self.enum.INVENTORY_MODE_ADJUST:
 | 
				
			||||||
 | 
					            if self.allow_adjustment_cases:
 | 
				
			||||||
 | 
					                return True
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def desktop_lookup(self):
 | 
					    def desktop_lookup(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Try to locate a product by UPC, and validate it in the context of
 | 
					        Try to locate a product by UPC, and validate it in the context of
 | 
				
			||||||
| 
						 | 
					@ -463,23 +475,26 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        self.viewing = True
 | 
					        self.viewing = True
 | 
				
			||||||
        row = self.get_row_instance()
 | 
					        row = self.get_row_instance()
 | 
				
			||||||
        parent = self.get_parent(row)
 | 
					        batch = self.get_parent(row)
 | 
				
			||||||
        form = self.make_mobile_row_form(row)
 | 
					        form = self.make_mobile_row_form(row)
 | 
				
			||||||
        context = {
 | 
					        context = {
 | 
				
			||||||
            'row': row,
 | 
					            'row': row,
 | 
				
			||||||
 | 
					            'batch': batch,
 | 
				
			||||||
            'instance': row,
 | 
					            'instance': row,
 | 
				
			||||||
            'instance_title': self.get_row_instance_title(row),
 | 
					            'instance_title': self.get_row_instance_title(row),
 | 
				
			||||||
            'parent_model_title': self.get_model_title(),
 | 
					            'parent_model_title': self.get_model_title(),
 | 
				
			||||||
            'parent_title': self.get_instance_title(parent),
 | 
					            'parent_title': self.get_instance_title(batch),
 | 
				
			||||||
            'parent_url': self.get_action_url('view', parent, mobile=True),
 | 
					            'parent_url': self.get_action_url('view', batch, mobile=True),
 | 
				
			||||||
            'product_image_url': pod.get_image_url(self.rattail_config, row.upc),
 | 
					            'product_image_url': pod.get_image_url(self.rattail_config, row.upc),
 | 
				
			||||||
            'form': form,
 | 
					            'form': form,
 | 
				
			||||||
 | 
					            'allow_cases': self.allow_cases(batch),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.request.has_perm('{}.edit_row'.format(self.get_permission_prefix())):
 | 
					        if self.request.has_perm('{}.edit_row'.format(self.get_permission_prefix())):
 | 
				
			||||||
            update_form = forms.Form(schema=InventoryForm(), request=self.request)
 | 
					            schema = InventoryForm().bind(session=self.Session())
 | 
				
			||||||
 | 
					            update_form = forms.Form(schema=schema, request=self.request)
 | 
				
			||||||
            if update_form.validate(newstyle=True):
 | 
					            if update_form.validate(newstyle=True):
 | 
				
			||||||
                row = update_form.validated['row']
 | 
					                row = self.Session.query(model.InventoryBatchRow).get(update_form.validated['row'])
 | 
				
			||||||
                cases = update_form.validated['cases']
 | 
					                cases = update_form.validated['cases']
 | 
				
			||||||
                units = update_form.validated['units']
 | 
					                units = update_form.validated['units']
 | 
				
			||||||
                if cases:
 | 
					                if cases:
 | 
				
			||||||
| 
						 | 
					@ -489,7 +504,8 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
                    row.cases = None
 | 
					                    row.cases = None
 | 
				
			||||||
                    row.units = units
 | 
					                    row.units = units
 | 
				
			||||||
                self.handler.refresh_row(row)
 | 
					                self.handler.refresh_row(row)
 | 
				
			||||||
                return self.redirect(self.request.route_url('mobile.{}.view'.format(self.get_route_prefix()), uuid=row.batch_uuid))
 | 
					                route_prefix = self.get_route_prefix()
 | 
				
			||||||
 | 
					                return self.redirect(self.request.route_url('mobile.{}.view'.format(route_prefix), uuid=batch.uuid))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.render_to_response('view_row', context, mobile=True)
 | 
					        return self.render_to_response('view_row', context, mobile=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -533,6 +549,7 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def configure_row_form(self, f):
 | 
					    def configure_row_form(self, f):
 | 
				
			||||||
        super(InventoryBatchView, self).configure_row_form(f)
 | 
					        super(InventoryBatchView, self).configure_row_form(f)
 | 
				
			||||||
 | 
					        row = f.model_instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # readonly fields
 | 
					        # readonly fields
 | 
				
			||||||
        f.set_readonly('upc')
 | 
					        f.set_readonly('upc')
 | 
				
			||||||
| 
						 | 
					@ -557,6 +574,11 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
        # upc
 | 
					        # upc
 | 
				
			||||||
        f.set_renderer('upc', self.render_upc)
 | 
					        f.set_renderer('upc', self.render_upc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # cases
 | 
				
			||||||
 | 
					        if self.editing:
 | 
				
			||||||
 | 
					            if not self.allow_cases(row.batch):
 | 
				
			||||||
 | 
					                f.set_readonly('cases')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def render_upc(self, row, field):
 | 
					    def render_upc(self, row, field):
 | 
				
			||||||
        upc = row.upc
 | 
					        upc = row.upc
 | 
				
			||||||
        if not upc:
 | 
					        if not upc:
 | 
				
			||||||
| 
						 | 
					@ -599,19 +621,26 @@ class InventoryBatchView(BatchMasterView):
 | 
				
			||||||
                        permission='{}.create_row'.format(permission_prefix))
 | 
					                        permission='{}.create_row'.format(permission_prefix))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InventoryBatchRowType(forms.types.ObjectType):
 | 
					# TODO: this is a stopgap measure to fix an obvious bug, which exists when the
 | 
				
			||||||
    model_class = model.InventoryBatchRow
 | 
					# session is not provided by the view at runtime (i.e. when it was instead
 | 
				
			||||||
 | 
					# being provided by the type instance, which was created upon app startup).
 | 
				
			||||||
    def deserialize(self, node, cstruct):
 | 
					@colander.deferred
 | 
				
			||||||
        row = super(InventoryBatchRowType, self).deserialize(node, cstruct)
 | 
					def valid_inventory_batch_row(node, kw):
 | 
				
			||||||
        if row and row.batch.executed:
 | 
					    session = kw['session']
 | 
				
			||||||
 | 
					    def validate(node, value):
 | 
				
			||||||
 | 
					        row = session.query(model.InventoryBatchRow).get(value)
 | 
				
			||||||
 | 
					        if not row:
 | 
				
			||||||
 | 
					            raise colander.Invalid(node, "Batch row not found")
 | 
				
			||||||
 | 
					        if row.batch.executed:
 | 
				
			||||||
            raise colander.Invalid(node, "Batch has already been executed")
 | 
					            raise colander.Invalid(node, "Batch has already been executed")
 | 
				
			||||||
        return row
 | 
					        return row.uuid
 | 
				
			||||||
 | 
					    return validate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InventoryForm(colander.MappingSchema):
 | 
					class InventoryForm(colander.MappingSchema):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    row = colander.SchemaNode(InventoryBatchRowType())
 | 
					    row = colander.SchemaNode(colander.String(),
 | 
				
			||||||
 | 
					                              validator=valid_inventory_batch_row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cases = colander.SchemaNode(colander.Decimal(), missing=colander.null)
 | 
					    cases = colander.SchemaNode(colander.Decimal(), missing=colander.null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue