Merge branch 'master' into partial-shipment

This commit is contained in:
Oliver 2021-10-27 01:05:55 +11:00
commit 75845ce1ca
6 changed files with 97 additions and 17 deletions

View File

@ -36,6 +36,13 @@ class InvenTreeMoneySerializer(MoneyField):
Ref: https://github.com/django-money/django-money/blob/master/djmoney/contrib/django_rest_framework/fields.py
"""
def __init__(self, *args, **kwargs):
kwargs["max_digits"] = kwargs.get("max_digits", 19)
kwargs["decimal_places"] = kwargs.get("decimal_places", 4)
super().__init__(*args, **kwargs)
def get_value(self, data):
"""
Test that the returned amount is a valid Decimal
@ -52,7 +59,7 @@ class InvenTreeMoneySerializer(MoneyField):
amount = Decimal(amount)
except:
raise ValidationError({
self.field_name: _("Must be a valid number")
self.field_name: [_("Must be a valid number")],
})
currency = data.get(get_currency_field_name(self.field_name), self.default_currency)

View File

@ -9,6 +9,7 @@ from rest_framework import serializers
from sql_util.utils import SubqueryCount
from InvenTree.serializers import InvenTreeModelSerializer
from InvenTree.serializers import InvenTreeMoneySerializer
from InvenTree.serializers import InvenTreeImageSerializerField
from part.serializers import PartBriefSerializer
@ -256,7 +257,11 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer):
quantity = serializers.FloatField()
price = serializers.CharField()
price = InvenTreeMoneySerializer(
allow_null=True,
required=True,
label=_('Price'),
)
price_currency = serializers.ChoiceField(
choices=currency_code_mappings(),

View File

@ -153,7 +153,6 @@ class POLineItemSerializer(InvenTreeModelSerializer):
supplier_part_detail = SupplierPartSerializer(source='part', many=False, read_only=True)
purchase_price = InvenTreeMoneySerializer(
max_digits=19, decimal_places=4,
allow_null=True
)
@ -556,8 +555,6 @@ class SOLineItemSerializer(InvenTreeModelSerializer):
fulfilled = serializers.FloatField(source='fulfilled_quantity', read_only=True)
sale_price = InvenTreeMoneySerializer(
max_digits=19,
decimal_places=4,
allow_null=True
)

View File

@ -109,7 +109,6 @@ class PartSalePriceSerializer(InvenTreeModelSerializer):
quantity = serializers.FloatField()
price = InvenTreeMoneySerializer(
max_digits=19, decimal_places=4,
allow_null=True
)
@ -134,7 +133,6 @@ class PartInternalPriceSerializer(InvenTreeModelSerializer):
quantity = serializers.FloatField()
price = InvenTreeMoneySerializer(
max_digits=19, decimal_places=4,
allow_null=True
)

View File

@ -148,7 +148,6 @@ class StockItemSerializer(InvenTreeModelSerializer):
purchase_price = InvenTreeMoneySerializer(
label=_('Purchase Price'),
max_digits=19, decimal_places=4,
allow_null=True
)

View File

@ -621,6 +621,10 @@ function submitFormData(fields, options) {
var has_files = false;
var data_valid = true;
var data_errors = {};
// Extract values for each field
for (var idx = 0; idx < options.field_names.length; idx++) {
@ -633,6 +637,21 @@ function submitFormData(fields, options) {
if (field) {
switch (field.type) {
// Ensure numerical fields are "valid"
case 'integer':
case 'float':
case 'decimal':
if (!validateFormField(name, options)) {
data_valid = false;
data_errors[name] = ['{% trans "Enter a valid number" %}'];
}
break;
default:
break;
}
var value = getFormFieldValue(name, field, options);
// Handle file inputs
@ -662,6 +681,11 @@ function submitFormData(fields, options) {
}
}
if (!data_valid) {
handleFormErrors(data_errors, fields, options);
return;
}
var upload_func = inventreePut;
if (has_files) {
@ -732,7 +756,8 @@ function updateFieldValues(fields, options) {
* Update the value of a named field
*/
function updateFieldValue(name, value, field, options) {
var el = $(options.modal).find(`#id_${name}`);
var el = getFormFieldElement(name, options);
if (!el) {
console.log(`WARNING: updateFieldValue could not find field '${name}'`);
@ -760,6 +785,46 @@ function updateFieldValue(name, value, field, options) {
}
// Find the named field element in the modal DOM
function getFormFieldElement(name, options) {
var el = $(options.modal).find(`#id_${name}`);
if (!el.exists) {
console.log(`ERROR: Could not find form element for field '${name}'`);
}
return el;
}
/*
* Check that a "numerical" input field has a valid number in it.
* An invalid number is expunged at the client side by the getFormFieldValue() function,
* which means that an empty string '' is sent to the server if the number is not valud.
* This can result in confusing error messages displayed under the form field.
*
* So, we can invalid numbers and display errors *before* the form is submitted!
*/
function validateFormField(name, options) {
if (getFormFieldElement(name, options)) {
var el = document.getElementById(`id_${name}`);
if (el.validity.valueMissing) {
// Accept empty strings (server will validate)
return true;
} else {
return el.validity.valid;
}
} else {
return false;
}
}
/*
* Extract and field value before sending back to the server
*
@ -771,7 +836,7 @@ function updateFieldValue(name, value, field, options) {
function getFormFieldValue(name, field, options) {
// Find the HTML element
var el = $(options.modal).find(`#id_${name}`);
var el = getFormFieldElement(name, options);
if (!el) {
return null;
@ -1086,7 +1151,9 @@ function addFieldCallbacks(fields, options) {
function addFieldCallback(name, field, options) {
$(options.modal).find(`#id_${name}`).change(function() {
var el = getFormFieldElement(name, options);
el.change(function() {
var value = getFormFieldValue(name, field, options);
@ -1299,7 +1366,7 @@ function initializeRelatedField(field, fields, options) {
}
// Find the select element and attach a select2 to it
var select = $(options.modal).find(`#id_${name}`);
var select = getFormFieldElement(name, options);
// Add a button to launch a 'secondary' modal
if (field.secondary != null) {
@ -1492,7 +1559,7 @@ function initializeRelatedField(field, fields, options) {
*/
function setRelatedFieldData(name, data, options) {
var select = $(options.modal).find(`#id_${name}`);
var select = getFormFieldElement(name, options);
var option = new Option(name, data.pk, true, true);
@ -1513,9 +1580,7 @@ function setRelatedFieldData(name, data, options) {
function initializeChoiceField(field, fields, options) {
var name = field.name;
var select = $(options.modal).find(`#id_${name}`);
var select = getFormFieldElement(field.name, options);
select.select2({
dropdownAutoWidth: false,
@ -1929,8 +1994,17 @@ function constructInputOptions(name, classes, type, parameters) {
opts.push(`placeholder='${parameters.placeholder}'`);
}
if (parameters.type == 'boolean') {
switch (parameters.type) {
case 'boolean':
opts.push(`style='display: inline-block; width: 20px; margin-right: 20px;'`);
break;
case 'integer':
case 'float':
case 'decimal':
opts.push(`step='any'`);
break;
default:
break;
}
if (parameters.multiline) {