This commit is contained in:
2025-03-31 20:17:05 +02:00
parent a03df0b268
commit d4d4c0c09d
1617 changed files with 1106381 additions and 268 deletions

View File

@@ -0,0 +1,42 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderDiscountsRefresher {
constructor() {
this.router = new Router();
}
refresh(orderId) {
$.ajax(this.router.generate('admin_orders_get_discounts', {orderId}))
.then((response) => {
$(OrderViewPageMap.productDiscountList.list).replaceWith(response);
});
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import InvoiceNoteManager from '../invoice-note-manager';
const {$} = window;
export default class OrderDocumentsRefresher {
constructor() {
this.router = new Router();
this.invoiceNoteManager = new InvoiceNoteManager();
}
refresh(orderId) {
$.getJSON(this.router.generate('admin_orders_get_documents', {orderId}))
.then((response) => {
$(OrderViewPageMap.orderDocumentsTabCount).text(response.total);
$(OrderViewPageMap.orderDocumentsTabBody).html(response.html);
this.invoiceNoteManager.setupListeners();
});
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderInvoicesRefresher {
constructor() {
this.router = new Router();
}
refresh(orderId) {
$.getJSON(this.router.generate('admin_orders_get_invoices', {orderId}))
.then((response) => {
if (!response || !response.invoices || Object.keys(response.invoices).length <= 0) {
return;
}
const $paymentInvoiceSelect = $(OrderViewPageMap.orderPaymentInvoiceSelect);
const $addProductInvoiceSelect = $(OrderViewPageMap.productAddInvoiceSelect);
const $existingInvoicesGroup = $addProductInvoiceSelect.find('optgroup:first');
const $productEditInvoiceSelect = $(OrderViewPageMap.productEditInvoiceSelect);
const $addDiscountInvoiceSelect = $(OrderViewPageMap.addCartRuleInvoiceIdSelect);
$existingInvoicesGroup.empty();
$paymentInvoiceSelect.empty();
$productEditInvoiceSelect.empty();
$addDiscountInvoiceSelect.empty();
Object.keys(response.invoices).forEach((invoiceName) => {
const invoiceId = response.invoices[invoiceName];
const invoiceNameWithoutPrice = invoiceName.split(' - ')[0];
$existingInvoicesGroup.append(`<option value="${invoiceId}">${invoiceNameWithoutPrice}</option>`);
$paymentInvoiceSelect.append(`<option value="${invoiceId}">${invoiceNameWithoutPrice}</option>`);
$productEditInvoiceSelect.append(`<option value="${invoiceId}">${invoiceNameWithoutPrice}</option>`);
$addDiscountInvoiceSelect.append(`<option value="${invoiceId}">${invoiceName}</option>`);
});
document.querySelector(OrderViewPageMap.productAddInvoiceSelect).selectedIndex = 0;
});
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderPaymentsRefresher {
constructor() {
this.router = new Router();
}
refresh(orderId) {
$.ajax(this.router.generate('admin_orders_get_payments', {orderId}))
.then(
(response) => {
$(OrderViewPageMap.viewOrderPaymentsAlert).remove();
$(`${OrderViewPageMap.viewOrderPaymentsBlock} .card-body`).prepend(response);
},
(response) => {
if (response.responseJSON && response.responseJSON.message) {
$.growl.error({message: response.responseJSON.message});
}
},
);
}
}

View File

@@ -0,0 +1,126 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderPricesRefresher {
constructor() {
this.router = new Router();
}
refresh(orderId) {
$.getJSON(this.router.generate('admin_orders_get_prices', {orderId})).then((response) => {
$(OrderViewPageMap.orderTotal).text(response.orderTotalFormatted);
$(OrderViewPageMap.orderDiscountsTotal).text(`-${response.discountsAmountFormatted}`);
$(OrderViewPageMap.orderDiscountsTotalContainer).toggleClass('d-none', !response.discountsAmountDisplayed);
$(OrderViewPageMap.orderProductsTotal).text(response.productsTotalFormatted);
$(OrderViewPageMap.orderShippingTotal).text(response.shippingTotalFormatted);
$(OrderViewPageMap.orderShippingTotalContainer).toggleClass('d-none', !response.shippingTotalDisplayed);
$(OrderViewPageMap.orderTaxesTotal).text(response.taxesTotalFormatted);
});
}
refreshProductPrices(orderId) {
$.getJSON(this.router.generate('admin_orders_product_prices', {orderId})).then((productPricesList) => {
productPricesList.forEach((productPrices) => {
const orderProductTrId = OrderViewPageMap.productsTableRow(productPrices.orderDetailId);
let $quantity = $(productPrices.quantity);
if (productPrices.quantity > 1) {
$quantity = $quantity.wrap('<span class="badge badge-secondary rounded-circle"></span>');
}
$(`${orderProductTrId} ${OrderViewPageMap.productEditUnitPrice}`).text(productPrices.unitPrice);
$(`${orderProductTrId} ${OrderViewPageMap.productEditQuantity}`).html($quantity.html());
$(`${orderProductTrId} ${OrderViewPageMap.productEditAvailableQuantity}`).text(productPrices.availableQuantity);
$(`${orderProductTrId} ${OrderViewPageMap.productEditTotalPrice}`).text(productPrices.totalPrice);
// update order row price values
const productEditButton = $(OrderViewPageMap.productEditBtn(productPrices.orderDetailId));
productEditButton.data('product-price-tax-incl', productPrices.unitPriceTaxInclRaw);
productEditButton.data('product-price-tax-excl', productPrices.unitPriceTaxExclRaw);
productEditButton.data('product-quantity', productPrices.quantity);
});
});
}
/**
* This method will check if the same product is already present in the order
* and if so and if the price of the 2 products doesn't match will return either
* 'invoice' if the 2 products are in 2 different invoices or 'product' if the 2 products
* are in the same invoice (or no invoice yet). Only products that have different customizations
* can be twice in a same invoice.
* Will return null if no matching products are found.
*/
checkOtherProductPricesMatch(givenPrice, productId, combinationId, invoiceId, orderDetailId) {
const productRows = document.querySelectorAll('tr.cellProduct');
// We convert the expected values into int/float to avoid a type mismatch that would be wrongly interpreted
const expectedProductId = Number(productId);
const expectedCombinationId = Number(combinationId);
const expectedGivenPrice = Number(givenPrice);
let unmatchingInvoicePriceExists = false;
let unmatchingProductPriceExists = false;
productRows.forEach((productRow) => {
const productRowId = $(productRow).attr('id');
// No need to check edited row (especially if it's the only one for this product)
if (orderDetailId && productRowId === `orderProduct_${orderDetailId}`) {
return;
}
const productEditBtn = $(`#${productRowId} ${OrderViewPageMap.productEditButtons}`);
const currentOrderInvoiceId = Number(productEditBtn.data('order-invoice-id'));
const currentProductId = Number(productEditBtn.data('product-id'));
const currentCombinationId = Number(productEditBtn.data('combination-id'));
if (currentProductId !== expectedProductId || currentCombinationId !== expectedCombinationId) {
return;
}
if (expectedGivenPrice !== Number(productEditBtn.data('product-price-tax-incl'))) {
if (invoiceId === '' || (invoiceId && currentOrderInvoiceId && invoiceId === currentOrderInvoiceId)) {
unmatchingProductPriceExists = true;
} else {
unmatchingInvoicePriceExists = true;
}
}
});
if (unmatchingInvoicePriceExists) {
return 'invoice';
}
if (unmatchingProductPriceExists) {
return 'product';
}
return null;
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
export default class OrderPrices {
calculateTaxExcluded(taxIncluded, taxRatePerCent, currencyPrecision) {
let priceTaxIncl = parseFloat(taxIncluded);
if (priceTaxIncl < 0 || Number.isNaN(priceTaxIncl)) {
priceTaxIncl = 0;
}
const taxRate = taxRatePerCent / 100 + 1;
return window.ps_round(priceTaxIncl / taxRate, currencyPrecision);
}
calculateTaxIncluded(taxExcluded, taxRatePerCent, currencyPrecision) {
let priceTaxExcl = parseFloat(taxExcluded);
if (priceTaxExcl < 0 || Number.isNaN(priceTaxExcl)) {
priceTaxExcl = 0;
}
const taxRate = taxRatePerCent / 100 + 1;
return window.ps_round(priceTaxExcl * taxRate, currencyPrecision);
}
calculateTotalPrice(quantity, unitPrice, currencyPrecision) {
return window.ps_round(unitPrice * quantity, currencyPrecision);
}
}

View File

@@ -0,0 +1,121 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderProductAutocomplete {
constructor(input) {
this.activeSearchRequest = null;
this.router = new Router();
this.input = input;
this.results = [];
this.dropdownMenu = $(OrderViewPageMap.productSearchInputAutocompleteMenu);
/**
* Permit to link to each value of dropdown a callback after item is clicked
*/
this.onItemClickedCallback = () => {};
}
listenForSearch() {
this.input.on('click', (event) => {
event.stopImmediatePropagation();
this.updateResults(this.results);
});
this.input.on('keyup', (event) => this.delaySearch(event.currentTarget));
$(document).on('click', () => this.dropdownMenu.hide());
}
delaySearch(input) {
clearTimeout(this.searchTimeoutId);
// Search only if the search phrase length is greater than 2 characters
if (input.value.length < 2) {
return;
}
this.searchTimeoutId = setTimeout(() => {
this.search(input.value, $(input).data('currency'), $(input).data('order'));
}, 300);
}
search(search, currency, orderId) {
const params = {search_phrase: search};
if (currency) {
params.currency_id = currency;
}
if (orderId) {
params.order_id = orderId;
}
if (this.activeSearchRequest !== null) {
this.activeSearchRequest.abort();
}
this.activeSearchRequest = $.get(this.router.generate('admin_orders_products_search', params));
this.activeSearchRequest
.then((response) => this.updateResults(response))
.always(() => {
this.activeSearchRequest = null;
});
}
updateResults(results) {
this.dropdownMenu.empty();
if (!results || !results.products || Object.keys(results.products).length <= 0) {
this.dropdownMenu.hide();
return;
}
this.results = results.products;
Object.values(this.results).forEach((val) => {
const link = $(`<a class="dropdown-item" data-id="${val.productId}" href="#">${val.name}</a>`);
link.on('click', (event) => {
event.preventDefault();
this.onItemClicked($(event.target).data('id'));
});
this.dropdownMenu.append(link);
});
this.dropdownMenu.show();
}
onItemClicked(id) {
const selectedProduct = this.results.filter((product) => product.productId === id);
if (selectedProduct.length !== 0) {
this.input.val(selectedProduct[0].name);
this.onItemClickedCallback(selectedProduct[0]);
}
}
}

View File

@@ -0,0 +1,299 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import {EventEmitter} from '@components/event-emitter';
import OrderViewEventMap from '@pages/order/view/order-view-event-map';
import OrderPrices from '@pages/order/view/order-prices';
import OrderProductRenderer from '@pages/order/view/order-product-renderer';
import ConfirmModal from '@components/modal';
import OrderPricesRefresher from '@pages/order/view/order-prices-refresher';
const {$} = window;
export default class OrderProductAdd {
constructor() {
this.router = new Router();
this.productAddActionBtn = $(OrderViewPageMap.productAddActionBtn);
this.productIdInput = $(OrderViewPageMap.productAddIdInput);
this.combinationsBlock = $(OrderViewPageMap.productAddCombinationsBlock);
this.combinationsSelect = $(OrderViewPageMap.productAddCombinationsSelect);
this.priceTaxIncludedInput = $(OrderViewPageMap.productAddPriceTaxInclInput);
this.priceTaxExcludedInput = $(OrderViewPageMap.productAddPriceTaxExclInput);
this.taxRateInput = $(OrderViewPageMap.productAddTaxRateInput);
this.quantityInput = $(OrderViewPageMap.productAddQuantityInput);
this.availableText = $(OrderViewPageMap.productAddAvailableText);
this.locationText = $(OrderViewPageMap.productAddLocationText);
this.totalPriceText = $(OrderViewPageMap.productAddTotalPriceText);
this.invoiceSelect = $(OrderViewPageMap.productAddInvoiceSelect);
this.freeShippingSelect = $(OrderViewPageMap.productAddFreeShippingSelect);
this.productAddMenuBtn = $(OrderViewPageMap.productAddBtn);
this.available = null;
this.setupListener();
this.product = {};
this.currencyPrecision = $(OrderViewPageMap.productsTable).data('currencyPrecision');
this.priceTaxCalculator = new OrderPrices();
this.orderProductRenderer = new OrderProductRenderer();
this.orderPricesRefresher = new OrderPricesRefresher();
this.isOrderTaxIncluded = $(OrderViewPageMap.productAddRow).data('isOrderTaxIncluded');
this.taxExcluded = null;
this.taxIncluded = null;
}
setupListener() {
this.combinationsSelect.on('change', (event) => {
const taxExcluded = window.ps_round(
$(event.currentTarget)
.find(':selected')
.data('priceTaxExcluded'),
this.currencyPrecision,
);
this.priceTaxExcludedInput.val(taxExcluded);
this.taxExcluded = parseFloat(taxExcluded);
const taxIncluded = window.ps_round(
$(event.currentTarget)
.find(':selected')
.data('priceTaxIncluded'),
this.currencyPrecision,
);
this.priceTaxIncludedInput.val(taxIncluded);
this.taxIncluded = parseFloat(taxIncluded);
this.locationText.html(
$(event.currentTarget)
.find(':selected')
.data('location'),
);
this.available = $(event.currentTarget)
.find(':selected')
.data('stock');
this.quantityInput.trigger('change');
this.orderProductRenderer.toggleColumn(OrderViewPageMap.productsCellLocation);
});
this.quantityInput.on('change keyup', (event) => {
if (this.available !== null) {
const newQuantity = Number(event.target.value);
const remainingAvailable = this.available - newQuantity;
const availableOutOfStock = this.availableText.data('availableOutOfStock');
this.availableText.text(remainingAvailable);
this.availableText.toggleClass('text-danger font-weight-bold', remainingAvailable < 0);
const disableAddActionBtn = newQuantity <= 0 || (remainingAvailable < 0 && !availableOutOfStock);
this.productAddActionBtn.prop('disabled', disableAddActionBtn);
this.invoiceSelect.prop('disabled', !availableOutOfStock && remainingAvailable < 0);
this.taxIncluded = parseFloat(this.priceTaxIncludedInput.val());
this.totalPriceText.html(
this.priceTaxCalculator.calculateTotalPrice(
newQuantity,
this.isOrderTaxIncluded ? this.taxIncluded : this.taxExcluded,
this.currencyPrecision,
),
);
}
});
this.productIdInput.on('change', () => {
this.productAddActionBtn.removeAttr('disabled');
this.invoiceSelect.removeAttr('disabled');
});
this.priceTaxIncludedInput.on('change keyup', (event) => {
this.taxIncluded = parseFloat(event.target.value);
this.taxExcluded = this.priceTaxCalculator.calculateTaxExcluded(
this.taxIncluded,
this.taxRateInput.val(),
this.currencyPrecision,
);
const quantity = parseInt(this.quantityInput.val(), 10);
this.priceTaxExcludedInput.val(this.taxExcluded);
this.totalPriceText.html(
this.priceTaxCalculator.calculateTotalPrice(
quantity,
this.isOrderTaxIncluded ? this.taxIncluded : this.taxExcluded,
this.currencyPrecision,
),
);
});
this.priceTaxExcludedInput.on('change keyup', (event) => {
this.taxExcluded = parseFloat(event.target.value);
this.taxIncluded = this.priceTaxCalculator.calculateTaxIncluded(
this.taxExcluded,
this.taxRateInput.val(),
this.currencyPrecision,
);
const quantity = parseInt(this.quantityInput.val(), 10);
this.priceTaxIncludedInput.val(this.taxIncluded);
this.totalPriceText.html(
this.priceTaxCalculator.calculateTotalPrice(
quantity,
this.isOrderTaxIncluded ? this.taxIncluded : this.taxExcluded,
this.currencyPrecision,
),
);
});
this.productAddActionBtn.on('click', (event) => this.confirmNewInvoice(event));
this.invoiceSelect.on('change', () => this.orderProductRenderer.toggleProductAddNewInvoiceInfo());
}
setProduct(product) {
this.productIdInput.val(product.productId).trigger('change');
const taxExcluded = window.ps_round(product.priceTaxExcl, this.currencyPrecision);
this.priceTaxExcludedInput.val(taxExcluded);
this.taxExcluded = parseFloat(taxExcluded);
const taxIncluded = window.ps_round(product.priceTaxIncl, this.currencyPrecision);
this.priceTaxIncludedInput.val(taxIncluded);
this.taxIncluded = parseFloat(taxIncluded);
this.taxRateInput.val(product.taxRate);
this.locationText.html(product.location);
this.available = product.stock;
this.availableText.data('availableOutOfStock', product.availableOutOfStock);
this.quantityInput.val(1);
this.quantityInput.trigger('change');
this.setCombinations(product.combinations);
this.orderProductRenderer.toggleColumn(OrderViewPageMap.productsCellLocation);
}
setCombinations(combinations) {
this.combinationsSelect.empty();
Object.values(combinations).forEach((val) => {
this.combinationsSelect.append(
/* eslint-disable-next-line max-len */
`<option value="${val.attributeCombinationId}" data-price-tax-excluded="${val.priceTaxExcluded}" data-price-tax-included="${val.priceTaxIncluded}" data-stock="${val.stock}" data-location="${val.location}">${val.attribute}</option>`,
);
});
this.combinationsBlock.toggleClass('d-none', Object.keys(combinations).length === 0);
if (Object.keys(combinations).length > 0) {
this.combinationsSelect.trigger('change');
}
}
addProduct(orderId) {
this.productAddActionBtn.prop('disabled', true);
this.invoiceSelect.prop('disabled', true);
this.combinationsSelect.prop('disabled', true);
const params = {
product_id: this.productIdInput.val(),
combination_id: $(':selected', this.combinationsSelect).val(),
price_tax_incl: this.priceTaxIncludedInput.val(),
price_tax_excl: this.priceTaxExcludedInput.val(),
quantity: this.quantityInput.val(),
invoice_id: this.invoiceSelect.val(),
free_shipping: this.freeShippingSelect.prop('checked'),
};
$.ajax({
url: this.router.generate('admin_orders_add_product', {orderId}),
method: 'POST',
data: params,
}).then(
(response) => {
EventEmitter.emit(OrderViewEventMap.productAddedToOrder, {
orderId,
orderProductId: params.product_id,
newRow: response,
});
},
(response) => {
this.productAddActionBtn.prop('disabled', false);
this.invoiceSelect.prop('disabled', false);
this.combinationsSelect.prop('disabled', false);
if (response.responseJSON && response.responseJSON.message) {
$.growl.error({message: response.responseJSON.message});
}
},
);
}
confirmNewInvoice(event) {
const invoiceId = parseInt(this.invoiceSelect.val(), 10);
const orderId = $(event.currentTarget).data('orderId');
// Explicit 0 value is used when we the user selected New Invoice
if (invoiceId === 0) {
const modal = new ConfirmModal(
{
id: 'modal-confirm-new-invoice',
confirmTitle: this.invoiceSelect.data('modal-title'),
confirmMessage: this.invoiceSelect.data('modal-body'),
confirmButtonLabel: this.invoiceSelect.data('modal-apply'),
closeButtonLabel: this.invoiceSelect.data('modal-cancel'),
},
() => {
this.confirmNewPrice(orderId, invoiceId);
},
);
modal.show();
} else {
// Last case is Nan, the selector is not even present, we simply add product and let the BO handle it
this.addProduct(orderId);
}
}
confirmNewPrice(orderId, invoiceId) {
const combinationValue = $(':selected', this.combinationsSelect).val();
const combinationId = typeof combinationValue === 'undefined' ? 0 : combinationValue;
const productPriceMatch = this.orderPricesRefresher.checkOtherProductPricesMatch(
this.priceTaxIncludedInput.val(),
this.productIdInput.val(),
combinationId,
invoiceId,
);
if (productPriceMatch === 'invoice') {
const modalEditPrice = new ConfirmModal(
{
id: 'modal-confirm-new-price',
confirmTitle: this.invoiceSelect.data('modal-edit-price-title'),
confirmMessage: this.invoiceSelect.data('modal-edit-price-body'),
confirmButtonLabel: this.invoiceSelect.data('modal-edit-price-apply'),
closeButtonLabel: this.invoiceSelect.data('modal-edit-price-cancel'),
},
() => {
this.addProduct(orderId);
},
);
modalEditPrice.show();
} else {
this.addProduct(orderId);
}
}
}

View File

@@ -0,0 +1,266 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import {NumberFormatter} from '@app/cldr';
const {$} = window;
/**
* manages all product cancel actions, that includes all refund operations
*/
export default class OrderProductCancel {
constructor() {
this.router = new Router();
this.cancelProductForm = $(OrderViewPageMap.cancelProduct.form);
this.orderId = this.cancelProductForm.data('orderId');
this.orderDelivered = parseInt(this.cancelProductForm.data('isDelivered'), 10) === 1;
this.isTaxIncluded = parseInt(this.cancelProductForm.data('isTaxIncluded'), 10) === 1;
this.discountsAmount = parseFloat(this.cancelProductForm.data('discountsAmount'));
this.currencyFormatter = NumberFormatter.build(
this.cancelProductForm.data('priceSpecification'),
);
this.useAmountInputs = true;
this.listenForInputs();
}
showPartialRefund() {
// Always start by hiding elements then show the others, since some elements are common
this.hideCancelElements();
$(OrderViewPageMap.cancelProduct.toggle.partialRefund).show();
this.useAmountInputs = true;
this.initForm(
$(OrderViewPageMap.cancelProduct.buttons.save).data('partialRefundLabel'),
this.router.generate('admin_orders_partial_refund', {
orderId: this.orderId,
}),
'partial-refund',
);
}
showStandardRefund() {
// Always start by hiding elements then show the others, since some elements are common
this.hideCancelElements();
$(OrderViewPageMap.cancelProduct.toggle.standardRefund).show();
this.useAmountInputs = false;
this.initForm(
$(OrderViewPageMap.cancelProduct.buttons.save).data('standardRefundLabel'),
this.router.generate('admin_orders_standard_refund', {
orderId: this.orderId,
}),
'standard-refund',
);
}
showReturnProduct() {
// Always start by hiding elements then show the others, since some elements are common
this.hideCancelElements();
$(OrderViewPageMap.cancelProduct.toggle.returnProduct).show();
this.useAmountInputs = false;
this.initForm(
$(OrderViewPageMap.cancelProduct.buttons.save).data('returnProductLabel'),
this.router.generate('admin_orders_return_product', {
orderId: this.orderId,
}),
'return-product',
);
}
hideRefund() {
this.hideCancelElements();
$(OrderViewPageMap.cancelProduct.table.actions).show();
}
hideCancelElements() {
$(OrderViewPageMap.cancelProduct.toggle.standardRefund).hide();
$(OrderViewPageMap.cancelProduct.toggle.partialRefund).hide();
$(OrderViewPageMap.cancelProduct.toggle.returnProduct).hide();
$(OrderViewPageMap.cancelProduct.table.actions).hide();
}
initForm(actionName, formAction, formClass) {
this.updateVoucherRefund();
this.cancelProductForm.prop('action', formAction);
this.cancelProductForm
.removeClass('standard-refund partial-refund return-product cancel-product')
.addClass(formClass);
$(OrderViewPageMap.cancelProduct.buttons.save).html(actionName);
$(OrderViewPageMap.cancelProduct.table.header).html(actionName);
$(OrderViewPageMap.cancelProduct.checkboxes.restock).prop('checked', this.orderDelivered);
$(OrderViewPageMap.cancelProduct.checkboxes.creditSlip).prop('checked', true);
$(OrderViewPageMap.cancelProduct.checkboxes.voucher).prop('checked', false);
}
listenForInputs() {
$(document).on('change', OrderViewPageMap.cancelProduct.inputs.quantity, (event) => {
const $productQuantityInput = $(event.target);
const $parentCell = $productQuantityInput.parents(OrderViewPageMap.cancelProduct.table.cell);
const $productAmount = $parentCell.find(OrderViewPageMap.cancelProduct.inputs.amount);
const productQuantity = parseInt($productQuantityInput.val(), 10);
if (productQuantity <= 0) {
$productAmount.val(0);
this.updateVoucherRefund();
return;
}
const priceFieldName = this.isTaxIncluded ? 'productPriceTaxIncl' : 'productPriceTaxExcl';
const productUnitPrice = parseFloat($productQuantityInput.data(priceFieldName));
const amountRefundable = parseFloat($productQuantityInput.data('amountRefundable'));
const guessedAmount = productUnitPrice * productQuantity < amountRefundable
? productUnitPrice * productQuantity
: amountRefundable;
const amountValue = parseFloat($productAmount.val());
if (this.useAmountInputs) {
this.updateAmountInput($productQuantityInput);
}
if ($productAmount.val() === '' || amountValue === 0 || amountValue > guessedAmount) {
$productAmount.val(guessedAmount);
this.updateVoucherRefund();
}
});
$(document).on('change', OrderViewPageMap.cancelProduct.inputs.amount, () => {
this.updateVoucherRefund();
});
$(document).on('change', OrderViewPageMap.cancelProduct.inputs.selector, (event) => {
const $productCheckbox = $(event.target);
const $parentCell = $productCheckbox.parents(OrderViewPageMap.cancelProduct.table.cell);
const productQuantityInput = $parentCell.find(OrderViewPageMap.cancelProduct.inputs.quantity);
const refundableQuantity = parseInt(productQuantityInput.data('quantityRefundable'), 10);
const productQuantity = parseInt(productQuantityInput.val(), 10);
if (!$productCheckbox.is(':checked')) {
productQuantityInput.val(0);
} else if (Number.isNaN(productQuantity) || productQuantity === 0) {
productQuantityInput.val(refundableQuantity);
}
this.updateVoucherRefund();
});
}
updateAmountInput($productQuantityInput) {
const $parentCell = $productQuantityInput.parents(OrderViewPageMap.cancelProduct.table.cell);
const $productAmount = $parentCell.find(OrderViewPageMap.cancelProduct.inputs.amount);
const productQuantity = parseInt($productQuantityInput.val(), 10);
if (productQuantity <= 0) {
$productAmount.val(0);
return;
}
const priceFieldName = this.isTaxIncluded ? 'productPriceTaxIncl' : 'productPriceTaxExcl';
const productUnitPrice = parseFloat($productQuantityInput.data(priceFieldName));
const amountRefundable = parseFloat($productQuantityInput.data('amountRefundable'));
const guessedAmount = productUnitPrice * productQuantity < amountRefundable
? productUnitPrice * productQuantity
: amountRefundable;
const amountValue = parseFloat($productAmount.val());
if ($productAmount.val() === '' || amountValue === 0 || amountValue > guessedAmount) {
$productAmount.val(guessedAmount);
}
}
getRefundAmount() {
let totalAmount = 0;
if (this.useAmountInputs) {
$(OrderViewPageMap.cancelProduct.inputs.amount).each((index, amount) => {
const floatValue = parseFloat(amount.value);
totalAmount += !Number.isNaN(floatValue) ? floatValue : 0;
});
} else {
$(OrderViewPageMap.cancelProduct.inputs.quantity).each((index, quantity) => {
const $quantityInput = $(quantity);
const priceFieldName = this.isTaxIncluded ? 'productPriceTaxIncl' : 'productPriceTaxExcl';
const productUnitPrice = parseFloat($quantityInput.data(priceFieldName));
const productQuantity = parseInt($quantityInput.val(), 10);
totalAmount += productQuantity * productUnitPrice;
});
}
return totalAmount;
}
updateVoucherRefund() {
const refundAmount = this.getRefundAmount();
this.updateVoucherRefundTypeLabel(
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.productPrices),
refundAmount,
);
const refundVoucherExcluded = refundAmount - this.discountsAmount;
this.updateVoucherRefundTypeLabel(
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.productPricesVoucherExcluded),
refundVoucherExcluded,
);
// Disable voucher excluded option when the voucher amount is too high
if (refundVoucherExcluded < 0) {
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.productPricesVoucherExcluded)
.prop('checked', false)
.prop('disabled', true);
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.productPrices).prop(
'checked',
true,
);
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.negativeErrorMessage).show();
} else {
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.productPricesVoucherExcluded).prop(
'disabled',
false,
);
$(OrderViewPageMap.cancelProduct.radios.voucherRefundType.negativeErrorMessage).hide();
}
}
updateVoucherRefundTypeLabel($input, refundAmount) {
const defaultLabel = $input.data('defaultLabel');
const $label = $input.parents('label');
const formattedAmount = this.currencyFormatter.format(refundAmount);
// Change the ending text part only to avoid removing the input (the EOL is on purpose for better display)
$label.get(0).lastChild.nodeValue = `
${defaultLabel} ${formattedAmount}`;
}
showCancelProductForm() {
const cancelProductRoute = this.router.generate('admin_orders_cancellation', {orderId: this.orderId});
this.initForm(
$(OrderViewPageMap.cancelProduct.buttons.save).data('cancelLabel'),
cancelProductRoute,
'cancel-product',
);
this.hideCancelElements();
$(OrderViewPageMap.cancelProduct.toggle.cancelProducts).show();
}
}

View File

@@ -0,0 +1,249 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import {EventEmitter} from '@components/event-emitter';
import OrderViewEventMap from '@pages/order/view/order-view-event-map';
import OrderPrices from '@pages/order/view/order-prices';
import ConfirmModal from '@components/modal';
import OrderPricesRefresher from '@pages/order/view/order-prices-refresher';
const {$} = window;
export default class OrderProductEdit {
constructor(orderDetailId) {
this.router = new Router();
this.orderDetailId = orderDetailId;
this.productRow = $(`#orderProduct_${this.orderDetailId}`);
this.product = {};
this.currencyPrecision = $(OrderViewPageMap.productsTable).data('currencyPrecision');
this.priceTaxCalculator = new OrderPrices();
this.productEditSaveBtn = $(OrderViewPageMap.productEditSaveBtn);
this.quantityInput = $(OrderViewPageMap.productEditQuantityInput);
this.orderPricesRefresher = new OrderPricesRefresher();
}
setupListener() {
this.quantityInput.on('change keyup', (event) => {
const newQuantity = Number(event.target.value);
const availableQuantity = parseInt($(event.currentTarget).data('availableQuantity'), 10);
const previousQuantity = parseInt(this.quantityInput.data('previousQuantity'), 10);
const remainingAvailable = availableQuantity - (newQuantity - previousQuantity);
const availableOutOfStock = this.availableText.data('availableOutOfStock');
this.quantity = newQuantity;
this.availableText.text(remainingAvailable);
this.availableText.toggleClass('text-danger font-weight-bold', remainingAvailable < 0);
this.updateTotal();
const disableEditActionBtn = newQuantity <= 0 || (remainingAvailable < 0 && !availableOutOfStock);
this.productEditSaveBtn.prop('disabled', disableEditActionBtn);
});
this.productEditInvoiceSelect.on('change', () => {
this.productEditSaveBtn.prop('disabled', false);
});
this.priceTaxIncludedInput.on('change keyup', (event) => {
this.taxIncluded = parseFloat(event.target.value);
this.taxExcluded = this.priceTaxCalculator.calculateTaxExcluded(
this.taxIncluded,
this.taxRate,
this.currencyPrecision,
);
this.priceTaxExcludedInput.val(this.taxExcluded);
this.updateTotal();
});
this.priceTaxExcludedInput.on('change keyup', (event) => {
this.taxExcluded = parseFloat(event.target.value);
this.taxIncluded = this.priceTaxCalculator.calculateTaxIncluded(
this.taxExcluded,
this.taxRate,
this.currencyPrecision,
);
this.priceTaxIncludedInput.val(this.taxIncluded);
this.updateTotal();
});
this.productEditSaveBtn.on('click', (event) => {
const $btn = $(event.currentTarget);
const confirmed = window.confirm($btn.data('updateMessage'));
if (!confirmed) {
return;
}
$btn.prop('disabled', true);
this.handleEditProductWithConfirmationModal(event);
});
this.productEditCancelBtn.on('click', () => {
EventEmitter.emit(OrderViewEventMap.productEditionCanceled, {
orderDetailId: this.orderDetailId,
});
});
}
updateTotal() {
const updatedTotal = this.priceTaxCalculator.calculateTotalPrice(
this.quantity,
this.isOrderTaxIncluded ? this.taxIncluded : this.taxExcluded,
this.currencyPrecision,
);
this.priceTotalText.html(updatedTotal);
this.productEditSaveBtn.prop('disabled', updatedTotal === this.initialTotal);
}
displayProduct(product) {
this.productRowEdit = $(OrderViewPageMap.productEditRowTemplate).clone(true);
this.productRowEdit.attr('id', `editOrderProduct_${this.orderDetailId}`);
this.productRowEdit.find('*[id]').each(function removeAllIds() {
$(this).removeAttr('id');
});
// Find controls
this.productEditSaveBtn = this.productRowEdit.find(OrderViewPageMap.productEditSaveBtn);
this.productEditCancelBtn = this.productRowEdit.find(OrderViewPageMap.productEditCancelBtn);
this.productEditInvoiceSelect = this.productRowEdit.find(OrderViewPageMap.productEditInvoiceSelect);
this.productEditImage = this.productRowEdit.find(OrderViewPageMap.productEditImage);
this.productEditName = this.productRowEdit.find(OrderViewPageMap.productEditName);
this.priceTaxIncludedInput = this.productRowEdit.find(OrderViewPageMap.productEditPriceTaxInclInput);
this.priceTaxExcludedInput = this.productRowEdit.find(OrderViewPageMap.productEditPriceTaxExclInput);
this.quantityInput = this.productRowEdit.find(OrderViewPageMap.productEditQuantityInput);
this.locationText = this.productRowEdit.find(OrderViewPageMap.productEditLocationText);
this.availableText = this.productRowEdit.find(OrderViewPageMap.productEditAvailableText);
this.priceTotalText = this.productRowEdit.find(OrderViewPageMap.productEditTotalPriceText);
// Init input values
this.priceTaxExcludedInput.val(
window.ps_round(product.price_tax_excl, this.currencyPrecision),
);
this.priceTaxIncludedInput.val(
window.ps_round(product.price_tax_incl, this.currencyPrecision),
);
this.quantityInput.val(product.quantity)
.data('availableQuantity', product.availableQuantity)
.data('previousQuantity', product.quantity);
this.availableText.data('availableOutOfStock', product.availableOutOfStock);
// set this product's orderInvoiceId as selected
if (product.orderInvoiceId) {
this.productEditInvoiceSelect.val(product.orderInvoiceId);
}
// Init editor data
this.taxRate = product.tax_rate;
this.initialTotal = this.priceTaxCalculator.calculateTotalPrice(
product.quantity,
product.isOrderTaxIncluded ? product.price_tax_incl : product.price_tax_excl,
this.currencyPrecision,
);
this.isOrderTaxIncluded = product.isOrderTaxIncluded;
this.quantity = product.quantity;
this.taxIncluded = product.price_tax_incl;
this.taxExcluded = product.price_tax_excl;
// Copy product content in cells
this.productEditImage.html(
this.productRow.find(OrderViewPageMap.productEditImage).html(),
);
this.productEditName.html(
this.productRow.find(OrderViewPageMap.productEditName).html(),
);
this.locationText.html(product.location);
this.availableText.html(product.availableQuantity);
this.priceTotalText.html(this.initialTotal);
this.productRow.addClass('d-none').after(this.productRowEdit.removeClass('d-none'));
this.setupListener();
}
handleEditProductWithConfirmationModal(event) {
const productEditBtn = $(`#orderProduct_${this.orderDetailId} ${OrderViewPageMap.productEditButtons}`);
const productId = productEditBtn.data('product-id');
const combinationId = productEditBtn.data('combination-id');
const orderInvoiceId = productEditBtn.data('order-invoice-id');
const productPriceMatch = this.orderPricesRefresher.checkOtherProductPricesMatch(
this.priceTaxIncludedInput.val(),
productId,
combinationId,
orderInvoiceId,
this.orderDetailId,
);
if (productPriceMatch === null) {
this.editProduct($(event.currentTarget).data('orderId'), this.orderDetailId);
return;
}
const dataSelector = productPriceMatch === 'product' ? this.priceTaxExcludedInput : this.productEditInvoiceSelect;
const modalEditPrice = new ConfirmModal(
{
id: 'modal-confirm-new-price',
confirmTitle: dataSelector.data('modal-edit-price-title'),
confirmMessage: dataSelector.data('modal-edit-price-body'),
confirmButtonLabel: dataSelector.data('modal-edit-price-apply'),
closeButtonLabel: dataSelector.data('modal-edit-price-cancel'),
},
() => {
this.editProduct($(event.currentTarget).data('orderId'), this.orderDetailId);
},
);
modalEditPrice.show();
}
editProduct(orderId, orderDetailId) {
const params = {
price_tax_incl: this.priceTaxIncludedInput.val(),
price_tax_excl: this.priceTaxExcludedInput.val(),
quantity: this.quantityInput.val(),
invoice: this.productEditInvoiceSelect.val(),
};
$.ajax({
url: this.router.generate('admin_orders_update_product', {
orderId,
orderDetailId,
}),
method: 'POST',
data: params,
}).then(
() => {
EventEmitter.emit(OrderViewEventMap.productUpdated, {
orderId,
orderDetailId,
});
},
(response) => {
if (response.responseJSON && response.responseJSON.message) {
$.growl.error({message: response.responseJSON.message});
}
},
);
}
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import {EventEmitter} from '@components/event-emitter';
import OrderViewEventMap from '@pages/order/view/order-view-event-map';
const {$} = window;
export default class OrderProductManager {
constructor() {
this.router = new Router();
}
handleDeleteProductEvent(event) {
event.preventDefault();
const $btn = $(event.currentTarget);
const confirmed = window.confirm($btn.data('deleteMessage'));
if (!confirmed) {
return;
}
$btn.pstooltip('dispose');
$btn.prop('disabled', true);
this.deleteProduct($btn.data('orderId'), $btn.data('orderDetailId'));
}
deleteProduct(orderId, orderDetailId) {
$.ajax(this.router.generate('admin_orders_delete_product', {orderId, orderDetailId}), {
method: 'POST',
}).then(() => {
EventEmitter.emit(OrderViewEventMap.productDeletedFromOrder, {
oldOrderDetailId: orderDetailId,
orderId,
});
}, (response) => {
if (response.responseJSON && response.responseJSON.message) {
$.growl.error({message: response.responseJSON.message});
}
});
}
}

View File

@@ -0,0 +1,307 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import OrderProductEdit from '@pages/order/view/order-product-edit';
import Router from '@components/router';
const {$} = window;
export default class OrderProductRenderer {
constructor() {
this.router = new Router();
}
addOrUpdateProductToList($productRow, newRow) {
if ($productRow.length > 0) {
$productRow.html($(newRow).html());
} else {
$(OrderViewPageMap.productAddRow).before(
$(newRow)
.hide()
.fadeIn(),
);
}
}
updateNumProducts(numProducts) {
$(OrderViewPageMap.productsCount).html(numProducts);
}
editProductFromList(
orderDetailId,
quantity,
priceTaxIncl,
priceTaxExcl,
taxRate,
location,
availableQuantity,
availableOutOfStock,
orderInvoiceId,
isOrderTaxIncluded,
) {
const $orderEdit = new OrderProductEdit(orderDetailId);
$orderEdit.displayProduct({
price_tax_excl: priceTaxExcl,
price_tax_incl: priceTaxIncl,
tax_rate: taxRate,
quantity,
location,
availableQuantity,
availableOutOfStock,
orderInvoiceId,
isOrderTaxIncluded,
});
$(OrderViewPageMap.productAddActionBtn).addClass('d-none');
$(OrderViewPageMap.productAddRow).addClass('d-none');
}
moveProductsPanelToModificationPosition(scrollTarget = 'body') {
$(OrderViewPageMap.productActionBtn).addClass('d-none');
$(
`${OrderViewPageMap.productAddActionBtn}, ${OrderViewPageMap.productAddRow}`,
).removeClass('d-none');
this.moveProductPanelToTop(scrollTarget);
}
moveProductsPanelToRefundPosition() {
this.resetAllEditRows();
$(
/* eslint-disable-next-line max-len */
`${OrderViewPageMap.productAddActionBtn}, ${OrderViewPageMap.productAddRow}, ${OrderViewPageMap.productActionBtn}`,
).addClass('d-none');
this.moveProductPanelToTop();
}
moveProductPanelToTop(scrollTarget = 'body') {
const $modificationPosition = $(
OrderViewPageMap.productModificationPosition,
);
if ($modificationPosition.find(OrderViewPageMap.productsPanel).length > 0) {
return;
}
$(OrderViewPageMap.productsPanel)
.detach()
.appendTo($modificationPosition);
$modificationPosition.closest('.row').removeClass('d-none');
// Show column location & refunded
this.toggleColumn(OrderViewPageMap.productsCellLocation);
this.toggleColumn(OrderViewPageMap.productsCellRefunded);
// Show all rows, hide pagination controls
const $rows = $(OrderViewPageMap.productsTable).find(
'tr[id^="orderProduct_"]',
);
$rows.removeClass('d-none');
$(OrderViewPageMap.productsPagination).addClass('d-none');
const scrollValue = $(scrollTarget).offset().top - $('.header-toolbar').height() - 100;
$('html,body').animate({scrollTop: scrollValue}, 'slow');
}
moveProductPanelToOriginalPosition() {
$(OrderViewPageMap.productAddNewInvoiceInfo).addClass('d-none');
$(OrderViewPageMap.productModificationPosition)
.closest('.row')
.addClass('d-none');
$(OrderViewPageMap.productsPanel)
.detach()
.appendTo(OrderViewPageMap.productOriginalPosition);
$(OrderViewPageMap.productsPagination).removeClass('d-none');
$(OrderViewPageMap.productActionBtn).removeClass('d-none');
$(
`${OrderViewPageMap.productAddActionBtn}, ${OrderViewPageMap.productAddRow}`,
).addClass('d-none');
// Restore pagination
this.paginate(1);
}
resetAddRow() {
$(OrderViewPageMap.productAddIdInput).val('');
$(OrderViewPageMap.productSearchInput).val('');
$(OrderViewPageMap.productAddCombinationsBlock).addClass('d-none');
$(OrderViewPageMap.productAddCombinationsSelect).val('');
$(OrderViewPageMap.productAddCombinationsSelect).prop('disabled', false);
$(OrderViewPageMap.productAddPriceTaxExclInput).val('');
$(OrderViewPageMap.productAddPriceTaxInclInput).val('');
$(OrderViewPageMap.productAddQuantityInput).val('');
$(OrderViewPageMap.productAddAvailableText).html('');
$(OrderViewPageMap.productAddLocationText).html('');
$(OrderViewPageMap.productAddNewInvoiceInfo).addClass('d-none');
$(OrderViewPageMap.productAddActionBtn).prop('disabled', true);
}
resetAllEditRows() {
$(OrderViewPageMap.productEditButtons).each((key, editButton) => {
this.resetEditRow($(editButton).data('orderDetailId'));
});
}
resetEditRow(orderProductId) {
const $productRow = $(OrderViewPageMap.productsTableRow(orderProductId));
const $productEditRow = $(
OrderViewPageMap.productsTableRowEdited(orderProductId),
);
$productEditRow.remove();
$productRow.removeClass('d-none');
}
paginate(originalNumPage) {
const $rows = $(OrderViewPageMap.productsTable).find(
'tr[id^="orderProduct_"]',
);
const $customizationRows = $(
OrderViewPageMap.productsTableCustomizationRows,
);
const $tablePagination = $(OrderViewPageMap.productsTablePagination);
const numRowsPerPage = parseInt($tablePagination.data('numPerPage'), 10);
const maxPage = Math.ceil($rows.length / numRowsPerPage);
const numPage = Math.max(1, Math.min(originalNumPage, maxPage));
this.paginateUpdateControls(numPage);
// Hide all rows...
$rows.addClass('d-none');
$customizationRows.addClass('d-none');
// ... and display good ones
const startRow = (numPage - 1) * numRowsPerPage + 1;
const endRow = numPage * numRowsPerPage;
for (let i = startRow - 1; i < Math.min(endRow, $rows.length); i += 1) {
$($rows[i]).removeClass('d-none');
}
$customizationRows.each(function () {
if (
!$(this)
.prev()
.hasClass('d-none')
) {
$(this).removeClass('d-none');
}
});
// Remove all edition rows (careful not to remove the template)
$(OrderViewPageMap.productEditRow)
.not(OrderViewPageMap.productEditRowTemplate)
.remove();
// Toggle Column Location & Refunded
this.toggleColumn(OrderViewPageMap.productsCellLocationDisplayed);
this.toggleColumn(OrderViewPageMap.productsCellRefundedDisplayed);
}
paginateUpdateControls(numPage) {
// Why 3 ? Next & Prev & Template
const totalPage = $(OrderViewPageMap.productsTablePagination).find('li.page-item').length
- 3;
$(OrderViewPageMap.productsTablePagination)
.find('.active')
.removeClass('active');
$(OrderViewPageMap.productsTablePagination)
.find(`li:has(> [data-page="${numPage}"])`)
.addClass('active');
$(OrderViewPageMap.productsTablePaginationPrev).removeClass('disabled');
if (numPage === 1) {
$(OrderViewPageMap.productsTablePaginationPrev).addClass('disabled');
}
$(OrderViewPageMap.productsTablePaginationNext).removeClass('disabled');
if (numPage === totalPage) {
$(OrderViewPageMap.productsTablePaginationNext).addClass('disabled');
}
this.togglePaginationControls();
}
updateNumPerPage(numPerPage) {
$(OrderViewPageMap.productsTablePagination).data('numPerPage', numPerPage);
this.updatePaginationControls();
}
togglePaginationControls() {
// Why 3 ? Next & Prev & Template
const totalPage = $(OrderViewPageMap.productsTablePagination).find('li.page-item').length
- 3;
$(OrderViewPageMap.productsNavPagination).toggleClass(
'd-none',
totalPage <= 1,
);
}
toggleProductAddNewInvoiceInfo() {
$(OrderViewPageMap.productAddNewInvoiceInfo).toggleClass(
'd-none',
parseInt($(OrderViewPageMap.productAddInvoiceSelect).val(), 10) !== 0,
);
}
toggleColumn(target, forceDisplay = null) {
let isColumnDisplayed = false;
if (forceDisplay === null) {
$(target)
.filter('td')
.each(function () {
if ($(this).html() !== '') {
isColumnDisplayed = true;
return false;
}
return true;
});
} else {
isColumnDisplayed = forceDisplay;
}
$(target).toggleClass('d-none', !isColumnDisplayed);
}
updatePaginationControls() {
const $tablePagination = $(OrderViewPageMap.productsTablePagination);
const numPerPage = $tablePagination.data('numPerPage');
const $rows = $(OrderViewPageMap.productsTable).find('tr[id^="orderProduct_"]');
const numPages = Math.ceil($rows.length / numPerPage);
// Update table data fields
$tablePagination.data('numPages', numPages);
// Clean all page links, reinsert the removed template
const $linkPaginationTemplate = $(OrderViewPageMap.productsTablePaginationTemplate);
$(OrderViewPageMap.productsTablePagination).find('li:has(> [data-page])').remove();
$(OrderViewPageMap.productsTablePaginationNext).before($linkPaginationTemplate);
// Add appropriate pages
for (let i = 1; i <= numPages; i += 1) {
const $linkPagination = $linkPaginationTemplate.clone();
$linkPagination.find('span').attr('data-page', i);
$linkPagination.find('span').html(i);
$linkPaginationTemplate.before($linkPagination.removeClass('d-none'));
}
this.togglePaginationControls();
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import Router from '@components/router';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
const {$} = window;
export default class OrderShippingRefresher {
constructor() {
this.router = new Router();
}
refresh(orderId) {
$.getJSON(this.router.generate('admin_orders_get_shipping', {orderId}))
.then((response) => {
$(OrderViewPageMap.orderShippingTabCount).text(response.total);
$(OrderViewPageMap.orderShippingTabBody).html(response.html);
});
}
}

View File

@@ -0,0 +1,33 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
export default {
productDeletedFromOrder: 'productDeletedFromOrder',
productAddedToOrder: 'productAddedToOrder',
productUpdated: 'productUpdated',
productEditionCanceled: 'productEditionCanceled',
productListPaginated: 'productListPaginated',
productListNumberPerPage: 'productListNumberPerPage',
};

View File

@@ -0,0 +1,369 @@
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
import OrderProductManager from '@pages/order/view/order-product-manager';
import OrderViewPageMap from '@pages/order/OrderViewPageMap';
import OrderViewEventMap from '@pages/order/view/order-view-event-map';
import {EventEmitter} from '@components/event-emitter';
import OrderDiscountsRefresher from '@pages/order/view/order-discounts-refresher';
import OrderProductRenderer from '@pages/order/view/order-product-renderer';
import OrderPricesRefresher from '@pages/order/view/order-prices-refresher';
import OrderPaymentsRefresher from '@pages/order/view/order-payments-refresher';
import OrderShippingRefresher from '@pages/order/view/order-shipping-refresher';
import Router from '@components/router';
import OrderInvoicesRefresher from './order-invoices-refresher';
import OrderProductCancel from './order-product-cancel';
import OrderDocumentsRefresher from './order-documents-refresher';
const {$} = window;
export default class OrderViewPage {
constructor() {
this.orderDiscountsRefresher = new OrderDiscountsRefresher();
this.orderProductManager = new OrderProductManager();
this.orderProductRenderer = new OrderProductRenderer();
this.orderPricesRefresher = new OrderPricesRefresher();
this.orderPaymentsRefresher = new OrderPaymentsRefresher();
this.orderShippingRefresher = new OrderShippingRefresher();
this.orderDocumentsRefresher = new OrderDocumentsRefresher();
this.orderInvoicesRefresher = new OrderInvoicesRefresher();
this.orderProductCancel = new OrderProductCancel();
this.router = new Router();
this.listenToEvents();
}
listenToEvents() {
$(OrderViewPageMap.invoiceAddressEditBtn).fancybox({
type: 'iframe',
width: '90%',
height: '90%',
});
$(OrderViewPageMap.deliveryAddressEditBtn).fancybox({
type: 'iframe',
width: '90%',
height: '90%',
});
EventEmitter.on(OrderViewEventMap.productDeletedFromOrder, (event) => {
this.orderPricesRefresher.refresh(event.orderId);
this.orderPaymentsRefresher.refresh(event.orderId);
this.refreshProductsList(event.orderId);
this.orderDiscountsRefresher.refresh(event.orderId);
this.orderDocumentsRefresher.refresh(event.orderId);
this.orderShippingRefresher.refresh(event.orderId);
});
EventEmitter.on(OrderViewEventMap.productEditionCanceled, (event) => {
this.orderProductRenderer.resetEditRow(event.orderDetailId);
const editRowsLeft = $(OrderViewPageMap.productEditRow).not(OrderViewPageMap.productEditRowTemplate).length;
if (editRowsLeft > 0) {
return;
}
this.orderProductRenderer.moveProductPanelToOriginalPosition();
});
EventEmitter.on(OrderViewEventMap.productUpdated, (event) => {
this.orderProductRenderer.resetEditRow(event.orderDetailId);
this.orderPricesRefresher.refresh(event.orderId);
this.orderPricesRefresher.refreshProductPrices(event.orderId);
this.refreshProductsList(event.orderId);
this.orderPaymentsRefresher.refresh(event.orderId);
this.orderDiscountsRefresher.refresh(event.orderId);
this.orderInvoicesRefresher.refresh(event.orderId);
this.orderDocumentsRefresher.refresh(event.orderId);
this.orderShippingRefresher.refresh(event.orderId);
this.listenForProductDelete();
this.listenForProductEdit();
this.resetToolTips();
const editRowsLeft = $(OrderViewPageMap.productEditRow).not(OrderViewPageMap.productEditRowTemplate).length;
if (editRowsLeft > 0) {
return;
}
this.orderProductRenderer.moveProductPanelToOriginalPosition();
});
EventEmitter.on(OrderViewEventMap.productAddedToOrder, (event) => {
this.orderProductRenderer.resetAddRow();
this.orderPricesRefresher.refreshProductPrices(event.orderId);
this.orderPricesRefresher.refresh(event.orderId);
this.refreshProductsList(event.orderId);
this.orderPaymentsRefresher.refresh(event.orderId);
this.orderDiscountsRefresher.refresh(event.orderId);
this.orderInvoicesRefresher.refresh(event.orderId);
this.orderDocumentsRefresher.refresh(event.orderId);
this.orderShippingRefresher.refresh(event.orderId);
this.orderProductRenderer.moveProductPanelToOriginalPosition();
});
}
listenForProductDelete() {
$(OrderViewPageMap.productDeleteBtn)
.off('click')
.on('click', (event) => this.orderProductManager.handleDeleteProductEvent(event));
}
resetToolTips() {
$(OrderViewPageMap.productEditButtons).pstooltip();
$(OrderViewPageMap.productDeleteBtn).pstooltip();
}
listenForProductEdit() {
$(OrderViewPageMap.productEditButtons).off('click').on('click', (event) => {
const $btn = $(event.currentTarget);
this.orderProductRenderer.moveProductsPanelToModificationPosition();
this.orderProductRenderer.editProductFromList(
$btn.data('orderDetailId'),
$btn.data('productQuantity'),
$btn.data('productPriceTaxIncl'),
$btn.data('productPriceTaxExcl'),
$btn.data('taxRate'),
$btn.data('location'),
$btn.data('availableQuantity'),
$btn.data('availableOutOfStock'),
$btn.data('orderInvoiceId'),
$btn.data('isOrderTaxIncluded'),
);
});
}
listenForProductPack() {
$(OrderViewPageMap.productPackModal.modal).on('show.bs.modal', (event) => {
const button = $(event.relatedTarget);
const packItems = button.data('packItems');
$(OrderViewPageMap.productPackModal.rows).remove();
packItems.forEach((item) => {
const $item = $(OrderViewPageMap.productPackModal.template).clone();
$item.attr('id', `productpack_${item.id}`).removeClass('d-none');
$item.find(OrderViewPageMap.productPackModal.product.img).attr('src', item.imagePath);
$item.find(OrderViewPageMap.productPackModal.product.name).html(item.name);
$item.find(OrderViewPageMap.productPackModal.product.link).attr(
'href',
this.router.generate('admin_product_form', {id: item.id}),
);
if (item.reference !== '') {
$item.find(OrderViewPageMap.productPackModal.product.ref).append(item.reference);
} else {
$item.find(OrderViewPageMap.productPackModal.product.ref).remove();
}
if (item.supplierReference !== '') {
$item.find(OrderViewPageMap.productPackModal.product.supplierRef).append(item.supplierReference);
} else {
$item.find(OrderViewPageMap.productPackModal.product.supplierRef).remove();
}
if (item.quantity > 1) {
$item.find(`${OrderViewPageMap.productPackModal.product.quantity} span`).html(item.quantity);
} else {
$item.find(OrderViewPageMap.productPackModal.product.quantity).html(item.quantity);
}
$item.find(OrderViewPageMap.productPackModal.product.availableQuantity).html(item.availableQuantity);
$(OrderViewPageMap.productPackModal.template).before($item);
});
});
}
listenForProductAdd() {
$(OrderViewPageMap.productAddBtn).on(
'click',
() => {
this.orderProductRenderer.toggleProductAddNewInvoiceInfo();
this.orderProductRenderer.moveProductsPanelToModificationPosition(OrderViewPageMap.productSearchInput);
},
);
$(OrderViewPageMap.productCancelAddBtn).on(
'click', () => this.orderProductRenderer.moveProductPanelToOriginalPosition(),
);
}
listenForProductPagination() {
$(OrderViewPageMap.productsTablePagination).on('click', OrderViewPageMap.productsTablePaginationLink, (event) => {
event.preventDefault();
const $btn = $(event.currentTarget);
EventEmitter.emit(OrderViewEventMap.productListPaginated, {
numPage: $btn.data('page'),
});
});
$(OrderViewPageMap.productsTablePaginationNext).on('click', (event) => {
event.preventDefault();
const $btn = $(event.currentTarget);
if ($btn.hasClass('disabled')) {
return;
}
const activePage = this.getActivePage();
EventEmitter.emit(OrderViewEventMap.productListPaginated, {
numPage: parseInt($(activePage).html(), 10) + 1,
});
});
$(OrderViewPageMap.productsTablePaginationPrev).on('click', (event) => {
event.preventDefault();
const $btn = $(event.currentTarget);
if ($btn.hasClass('disabled')) {
return;
}
const activePage = this.getActivePage();
EventEmitter.emit(OrderViewEventMap.productListPaginated, {
numPage: parseInt($(activePage).html(), 10) - 1,
});
});
$(OrderViewPageMap.productsTablePaginationNumberSelector).on('change', (event) => {
event.preventDefault();
const $select = $(event.currentTarget);
const numPerPage = parseInt($select.val(), 10);
EventEmitter.emit(OrderViewEventMap.productListNumberPerPage, {
numPerPage,
});
});
EventEmitter.on(OrderViewEventMap.productListPaginated, (event) => {
this.orderProductRenderer.paginate(event.numPage);
this.listenForProductDelete();
this.listenForProductEdit();
this.resetToolTips();
});
EventEmitter.on(OrderViewEventMap.productListNumberPerPage, (event) => {
// Update pagination num per page (page links are regenerated)
this.orderProductRenderer.updateNumPerPage(event.numPerPage);
// Paginate to page 1
EventEmitter.emit(OrderViewEventMap.productListPaginated, {
numPage: 1,
});
// Save new config
$.ajax({
url: this.router.generate('admin_orders_configure_product_pagination'),
method: 'POST',
data: {numPerPage: event.numPerPage},
});
});
}
listenForRefund() {
$(OrderViewPageMap.cancelProduct.buttons.partialRefund).on('click', () => {
this.orderProductRenderer.moveProductsPanelToRefundPosition();
this.orderProductCancel.showPartialRefund();
});
$(OrderViewPageMap.cancelProduct.buttons.standardRefund).on('click', () => {
this.orderProductRenderer.moveProductsPanelToRefundPosition();
this.orderProductCancel.showStandardRefund();
});
$(OrderViewPageMap.cancelProduct.buttons.returnProduct).on('click', () => {
this.orderProductRenderer.moveProductsPanelToRefundPosition();
this.orderProductCancel.showReturnProduct();
});
$(OrderViewPageMap.cancelProduct.buttons.abort).on('click', () => {
this.orderProductRenderer.moveProductPanelToOriginalPosition();
this.orderProductCancel.hideRefund();
});
}
listenForCancelProduct() {
$(OrderViewPageMap.cancelProduct.buttons.cancelProducts).on('click', () => {
this.orderProductRenderer.moveProductsPanelToRefundPosition();
this.orderProductCancel.showCancelProductForm();
});
}
getActivePage() {
return $(OrderViewPageMap.productsTablePagination).find('.active span').get(0);
}
refreshProductsList(orderId) {
$(OrderViewPageMap.refreshProductsListLoadingSpinner).show();
const $tablePagination = $(OrderViewPageMap.productsTablePagination);
const numRowsPerPage = $tablePagination.data('numPerPage');
const initialNumProducts = $(OrderViewPageMap.productsTableRows).length;
const currentPage = parseInt($(OrderViewPageMap.productsTablePaginationActive).html(), 10);
$.ajax(this.router.generate('admin_orders_get_products', {orderId}))
.done((response) => {
// Delete previous product lines
$(OrderViewPageMap.productsTable).find(OrderViewPageMap.productsTableRows).remove();
$(OrderViewPageMap.productsTableCustomizationRows).remove();
$(`${OrderViewPageMap.productsTable} tbody`).prepend(response);
$(OrderViewPageMap.refreshProductsListLoadingSpinner).hide();
const newNumProducts = $(OrderViewPageMap.productsTableRows).length;
const newPagesNum = Math.ceil(newNumProducts / numRowsPerPage);
this.orderProductRenderer.updateNumProducts(newNumProducts);
this.orderProductRenderer.updatePaginationControls();
let numPage = 1;
let message = '';
// Display alert
if (initialNumProducts > newNumProducts) { // product deleted
message = (initialNumProducts - newNumProducts === 1)
? window.translate_javascripts['The product was successfully removed.']
: window.translate_javascripts['[1] products were successfully removed.']
.replace('[1]', (initialNumProducts - newNumProducts));
// Set target page to the page of the deleted item
numPage = (newPagesNum === 1) ? 1 : currentPage;
} else if (initialNumProducts < newNumProducts) { // product added
message = (newNumProducts - initialNumProducts === 1)
? window.translate_javascripts['The product was successfully added.']
: window.translate_javascripts['[1] products were successfully added.']
.replace('[1]', (newNumProducts - initialNumProducts));
// Move to first page to see the added product
numPage = 1;
}
if (message !== '') {
$.growl.notice({
title: '',
message,
});
}
// Move to page of the modified item
EventEmitter.emit(OrderViewEventMap.productListPaginated, {
numPage,
});
// Bind hover on product rows buttons
this.resetToolTips();
})
.fail(() => {
$.growl.error({
title: '',
message: 'Failed to reload the products list. Please reload the page',
});
});
}
}