[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:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user