[FIX] pos_sale: correctly assign partners in the invoice
When settling a sale.order from the pos app, it's possible that the sale.order have different partners assigned to it (partner_id, partner_shipping_id, partner_invoice_id). After this commit, we are now properly assigning these partners to the generated invoice. Additionally, this commit makes the settling of sale.order more robust by avoiding issue on having multiple incompatible sale.orders in a pos.order (more than 2 sale.orders and their partners are not the same). After this commit, we are only reusing the current pos.order as container of the new sale.order to settle if the sale.order is compatible to the current pos.order. Basically, we now only allow adding new sale order to the current order if the partner_id, partner_invoice_id and partner_shipping_id of the new sale.order are the same to the current pos.order's linked sale.order. In other words, if the new sale.order to settle is incompatible to the current pos.order, we create a new pos.order to settle that sale.order. closes odoo/odoo#120649 X-original-commit: 2782bedafb9fcbe7c65f4c6951ce270c3a5a5bd3 Signed-off-by: Heinz Robin (rhe) <rhe@odoo.com> Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
@@ -32,13 +32,16 @@ class PosOrder(models.Model):
|
||||
invoice_vals = super(PosOrder, self)._prepare_invoice_vals()
|
||||
invoice_vals['team_id'] = self.crm_team_id.id
|
||||
sale_orders = self.lines.mapped('sale_order_origin_id')
|
||||
if sale_orders and (sale_orders.partner_invoice_id.id != sale_orders.partner_shipping_id.id):
|
||||
invoice_vals['partner_shipping_id'] = sale_orders.partner_shipping_id.id
|
||||
else:
|
||||
addr = self.partner_id.address_get(['delivery'])
|
||||
invoice_vals['partner_shipping_id'] = addr['delivery']
|
||||
if sale_orders and sale_orders[0].payment_term_id:
|
||||
invoice_vals['invoice_payment_term_id'] = sale_orders[0].payment_term_id.id,
|
||||
if sale_orders:
|
||||
if sale_orders[0].partner_invoice_id.id != sale_orders[0].partner_shipping_id.id:
|
||||
invoice_vals['partner_shipping_id'] = sale_orders[0].partner_shipping_id.id
|
||||
else:
|
||||
addr = self.partner_id.address_get(['delivery'])
|
||||
invoice_vals['partner_shipping_id'] = addr['delivery']
|
||||
if sale_orders[0].payment_term_id:
|
||||
invoice_vals['invoice_payment_term_id'] = sale_orders[0].payment_term_id.id
|
||||
if sale_orders[0].partner_invoice_id != sale_orders[0].partner_id:
|
||||
invoice_vals['partner_id'] = sale_orders[0].partner_invoice_id.id
|
||||
return invoice_vals
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -18,6 +18,15 @@ import { SaleOrderList } from "./SaleOrderList";
|
||||
import { SaleOrderManagementControlPanel } from "./SaleOrderManagementControlPanel";
|
||||
import { onMounted, useRef, useState } from "@odoo/owl";
|
||||
|
||||
/**
|
||||
* ID getter to take into account falsy many2one value.
|
||||
* @param {[id: number, display_name: string] | false} fieldVal many2one field value
|
||||
* @returns {number | false}
|
||||
*/
|
||||
function getId(fieldVal) {
|
||||
return fieldVal && fieldVal[0];
|
||||
}
|
||||
|
||||
export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentToOrderScreen) {
|
||||
static components = { SaleOrderList, SaleOrderManagementControlPanel };
|
||||
static template = "SaleOrderManagementScreen";
|
||||
@@ -29,6 +38,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
|
||||
this.root = useRef("root");
|
||||
this.numberBuffer = useService("number_buffer");
|
||||
this.saleOrderFetcher = useService("sale_order_fetcher");
|
||||
this.notification = useService("pos_notification");
|
||||
|
||||
useBus(this.saleOrderFetcher, "update", this.render);
|
||||
this.orderManagementContext = useState(orderManagement);
|
||||
@@ -48,6 +58,14 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
|
||||
);
|
||||
this.saleOrderFetcher.setNPerPage(val);
|
||||
this.saleOrderFetcher.fetch();
|
||||
}
|
||||
_getSaleOrderOrigin(order) {
|
||||
for (const line of order.get_orderlines()) {
|
||||
if (line.sale_order_origin_id) {
|
||||
return line.sale_order_origin_id
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
get selectedPartner() {
|
||||
const order = this.orderManagementContext.selectedOrder;
|
||||
@@ -82,9 +100,25 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
const currentPOSOrder = this.env.pos.get_order();
|
||||
let currentPOSOrder = this.env.pos.get_order();
|
||||
const sale_order = await this._getSaleOrder(clickedOrder.id);
|
||||
clickedOrder.shipping_date = sale_order.shipping_date;
|
||||
|
||||
const currentSaleOrigin = this._getSaleOrderOrigin(currentPOSOrder);
|
||||
const currentSaleOriginId = currentSaleOrigin && currentSaleOrigin.id;
|
||||
|
||||
if (currentSaleOriginId) {
|
||||
const linkedSO = await this._getSaleOrder(currentSaleOriginId);
|
||||
if (
|
||||
getId(linkedSO.partner_id) !== getId(sale_order.partner_id) ||
|
||||
getId(linkedSO.partner_invoice_id) !== getId(sale_order.partner_invoice_id) ||
|
||||
getId(linkedSO.partner_shipping_id) !== getId(sale_order.partner_shipping_id)
|
||||
) {
|
||||
currentPOSOrder = this.env.pos.add_new_order();
|
||||
this.notification.add(this.env._t("A new order has been created."), 4000);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.env.pos.load_new_partners();
|
||||
} catch {
|
||||
@@ -318,6 +352,8 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo
|
||||
"amount_untaxed",
|
||||
"amount_unpaid",
|
||||
"picking_ids",
|
||||
"partner_shipping_id",
|
||||
"partner_invoice_id"
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -25,6 +25,18 @@ class DoExt extends Do {
|
||||
}
|
||||
];
|
||||
}
|
||||
selectNthOrder(n) {
|
||||
return [
|
||||
{
|
||||
content: `select order`,
|
||||
trigger: `.order-list .order-row:nth-child(${n})`,
|
||||
},
|
||||
{
|
||||
content: `click on select the order`,
|
||||
trigger: `.selection-item:contains('Settle the order')`,
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
class CheckExt extends Check {}
|
||||
|
||||
|
||||
@@ -25,3 +25,22 @@ Chrome.do.clickMenuButton();
|
||||
Chrome.do.clickTicketButton();
|
||||
|
||||
registry.category("web_tour.tours").add('PosSettleOrder', { test: true, url: '/pos/ui', steps: getSteps() });
|
||||
|
||||
startSteps();
|
||||
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
ProductScreen.do.clickQuotationButton();
|
||||
// The second item in the list is the first sale.order.
|
||||
ProductScreen.do.selectNthOrder(2);
|
||||
ProductScreen.check.selectedOrderlineHas('product1', 1);
|
||||
ProductScreen.check.totalAmountIs("10.00");
|
||||
|
||||
ProductScreen.do.clickQuotationButton();
|
||||
// The first item in the list is the second sale.order.
|
||||
// Selecting the 2nd sale.order should use a new order,
|
||||
// therefore, the total amount will change.
|
||||
ProductScreen.do.selectNthOrder(1);
|
||||
ProductScreen.check.selectedOrderlineHas('product2', 1);
|
||||
ProductScreen.check.totalAmountIs("11.00");
|
||||
|
||||
registry.category("web_tour.tours").add('PosSettleOrderIncompatiblePartner', { test: true, url: '/pos/ui', steps: getSteps() });
|
||||
|
||||
@@ -70,3 +70,35 @@ class TestPoSSale(TestPointOfSaleHttpCommon):
|
||||
self.assertEqual(sale_order.picking_ids[0].move_ids.quantity_done, 0)
|
||||
self.assertEqual(sale_order.picking_ids[1].move_ids.product_qty, 300)
|
||||
self.assertEqual(sale_order.picking_ids[1].move_ids.quantity_done, 300) # 1 delivered => 300 * 2 = 600
|
||||
|
||||
def test_settle_order_with_incompatible_partner(self):
|
||||
""" If the partner of the sale order is not compatible with the current pos order,
|
||||
then a new pos order should be to settle the newly selected sale order.
|
||||
"""
|
||||
|
||||
product1 = self.env['product.product'].create({
|
||||
'name': 'product1',
|
||||
'available_in_pos': True,
|
||||
'type': 'product',
|
||||
'lst_price': 10,
|
||||
'taxes_id': [odoo.Command.clear()],
|
||||
})
|
||||
product2 = self.env['product.product'].create({
|
||||
'name': 'product2',
|
||||
'available_in_pos': True,
|
||||
'type': 'product',
|
||||
'lst_price': 11,
|
||||
'taxes_id': [odoo.Command.clear()],
|
||||
})
|
||||
self.env['sale.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_1').id,
|
||||
'partner_shipping_id': self.env.ref('base.res_partner_2').id,
|
||||
'order_line': [(0, 0, {'product_id': product1.id})],
|
||||
})
|
||||
self.env['sale.order'].create({
|
||||
'partner_id': self.env.ref('base.res_partner_1').id,
|
||||
'partner_shipping_id': self.env.ref('base.res_partner_1').id,
|
||||
'order_line': [(0, 0, {'product_id': product2.id})],
|
||||
})
|
||||
self.main_pos_config.open_ui()
|
||||
self.start_tour("/pos/ui?config_id=%d" % self.main_pos_config.id, 'PosSettleOrderIncompatiblePartner', login="accountman")
|
||||
|
||||
Reference in New Issue
Block a user