Allow pending product fields to be required, for new custorder
This commit is contained in:
parent
e308108bf7
commit
4247804707
|
@ -79,15 +79,6 @@
|
||||||
</b-checkbox>
|
</b-checkbox>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field message="If set, user can enter details of an arbitrary new "pending" product.">
|
|
||||||
<b-checkbox name="rattail.custorders.allow_unknown_product"
|
|
||||||
v-model="simpleSettings['rattail.custorders.allow_unknown_product']"
|
|
||||||
native-value="true"
|
|
||||||
@input="settingsNeedSaved = true">
|
|
||||||
Allow creating orders for "unknown" products
|
|
||||||
</b-checkbox>
|
|
||||||
</b-field>
|
|
||||||
|
|
||||||
<b-field>
|
<b-field>
|
||||||
<b-checkbox name="rattail.custorders.allow_item_discounts"
|
<b-checkbox name="rattail.custorders.allow_item_discounts"
|
||||||
v-model="simpleSettings['rattail.custorders.allow_item_discounts']"
|
v-model="simpleSettings['rattail.custorders.allow_item_discounts']"
|
||||||
|
@ -130,6 +121,41 @@
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h3 class="block is-size-3">Unknown Products</h3>
|
||||||
|
<div class="block" style="padding-left: 2rem;">
|
||||||
|
|
||||||
|
<b-field message="If set, user can enter details of an arbitrary new "pending" product.">
|
||||||
|
<b-checkbox name="rattail.custorders.allow_unknown_product"
|
||||||
|
v-model="simpleSettings['rattail.custorders.allow_unknown_product']"
|
||||||
|
native-value="true"
|
||||||
|
@input="settingsNeedSaved = true">
|
||||||
|
Allow creating orders for "unknown" products
|
||||||
|
</b-checkbox>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<div v-if="simpleSettings['rattail.custorders.allow_unknown_product']">
|
||||||
|
|
||||||
|
<p class="block">
|
||||||
|
Require these fields for new product:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div style="margin-left: 2rem;">
|
||||||
|
% for field in pending_product_fields:
|
||||||
|
<b-field>
|
||||||
|
<b-checkbox name="rattail.custorders.unknown_product.fields.${field}.required"
|
||||||
|
v-model="simpleSettings['rattail.custorders.unknown_product.fields.${field}.required']"
|
||||||
|
native-value="true"
|
||||||
|
@input="settingsNeedSaved = true">
|
||||||
|
${field}
|
||||||
|
</b-checkbox>
|
||||||
|
</b-field>
|
||||||
|
% endfor
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
:disabled="submittingOrder"
|
:disabled="submittingOrder"
|
||||||
icon-pack="fas"
|
icon-pack="fas"
|
||||||
icon-left="fas fa-upload">
|
icon-left="fas fa-upload">
|
||||||
{{ submitOrderButtonText }}
|
{{ submittingOrder ? "Working, please wait..." : "Submit this Order" }}
|
||||||
</b-button>
|
</b-button>
|
||||||
<b-button @click="startOverEntirely()"
|
<b-button @click="startOverEntirely()"
|
||||||
icon-pack="fas"
|
icon-pack="fas"
|
||||||
|
@ -644,18 +644,29 @@
|
||||||
|
|
||||||
<b-field grouped>
|
<b-field grouped>
|
||||||
|
|
||||||
<b-field label="Brand">
|
<b-field label="Brand"
|
||||||
|
% if 'brand_name' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.brand_name ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
<b-input v-model="pendingProduct.brand_name">
|
<b-input v-model="pendingProduct.brand_name">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Description"
|
<b-field label="Description"
|
||||||
:type="pendingProduct.description ? null : 'is-danger'">
|
% if 'description' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.description ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
<b-input v-model="pendingProduct.description">
|
<b-input v-model="pendingProduct.description">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Unit Size">
|
<b-field label="Unit Size"
|
||||||
|
% if 'size' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.size ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
<b-input v-model="pendingProduct.size">
|
<b-input v-model="pendingProduct.size">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
@ -664,12 +675,20 @@
|
||||||
|
|
||||||
<b-field grouped>
|
<b-field grouped>
|
||||||
|
|
||||||
<b-field :label="productKeyLabel">
|
<b-field :label="productKeyLabel"
|
||||||
|
% if 'key' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct[productKeyField] ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
<b-input v-model="pendingProduct[productKeyField]">
|
<b-input v-model="pendingProduct[productKeyField]">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Department">
|
<b-field label="Department"
|
||||||
|
% if 'department_uuid' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.department_uuid ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
<b-select v-model="pendingProduct.department_uuid">
|
<b-select v-model="pendingProduct.department_uuid">
|
||||||
<option :value="null">(not known)</option>
|
<option :value="null">(not known)</option>
|
||||||
<option v-for="option in departmentOptions"
|
<option v-for="option in departmentOptions"
|
||||||
|
@ -680,9 +699,36 @@
|
||||||
</b-select>
|
</b-select>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Unit Reg. Price">
|
</b-field>
|
||||||
<b-input v-model="pendingProduct.regular_price_amount"
|
|
||||||
type="number" step="0.01">
|
<b-field grouped>
|
||||||
|
|
||||||
|
<b-field label="Vendor"
|
||||||
|
% if 'vendor_name' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.vendor_name ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
|
<b-input v-model="pendingProduct.vendor_name">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Vendor Item Code"
|
||||||
|
% if 'vendor_item_code' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.vendor_item_code ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
|
<b-input v-model="pendingProduct.vendor_item_code">
|
||||||
|
</b-input>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Case Size"
|
||||||
|
% if 'case_size' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.case_size ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
|
<b-input v-model="pendingProduct.case_size"
|
||||||
|
type="number" step="0.01"
|
||||||
|
style="width: 7rem;">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
|
@ -690,27 +736,24 @@
|
||||||
|
|
||||||
<b-field grouped>
|
<b-field grouped>
|
||||||
|
|
||||||
<b-field label="Vendor">
|
<b-field label="Unit Cost"
|
||||||
<b-input v-model="pendingProduct.vendor_name">
|
% if 'unit_cost' in pending_product_required_fields:
|
||||||
</b-input>
|
:type="pendingProduct.unit_cost ? null : 'is-danger'"
|
||||||
</b-field>
|
% endif
|
||||||
|
>
|
||||||
<b-field label="Vendor Item Code">
|
|
||||||
<b-input v-model="pendingProduct.vendor_item_code">
|
|
||||||
</b-input>
|
|
||||||
</b-field>
|
|
||||||
|
|
||||||
<b-field label="Unit Cost">
|
|
||||||
<b-input v-model="pendingProduct.unit_cost"
|
<b-input v-model="pendingProduct.unit_cost"
|
||||||
type="number" step="0.01"
|
type="number" step="0.01"
|
||||||
style="width: 10rem;">
|
style="width: 10rem;">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Case Size">
|
<b-field label="Unit Reg. Price"
|
||||||
<b-input v-model="pendingProduct.case_size"
|
% if 'regular_price_amount' in pending_product_required_fields:
|
||||||
type="number" step="0.01"
|
:type="pendingProduct.regular_price_amount ? null : 'is-danger'"
|
||||||
style="width: 7rem;">
|
% endif
|
||||||
|
>
|
||||||
|
<b-input v-model="pendingProduct.regular_price_amount"
|
||||||
|
type="number" step="0.01">
|
||||||
</b-input>
|
</b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
|
@ -854,7 +897,7 @@
|
||||||
:disabled="itemDialogSaveDisabled"
|
:disabled="itemDialogSaveDisabled"
|
||||||
icon-pack="fas"
|
icon-pack="fas"
|
||||||
icon-left="save">
|
icon-left="save">
|
||||||
{{ itemDialogSaveButtonText }}
|
{{ itemDialogSaving ? "Working, please wait..." : (this.editingItem ? "Update Item" : "Add Item") }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1197,6 +1240,7 @@
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
pendingProduct: {},
|
pendingProduct: {},
|
||||||
|
pendingProductRequiredFields: ${json.dumps(pending_product_required_fields)|n},
|
||||||
departmentOptions: ${json.dumps(department_options)|n},
|
departmentOptions: ${json.dumps(department_options)|n},
|
||||||
|
|
||||||
submittingOrder: false,
|
submittingOrder: false,
|
||||||
|
@ -1385,37 +1429,30 @@
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
itemDialogSaveDisabled() {
|
itemDialogSaveDisabled() {
|
||||||
|
|
||||||
if (this.itemDialogSaving) {
|
if (this.itemDialogSaving) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.productIsKnown) {
|
if (this.productIsKnown) {
|
||||||
if (!this.productUUID) {
|
if (!this.productUUID) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.pendingProduct.description) {
|
for (let field of this.pendingProductRequiredFields) {
|
||||||
|
if (!this.pendingProduct[field]) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.productUOM) {
|
if (!this.productUOM) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|
||||||
itemDialogSaveButtonText() {
|
|
||||||
if (this.itemDialogSaving) {
|
|
||||||
return "Working, please wait..."
|
|
||||||
}
|
|
||||||
return this.editingItem ? "Update Item" : "Add Item"
|
|
||||||
},
|
|
||||||
|
|
||||||
submitOrderButtonText() {
|
|
||||||
if (this.submittingOrder) {
|
|
||||||
return "Working, please wait..."
|
|
||||||
}
|
|
||||||
return "Submit this Order"
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.customerStatusType) {
|
if (this.customerStatusType) {
|
||||||
|
@ -1925,11 +1962,14 @@
|
||||||
|
|
||||||
this.productIsKnown = !!row.product_uuid
|
this.productIsKnown = !!row.product_uuid
|
||||||
this.productUUID = row.product_uuid
|
this.productUUID = row.product_uuid
|
||||||
this.pendingProduct = {}
|
|
||||||
|
// nb. must construct new object before updating data
|
||||||
|
// (otherwise vue does not notice the changes?)
|
||||||
|
let pending = {}
|
||||||
if (row.pending_product) {
|
if (row.pending_product) {
|
||||||
this.copyPendingProductAttrs(row.pending_product,
|
this.copyPendingProductAttrs(row.pending_product, pending)
|
||||||
this.pendingProduct)
|
|
||||||
}
|
}
|
||||||
|
this.pendingProduct = pending
|
||||||
|
|
||||||
this.productDisplay = row.product_full_description
|
this.productDisplay = row.product_full_description
|
||||||
this.productKey = row.product_key
|
this.productKey = row.product_key
|
||||||
|
|
|
@ -102,6 +102,19 @@ class CustomerOrderView(MasterView):
|
||||||
'flagged',
|
'flagged',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
PENDING_PRODUCT_ENTRY_FIELDS = [
|
||||||
|
'key',
|
||||||
|
'department_uuid',
|
||||||
|
'brand_name',
|
||||||
|
'description',
|
||||||
|
'size',
|
||||||
|
'vendor_name',
|
||||||
|
'vendor_item_code',
|
||||||
|
'unit_cost',
|
||||||
|
'case_size',
|
||||||
|
'regular_price_amount',
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(CustomerOrderView, self).__init__(request)
|
super(CustomerOrderView, self).__init__(request)
|
||||||
self.batch_handler = self.get_batch_handler()
|
self.batch_handler = self.get_batch_handler()
|
||||||
|
@ -361,6 +374,7 @@ class CustomerOrderView(MasterView):
|
||||||
'order_items': items,
|
'order_items': items,
|
||||||
'product_key_label': app.get_product_key_label(),
|
'product_key_label': app.get_product_key_label(),
|
||||||
'allow_unknown_product': self.batch_handler.allow_unknown_product(),
|
'allow_unknown_product': self.batch_handler.allow_unknown_product(),
|
||||||
|
'pending_product_required_fields': self.get_pending_product_required_fields(),
|
||||||
'department_options': self.get_department_options(),
|
'department_options': self.get_department_options(),
|
||||||
'default_uom_choices': self.batch_handler.uom_choices_for_product(None),
|
'default_uom_choices': self.batch_handler.uom_choices_for_product(None),
|
||||||
'default_uom': None,
|
'default_uom': None,
|
||||||
|
@ -390,6 +404,17 @@ class CustomerOrderView(MasterView):
|
||||||
'value': department.uuid})
|
'value': department.uuid})
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
def get_pending_product_required_fields(self):
|
||||||
|
required = []
|
||||||
|
for field in self.PENDING_PRODUCT_ENTRY_FIELDS:
|
||||||
|
require = self.rattail_config.getbool('rattail.custorders',
|
||||||
|
f'unknown_product.fields.{field}.required')
|
||||||
|
if require is None and field == 'description':
|
||||||
|
require = True
|
||||||
|
if require:
|
||||||
|
required.append(field)
|
||||||
|
return required
|
||||||
|
|
||||||
def get_current_batch(self):
|
def get_current_batch(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
if not user:
|
if not user:
|
||||||
|
@ -1044,7 +1069,7 @@ class CustomerOrderView(MasterView):
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure_get_simple_settings(self):
|
def configure_get_simple_settings(self):
|
||||||
return [
|
settings = [
|
||||||
|
|
||||||
# customer handling
|
# customer handling
|
||||||
{'section': 'rattail.custorders',
|
{'section': 'rattail.custorders',
|
||||||
|
@ -1067,9 +1092,6 @@ class CustomerOrderView(MasterView):
|
||||||
{'section': 'rattail.custorders',
|
{'section': 'rattail.custorders',
|
||||||
'option': 'product_price_may_be_questionable',
|
'option': 'product_price_may_be_questionable',
|
||||||
'type': bool},
|
'type': bool},
|
||||||
{'section': 'rattail.custorders',
|
|
||||||
'option': 'allow_unknown_product',
|
|
||||||
'type': bool},
|
|
||||||
{'section': 'rattail.custorders',
|
{'section': 'rattail.custorders',
|
||||||
'option': 'allow_item_discounts',
|
'option': 'allow_item_discounts',
|
||||||
'type': bool},
|
'type': bool},
|
||||||
|
@ -1082,8 +1104,30 @@ class CustomerOrderView(MasterView):
|
||||||
{'section': 'rattail.custorders',
|
{'section': 'rattail.custorders',
|
||||||
'option': 'allow_past_item_reorder',
|
'option': 'allow_past_item_reorder',
|
||||||
'type': bool},
|
'type': bool},
|
||||||
|
|
||||||
|
# unknown products
|
||||||
|
{'section': 'rattail.custorders',
|
||||||
|
'option': 'allow_unknown_product',
|
||||||
|
'type': bool},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
for field in self.PENDING_PRODUCT_ENTRY_FIELDS:
|
||||||
|
setting = {'section': 'rattail.custorders',
|
||||||
|
'option': f'unknown_product.fields.{field}.required',
|
||||||
|
'type': bool}
|
||||||
|
if field == 'description':
|
||||||
|
setting['default'] = True
|
||||||
|
settings.append(setting)
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
|
def configure_get_context(self, **kwargs):
|
||||||
|
context = super().configure_get_context(**kwargs)
|
||||||
|
|
||||||
|
context['pending_product_fields'] = self.PENDING_PRODUCT_ENTRY_FIELDS
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def defaults(cls, config):
|
def defaults(cls, config):
|
||||||
cls._order_defaults(config)
|
cls._order_defaults(config)
|
||||||
|
|
Loading…
Reference in a new issue