You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
7.5 KiB
198 lines
7.5 KiB
/** @odoo-module **/
|
|
|
|
import publicWidget from "@web/legacy/js/public/public_widget";
|
|
import { rpc } from "@web/core/network/rpc";
|
|
import { _t } from '@web/core/l10n/translation';
|
|
|
|
// Extend a new widget named DeliveryMethods for loading delivery methods in payment page
|
|
publicWidget.registry.DeliveryMethods = publicWidget.Widget.extend({
|
|
selector: '.o_website_sale_checkout',
|
|
events: {
|
|
'click [name="o_delivery_radio"]': '_selectDeliveryMethod',
|
|
},
|
|
init() {
|
|
this._super(...arguments);
|
|
this.orm = this.bindService("orm");
|
|
},
|
|
/**
|
|
* @override
|
|
*/
|
|
async start() {
|
|
this.mainButton = document.querySelector('a[name="o_payment_submit_button"]');
|
|
await this._prepareDeliveryMethods();
|
|
},
|
|
/**
|
|
* Copied from checkout.js for loading delivery method template in payment template
|
|
*/
|
|
async _selectDeliveryMethod(ev) {
|
|
const checkedRadio = ev.currentTarget;
|
|
if (checkedRadio.disabled) { // The delivery rate request failed.
|
|
return; // Failing delivery methods cannot be selected.
|
|
}
|
|
|
|
// Disable the main button while fetching delivery rates.
|
|
this._disableMainButton();
|
|
|
|
// Fetch delivery rates and update the cart summary and the price badge accordingly.
|
|
await this._updateDeliveryMethod(checkedRadio);
|
|
|
|
// Re-enable the main button after delivery rates have been fetched.
|
|
this._enableMainButton();
|
|
|
|
// Show a button to open the location selector if required for the selected delivery method.
|
|
await this._showPickupLocation(checkedRadio);
|
|
},
|
|
|
|
async _prepareDeliveryMethods() {
|
|
// Load the radios from the DOM here to update them if the template is re-rendered.
|
|
this.dmRadios = Array.from(document.querySelectorAll('input[name="o_delivery_radio"]'));
|
|
if (this.dmRadios.length > 0) {
|
|
const checkedRadio = document.querySelector('input[name="o_delivery_radio"]:checked');
|
|
this._disableMainButton();
|
|
if (checkedRadio) {
|
|
await this._updateDeliveryMethod(checkedRadio);
|
|
this._enableMainButton();
|
|
}
|
|
}
|
|
// Asynchronously fetch delivery rates to mitigate delays from third-party APIs
|
|
await Promise.all(this.dmRadios.filter(radio => !radio.checked).map(async radio => {
|
|
this._showLoadingBadge((radio));
|
|
const rateData = await this._getDeliveryRate(radio);
|
|
this._updateAmountBadge(radio, rateData);
|
|
}));
|
|
},
|
|
|
|
async _updateDeliveryMethod(radio) {
|
|
this._showLoadingBadge(radio);
|
|
const result = await this._setDeliveryMethod(radio.dataset.dmId);
|
|
this._updateAmountBadge(radio, result);
|
|
this._updateCartSummary(result);
|
|
},
|
|
|
|
async _showPickupLocation(radio) {
|
|
if (!radio.dataset.isPickupLocationRequired || radio.disabled) {
|
|
return; // Fetching the delivery rate failed.
|
|
}
|
|
const deliveryMethodContainer = this._getDeliveryMethodContainer(radio);
|
|
const pickupLocation = deliveryMethodContainer.querySelector('[name="o_pickup_location"]');
|
|
|
|
const editPickupLocationButton = pickupLocation.querySelector(
|
|
'span[name="o_pickup_location_selector"]'
|
|
);
|
|
if (editPickupLocationButton.dataset.pickupLocationData) {
|
|
await this._setPickupLocation(editPickupLocationButton.dataset.pickupLocationData);
|
|
}
|
|
|
|
pickupLocation.classList.remove('d-none'); // Show the whole div.
|
|
},
|
|
|
|
async _setPickupLocation(pickupLocationData) {
|
|
await rpc('/website_sale/set_pickup_location', {pickup_location_data: pickupLocationData});
|
|
},
|
|
_updateAmountBadge(radio, rateData) {
|
|
const deliveryPriceBadge = this._getDeliveryPriceBadge(radio);
|
|
if (rateData.success) {
|
|
// If it's a free delivery (`free_over` field), show 'Free', not '$ 0'.
|
|
if (rateData.is_free_delivery) {
|
|
deliveryPriceBadge.textContent = _t("Free");
|
|
} else {
|
|
deliveryPriceBadge.innerHTML = rateData.amount_delivery;
|
|
}
|
|
this._toggleDeliveryMethodRadio(radio);
|
|
} else {
|
|
deliveryPriceBadge.textContent = rateData.error_message;
|
|
this._toggleDeliveryMethodRadio(radio, true);
|
|
}
|
|
},
|
|
|
|
_toggleDeliveryMethodRadio(radio, disable=false) {
|
|
const deliveryMethodContainer = this._getDeliveryMethodContainer(radio);
|
|
radio.disabled = disable;
|
|
if (disable) {
|
|
deliveryMethodContainer.classList.add('text-muted');
|
|
}
|
|
else {
|
|
deliveryMethodContainer.classList.remove('text-muted');
|
|
}
|
|
},
|
|
|
|
_updateCartSummary(result) {
|
|
const amountDelivery = document.querySelector('#order_delivery .monetary_field');
|
|
const amountUntaxed = document.querySelector('#order_total_untaxed .monetary_field');
|
|
const amountTax = document.querySelector('#order_total_taxes .monetary_field');
|
|
const amountTotal = document.querySelectorAll(
|
|
'#order_total .monetary_field, #amount_total_summary.monetary_field'
|
|
);
|
|
amountDelivery.innerHTML = result.amount_delivery;
|
|
amountUntaxed.innerHTML = result.amount_untaxed;
|
|
amountTax.innerHTML = result.amount_tax;
|
|
amountTotal.forEach(total => total.innerHTML = result.amount_total);
|
|
},
|
|
|
|
async _setDeliveryMethod(dmId) {
|
|
return await rpc('/shop/set_delivery_method', {'dm_id': dmId});
|
|
},
|
|
|
|
async _getDeliveryRate(radio) {
|
|
return await rpc('/shop/get_delivery_rate', {'dm_id': radio.dataset.dmId});
|
|
},
|
|
|
|
_disableMainButton() {
|
|
this.mainButton?.classList.add('disabled');
|
|
},
|
|
|
|
_enableMainButton() {
|
|
if (this._isDeliveryMethodReady()) {
|
|
this.mainButton?.classList.remove('disabled');
|
|
}
|
|
},
|
|
|
|
_showLoadingBadge(radio) {
|
|
const deliveryPriceBadge = this._getDeliveryPriceBadge(radio);
|
|
this._clearElement(deliveryPriceBadge);
|
|
deliveryPriceBadge.appendChild(this._createLoadingElement());
|
|
},
|
|
|
|
_clearElement(el) {
|
|
while (el.firstChild) {
|
|
el.removeChild(el.lastChild);
|
|
}
|
|
},
|
|
|
|
_createLoadingElement() {
|
|
const loadingElement = document.createElement('i');
|
|
loadingElement.classList.add('fa', 'fa-circle-o-notch', 'fa-spin', 'center');
|
|
return loadingElement;
|
|
},
|
|
|
|
_isDeliveryMethodReady() {
|
|
if (this.dmRadios.length === 0) { // No delivery method is available.
|
|
return true; // Ignore the check.
|
|
}
|
|
const checkedRadio = document.querySelector('input[name="o_delivery_radio"]:checked');
|
|
return checkedRadio
|
|
&& !checkedRadio.disabled
|
|
&& !this._isPickupLocationMissing(checkedRadio);
|
|
},
|
|
|
|
_getDeliveryPriceBadge(radio) {
|
|
const deliveryMethodContainer = this._getDeliveryMethodContainer(radio);
|
|
return deliveryMethodContainer.querySelector('.o_wsale_delivery_price_badge');
|
|
},
|
|
|
|
_isPickupLocationMissing(radio) {
|
|
const deliveryMethodContainer = this._getDeliveryMethodContainer(radio);
|
|
if (!this._isPickupLocationRequired(radio)) return false;
|
|
return !deliveryMethodContainer.querySelector(
|
|
'span[name="o_pickup_location_selector"]'
|
|
).dataset.locationId;
|
|
},
|
|
|
|
_getDeliveryMethodContainer(el) {
|
|
return el.closest('[name="o_delivery_method"]');
|
|
},
|
|
|
|
_isPickupLocationRequired(radio) {
|
|
return Boolean(radio.dataset.isPickupLocationRequired);
|
|
},
|
|
});
|
|
|