feat: add per-department default item discount
This commit is contained in:
parent
7e1d68e2cf
commit
aa31d23fc8
|
@ -234,7 +234,10 @@
|
||||||
<b-field horizontal label="Sold by Weight">
|
<b-field horizontal label="Sold by Weight">
|
||||||
<span>${app.render_boolean(item.product_weighed)}</span>
|
<span>${app.render_boolean(item.product_weighed)}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field horizontal label="Department">
|
<b-field horizontal label="Department ID">
|
||||||
|
<span>${item.department_id}</span>
|
||||||
|
</b-field>
|
||||||
|
<b-field horizontal label="Department Name">
|
||||||
<span>${item.department_name}</span>
|
<span>${item.department_name}</span>
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field horizontal label="Special Order">
|
<b-field horizontal label="Special Order">
|
||||||
|
|
|
@ -107,15 +107,111 @@
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<div v-show="simpleSettings['sideshow.orders.allow_item_discounts']"
|
<div v-show="simpleSettings['sideshow.orders.allow_item_discounts']"
|
||||||
class="level-left block">
|
class="block"
|
||||||
<div class="level-item">Default item discount</div>
|
style="display: flex; gap: 0.5rem; align-items: center;">
|
||||||
<div class="level-item">
|
<span>Global default item discount</span>
|
||||||
<b-input name="sideshow.orders.default_item_discount"
|
<b-input name="sideshow.orders.default_item_discount"
|
||||||
v-model="simpleSettings['sideshow.orders.default_item_discount']"
|
v-model="simpleSettings['sideshow.orders.default_item_discount']"
|
||||||
@input="settingsNeedSaved = true"
|
@input="settingsNeedSaved = true"
|
||||||
style="width: 5rem;" />
|
style="width: 5rem;" />
|
||||||
|
<span>%</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="simpleSettings['sideshow.orders.allow_item_discounts']"
|
||||||
|
style="width: 50%;">
|
||||||
|
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||||
|
<p>Per-Department default item discounts</p>
|
||||||
|
<div>
|
||||||
|
<b-button type="is-primary"
|
||||||
|
@click="deptItemDiscountInit()"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="plus">
|
||||||
|
Add
|
||||||
|
</b-button>
|
||||||
|
<input type="hidden" name="dept_item_discounts" :value="JSON.stringify(deptItemDiscounts)" />
|
||||||
|
<${b}-modal has-modal-card
|
||||||
|
% if request.use_oruga:
|
||||||
|
v-model:active="deptItemDiscountShowDialog"
|
||||||
|
% else:
|
||||||
|
:active.sync="deptItemDiscountShowDialog"
|
||||||
|
% endif
|
||||||
|
>
|
||||||
|
<div class="modal-card">
|
||||||
|
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Default Discount for Department</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<div style="display: flex; gap: 1rem;">
|
||||||
|
<b-field label="Dept. ID"
|
||||||
|
:type="deptItemDiscountDeptID ? null : 'is-danger'">
|
||||||
|
<b-input v-model="deptItemDiscountDeptID"
|
||||||
|
ref="deptItemDiscountDeptID"
|
||||||
|
style="width: 6rem;;" />
|
||||||
|
</b-field>
|
||||||
|
<b-field label="Department Name"
|
||||||
|
:type="deptItemDiscountDeptName ? null : 'is-danger'"
|
||||||
|
style="flex-grow: 1;">
|
||||||
|
<b-input v-model="deptItemDiscountDeptName" />
|
||||||
|
</b-field>
|
||||||
|
<b-field label="Discount"
|
||||||
|
:type="deptItemDiscountPercent ? null : 'is-danger'">
|
||||||
|
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
||||||
|
<b-input v-model="deptItemDiscountPercent"
|
||||||
|
ref="deptItemDiscountPercent"
|
||||||
|
style="width: 6rem;" />
|
||||||
|
<span>%</span>
|
||||||
|
</div>
|
||||||
|
</b-field>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<b-button type="is-primary"
|
||||||
|
icon-pack="fas"
|
||||||
|
icon-left="save"
|
||||||
|
:disabled="deptItemDiscountSaveDisabled"
|
||||||
|
@click="deptItemDiscountSave()">
|
||||||
|
Save
|
||||||
|
</b-button>
|
||||||
|
<b-button @click="deptItemDiscountShowDialog = false">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</${b}-modal>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="level-item">%</div>
|
<${b}-table :data="deptItemDiscounts">
|
||||||
|
<${b}-table-column field="department_id"
|
||||||
|
label="Dept. ID"
|
||||||
|
v-slot="props">
|
||||||
|
{{ props.row.department_id }}
|
||||||
|
</${b}-table-column>
|
||||||
|
<${b}-table-column field="department_name"
|
||||||
|
label="Department Name"
|
||||||
|
v-slot="props">
|
||||||
|
{{ props.row.department_name }}
|
||||||
|
</${b}-table-column>
|
||||||
|
<${b}-table-column field="default_item_discount"
|
||||||
|
label="Discount"
|
||||||
|
v-slot="props">
|
||||||
|
{{ props.row.default_item_discount }} %
|
||||||
|
</${b}-table-column>
|
||||||
|
<${b}-table-column label="Actions"
|
||||||
|
v-slot="props">
|
||||||
|
<a href="#" @click.prevent="deptItemDiscountInit(props.row)">
|
||||||
|
<i class="fas fa-edit" />
|
||||||
|
Edit
|
||||||
|
</a>
|
||||||
|
<a href="#" @click.prevent="deptItemDiscountDelete(props.row)"
|
||||||
|
class="has-text-danger">
|
||||||
|
<i class="fas fa-trash" />
|
||||||
|
Delete
|
||||||
|
</a>
|
||||||
|
</${b}-table-column>
|
||||||
|
</${b}-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -145,5 +241,62 @@
|
||||||
|
|
||||||
ThisPageData.batchHandlers = ${json.dumps(batch_handlers)|n}
|
ThisPageData.batchHandlers = ${json.dumps(batch_handlers)|n}
|
||||||
|
|
||||||
|
ThisPageData.deptItemDiscounts = ${json.dumps(dept_item_discounts)|n}
|
||||||
|
ThisPageData.deptItemDiscountShowDialog = false
|
||||||
|
ThisPageData.deptItemDiscountRow = null
|
||||||
|
ThisPageData.deptItemDiscountDeptID = null
|
||||||
|
ThisPageData.deptItemDiscountDeptName = null
|
||||||
|
ThisPageData.deptItemDiscountPercent = null
|
||||||
|
|
||||||
|
ThisPage.computed.deptItemDiscountSaveDisabled = function() {
|
||||||
|
if (!this.deptItemDiscountDeptID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (!this.deptItemDiscountDeptName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (!this.deptItemDiscountPercent) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.deptItemDiscountDelete = function(row) {
|
||||||
|
const i = this.deptItemDiscounts.indexOf(row)
|
||||||
|
this.deptItemDiscounts.splice(i, 1)
|
||||||
|
this.settingsNeedSaved = true
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.deptItemDiscountInit = function(row) {
|
||||||
|
this.deptItemDiscountRow = row
|
||||||
|
this.deptItemDiscountDeptID = row?.department_id
|
||||||
|
this.deptItemDiscountDeptName = row?.department_name
|
||||||
|
this.deptItemDiscountPercent = row?.default_item_discount
|
||||||
|
this.deptItemDiscountShowDialog = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (row) {
|
||||||
|
this.$refs.deptItemDiscountPercent.focus()
|
||||||
|
} else {
|
||||||
|
this.$refs.deptItemDiscountDeptID.focus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ThisPage.methods.deptItemDiscountSave = function() {
|
||||||
|
if (this.deptItemDiscountRow) {
|
||||||
|
this.deptItemDiscountRow.department_id = this.deptItemDiscountDeptID
|
||||||
|
this.deptItemDiscountRow.department_name = this.deptItemDiscountDeptName
|
||||||
|
this.deptItemDiscountRow.default_item_discount = this.deptItemDiscountPercent
|
||||||
|
} else {
|
||||||
|
this.deptItemDiscounts.push({
|
||||||
|
department_id: this.deptItemDiscountDeptID,
|
||||||
|
department_name: this.deptItemDiscountDeptName,
|
||||||
|
default_item_discount: this.deptItemDiscountPercent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.deptItemDiscountShowDialog = false
|
||||||
|
this.settingsNeedSaved = true
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -504,7 +504,16 @@
|
||||||
<b-input v-model="pendingProduct.scancode" />
|
<b-input v-model="pendingProduct.scancode" />
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Department"
|
<b-field label="Dept. ID"
|
||||||
|
% if 'department_id' in pending_product_required_fields:
|
||||||
|
:type="pendingProduct.department_id ? null : 'is-danger'"
|
||||||
|
% endif
|
||||||
|
style="width: 15rem;">
|
||||||
|
<b-input v-model="pendingProduct.department_id"
|
||||||
|
@input="updateDiscount" />
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Department Name"
|
||||||
% if 'department_name' in pending_product_required_fields:
|
% if 'department_name' in pending_product_required_fields:
|
||||||
:type="pendingProduct.department_name ? null : 'is-danger'"
|
:type="pendingProduct.department_name ? null : 'is-danger'"
|
||||||
% endif
|
% endif
|
||||||
|
@ -512,8 +521,7 @@
|
||||||
<b-input v-model="pendingProduct.department_name" />
|
<b-input v-model="pendingProduct.department_name" />
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<b-field label="Special Order"
|
<b-field label="Special Order">
|
||||||
style="width: 100%;">
|
|
||||||
<b-checkbox v-model="pendingProduct.special_order" />
|
<b-checkbox v-model="pendingProduct.special_order" />
|
||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
|
@ -750,7 +758,7 @@
|
||||||
|
|
||||||
<${b}-table-column label="Department"
|
<${b}-table-column label="Department"
|
||||||
v-slot="props">
|
v-slot="props">
|
||||||
{{ props.row.department_display }}
|
{{ props.row.department_name }}
|
||||||
</${b}-table-column>
|
</${b}-table-column>
|
||||||
|
|
||||||
<${b}-table-column label="Quantity"
|
<${b}-table-column label="Quantity"
|
||||||
|
@ -922,8 +930,10 @@
|
||||||
productCaseSize: null,
|
productCaseSize: null,
|
||||||
|
|
||||||
% if allow_item_discounts:
|
% if allow_item_discounts:
|
||||||
productDiscountPercent: ${json.dumps(default_item_discount)|n},
|
defaultItemDiscount: ${json.dumps(default_item_discount)|n},
|
||||||
|
deptItemDiscounts: ${json.dumps(dept_item_discounts)|n},
|
||||||
allowDiscountsIfOnSale: ${json.dumps(allow_item_discounts_if_on_sale)|n},
|
allowDiscountsIfOnSale: ${json.dumps(allow_item_discounts_if_on_sale)|n},
|
||||||
|
productDiscountPercent: null,
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
pendingProduct: {},
|
pendingProduct: {},
|
||||||
|
@ -1259,6 +1269,21 @@
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
% if allow_item_discounts:
|
||||||
|
|
||||||
|
updateDiscount(deptID) {
|
||||||
|
// nb. our map requires ID is string
|
||||||
|
deptID = deptID.toString()
|
||||||
|
const i = Object.keys(this.deptItemDiscounts).indexOf(deptID)
|
||||||
|
if (i == -1) {
|
||||||
|
this.productDiscountPercent = this.defaultItemDiscount
|
||||||
|
} else {
|
||||||
|
this.productDiscountPercent = this.deptItemDiscounts[deptID]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
% endif
|
||||||
|
|
||||||
editNewCustomerSave() {
|
editNewCustomerSave() {
|
||||||
this.editNewCustomerSaving = true
|
this.editNewCustomerSaving = true
|
||||||
|
|
||||||
|
@ -1397,7 +1422,7 @@
|
||||||
this.productUnitChoices = this.defaultUnitChoices
|
this.productUnitChoices = this.defaultUnitChoices
|
||||||
|
|
||||||
% if allow_item_discounts:
|
% if allow_item_discounts:
|
||||||
this.productDiscountPercent = ${json.dumps(default_item_discount)|n}
|
this.productDiscountPercent = this.defaultItemDiscount
|
||||||
% endif
|
% endif
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1436,7 +1461,15 @@
|
||||||
this.productSaleEndsDisplay = data.sale_ends_display
|
this.productSaleEndsDisplay = data.sale_ends_display
|
||||||
|
|
||||||
% if allow_item_discounts:
|
% if allow_item_discounts:
|
||||||
this.productDiscountPercent = this.allowItemDiscount ? data.default_item_discount : null
|
if (this.allowItemDiscount) {
|
||||||
|
if (data?.default_item_discount != null) {
|
||||||
|
this.productDiscountPercent = data.default_item_discount
|
||||||
|
} else {
|
||||||
|
this.updateDiscount(data?.department_id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.productDiscountPercent = null
|
||||||
|
}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
// this.setProductUnitChoices(data.uom_choices)
|
// this.setProductUnitChoices(data.uom_choices)
|
||||||
|
@ -1514,7 +1547,7 @@
|
||||||
this.productUOM = this.defaultUOM
|
this.productUOM = this.defaultUOM
|
||||||
|
|
||||||
% if allow_item_discounts:
|
% if allow_item_discounts:
|
||||||
this.productDiscountPercent = ${json.dumps(default_item_discount)|n}
|
this.productDiscountPercent = this.defaultItemDiscount
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
% if request.use_oruga:
|
% if request.use_oruga:
|
||||||
|
@ -1615,7 +1648,7 @@
|
||||||
this.editItemLoading = true
|
this.editItemLoading = true
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
order_qty: this.productQuantity,
|
order_qty: parseFloat(this.productQuantity),
|
||||||
order_uom: this.productUOM,
|
order_uom: this.productUOM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1626,7 +1659,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
% if allow_item_discounts:
|
% if allow_item_discounts:
|
||||||
params.discount_percent = this.productDiscountPercent
|
if (this.productDiscountPercent) {
|
||||||
|
params.discount_percent = parseFloat(this.productDiscountPercent)
|
||||||
|
}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
if (this.editItemRow) {
|
if (this.editItemRow) {
|
||||||
|
|
|
@ -25,7 +25,9 @@ Views for Orders
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import decimal
|
import decimal
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
@ -144,6 +146,7 @@ class OrderView(MasterView):
|
||||||
'brand_name',
|
'brand_name',
|
||||||
'description',
|
'description',
|
||||||
'size',
|
'size',
|
||||||
|
'department_id',
|
||||||
'department_name',
|
'department_name',
|
||||||
'vendor_name',
|
'vendor_name',
|
||||||
'vendor_item_code',
|
'vendor_item_code',
|
||||||
|
@ -304,6 +307,8 @@ class OrderView(MasterView):
|
||||||
# nb. render quantity so that '10.0' => '10'
|
# nb. render quantity so that '10.0' => '10'
|
||||||
context['default_item_discount'] = self.app.render_quantity(
|
context['default_item_discount'] = self.app.render_quantity(
|
||||||
self.batch_handler.get_default_item_discount())
|
self.batch_handler.get_default_item_discount())
|
||||||
|
context['dept_item_discounts'] = dict([(d['department_id'], d['default_item_discount'])
|
||||||
|
for d in self.get_dept_item_discounts()])
|
||||||
|
|
||||||
return self.render_to_response('create', context)
|
return self.render_to_response('create', context)
|
||||||
|
|
||||||
|
@ -401,6 +406,43 @@ class OrderView(MasterView):
|
||||||
required.append(field)
|
required.append(field)
|
||||||
return required
|
return required
|
||||||
|
|
||||||
|
def get_dept_item_discounts(self):
|
||||||
|
"""
|
||||||
|
Returns the list of per-department default item discount settings.
|
||||||
|
|
||||||
|
Each entry in the list will look like::
|
||||||
|
|
||||||
|
{
|
||||||
|
'department_id': '42',
|
||||||
|
'department_name': 'Grocery',
|
||||||
|
'default_item_discount': 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
:returns: List of department settings as shown above.
|
||||||
|
"""
|
||||||
|
model = self.app.model
|
||||||
|
session = self.Session()
|
||||||
|
pattern = re.compile(r'^sideshow\.orders\.departments\.([^.]+)\.default_item_discount$')
|
||||||
|
|
||||||
|
dept_item_discounts = []
|
||||||
|
settings = session.query(model.Setting)\
|
||||||
|
.filter(model.Setting.name.like('sideshow.orders.departments.%.default_item_discount'))\
|
||||||
|
.all()
|
||||||
|
for setting in settings:
|
||||||
|
match = pattern.match(setting.name)
|
||||||
|
if not match:
|
||||||
|
log.warning("invalid setting name: %s", setting.name)
|
||||||
|
continue
|
||||||
|
deptid = match.group(1)
|
||||||
|
name = self.app.get_setting(session, f'sideshow.orders.departments.{deptid}.name')
|
||||||
|
dept_item_discounts.append({
|
||||||
|
'department_id': deptid,
|
||||||
|
'department_name': name,
|
||||||
|
'default_item_discount': setting.value,
|
||||||
|
})
|
||||||
|
dept_item_discounts.sort(key=lambda d: d['department_name'])
|
||||||
|
return dept_item_discounts
|
||||||
|
|
||||||
def start_over(self, batch):
|
def start_over(self, batch):
|
||||||
"""
|
"""
|
||||||
This will delete the user's current batch, then redirect user
|
This will delete the user's current batch, then redirect user
|
||||||
|
@ -598,9 +640,6 @@ class OrderView(MasterView):
|
||||||
if 'case_price_quoted' in data and 'case_price_quoted_display' not in data:
|
if 'case_price_quoted' in data and 'case_price_quoted_display' not in data:
|
||||||
data['case_price_quoted_display'] = self.app.render_currency(data['case_price_quoted'])
|
data['case_price_quoted_display'] = self.app.render_currency(data['case_price_quoted'])
|
||||||
|
|
||||||
if 'default_item_discount' not in data:
|
|
||||||
data['default_item_discount'] = self.batch_handler.get_default_item_discount()
|
|
||||||
|
|
||||||
decimal_fields = [
|
decimal_fields = [
|
||||||
'case_size',
|
'case_size',
|
||||||
'unit_price_reg',
|
'unit_price_reg',
|
||||||
|
@ -753,7 +792,8 @@ class OrderView(MasterView):
|
||||||
row.product_description,
|
row.product_description,
|
||||||
row.product_size),
|
row.product_size),
|
||||||
'product_weighed': row.product_weighed,
|
'product_weighed': row.product_weighed,
|
||||||
'department_display': row.department_name,
|
'department_id': row.department_id,
|
||||||
|
'department_name': row.department_name,
|
||||||
'special_order': row.special_order,
|
'special_order': row.special_order,
|
||||||
'case_size': float(row.case_size) if row.case_size is not None else None,
|
'case_size': float(row.case_size) if row.case_size is not None else None,
|
||||||
'order_qty': float(row.order_qty),
|
'order_qty': float(row.order_qty),
|
||||||
|
@ -990,8 +1030,39 @@ class OrderView(MasterView):
|
||||||
handlers = [{'spec': spec} for spec in handlers]
|
handlers = [{'spec': spec} for spec in handlers]
|
||||||
context['batch_handlers'] = handlers
|
context['batch_handlers'] = handlers
|
||||||
|
|
||||||
|
context['dept_item_discounts'] = self.get_dept_item_discounts()
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def configure_gather_settings(self, data, simple_settings=None):
|
||||||
|
""" """
|
||||||
|
settings = super().configure_gather_settings(data, simple_settings=simple_settings)
|
||||||
|
|
||||||
|
for dept in json.loads(data['dept_item_discounts']):
|
||||||
|
deptid = dept['department_id']
|
||||||
|
settings.append({'name': f'sideshow.orders.departments.{deptid}.name',
|
||||||
|
'value': dept['department_name']})
|
||||||
|
settings.append({'name': f'sideshow.orders.departments.{deptid}.default_item_discount',
|
||||||
|
'value': dept['default_item_discount']})
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
|
def configure_remove_settings(self, **kwargs):
|
||||||
|
""" """
|
||||||
|
model = self.app.model
|
||||||
|
session = self.Session()
|
||||||
|
|
||||||
|
super().configure_remove_settings(**kwargs)
|
||||||
|
|
||||||
|
to_delete = session.query(model.Setting)\
|
||||||
|
.filter(sa.or_(
|
||||||
|
model.Setting.name.like('sideshow.orders.departments.%.name'),
|
||||||
|
model.Setting.name.like('sideshow.orders.departments.%.default_item_discount')))\
|
||||||
|
.all()
|
||||||
|
for setting in to_delete:
|
||||||
|
self.app.delete_setting(session, setting.name)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def defaults(cls, config):
|
def defaults(cls, config):
|
||||||
cls._order_defaults(config)
|
cls._order_defaults(config)
|
||||||
|
|
|
@ -235,6 +235,7 @@ class PendingProductView(MasterView):
|
||||||
url_prefix = '/pending/products'
|
url_prefix = '/pending/products'
|
||||||
|
|
||||||
labels = {
|
labels = {
|
||||||
|
'department_id': "Department ID",
|
||||||
'product_id': "Product ID",
|
'product_id': "Product ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
|
import json
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
@ -291,6 +292,50 @@ class TestOrderView(WebTestCase):
|
||||||
fields = view.get_pending_product_required_fields()
|
fields = view.get_pending_product_required_fields()
|
||||||
self.assertEqual(fields, ['brand_name', 'size', 'unit_price_reg'])
|
self.assertEqual(fields, ['brand_name', 'size', 'unit_price_reg'])
|
||||||
|
|
||||||
|
def test_get_dept_item_discounts(self):
|
||||||
|
model = self.app.model
|
||||||
|
view = self.make_view()
|
||||||
|
|
||||||
|
with patch.object(view, 'Session', return_value=self.session):
|
||||||
|
|
||||||
|
# empty list by default
|
||||||
|
discounts = view.get_dept_item_discounts()
|
||||||
|
self.assertEqual(discounts, [])
|
||||||
|
|
||||||
|
# mock settings
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.5.name', 'Bulk')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.5.default_item_discount', '15')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.6.name', 'Produce')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.6.default_item_discount', '5')
|
||||||
|
discounts = view.get_dept_item_discounts()
|
||||||
|
self.assertEqual(len(discounts), 2)
|
||||||
|
self.assertEqual(discounts[0], {
|
||||||
|
'department_id': '5',
|
||||||
|
'department_name': 'Bulk',
|
||||||
|
'default_item_discount': '15',
|
||||||
|
})
|
||||||
|
self.assertEqual(discounts[1], {
|
||||||
|
'department_id': '6',
|
||||||
|
'department_name': 'Produce',
|
||||||
|
'default_item_discount': '5',
|
||||||
|
})
|
||||||
|
|
||||||
|
# invalid setting
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.I.N.V.A.L.I.D.name', 'Bad News')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.I.N.V.A.L.I.D.default_item_discount', '42')
|
||||||
|
discounts = view.get_dept_item_discounts()
|
||||||
|
self.assertEqual(len(discounts), 2)
|
||||||
|
self.assertEqual(discounts[0], {
|
||||||
|
'department_id': '5',
|
||||||
|
'department_name': 'Bulk',
|
||||||
|
'default_item_discount': '15',
|
||||||
|
})
|
||||||
|
self.assertEqual(discounts[1], {
|
||||||
|
'department_id': '6',
|
||||||
|
'department_name': 'Produce',
|
||||||
|
'default_item_discount': '5',
|
||||||
|
})
|
||||||
|
|
||||||
def test_get_context_customer(self):
|
def test_get_context_customer(self):
|
||||||
self.pyramid_config.add_route('orders', '/orders/')
|
self.pyramid_config.add_route('orders', '/orders/')
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
|
@ -1288,6 +1333,12 @@ class TestOrderView(WebTestCase):
|
||||||
model = self.app.model
|
model = self.app.model
|
||||||
view = self.make_view()
|
view = self.make_view()
|
||||||
|
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.5.name', 'Bulk')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.5.default_item_discount', '15')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.6.name', 'Produce')
|
||||||
|
self.app.save_setting(self.session, 'sideshow.orders.departments.6.default_item_discount', '5')
|
||||||
|
self.session.commit()
|
||||||
|
|
||||||
with patch.object(view, 'Session', return_value=self.session):
|
with patch.object(view, 'Session', return_value=self.session):
|
||||||
with patch.multiple(self.config, usedb=True, preferdb=True):
|
with patch.multiple(self.config, usedb=True, preferdb=True):
|
||||||
|
|
||||||
|
@ -1295,7 +1346,19 @@ class TestOrderView(WebTestCase):
|
||||||
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
||||||
session=self.session)
|
session=self.session)
|
||||||
self.assertIsNone(allowed)
|
self.assertIsNone(allowed)
|
||||||
self.assertEqual(self.session.query(model.Setting).count(), 0)
|
self.assertEqual(self.session.query(model.Setting).count(), 4)
|
||||||
|
discounts = view.get_dept_item_discounts()
|
||||||
|
self.assertEqual(len(discounts), 2)
|
||||||
|
self.assertEqual(discounts[0], {
|
||||||
|
'department_id': '5',
|
||||||
|
'department_name': 'Bulk',
|
||||||
|
'default_item_discount': '15',
|
||||||
|
})
|
||||||
|
self.assertEqual(discounts[1], {
|
||||||
|
'department_id': '6',
|
||||||
|
'department_name': 'Produce',
|
||||||
|
'default_item_discount': '5',
|
||||||
|
})
|
||||||
|
|
||||||
# fetch initial page
|
# fetch initial page
|
||||||
response = view.configure()
|
response = view.configure()
|
||||||
|
@ -1305,13 +1368,18 @@ class TestOrderView(WebTestCase):
|
||||||
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
||||||
session=self.session)
|
session=self.session)
|
||||||
self.assertIsNone(allowed)
|
self.assertIsNone(allowed)
|
||||||
self.assertEqual(self.session.query(model.Setting).count(), 0)
|
self.assertEqual(self.session.query(model.Setting).count(), 4)
|
||||||
|
|
||||||
# post new settings
|
# post new settings
|
||||||
with patch.multiple(self.request, create=True,
|
with patch.multiple(self.request, create=True,
|
||||||
method='POST',
|
method='POST',
|
||||||
POST={
|
POST={
|
||||||
'sideshow.orders.allow_unknown_products': 'true',
|
'sideshow.orders.allow_unknown_products': 'true',
|
||||||
|
'dept_item_discounts': json.dumps([{
|
||||||
|
'department_id': '5',
|
||||||
|
'department_name': 'Grocery',
|
||||||
|
'default_item_discount': 10,
|
||||||
|
}])
|
||||||
}):
|
}):
|
||||||
response = view.configure()
|
response = view.configure()
|
||||||
self.assertIsInstance(response, HTTPFound)
|
self.assertIsInstance(response, HTTPFound)
|
||||||
|
@ -1320,6 +1388,13 @@ class TestOrderView(WebTestCase):
|
||||||
session=self.session)
|
session=self.session)
|
||||||
self.assertTrue(allowed)
|
self.assertTrue(allowed)
|
||||||
self.assertTrue(self.session.query(model.Setting).count() > 1)
|
self.assertTrue(self.session.query(model.Setting).count() > 1)
|
||||||
|
discounts = view.get_dept_item_discounts()
|
||||||
|
self.assertEqual(len(discounts), 1)
|
||||||
|
self.assertEqual(discounts[0], {
|
||||||
|
'department_id': '5',
|
||||||
|
'department_name': 'Grocery',
|
||||||
|
'default_item_discount': '10',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class OrderItemViewTestMixin:
|
class OrderItemViewTestMixin:
|
||||||
|
|
Loading…
Reference in a new issue