diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 711fcd03a3f..eba93a1c99c 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -1285,6 +1285,7 @@ class PosOrderLine(models.Model): if line and 'tax_ids' not in line[2]: product = self.env['product.product'].browse(line[2]['product_id']) line[2]['tax_ids'] = [(6, 0, [x.id for x in product.taxes_id])] + # Clean up fields sent by the JS line = [ line[0], line[1], {k: v for k, v in line[2].items() if k in self.env['pos.order.line']._fields} diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js index 57f0d852e23..62bdfb4d2af 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js @@ -208,22 +208,23 @@ export class ProductScreen extends ControlButtonsMixin(Component) { const order = this.env.pos.get_order(); const selectedLine = this.env.pos.get_order().get_selected_orderline(); const currentQuantity = selectedLine.get_quantity(); - if ( - selectedLine.is_last_line() && - currentQuantity === 1 && - newQuantity < currentQuantity - ) { + if (newQuantity >= currentQuantity) { selectedLine.set_quantity(newQuantity); - } else if (newQuantity >= currentQuantity) { - selectedLine.set_quantity(newQuantity); - } else { - const newLine = selectedLine.clone(); - const decreasedQuantity = currentQuantity - newQuantity; - newLine.order = order; - - newLine.set_quantity(-decreasedQuantity, true); - order.add_orderline(newLine); + return; } + if (newQuantity >= selectedLine.saved_quantity) { + if (newQuantity == 0) { + order.remove_orderline(selectedLine) + } + selectedLine.set_quantity(newQuantity) + return; + } + const newLine = selectedLine.clone(); + const decreasedQuantity = selectedLine.saved_quantity - newQuantity; + newLine.order = order; + newLine.set_quantity(-decreasedQuantity, true); + selectedLine.set_quantity(selectedLine.saved_quantity); + order.add_orderline(newLine); } } async onClickPay() { diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 893abdec2a8..ad37eca3349 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -395,10 +395,13 @@ export class PosGlobalState extends PosModel { this.ordersToUpdateSet.delete(order); } if (order.server_id && !order.finalized) { - this.db.set_order_to_remove_from_server(order); + this.setOrderToRemove(order); } } } + setOrderToRemove(order) { + this.db.set_order_to_remove_from_server(order); + } /** * Return the current cashier (in this case, the user) @@ -439,6 +442,10 @@ export class PosGlobalState extends PosModel { if (this.isOpenOrderShareable()) { this.sendDraftToServer(); } + if (this.selectedOrder) { + this.selectedOrder.firstDraft = false; + this.selectedOrder.updateSavedQuantity(); + } const order = this.createReactiveOrder(); this.orders.add(order); this.selectedOrder = order; @@ -629,6 +636,7 @@ export class PosGlobalState extends PosModel { } // important to throw error here and let the rendering component handle the error console.warn("Failed to remove orders:", removedOrdersIds); + this._postRemoveFromServer(removedOrdersIds); throw error; } } @@ -899,6 +907,10 @@ export class PosGlobalState extends PosModel { // change the current order set_order(order, options) { + if (this.selectedOrder) { + this.selectedOrder.firstDraft = false; + this.selectedOrder.updateSavedQuantity(); + } this.selectedOrder = order; } @@ -1914,6 +1926,7 @@ export class Orderline extends PosModel { this.full_product_name = options.description || ""; this.id = orderline_id++; this.customerNote = this.customerNote || ""; + this.saved_quantity = 0; if (options.price) { this.set_unit_price(options.price); @@ -1946,6 +1959,7 @@ export class Orderline extends PosModel { this.set_customer_note(json.customer_note); this.refunded_qty = json.refunded_qty; this.refunded_orderline_id = json.refunded_orderline_id; + this.saved_quantity = json.qty; } clone() { var orderline = new Orderline( @@ -2056,6 +2070,9 @@ export class Orderline extends PosModel { get_price_extra() { return this.price_extra; } + updateSavedQuantity() { + this.saved_quantity = this.quantity; + } // sets the quantity of the product. The quantity will be rounded according to the // product's unity of measure properties. Quantities greater than zero will not get // rounded to zero @@ -2797,6 +2814,7 @@ export class Order extends PosModel { this.cashier = this.pos.get_cashier(); this.finalized = false; // if true, cannot be modified. this.shippingDate = null; + this.firstDraft = true; this.partner = null; @@ -2863,6 +2881,7 @@ export class Order extends PosModel { this.validation_date = json.creation_date; this.server_id = json.server_id ? json.server_id : false; this.user_id = json.user_id; + this.firstDraft = false; if (json.fiscal_position_id) { var fiscal_position = _.find(this.pos.fiscal_positions, function (fp) { @@ -3147,6 +3166,9 @@ export class Order extends PosModel { zero_pad(this.sequence_number, 4) ); } + updateSavedQuantity() { + this.orderlines.forEach((line) => line.updateSavedQuantity()); + } get_name() { return this.name; } @@ -3303,6 +3325,10 @@ export class Order extends PosModel { this.select_orderline(this.get_last_orderline()); } + isFirstDraft(){ + return this.firstDraft; + } + fix_tax_included_price(line) { line.set_unit_price(line.compute_fixed_price(line.price)); } diff --git a/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js index 1340044a69c..7dca365734a 100644 --- a/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js @@ -78,19 +78,19 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { } }, //@override - async onDeleteOrder() { - await this._super(...arguments); + async onDeleteOrder(order) { + const _super = this._super; if (this.env.pos.config.iface_floorplan) { + this.env.pos.setOrderToRemove(order); if (!this.env.pos.table) { - this.env.pos._removeOrdersFromServer(); - } - const orderList = this.env.pos.table - ? this.env.pos.getTableOrders(this.env.pos.table.id) - : this.env.pos.orders; - if (orderList.length == 0) { - this.pos.showScreen("FloorScreen"); + try { + await this.env.pos._removeOrdersFromServer(); + } catch (error) { + throw error; + } } } + await _super(...arguments); }, async setTip(order, serverId, amount) { try { diff --git a/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js b/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js index 583426b4f46..e78d59dacc6 100644 --- a/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js +++ b/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js @@ -21,7 +21,7 @@ ProductScreen.check.isShown(); Chrome.do.clickTicketButton(); TicketScreen.check.nthRowContains(2, "-0001"); TicketScreen.do.deleteOrder("-0001"); -FloorScreen.check.isShown(); +TicketScreen.do.clickDiscard(); // Create 2 items in a table. From floorscreen, delete 1 item. Then select the other item. // Correct order and screen should be displayed and the BackToFloorButton is shown.