[FIX] delivery: pick up point delivery address not showing

Fixed the problem where the address of the delivery was not correct on
	- emails
	- order pdf
	- order confirmation page

The solution is to create a new partner of type delivery linked to the existing partner.
We first check if the partner exists based on the address to avoid creating an infinite number of res.partner

Fixed the problem where the non-logged user could not check the pick up locations

Remove the possibility to pay if no carriers are selected

closes odoo/odoo#105848

Related: odoo/upgrade#4124
Related: odoo/enterprise#33986
Signed-off-by: Arnold Moyaux (arm) <arm@odoo.com>
This commit is contained in:
Martin Maes
2023-03-01 23:27:55 +01:00
parent cb1b5970a5
commit 0967efaa24
6 changed files with 363 additions and 277 deletions
@@ -12,7 +12,6 @@ Configure your own methods with a pricing grid or integrate with carriers for a
'views/website_sale_delivery_templates.xml',
'views/website_sale_delivery_views.xml',
'views/res_config_settings_views.xml',
'views/locations_carrier_templates.xml',
'data/website_sale_delivery_data.xml'
],
'demo': [
@@ -28,7 +28,7 @@ class WebsiteSaleDelivery(WebsiteSale):
return super(WebsiteSaleDelivery, self).shop_payment(**post)
@http.route(['/shop/update_carrier'], type='json', auth='public', methods=['POST'], website=True, csrf=False)
@http.route(['/shop/update_carrier'], type='json', auth='public', methods=['POST'], website=True)
def update_eshop_carrier(self, **post):
order = request.website.sale_get_order()
order.access_point_address = {}
@@ -203,39 +203,40 @@ class WebsiteSaleDelivery(WebsiteSale):
order_sudo.currency_id,
),
} for carrier in order_sudo._get_delivery_methods()],
key=lambda carrier: carrier['minorAmount'])
key=lambda carrier: carrier['minorAmount'])
@http.route('/shop/access_point/set', type='json', auth='public', methods=['POST'], csrf=False, website=True, sitemap=False)
@http.route('/shop/access_point/set', type='json', auth='public', methods=['POST'], website=True, sitemap=False)
def set_access_point(self, access_point_encoded):
order = request.website.sale_get_order()
if hasattr(order.carrier_id, order.carrier_id.delivery_type + '_use_locations'):
use_location = getattr(order.carrier_id, order.carrier_id.delivery_type + '_use_locations')
access_point = use_location and access_point_encoded or None
access_point = use_location and (json.loads(access_point_encoded) if access_point_encoded else False) or False
order.write({'access_point_address': access_point})
@http.route('/shop/access_point/get', type='json', auth='public', csrf=False, website=True, sitemap=False)
@http.route('/shop/access_point/get', type='json', auth='public', website=True, sitemap=False)
def get_access_point(self):
order = request.website.sale_get_order()
if not order.carrier_id.delivery_type:
if not order.carrier_id.delivery_type or not order.carrier_id.display_name:
return {}
order_location = json.loads(order.access_point_address) if order.access_point_address else False
order_location = order.access_point_address
if not order_location:
return {}
address = order_location['address']
return {order.carrier_id.delivery_type + '_access_point': address}
name = order_location['pick_up_point_name']
return {order.carrier_id.delivery_type + '_access_point': address, 'name': name, 'delivery_name': order.carrier_id.display_name}
@http.route('/shop/access_point/close_locations', type='json', auth='public', csrf=False, website=True, sitemap=False)
@http.route('/shop/access_point/close_locations', type='json', auth='public', website=True, sitemap=False)
def get_close_locations(self):
order = request.website.sale_get_order()
try:
error = {'error': 'No pick-up point available for that shipping address'}
error = {'error': _('No pick-up point available for that shipping address')}
if not hasattr(order.carrier_id, '_' + order.carrier_id.delivery_type + '_get_close_locations'):
return error
close_locations = getattr(order.carrier_id, '_' + order.carrier_id.delivery_type + '_get_close_locations')(order.partner_shipping_id)
partner_address = order.partner_shipping_id
inline_partner_address = ' '.join((part or '') for part in [partner_address.street, partner_address.street2, partner_address.zip, partner_address.country_id.code])
if len(close_locations) < 0:
return {'error': 'No pick-up point available for that shipping address'}
return error
for location in close_locations:
location['address_stringified'] = json.dumps(location)
return {'close_locations': close_locations, 'partner_address': inline_partner_address}
@@ -11,7 +11,7 @@ class SaleOrder(models.Model):
compute='_compute_amount_delivery',
string='Delivery Amount',
help="The amount without tax.", store=True, tracking=True)
access_point_address = fields.Text('Delivery Point Address')
access_point_address = fields.Json('Delivery Point Address')
@api.depends('order_line.price_unit', 'order_line.tax_id', 'order_line.discount', 'order_line.product_uom_qty')
def _compute_amount_delivery(self):
@@ -21,6 +21,51 @@ class SaleOrder(models.Model):
else:
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_total'))
def _action_confirm(self):
for order in self:
order_location = order.access_point_address
if not order_location:
continue
# retreive all the data :
# name, street, city, state, zip, country
name = order.partner_shipping_id.name
street = order_location['pick_up_point_address']
city = order_location['pick_up_point_town']
zip_code = order_location['pick_up_point_postal_code']
country = order.env['res.country'].search([('code', '=', order_location['pick_up_point_country'])]).id
state = order.env['res.country.state'].search(['&', ('code', '=', order_location['pick_up_point_state']), ('country_id.id', '=', country)]).id if (order_location['pick_up_point_state'] and country) else None
parent_id = order.partner_shipping_id.id
email = order.partner_shipping_id.email
phone = order.partner_shipping_id.phone
# we can check if the current partner has a partner of type "delivery" that has the same address
existing_partner = order.env['res.partner'].search(['&', '&', '&', '&',
('street', '=', street),
('city', '=', city),
('state_id', '=', state),
('country_id', '=', country),
('type', '=', 'delivery')], limit=1)
if existing_partner:
order.partner_shipping_id = existing_partner
else:
# if not, we create that res.partner
order.partner_shipping_id = order.env['res.partner'].create({
'parent_id': parent_id,
'type': 'delivery',
'name': name,
'street': street,
'city': city,
'state_id': state,
'zip': zip_code,
'country_id': country,
'email': email,
'phone': phone
})
return super()._action_confirm()
def _check_carrier_quotation(self, force_carrier_id=None, keep_carrier=False):
self.ensure_one()
DeliveryCarrier = self.env['delivery.carrier']
@@ -4,10 +4,9 @@ odoo.define('website_sale_delivery.checkout', function (require) {
var core = require('web.core');
var publicWidget = require('web.public.widget');
var _t = core._t;
var qweb = core.qweb;
const _t = core._t;
const qweb = core.qweb;
var concurrency = require('web.concurrency');
var dp = new concurrency.DropPrevious();
publicWidget.registry.websiteSaleDelivery = publicWidget.Widget.extend({
selector: '.oe_website_sale',
@@ -17,42 +16,36 @@ publicWidget.registry.websiteSaleDelivery = publicWidget.Widget.extend({
"click .o_address_select": "_onClickLocation",
"click .o_remove_order_location": "_onClickRemoveLocation",
"click .o_show_pickup_locations": "_onClickShowLocations",
"click .o_payment_option_card": "_onClickPaymentMethod"
},
/**
* @override
*/
start: function () {
var self = this;
var $carriers = $('#delivery_carrier input[name="delivery_type"]');
var $payButton = $('button[name="o_payment_submit_button"]');
start: async function () {
const carriers = Array.from(document.querySelectorAll('input[name="delivery_type"]'));
this.dp = new concurrency.DropPrevious();
// Workaround to:
// - update the amount/error on the label at first rendering
// - prevent clicking on 'Pay Now' if the shipper rating fails
if ($carriers.length > 0) {
if ($carriers.filter(':checked').length === 0) {
$payButton.prop('disabled', true);
var disabledReasons = $payButton.data('disabled_reasons') || {};
disabledReasons.carrier_selection = true;
$payButton.data('disabled_reasons', disabledReasons);
if (carriers.length > 0) {
const carrierChecked = carriers.filter(e =>e.checked)
if (carrierChecked.length === 0) {
const payButton = document.querySelector('button[name="o_payment_submit_button"]');
payButton? payButton.disabled = true : null;
} else {
carrierChecked[0].click();
}
$carriers.filter(':checked').click();
}
self._getCurrentLocation();
_.each($carriers, async function (carrierInput, k) {
self._showLoading($(carrierInput));
const result = await self._rpc({
route: '/shop/carrier_rate_shipment',
params: {
'carrier_id': carrierInput.value,
},
})
self._handleCarrierUpdateResult(result)
await this._getCurrentLocation();
await _.each(carriers, async carrierInput => {
this._showLoading((carrierInput));
await this._handleCarrierUpdateResult(carrierInput)
});
return this._super.apply(this, arguments);
if (this._super && typeof(this._super.apply)==="function") {
return this._super.apply(this, arguments);
}
},
//--------------------------------------------------------------------------
@@ -62,228 +55,112 @@ publicWidget.registry.websiteSaleDelivery = publicWidget.Widget.extend({
* @private
*/
_getCurrentLocation: async function () {
const self=this;
const data = await self._rpc({
const data = await this._rpc({
route: "/shop/access_point/get",
})
const order_locations = document.getElementsByClassName("o_order_location");
for (const order_loc of order_locations) {
const show_loc = order_loc.parentElement.nextElementSibling;
// We could end not having the property
let delivery_type=""
if(order_loc.parentElement.parentElement.parentElement.children[0].attributes[8]){
delivery_type = order_loc.parentElement.parentElement.parentElement.children[0].attributes[8].nodeValue;
}
if (!show_loc)
const carriers = document.querySelectorAll('.o_delivery_carrier_select')
for (let carrier of carriers) {
const deliveryType = carrier.querySelector('input[type="radio"]').getAttribute("delivery_type");
const deliveryName = carrier.querySelector('label').innerText;
const showLoc = carrier.querySelector(".o_show_pickup_locations");
if (!showLoc) {
continue;
if (data[delivery_type+'_access_point']) {
order_loc.innerText = data[delivery_type+'_access_point']
order_loc.parentElement.classList.remove("d-none");
show_loc.classList.add("d-none");
}
const orderLoc = carrier.querySelector(".o_order_location");
if (data[deliveryType + '_access_point'] && data.delivery_name == deliveryName) {
orderLoc.querySelector(".o_order_location_name").innerText = data.name
orderLoc.querySelector(".o_order_location_address").innerText = data[deliveryType + '_access_point']
orderLoc.parentElement.classList.remove("d-none");
showLoc.classList.add("d-none");
break;
} else {
order_loc.parentElement.classList.add("d-none");
show_loc.classList.remove("d-none");
orderLoc.parentElement.classList.add("d-none");
showLoc.classList.remove("d-none");
}
}
},
/**
* @private
* @param {Element} docCarrier //carrier element from document
*/
_onClickRemoveLocation: async function (ev) {
ev.stopPropagation();
const self = this;
await this._rpc({
route: "/shop/access_point/set",
params: {
access_point_encoded: null,
},
})
self._getCurrentLocation();
},
/**
* @private
* @param {Event} ev
*/
_onClickShowLocations: async function (ev) {
const self = this;
const show_pickup_locations = ev.currentTarget;
let modal = show_pickup_locations.nextElementSibling;
if (!show_pickup_locations.getElementsByClassName("link-primary").length)
return;
const should_load_content = modal.firstChild ? false : true;
while (modal.firstChild) {
modal.lastChild.remove();
}
if (!should_load_content)
return;
var delivery_type = ev.currentTarget.closest(".o_delivery_carrier_select").childNodes[1].attributes[8].nodeValue;
const delivery_type_id = ev.currentTarget.closest(".o_delivery_carrier_select").childNodes[1].value;
await this._checkCarrier(ev,delivery_type_id)
$(qweb.render(delivery_type + "_pickup_location_loading")).appendTo($(modal));
const data = await self._rpc({
route: "/shop/access_point/close_locations",
})
if (modal.firstChild)
modal.firstChild.remove();
if(!data || data && data.error || (data && data.close_locations && data.close_locations.length==0)){
const error_message = document.createElement("em");
error_message.classList.add("text-error");
error_message.innerText = data.error ? data.error : "No available Pick-Up Locations";
modal.appendChild(error_message);
_specificDropperDisplay: function (docCarrier) {
if(!docCarrier?.closest("li").getElementsByTagName("input")[0].getAttribute("delivery_type")){
return;
}
var list_to_render = delivery_type + "_pickup_location_list";
var data_to_render = {partner_address: data.partner_address};
data_to_render[delivery_type+"_pickup_locations"] = data.close_locations;
$(qweb.render(list_to_render, data_to_render)).appendTo($(modal));
this._displayCarrierDropper(ev);
},
/**
* @private
* @param {Object} obj // can be either an event or an objet returned by the controller
*/
_displayCarrierDropper: async function (obj) {
let current_id = obj.carrier_id
const show_locations = document
.getElementById("delivery_carrier")
.getElementsByClassName("o_show_pickup_locations");
// We check if it's an event
if('currentTarget' in obj){
const is_full_page_event = !obj.currentTarget.closest(".o_delivery_carrier_select")
if(is_full_page_event)return;
for (const show_loc of show_locations){
this._specificDropperDisplay(show_loc);
}
while (docCarrier.firstChild) {
docCarrier.lastChild.remove();
}
else{
for (const show_loc of show_locations){
const current_carrier_id = show_loc.closest("li").getElementsByTagName("input")[0].value;
if (current_carrier_id == current_id) {
this._specificDropperDisplay(show_loc);
break;
}
}
}
},
/**
* @private
* @param {Object} doc_carrier //carrier element from document
*/
_specificDropperDisplay: function (doc_carrier) {
if(!doc_carrier)
return;
if(!doc_carrier.closest("li").getElementsByTagName("input")[0].attributes[8])
return;
const current_carrier_type = doc_carrier.closest("li").getElementsByTagName("input")[0].attributes[8].nodeValue;
const location_still_loading = document.getElementById("#"+current_carrier_type+"_addresses")
if(location_still_loading)return
while (doc_carrier.firstChild) {
doc_carrier.lastChild.remove();
}
const current_carrier_checked = doc_carrier.closest("li").getElementsByTagName("input")[0].checked;
const currentCarrierChecked = docCarrier.closest("li").getElementsByTagName("input")[0].checked;
const span = document.createElement("em");
const is_pick_up_location_list = doc_carrier.nextElementSibling.childNodes.length > 0
if(current_carrier_checked){
const chevron_down = document.createElement("i");
if(is_pick_up_location_list)
chevron_down.classList.add("fa", "fa-angle-up");
else
chevron_down.classList.add("fa", "fa-angle-down");
span.textContent = "Pick-Up Locations ";
span.classList.add("link-primary");
span.appendChild(chevron_down);
}
else {
if (!currentCarrierChecked) {
span.textContent = "select to see available Pick-Up Locations";
span.classList.add("text-muted");
}
doc_carrier.appendChild(span);
docCarrier.appendChild(span);
},
/**
* @private
* @param {Event} ev
* @param {Element} carrierInput
*/
_onClickLocation: async function (ev) {
ev.preventDefault();
const carrierId = ev.currentTarget.closest(".o_delivery_carrier_select").childNodes[1].value;
await this._checkCarrier(ev,carrierId)
const self = this;
const modal = ev.target.closest(".o_list_pickup_locations");
const encoded_location = ev.target.previousElementSibling.innerText;
await self._rpc({
route: "/shop/access_point/set",
params: {
access_point_encoded: encoded_location,
},
})
while (modal.firstChild) {
modal.lastChild.remove();
_showLoading: function (carrierInput) {
const priceTag = carrierInput.parentNode.querySelector('.o_wsale_delivery_badge_price')
while (priceTag.firstChild) {
priceTag.removeChild(priceTag.lastChild);
}
self._getCurrentLocation();
},
/**
* @private
* @param {jQuery} $carrierInput
*/
_showLoading: function ($carrierInput) {
$carrierInput.siblings('.o_wsale_delivery_badge_price').empty();
$carrierInput.siblings('.o_wsale_delivery_badge_price').append('<span class="fa fa-circle-o-notch fa-spin"/>');
const loadingCircle = priceTag.appendChild(document.createElement('span'));
loadingCircle.classList.add("fa", "fa-circle-o-notch", "fa-spin");
},
/**
* Update the total cost according to the selected shipping method
*
*
* @private
* @param {float} amount : The new total amount of to be paid
*/
_updateShippingCost: function(amount){
_updateShippingCost: function(amount) {
core.bus.trigger('update_shipping_cost', amount);
},
/**
* @private
* @param {Object} result
*/
_handleCarrierUpdateResult: function (result) {
this._handleCarrierUpdateResultBadge(result);
var $payButton = $('button[name="o_payment_submit_button"]');
var $amountDelivery = $('#order_delivery .monetary_field');
var $amountUntaxed = $('#order_total_untaxed .monetary_field');
var $amountTax = $('#order_total_taxes .monetary_field');
var $amountTotal = $('#order_total .monetary_field, #amount_total_summary.monetary_field');
if (result.status === true) {
$amountDelivery.html(result.new_amount_delivery);
$amountUntaxed.html(result.new_amount_untaxed);
$amountTax.html(result.new_amount_tax);
$amountTotal.html(result.new_amount_total);
var disabledReasons = $payButton.data('disabled_reasons') || {};
disabledReasons.carrier_selection = false;
$payButton.data('disabled_reasons', disabledReasons);
$payButton.prop('disabled', _.contains($payButton.data('disabled_reasons'), true));
} else {
$amountDelivery.html(result.new_amount_delivery);
$amountUntaxed.html(result.new_amount_untaxed);
$amountTax.html(result.new_amount_tax);
$amountTotal.html(result.new_amount_total);
}
if (result.new_amount_total_raw !== undefined) {
this._updateShippingCost(result.new_amount_total_raw);
}
var $carriers_inputs = $('#delivery_carrier input[name="delivery_type"]');
var carriers = [];
_.each($carriers_inputs, function (carrierInput, k) {
carriers.push(carrierInput.dataset.deliveryType);
_handleCarrierUpdateResult: async function (carrierInput) {
const result = await this._rpc({
route: '/shop/update_carrier',
params: {
'carrier_id': carrierInput.value,
},
})
this._displayCarrierDropper(result);
this._handleCarrierUpdateResultBadge(result);
if (carrierInput.checked) {
var amountDelivery = document.querySelector('#order_delivery .monetary_field');
var amountUntaxed = document.querySelector('#order_total_untaxed .monetary_field');
var amountTax = document.querySelector('#order_total_taxes .monetary_field');
var amountTotal = document.querySelector('#order_total .monetary_field, #amount_total_summary.monetary_field');
amountDelivery.innerHTML = result.new_amount_delivery;
amountUntaxed.innerHTML = result.new_amount_untaxed;
amountTax.innerHTML = result.new_amount_tax;
amountTotal.innerHTML = result.new_amount_total;
// we need to check if it's the carrier that is selected
if (result.new_amount_total_raw !== undefined) {
this._updateShippingCost(result.new_amount_total_raw);
}
this._updateShippingCost(result.new_amount_delivery);
}
this._setIsPayable(result.status);
let currentId = result.carrier_id
const showLocations = document.querySelectorAll(".o_show_pickup_locations");
for (const showLoc of showLocations) {
const currentCarrierId = showLoc.closest("li").getElementsByTagName("input")[0].value;
if (currentCarrierId == currentId) {
this._specificDropperDisplay(showLoc);
break;
}
}
},
/**
* @private
* @param {Object} result
@@ -291,7 +168,7 @@ publicWidget.registry.websiteSaleDelivery = publicWidget.Widget.extend({
_handleCarrierUpdateResultBadge: function (result) {
var $carrierBadge = $('#delivery_carrier input[name="delivery_type"][value=' + result.carrier_id + '] ~ .o_wsale_delivery_badge_price');
if (result.status === true) {
if (result.status === true) {
// if free delivery (`free_over` field), show 'Free', not '$0'
if (result.is_free_delivery) {
$carrierBadge.text(_t('Free'));
@@ -305,44 +182,219 @@ publicWidget.registry.websiteSaleDelivery = publicWidget.Widget.extend({
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
_disablePayButtonNoPickupPoint : function (ev){
const selectedCarrierEl = ev.currentTarget.closest('.o_delivery_carrier_select');
const address = selectedCarrierEl.querySelector('.o_order_location_address').innerText
const isPickUp = selectedCarrierEl.lastChild.previousSibling.children;
/**
* @private
* @param {Event} ev
*/
_onCarrierClick: async function (ev) {
var $radio = $(ev.currentTarget).find('input[type="radio"]');
this._showLoading($radio);
$radio.prop("checked", true);
var $payButton = $('button[name="o_payment_submit_button"]');
$payButton.prop('disabled', true);
var disabledReasons = $payButton.data('disabled_reasons') || {};
disabledReasons.carrier_selection = true;
$payButton.data('disabled_reasons', disabledReasons);
const data = await dp.add(this._rpc({
route: '/shop/update_carrier',
params: {
carrier_id: $radio.val(),
},
}))
this._handleCarrierUpdateResult(data);
document.querySelectorAll('.error_no_pick_up_point').forEach(el => el.remove());
if (isPickUp.length > 1 && (address == "" || isPickUp[0].classList.contains("d-none"))) {
var payButton = document.querySelector('button[name="o_payment_submit_button"]');
payButton? payButton.disabled = true : null;
const errorNode = document.createElement("i");
errorNode.classList.add("small", "error_no_pick_up_point","ms-2");
errorNode.textContent = _t("Select a pick-up point");
errorNode.style = "color:red;";
selectedCarrierEl.insertBefore(errorNode, selectedCarrierEl.querySelector("label").nextElementSibling);
}
},
_checkCarrier: async function (ev, carrier_id) {
ev.stopPropagation();
await dp.add(this._rpc({
await this.dp.add(this._rpc({
route: '/shop/update_carrier',
params: {
carrier_id: carrier_id,
},
}))
var closestDocElement = ev.currentTarget.closest('.o_delivery_carrier_select');
var $radio = $(closestDocElement).find('input[type="radio"]');
$radio.prop("checked", true);
var radio = closestDocElement.querySelector('input[type="radio"]');
radio.checked = true;
this._disablePayButtonNoPickupPoint(ev)
},
_onClickPaymentMethod: async function (ev) {
const carriers = Array.from(document.querySelectorAll('.o_delivery_carrier_select'))
let carrierChecked = null;
carriers.forEach((carrier) => {
if (carrier.querySelector('input').checked){
carrierChecked = carrier;
}
})
if (!carrierChecked) {
return;
}
const carrier_id = carrierChecked?.querySelector('input')?.value;
const result = await this._rpc({
route: '/shop/update_carrier',
params: {
'carrier_id': carrier_id,
},
})
this._setIsPayable(result.status)
},
/**
* @private
* @param {boolean} status : the status of the rate_shipment request
*/
// FYI we don't cover the case where the payement method is not selected because it already throws an error
_setIsPayable: function(status=false){
// abort if no paybutton
var payButton = document.querySelector('button[name="o_payment_submit_button"]');
if (!payButton) {
return;
}
// abort if the rating failed
if (!status){
payButton.disabled = true;
return;
}
const carriers = Array.from(document.querySelectorAll('.o_delivery_carrier_select'))
let carrierChecked = null;
carriers.forEach((carrier) => {
if (carrier.querySelector('input').checked){
carrierChecked = carrier;
}
})
//abort if no carrier is selected
if (!carrierChecked){
payButton.disabled = true;
return;
}
// if the carrier does not need a pickup point
const isPickUpPointNeeded = carrierChecked.querySelector('.o_show_pickup_locations')
if (!isPickUpPointNeeded){
payButton.disabled = false;
return;
}
const address = carrierChecked.querySelector('.o_order_location_address').innerText
const isPickUp = carrierChecked.lastChild.previousSibling.children;
if (isPickUp.length > 1 && (address == "" || isPickUp[0].classList.contains("d-none"))) {
payButton.disabled = true ;
return
}
payButton.disabled = false;
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
*/
_onClickRemoveLocation: async function (ev) {
ev.stopPropagation();
await this._rpc({
route: "/shop/access_point/set",
params: {
access_point_encoded: null,
},
})
const deliveryTypeInput = ev.currentTarget.closest(".o_delivery_carrier_select").querySelector('input[name="delivery_type"]');
const deliveryTypeId = deliveryTypeInput.value;
await Promise.all([this._getCurrentLocation(),this._checkCarrier(ev,deliveryTypeId)])
await this._onClickShowLocations(ev);
},
/**
* @private
* @param {Event} ev
*/
_onClickShowLocations: async function (ev) {
// This checks if there is a pick up point already select with that carrier
if (!ev.currentTarget.closest('.o_delivery_carrier_select').querySelector(".o_order_location").parentElement.classList.contains("d-none")) {
return;
}
const showPickupLocations = ev.currentTarget.closest('.o_delivery_carrier_select').querySelector('.o_show_pickup_locations');
const modal = showPickupLocations?.nextElementSibling;
if (!modal) {
return;
}
while (modal.firstChild) {
modal.lastChild.remove();
}
const deliveryTypeInput = ev.currentTarget.closest(".o_delivery_carrier_select").querySelector('input[name="delivery_type"]');
const deliveryType = deliveryTypeInput.getAttribute("delivery_type");
const deliveryTypeId = deliveryTypeInput.value;
await this._checkCarrier(ev,deliveryTypeId)
$(qweb.render(deliveryType + "_pickup_location_loading")).appendTo($(modal));
const data = await this._rpc({
route: "/shop/access_point/close_locations",
})
if (modal.firstChild){
modal.firstChild.remove();
}
if (data.error || (data.close_locations.length === 0)) {
const errorMessage = document.createElement("em");
errorMessage.classList.add("text-error");
errorMessage.innerText = data.error ? data.error : "No available Pick-Up Locations";
modal.appendChild(errorMessage);
return;
}
var listToRender = deliveryType + "_pickup_location_list";
var dataToRender = {partner_address: data.partner_address};
dataToRender[deliveryType + "_pickup_locations"] = data.close_locations;
$(qweb.render(listToRender, dataToRender)).appendTo($(modal));
const showLocations = document.querySelectorAll(".o_show_pickup_locations");
if (!ev.currentTarget.closest(".o_delivery_carrier_select")) {
return;
}
for (const showLoc of showLocations) {
this._specificDropperDisplay(showLoc);
}
},
/**
* @private
* @param {Event} ev
*/
_onCarrierClick: async function (ev) {
const radio = ev.currentTarget.closest('.o_delivery_carrier_select').querySelector('input[type="radio"]');
if (radio.checked) {
return;
}
this._showLoading(radio);
radio.checked = true;
await this._onClickShowLocations(ev);
await this._handleCarrierUpdateResult(radio);
this._disablePayButtonNoPickupPoint(ev);
},
/**
* @private
* @param {Event} ev
*/
_onClickLocation: async function (ev) {
const carrierId = ev.currentTarget.closest(".o_delivery_carrier_select").childNodes[1].value;
await this._checkCarrier(ev,carrierId)
const modal = ev.target.closest(".o_list_pickup_locations");
const encodedLocation = ev.target.previousElementSibling.innerText;
await this._rpc({
route: "/shop/access_point/set",
params: {
access_point_encoded: encodedLocation,
},
})
while (modal.firstChild) {
modal.lastChild.remove();
}
await this._getCurrentLocation();
document.querySelectorAll('.error_no_pick_up_point').forEach(el => el.remove());
const result = await this._rpc({
route: '/shop/update_carrier',
params: {
'carrier_id': carrierId,
},
})
this._setIsPayable(result.status)
},
/**
* @private
* @param {Event} ev
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="payment_delivery_methods_inherit_website_sale_delivery" inherit_id="website_sale_delivery.payment_delivery_methods">
<xpath expr="//span[@name='price']" position="after">
<t t-set='delivery_method' t-value="delivery.delivery_type+'_use_locations'" />
<div class="small">
<div class="d-none">
<b class="o_order_location"/>
<span class="fa fa-trash-o ms-2 o_remove_order_location" aria-label="Remove this location" title="Remove this location"/>
</div>
<t t-if="delivery_method in delivery.fields_get()">
<t t-if="delivery[delivery_method]">
<div class="o_show_pickup_locations"/>
<div class="o_list_pickup_locations"/>
</t>
</t>
</div>
</xpath>
</template>
</odoo>
@@ -20,17 +20,26 @@
<label class="label-optional" t-field="delivery.name"/>
<t t-set='badge_class' t-value="'float-end ' + 'badge text-bg-secondary'" />
<span t-attf-class="#{badge_class} o_wsale_delivery_badge_price" name="price">Select to compute delivery rate</span>
<t t-set='delivery_method' t-value="delivery.delivery_type+'_use_locations'" />
<div class="small">
<div class="d-none">
<span class="o_order_location">
<b class="o_order_location_name"/>
<br/>
<i class="o_order_location_address"/>
</span>
<span class="fa fa-times ms-2 o_remove_order_location" aria-label="Remove this location" title="Remove this location"/>
</div>
<t t-if="delivery_method in delivery.fields_get() and delivery[delivery_method]">
<div class="o_show_pickup_locations"/>
<div class="o_list_pickup_locations"/>
</t>
</div>
<t t-if="delivery.website_description">
<div t-field="delivery.website_description" class="text-muted mt8"/>
</t>
</template>
<template id="payment_delivery_shipping_method" name="Delivery Shipping method" inherit_id="website_sale.address_on_payment">
<xpath expr="//div[@id='shipping_and_billing']" position="inside">
<t t-set="delivery_nb" t-value="deliveries and len(deliveries) or 0"/>
</xpath>
</template>
<template id="payment_delivery" name="Delivery Costs" inherit_id="website_sale.payment">
<xpath expr="//t[@t-if='website_sale_order.amount_total']" position="before">
<div t-if="deliveries" id="delivery_carrier">