From 0967efaa24db47619b850bd4edcd8d196ad2ae5f Mon Sep 17 00:00:00 2001 From: Martin Maes Date: Fri, 6 Jan 2023 13:55:50 +0000 Subject: [PATCH] [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) --- addons/website_sale_delivery/__manifest__.py | 1 - .../website_sale_delivery/controllers/main.py | 23 +- .../models/sale_order.py | 47 +- .../static/src/js/website_sale_delivery.js | 528 ++++++++++-------- .../views/locations_carrier_templates.xml | 20 - .../views/website_sale_delivery_templates.xml | 21 +- 6 files changed, 363 insertions(+), 277 deletions(-) delete mode 100644 addons/website_sale_delivery/views/locations_carrier_templates.xml diff --git a/addons/website_sale_delivery/__manifest__.py b/addons/website_sale_delivery/__manifest__.py index 3be003a3954..13c8309b6d4 100644 --- a/addons/website_sale_delivery/__manifest__.py +++ b/addons/website_sale_delivery/__manifest__.py @@ -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': [ diff --git a/addons/website_sale_delivery/controllers/main.py b/addons/website_sale_delivery/controllers/main.py index 91d841a488a..9d26aacffd1 100644 --- a/addons/website_sale_delivery/controllers/main.py +++ b/addons/website_sale_delivery/controllers/main.py @@ -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} diff --git a/addons/website_sale_delivery/models/sale_order.py b/addons/website_sale_delivery/models/sale_order.py index 9b0a3ff01b8..afb429a3480 100644 --- a/addons/website_sale_delivery/models/sale_order.py +++ b/addons/website_sale_delivery/models/sale_order.py @@ -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'] diff --git a/addons/website_sale_delivery/static/src/js/website_sale_delivery.js b/addons/website_sale_delivery/static/src/js/website_sale_delivery.js index ba5c2fc2a91..8371ae5bf31 100644 --- a/addons/website_sale_delivery/static/src/js/website_sale_delivery.js +++ b/addons/website_sale_delivery/static/src/js/website_sale_delivery.js @@ -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(''); + 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 diff --git a/addons/website_sale_delivery/views/locations_carrier_templates.xml b/addons/website_sale_delivery/views/locations_carrier_templates.xml deleted file mode 100644 index 8b2d0991f9d..00000000000 --- a/addons/website_sale_delivery/views/locations_carrier_templates.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/addons/website_sale_delivery/views/website_sale_delivery_templates.xml b/addons/website_sale_delivery/views/website_sale_delivery_templates.xml index 7031f67886c..1764eb95ef1 100644 --- a/addons/website_sale_delivery/views/website_sale_delivery_templates.xml +++ b/addons/website_sale_delivery/views/website_sale_delivery_templates.xml @@ -20,17 +20,26 @@