Allow pending product fields to be required, for new custorder

This commit is contained in:
Lance Edgar 2023-10-24 19:17:36 -05:00
parent e308108bf7
commit 4247804707
3 changed files with 167 additions and 57 deletions

View file

@ -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 &quot;pending&quot; 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 &quot;pending&quot; 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>

View file

@ -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

View file

@ -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)