Fix the "new custorder" page for butterball

reasonably confident this one is complete, and didn't break buefy theme..
This commit is contained in:
Lance Edgar 2024-06-02 19:56:42 -05:00
parent 3dc8deef67
commit 58f9588261
4 changed files with 559 additions and 347 deletions

View file

@ -56,12 +56,19 @@
${self.order_form_buttons()} ${self.order_form_buttons()}
<b-collapse class="panel" :class="customerPanelType" <${b}-collapse class="panel"
:open.sync="customerPanelOpen"> :class="customerPanelType"
% if request.use_oruga:
v-model:open="customerPanelOpen"
% else:
:open.sync="customerPanelOpen"
% endif
>
<template #trigger="props"> <template #trigger="props">
<div class="panel-heading" <div class="panel-heading"
role="button"> role="button"
style="cursor: pointer;">
## TODO: for some reason buefy will "reuse" the icon ## TODO: for some reason buefy will "reuse" the icon
## element in such a way that its display does not ## element in such a way that its display does not
@ -89,11 +96,33 @@
<div style="display: flex; flex-direction: row;"> <div style="display: flex; flex-direction: row;">
<div style="flex-grow: 1; margin-right: 1rem;"> <div style="flex-grow: 1; margin-right: 1rem;">
% if request.use_oruga:
## TODO: for some reason o-notification variant is not
## being updated properly, so for now the workaround is
## to maintain a separate component for each variant
## i tried to reproduce the problem in a simple page
## but was unable; this is really a hack but it works..
<o-notification v-if="customerStatusType == null"
:closable="false">
{{ customerStatusText }}
</o-notification>
<o-notification v-if="customerStatusType == 'is-warning'"
variant="warning"
:closable="false">
{{ customerStatusText }}
</o-notification>
<o-notification v-if="customerStatusType == 'is-danger'"
variant="danger"
:closable="false">
{{ customerStatusText }}
</o-notification>
% else:
<b-notification :type="customerStatusType" <b-notification :type="customerStatusType"
position="is-bottom-right" position="is-bottom-right"
:closable="false"> :closable="false">
{{ customerStatusText }} {{ customerStatusText }}
</b-notification> </b-notification>
% endif
</div> </div>
<!-- <div class="buttons"> --> <!-- <div class="buttons"> -->
<!-- <b-button @click="startOverCustomer()" --> <!-- <b-button @click="startOverCustomer()" -->
@ -117,23 +146,28 @@
<div :style="{'flex-grow': contactNotes.length ? 0 : 1}"> <div :style="{'flex-grow': contactNotes.length ? 0 : 1}">
<b-field label="Customer" grouped> <b-field label="Customer">
<b-field style="margin-left: 1rem;" <div style="display: flex; gap: 1rem; width: 100%;">
:expanded="!contactUUID">
<tailbone-autocomplete ref="contactAutocomplete" <tailbone-autocomplete ref="contactAutocomplete"
v-model="contactUUID" v-model="contactUUID"
:style="{'flex-grow': contactUUID ? '0' : '1'}"
expanded
placeholder="Enter name or phone number" placeholder="Enter name or phone number"
:initial-label="contactDisplay"
% if new_order_requires_customer: % if new_order_requires_customer:
serviceUrl="${url('{}.customer_autocomplete'.format(route_prefix))}" serviceUrl="${url('{}.customer_autocomplete'.format(route_prefix))}"
% else: % else:
serviceUrl="${url('{}.person_autocomplete'.format(route_prefix))}" serviceUrl="${url('{}.person_autocomplete'.format(route_prefix))}"
% endif % endif
@input="contactChanged"> % if request.use_oruga:
:assigned-label="contactDisplay"
@update:model-value="contactChanged"
% else:
:initial-label="contactDisplay"
@input="contactChanged"
% endif
>
</tailbone-autocomplete> </tailbone-autocomplete>
</b-field> <b-button v-if="contactUUID && contactProfileURL"
<div v-if="contactUUID">
<b-button v-if="contactProfileURL"
type="is-primary" type="is-primary"
tag="a" target="_blank" tag="a" target="_blank"
:href="contactProfileURL" :href="contactProfileURL"
@ -141,8 +175,8 @@
icon-left="external-link-alt"> icon-left="external-link-alt">
View Profile View Profile
</b-button> </b-button>
&nbsp; <b-button v-if="contactUUID"
<b-button @click="refreshContact" @click="refreshContact"
icon-pack="fas" icon-pack="fas"
icon-left="redo" icon-left="redo"
:disabled="refreshingContact"> :disabled="refreshingContact">
@ -186,8 +220,13 @@
Edit Edit
</b-button> </b-button>
<b-modal has-modal-card <${b}-modal has-modal-card
:active.sync="editPhoneNumberShowDialog"> % if request.use_oruga:
v-model:active="editPhoneNumberShowDialog"
% else:
:active.sync="editPhoneNumberShowDialog"
% endif
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
@ -241,7 +280,7 @@
</b-button> </b-button>
</footer> </footer>
</div> </div>
</b-modal> </${b}-modal>
</div> </div>
% endif % endif
@ -279,8 +318,13 @@
icon-left="edit"> icon-left="edit">
Edit Edit
</b-button> </b-button>
<b-modal has-modal-card <${b}-modal has-modal-card
:active.sync="editEmailAddressShowDialog"> % if request.use_oruga:
v-model:active.sync="editEmailAddressShowDialog"
% else:
:active.sync="editEmailAddressShowDialog"
% endif
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
@ -334,7 +378,7 @@
</b-button> </b-button>
</footer> </footer>
</div> </div>
</b-modal> </${b}-modal>
</div> </div>
% endif % endif
</div> </div>
@ -409,8 +453,13 @@
</b-notification> </b-notification>
</div> </div>
<b-modal has-modal-card <${b}-modal has-modal-card
:active.sync="editNewCustomerShowDialog"> % if request.use_oruga:
v-model:active="editNewCustomerShowDialog"
% else:
:active.sync="editNewCustomerShowDialog"
% endif
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
@ -452,20 +501,21 @@
</b-button> </b-button>
</footer> </footer>
</div> </div>
</b-modal> </${b}-modal>
</div> </div>
</div> </div>
</div> <!-- panel-block --> </div> <!-- panel-block -->
</b-collapse> </${b}-collapse>
<b-collapse class="panel" <${b}-collapse class="panel"
open> open>
<template #trigger="props"> <template #trigger="props">
<div class="panel-heading" <div class="panel-heading"
role="button"> role="button"
style="cursor: pointer;">
## TODO: for some reason buefy will "reuse" the icon ## TODO: for some reason buefy will "reuse" the icon
## element in such a way that its display does not ## element in such a way that its display does not
@ -507,15 +557,28 @@
% endif % endif
</div> </div>
<b-modal :active.sync="showingItemDialog"> <${b}-modal
% if request.use_oruga:
v-model:active="showingItemDialog"
% else:
:active.sync="showingItemDialog"
% endif
>
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<b-tabs type="is-boxed is-toggle" <${b}-tabs :animated="false"
% if request.use_oruga:
v-model="itemDialogTab"
type="toggle"
% else:
v-model="itemDialogTabIndex" v-model="itemDialogTabIndex"
:animated="false"> type="is-boxed is-toggle"
% endif
>
<b-tab-item label="Product"> <${b}-tab-item label="Product"
value="product">
<div class="field"> <div class="field">
<b-radio v-model="productIsKnown" <b-radio v-model="productIsKnown"
@ -525,12 +588,10 @@
</div> </div>
<div v-show="productIsKnown" <div v-show="productIsKnown"
style="padding-left: 5rem;"> style="padding-left: 3rem; display: flex; gap: 1rem;">
<b-field grouped> <div style="flex-grow: 1;">
<p class="label control"> <b-field label="Product">
Product
</p>
<tailbone-product-lookup ref="productLookup" <tailbone-product-lookup ref="productLookup"
:product="selectedProduct" :product="selectedProduct"
@selected="productLookupSelected" @selected="productLookupSelected"
@ -540,11 +601,6 @@
<div v-if="productUUID"> <div v-if="productUUID">
<div class="is-pulled-right has-text-centered">
<img :src="productImageURL"
style="max-height: 150px; max-width: 150px; "/>
</div>
<b-field grouped> <b-field grouped>
<b-field :label="productKeyLabel"> <b-field :label="productKeyLabel">
<span>{{ productKey }}</span> <span>{{ productKey }}</span>
@ -602,6 +658,11 @@
</b-checkbox> </b-checkbox>
% endif % endif
</div> </div>
</div>
<img v-if="productUUID"
:src="productImageURL"
style="max-height: 150px; max-width: 150px; "/>
</div> </div>
@ -744,22 +805,23 @@
<b-field label="Notes"> <b-field label="Notes">
<b-input v-model="pendingProduct.notes" <b-input v-model="pendingProduct.notes"
type="textarea"> type="textarea"
</b-input> expanded />
</b-field> </b-field>
</div> </div>
</b-tab-item> </${b}-tab-item>
<b-tab-item label="Quantity"> <${b}-tab-item label="Quantity"
value="quantity">
<div class="is-pulled-right has-text-centered"> <div style="display: flex; gap: 1rem; white-space: nowrap;">
<img :src="productImageURL"
style="max-height: 150px; max-width: 150px; "/>
</div>
<div style="flex-grow: 1;">
<b-field grouped> <b-field grouped>
<b-field label="Product" horizontal> <b-field label="Product" horizontal>
<span :class="productIsKnown ? null : 'has-text-success'"> <span :class="productIsKnown ? null : 'has-text-success'"
## nb. hack to force refresh for vue3
:key="refreshProductDescription">
{{ productIsKnown ? productDisplay : (pendingProduct.brand_name || '') + ' ' + (pendingProduct.description || '') + ' ' + (pendingProduct.size || '') }} {{ productIsKnown ? productDisplay : (pendingProduct.brand_name || '') + ' ' + (pendingProduct.description || '') + ' ' + (pendingProduct.size || '') }}
</span> </span>
</b-field> </b-field>
@ -831,11 +893,13 @@
<b-field label="Quantity" horizontal> <b-field label="Quantity" horizontal>
<numeric-input v-model="productQuantity" <numeric-input v-model="productQuantity"
@input="refreshTotalPrice += 1"
style="width: 5rem;"> style="width: 5rem;">
</numeric-input> </numeric-input>
</b-field> </b-field>
<b-select v-model="productUOM"> <b-select v-model="productUOM"
@input="refreshTotalPrice += 1">
<option v-for="choice in productUnitChoices" <option v-for="choice in productUnitChoices"
:key="choice.key" :key="choice.key"
:value="choice.key" :value="choice.key"
@ -845,12 +909,13 @@
</b-field> </b-field>
<b-field grouped> <div style="display: flex; gap: 1rem;">
% if allow_item_discounts: % if allow_item_discounts:
<b-field label="Discount" horizontal> <b-field label="Discount" horizontal>
<div class="level"> <div class="level">
<div class="level-item"> <div class="level-item">
<numeric-input v-model="productDiscountPercent" <numeric-input v-model="productDiscountPercent"
@input="refreshTotalPrice += 1"
style="width: 5rem;" style="width: 5rem;"
:disabled="!allowItemDiscount"> :disabled="!allowItemDiscount">
</numeric-input> </numeric-input>
@ -861,15 +926,27 @@
</div> </div>
</b-field> </b-field>
% endif % endif
<b-field label="Total Price" horizontal expanded> <b-field label="Total Price" horizontal expanded
:key="refreshTotalPrice">
<span :class="productSalePriceDisplay ? 'has-background-warning': null"> <span :class="productSalePriceDisplay ? 'has-background-warning': null">
{{ getItemTotalPriceDisplay() }} {{ getItemTotalPriceDisplay() }}
</span> </span>
</b-field> </b-field>
</b-field> </div>
</b-tab-item> <!-- <b-field grouped> -->
</b-tabs> <!-- </b-field> -->
</div>
<!-- <div class="is-pulled-right has-text-centered"> -->
<img :src="productImageURL"
style="max-height: 150px; max-width: 150px; "/>
<!-- </div> -->
</div>
</${b}-tab-item>
</${b}-tabs>
<div class="buttons"> <div class="buttons">
<b-button @click="showingItemDialog = false"> <b-button @click="showingItemDialog = false">
@ -886,11 +963,16 @@
</div> </div>
</div> </div>
</b-modal> </${b}-modal>
% if unknown_product_confirm_price: % if unknown_product_confirm_price:
<b-modal has-modal-card <${b}-modal has-modal-card
:active.sync="confirmPriceShowDialog"> % if request.use_oruga:
v-model:active="confirmPriceShowDialog"
% else:
:active.sync="confirmPriceShowDialog"
% endif
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
@ -931,87 +1013,97 @@
</b-button> </b-button>
</footer> </footer>
</div> </div>
</b-modal> </${b}-modal>
% endif % endif
% if allow_past_item_reorder: % if allow_past_item_reorder:
<b-modal :active.sync="pastItemsShowDialog"> <${b}-modal
% if request.use_oruga:
v-model:active="pastItemsShowDialog"
% else:
:active.sync="pastItemsShowDialog"
% endif
>
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<b-table :data="pastItems" <${b}-table :data="pastItems"
icon-pack="fas" icon-pack="fas"
:loading="pastItemsLoading" :loading="pastItemsLoading"
% if request.use_oruga:
v-model:selected="pastItemsSelected"
% else:
:selected.sync="pastItemsSelected" :selected.sync="pastItemsSelected"
% endif
sortable sortable
paginated paginated
per-page="5" per-page="5"
:debounce-search="1000"> :debounce-search="1000">
<b-table-column :label="productKeyLabel" <${b}-table-column :label="productKeyLabel"
field="key" field="key"
v-slot="props" v-slot="props"
sortable> sortable>
{{ props.row.key }} {{ props.row.key }}
</b-table-column> </${b}-table-column>
<b-table-column label="Brand" <${b}-table-column label="Brand"
field="brand_name" field="brand_name"
v-slot="props" v-slot="props"
sortable sortable
searchable> searchable>
{{ props.row.brand_name }} {{ props.row.brand_name }}
</b-table-column> </${b}-table-column>
<b-table-column label="Description" <${b}-table-column label="Description"
field="description" field="description"
v-slot="props" v-slot="props"
sortable sortable
searchable> searchable>
{{ props.row.description }} {{ props.row.description }}
{{ props.row.size }} {{ props.row.size }}
</b-table-column> </${b}-table-column>
<b-table-column label="Unit Price" <${b}-table-column label="Unit Price"
field="unit_price" field="unit_price"
v-slot="props" v-slot="props"
sortable> sortable>
{{ props.row.unit_price_display }} {{ props.row.unit_price_display }}
</b-table-column> </${b}-table-column>
<b-table-column label="Sale Price" <${b}-table-column label="Sale Price"
field="sale_price" field="sale_price"
v-slot="props" v-slot="props"
sortable> sortable>
<span class="has-background-warning"> <span class="has-background-warning">
{{ props.row.sale_price_display }} {{ props.row.sale_price_display }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Sale Ends" <${b}-table-column label="Sale Ends"
field="sale_ends" field="sale_ends"
v-slot="props" v-slot="props"
sortable> sortable>
<span class="has-background-warning"> <span class="has-background-warning">
{{ props.row.sale_ends_display }} {{ props.row.sale_ends_display }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Department" <${b}-table-column label="Department"
field="department_name" field="department_name"
v-slot="props" v-slot="props"
sortable sortable
searchable> searchable>
{{ props.row.department_name }} {{ props.row.department_name }}
</b-table-column> </${b}-table-column>
<b-table-column label="Vendor" <${b}-table-column label="Vendor"
field="vendor_name" field="vendor_name"
v-slot="props" v-slot="props"
sortable sortable
searchable> searchable>
{{ props.row.vendor_name }} {{ props.row.vendor_name }}
</b-table-column> </${b}-table-column>
<template #empty> <template #empty>
<div class="content has-text-grey has-text-centered"> <div class="content has-text-grey has-text-centered">
@ -1025,7 +1117,7 @@
<p>Nothing here.</p> <p>Nothing here.</p>
</div> </div>
</template> </template>
</b-table> </${b}-table>
<div class="buttons"> <div class="buttons">
<b-button @click="pastItemsShowDialog = false"> <b-button @click="pastItemsShowDialog = false">
@ -1042,44 +1134,44 @@
</div> </div>
</div> </div>
</b-modal> </${b}-modal>
% endif % endif
<b-table v-if="items.length" <${b}-table v-if="items.length"
:data="items" :data="items"
:row-class="(row, i) => row.product_uuid ? null : 'has-text-success'"> :row-class="(row, i) => row.product_uuid ? null : 'has-text-success'">
<b-table-column :label="productKeyLabel" <${b}-table-column :label="productKeyLabel"
v-slot="props"> v-slot="props">
{{ props.row.product_key }} {{ props.row.product_key }}
</b-table-column> </${b}-table-column>
<b-table-column label="Brand" <${b}-table-column label="Brand"
v-slot="props"> v-slot="props">
{{ props.row.product_brand }} {{ props.row.product_brand }}
</b-table-column> </${b}-table-column>
<b-table-column label="Description" <${b}-table-column label="Description"
v-slot="props"> v-slot="props">
{{ props.row.product_description }} {{ props.row.product_description }}
</b-table-column> </${b}-table-column>
<b-table-column label="Size" <${b}-table-column label="Size"
v-slot="props"> v-slot="props">
{{ props.row.product_size }} {{ props.row.product_size }}
</b-table-column> </${b}-table-column>
<b-table-column label="Department" <${b}-table-column label="Department"
v-slot="props"> v-slot="props">
{{ props.row.department_display }} {{ props.row.department_display }}
</b-table-column> </${b}-table-column>
<b-table-column label="Quantity" <${b}-table-column label="Quantity"
v-slot="props"> v-slot="props">
<span v-html="props.row.order_quantity_display"></span> <span v-html="props.row.order_quantity_display"></span>
</b-table-column> </${b}-table-column>
<b-table-column label="Unit Price" <${b}-table-column label="Unit Price"
v-slot="props"> v-slot="props">
<span <span
% if product_price_may_be_questionable: % if product_price_may_be_questionable:
@ -1090,16 +1182,16 @@
> >
{{ props.row.unit_price_display }} {{ props.row.unit_price_display }}
</span> </span>
</b-table-column> </${b}-table-column>
% if allow_item_discounts: % if allow_item_discounts:
<b-table-column label="Discount" <${b}-table-column label="Discount"
v-slot="props"> v-slot="props">
{{ props.row.discount_percent }}{{ props.row.discount_percent ? " %" : "" }} {{ props.row.discount_percent }}{{ props.row.discount_percent ? " %" : "" }}
</b-table-column> </${b}-table-column>
% endif % endif
<b-table-column label="Total" <${b}-table-column label="Total"
v-slot="props"> v-slot="props">
<span <span
% if product_price_may_be_questionable: % if product_price_may_be_questionable:
@ -1110,35 +1202,57 @@
> >
{{ props.row.total_price_display }} {{ props.row.total_price_display }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Vendor" <${b}-table-column label="Vendor"
v-slot="props"> v-slot="props">
{{ props.row.vendor_display }} {{ props.row.vendor_display }}
</b-table-column> </${b}-table-column>
<b-table-column field="actions" <${b}-table-column field="actions"
label="Actions" label="Actions"
v-slot="props"> v-slot="props">
<a href="#" class="grid-action" <a href="#"
% if not request.use_oruga:
class="grid-action"
% endif
@click.prevent="showEditItemDialog(props.row)"> @click.prevent="showEditItemDialog(props.row)">
% if request.use_oruga:
<span class="icon-text">
<o-icon icon="edit" />
<span>Edit</span>
</span>
% else:
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
Edit Edit
% endif
</a> </a>
&nbsp; &nbsp;
<a href="#" class="grid-action has-text-danger" <a href="#"
% if request.use_oruga:
class="has-text-danger"
% else:
class="grid-action has-text-danger"
% endif
@click.prevent="deleteItem(props.index)"> @click.prevent="deleteItem(props.index)">
% if request.use_oruga:
<span class="icon-text">
<o-icon icon="trash" />
<span>Delete</span>
</span>
% else:
<i class="fas fa-trash"></i> <i class="fas fa-trash"></i>
Delete Delete
% endif
</a> </a>
&nbsp; &nbsp;
</b-table-column> </${b}-table-column>
</b-table> </${b}-table>
</div> </div>
</div> </div>
</b-collapse> </${b}-collapse>
${self.order_form_buttons()} ${self.order_form_buttons()}
@ -1222,7 +1336,11 @@
editingItem: null, editingItem: null,
showingItemDialog: false, showingItemDialog: false,
itemDialogSaving: false, itemDialogSaving: false,
% if request.use_oruga:
itemDialogTab: 'product',
% else:
itemDialogTabIndex: 0, itemDialogTabIndex: 0,
% endif
% if allow_past_item_reorder: % if allow_past_item_reorder:
pastItemsShowDialog: false, pastItemsShowDialog: false,
pastItemsLoading: false, pastItemsLoading: false,
@ -1271,6 +1389,10 @@
confirmPriceShowDialog: false, confirmPriceShowDialog: false,
% endif % endif
// nb. hack to force refresh for vue3
refreshProductDescription: 1,
refreshTotalPrice: 1,
submittingOrder: false, submittingOrder: false,
} }
}, },
@ -1632,22 +1754,21 @@
uuid: this.contactUUID, uuid: this.contactUUID,
} }
} }
let that = this this.submitBatchData(params, response => {
this.submitBatchData(params, function(response) {
% if new_order_requires_customer: % if new_order_requires_customer:
that.contactUUID = response.data.customer_uuid this.contactUUID = response.data.customer_uuid
% else: % else:
that.contactUUID = response.data.person_uuid this.contactUUID = response.data.person_uuid
% endif % endif
that.contactDisplay = response.data.contact_display this.contactDisplay = response.data.contact_display
that.orderPhoneNumber = response.data.phone_number this.orderPhoneNumber = response.data.phone_number
that.orderEmailAddress = response.data.email_address this.orderEmailAddress = response.data.email_address
that.addOtherPhoneNumber = response.data.add_phone_number this.addOtherPhoneNumber = response.data.add_phone_number
that.addOtherEmailAddress = response.data.add_email_address this.addOtherEmailAddress = response.data.add_email_address
that.contactProfileURL = response.data.contact_profile_url this.contactProfileURL = response.data.contact_profile_url
that.contactPhones = response.data.contact_phones this.contactPhones = response.data.contact_phones
that.contactEmails = response.data.contact_emails this.contactEmails = response.data.contact_emails
that.contactNotes = response.data.contact_notes this.contactNotes = response.data.contact_notes
if (callback) { if (callback) {
callback() callback()
} }
@ -1937,7 +2058,11 @@
this.productDiscountPercent = ${json.dumps(default_item_discount)|n} this.productDiscountPercent = ${json.dumps(default_item_discount)|n}
% endif % endif
% if request.use_oruga:
this.itemDialogTab = 'product'
% else:
this.itemDialogTabIndex = 0 this.itemDialogTabIndex = 0
% endif
this.showingItemDialog = true this.showingItemDialog = true
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.productLookup.focus() this.$refs.productLookup.focus()
@ -1993,7 +2118,15 @@
this.productPriceNeedsConfirmation = false this.productPriceNeedsConfirmation = false
% endif % endif
// nb. hack to force refresh for vue3
this.refreshProductDescription += 1
this.refreshTotalPrice += 1
% if request.use_oruga:
this.itemDialogTab = 'quantity'
% else:
this.itemDialogTabIndex = 1 this.itemDialogTabIndex = 1
% endif
this.showingItemDialog = true this.showingItemDialog = true
}, },
@ -2050,7 +2183,15 @@
this.productDiscountPercent = row.discount_percent this.productDiscountPercent = row.discount_percent
% endif % endif
// nb. hack to force refresh for vue3
this.refreshProductDescription += 1
this.refreshTotalPrice += 1
% if request.use_oruga:
this.itemDialogTab = 'quantity'
% else:
this.itemDialogTabIndex = 1 this.itemDialogTabIndex = 1
% endif
this.showingItemDialog = true this.showingItemDialog = true
}, },
@ -2160,7 +2301,15 @@
this.productPriceNeedsConfirmation = false this.productPriceNeedsConfirmation = false
% endif % endif
% if request.use_oruga:
this.itemDialogTab = 'quantity'
% else:
this.itemDialogTabIndex = 1 this.itemDialogTabIndex = 1
% endif
// nb. hack to force refresh for vue3
this.refreshProductDescription += 1
this.refreshTotalPrice += 1
}, response => { }, response => {
this.clearProduct() this.clearProduct()
@ -2250,6 +2399,7 @@
} }
Vue.component('customer-order-creator', CustomerOrderCreator) Vue.component('customer-order-creator', CustomerOrderCreator)
<% request.register_component('customer-order-creator', 'CustomerOrderCreator') %>
</script> </script>
</%def> </%def>

View file

@ -3,21 +3,26 @@
<%def name="tailbone_product_lookup_template()"> <%def name="tailbone_product_lookup_template()">
<script type="text/x-template" id="tailbone-product-lookup-template"> <script type="text/x-template" id="tailbone-product-lookup-template">
<div style="width: 100%;"> <div style="width: 100%;">
<div style="display: flex; gap: 0.5rem;">
<b-field grouped> <b-field :style="{'flex-grow': product ? '0' : '1'}">
<${b}-autocomplete v-if="!product"
<b-field :expanded="!product"> ref="productAutocomplete"
<b-autocomplete ref="productAutocomplete"
v-if="!product"
v-model="autocompleteValue" v-model="autocompleteValue"
expanded
placeholder="Enter UPC or brand, description etc." placeholder="Enter UPC or brand, description etc."
:data="autocompleteOptions" :data="autocompleteOptions"
field="value" % if request.use_oruga:
:custom-formatter="option => option.label" @input="getAutocompleteOptions"
:formatter="option => option.label"
% else:
@typing="getAutocompleteOptions" @typing="getAutocompleteOptions"
:custom-formatter="option => option.label"
field="value"
% endif
@select="autocompleteSelected" @select="autocompleteSelected"
style="width: 100%;"> style="width: 100%;">
</b-autocomplete> </${b}-autocomplete>
<b-button v-if="product" <b-button v-if="product"
@click="clearSelection(true)"> @click="clearSelection(true)">
{{ product.full_description }} {{ product.full_description }}
@ -42,7 +47,7 @@
View Product View Product
</b-button> </b-button>
</b-field> </div>
<b-modal :active.sync="lookupShowDialog"> <b-modal :active.sync="lookupShowDialog">
<div class="card"> <div class="card">
@ -88,68 +93,72 @@
</b-field> </b-field>
<b-table :data="searchResults" <${b}-table :data="searchResults"
narrowed narrowed
% if request.use_oruga:
v-model:selected="searchResultSelected"
% else:
:selected.sync="searchResultSelected"
icon-pack="fas" icon-pack="fas"
:loading="searchResultsLoading" % endif
:selected.sync="searchResultSelected"> :loading="searchResultsLoading">
<b-table-column label="${request.rattail_config.product_key_title()}" <${b}-table-column label="${request.rattail_config.product_key_title()}"
field="product_key" field="product_key"
v-slot="props"> v-slot="props">
{{ props.row.product_key }} {{ props.row.product_key }}
</b-table-column> </${b}-table-column>
<b-table-column label="Brand" <${b}-table-column label="Brand"
field="brand_name" field="brand_name"
v-slot="props"> v-slot="props">
{{ props.row.brand_name }} {{ props.row.brand_name }}
</b-table-column> </${b}-table-column>
<b-table-column label="Description" <${b}-table-column label="Description"
field="description" field="description"
v-slot="props"> v-slot="props">
<span :class="{organic: props.row.organic}"> <span :class="{organic: props.row.organic}">
{{ props.row.description }} {{ props.row.description }}
{{ props.row.size }} {{ props.row.size }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Unit Price" <${b}-table-column label="Unit Price"
field="unit_price" field="unit_price"
v-slot="props"> v-slot="props">
{{ props.row.unit_price_display }} {{ props.row.unit_price_display }}
</b-table-column> </${b}-table-column>
<b-table-column label="Sale Price" <${b}-table-column label="Sale Price"
field="sale_price" field="sale_price"
v-slot="props"> v-slot="props">
<span class="has-background-warning"> <span class="has-background-warning">
{{ props.row.sale_price_display }} {{ props.row.sale_price_display }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Sale Ends" <${b}-table-column label="Sale Ends"
field="sale_ends" field="sale_ends"
v-slot="props"> v-slot="props">
<span class="has-background-warning"> <span class="has-background-warning">
{{ props.row.sale_ends_display }} {{ props.row.sale_ends_display }}
</span> </span>
</b-table-column> </${b}-table-column>
<b-table-column label="Department" <${b}-table-column label="Department"
field="department_name" field="department_name"
v-slot="props"> v-slot="props">
{{ props.row.department_name }} {{ props.row.department_name }}
</b-table-column> </${b}-table-column>
<b-table-column label="Vendor" <${b}-table-column label="Vendor"
field="vendor_name" field="vendor_name"
v-slot="props"> v-slot="props">
{{ props.row.vendor_name }} {{ props.row.vendor_name }}
</b-table-column> </${b}-table-column>
<b-table-column label="Actions" <${b}-table-column label="Actions"
v-slot="props"> v-slot="props">
<a :href="props.row.url" <a :href="props.row.url"
target="_blank" target="_blank"
@ -157,7 +166,7 @@
<i class="fas fa-external-link-alt"></i> <i class="fas fa-external-link-alt"></i>
View View
</a> </a>
</b-table-column> </${b}-table-column>
<template #empty> <template #empty>
<div class="content has-text-grey has-text-centered"> <div class="content has-text-grey has-text-centered">
@ -171,7 +180,7 @@
<p>Nothing here.</p> <p>Nothing here.</p>
</div> </div>
</template> </template>
</b-table> </${b}-table>
<br /> <br />
<div class="level"> <div class="level">
@ -263,7 +272,12 @@
} }
}, },
## TODO: add debounce for oruga?
% if request.use_oruga:
getAutocompleteOptions(entry) {
% else:
getAutocompleteOptions: debounce(function (entry) { getAutocompleteOptions: debounce(function (entry) {
% endif
// since the `@typing` event from buefy component does not // since the `@typing` event from buefy component does not
// "self-regulate" in any way, we a) use `debounce` above, // "self-regulate" in any way, we a) use `debounce` above,
@ -282,7 +296,11 @@
this.autocompleteOptions = [] this.autocompleteOptions = []
throw error throw error
}) })
% if request.use_oruga:
},
% else:
}), }),
% endif
autocompleteSelected(option) { autocompleteSelected(option) {
this.$emit('selected', { this.$emit('selected', {
@ -359,6 +377,7 @@
} }
Vue.component('tailbone-product-lookup', TailboneProductLookup) Vue.component('tailbone-product-lookup', TailboneProductLookup)
<% request.register_component('tailbone-product-lookup', 'TailboneProductLookup') %>
</script> </script>
</%def> </%def>

View file

@ -13,6 +13,7 @@
${self.make_b_loading_component()} ${self.make_b_loading_component()}
${self.make_b_modal_component()} ${self.make_b_modal_component()}
${self.make_b_notification_component()} ${self.make_b_notification_component()}
${self.make_b_radio_component()}
${self.make_b_select_component()} ${self.make_b_select_component()}
${self.make_b_steps_component()} ${self.make_b_steps_component()}
${self.make_b_step_item_component()} ${self.make_b_step_item_component()}
@ -468,6 +469,41 @@
<% request.register_component('b-notification', 'BNotification') %> <% request.register_component('b-notification', 'BNotification') %>
</%def> </%def>
<%def name="make_b_radio_component()">
<script type="text/x-template" id="b-radio-template">
<o-radio v-model="orugaValue"
@update:model-value="orugaValueUpdated"
:native-value="nativeValue">
<slot />
</o-radio>
</script>
<script>
const BRadio = {
template: '#b-radio-template',
props: {
modelValue: null,
nativeValue: null,
},
data() {
return {
orugaValue: this.modelValue,
}
},
watch: {
modelValue(to, from) {
this.orugaValue = to
},
},
methods: {
orugaValueUpdated(value) {
this.$emit('update:modelValue', value)
},
},
}
</script>
<% request.register_component('b-radio', 'BRadio') %>
</%def>
<%def name="make_b_select_component()"> <%def name="make_b_select_component()">
<script type="text/x-template" id="b-select-template"> <script type="text/x-template" id="b-select-template">
<o-select :name="name" <o-select :name="name"

View file

@ -112,7 +112,7 @@
@select="optionSelected" @select="optionSelected"
keep-first keep-first
open-on-focus open-on-focus
expanded :expanded="expanded"
:clearable="clearable" :clearable="clearable"
:clear-on-select="clearOnSelect"> :clear-on-select="clearOnSelect">
<template #default="{ option }"> <template #default="{ option }">
@ -325,6 +325,7 @@
// the selection is cleared we want user to start over // the selection is cleared we want user to start over
// anyway // anyway
this.orugaValue = null this.orugaValue = null
this.fetchedData = []
// here is where we alert callers to the new value // here is where we alert callers to the new value
if (option) { if (option) {
@ -366,6 +367,12 @@
} }
}, },
// nb. this used to be relevant but now is here only for sake
// of backward-compatibility (for callers)
getDisplayText() {
return this.internalLabel
},
// set focus to this component, which will just set focus // set focus to this component, which will just set focus
// to the oruga autocomplete component // to the oruga autocomplete component
focus() { focus() {