Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bd40116bd |
@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
{
|
{
|
||||||
'name': 'POS Reverse Downpayment',
|
'name': 'POS Reverse Downpayment',
|
||||||
'version': '1.0',
|
'version': '19.0.1.0.0',
|
||||||
'category': 'Sales/Point of Sale',
|
'category': 'Sales/Point of Sale',
|
||||||
'summary': 'Create Quotation from POS Cart and Zero-out Standard Items',
|
'summary': 'Create Quotation from POS Cart and Zero-out Standard Items',
|
||||||
'description': """
|
'description': """
|
||||||
|
|||||||
@ -77,19 +77,6 @@ class PosOrder(models.Model):
|
|||||||
pickings = self.env['stock.picking']._create_picking_from_pos_order_lines(destination_id, lines_to_pick, picking_type, self.partner_id)
|
pickings = self.env['stock.picking']._create_picking_from_pos_order_lines(destination_id, lines_to_pick, picking_type, self.partner_id)
|
||||||
pickings.write({'pos_session_id': self.session_id.id, 'pos_order_id': self.id, 'origin': self.name})
|
pickings.write({'pos_session_id': self.session_id.id, 'pos_order_id': self.id, 'origin': self.name})
|
||||||
|
|
||||||
def _process_preparation_changes(self, cancelled=False, note_history=None):
|
|
||||||
"""
|
|
||||||
Intercepts preparation display generation. If this POS order is actually a Quotation
|
|
||||||
we don't want it to be processed by the kitchen display.
|
|
||||||
"""
|
|
||||||
if any(line.is_quotation_line for line in self.lines):
|
|
||||||
return {'change': False, 'sound': False, 'category_ids': []}
|
|
||||||
# Check if pos_preparation_display is installed and we can call super
|
|
||||||
if hasattr(super(), '_process_preparation_changes'):
|
|
||||||
return super()._process_preparation_changes(cancelled=cancelled, note_history=note_history)
|
|
||||||
return {'change': False, 'sound': False, 'category_ids': []}
|
|
||||||
|
|
||||||
|
|
||||||
class PosOrderLine(models.Model):
|
class PosOrderLine(models.Model):
|
||||||
_inherit = 'pos.order.line'
|
_inherit = 'pos.order.line'
|
||||||
|
|
||||||
@ -99,14 +86,8 @@ class PosOrderLine(models.Model):
|
|||||||
default=False
|
default=False
|
||||||
)
|
)
|
||||||
|
|
||||||
def _export_for_ui(self, orderline):
|
@api.model
|
||||||
result = super()._export_for_ui(orderline)
|
def _load_pos_data_fields(self, config):
|
||||||
result['is_quotation_line'] = orderline.is_quotation_line
|
result = super()._load_pos_data_fields(config)
|
||||||
|
result.append('is_quotation_line')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _order_line_fields(self, line, session_id=None):
|
|
||||||
result = super()._order_line_fields(line, session_id)
|
|
||||||
if 'is_quotation_line' in line[2]:
|
|
||||||
result[2]['is_quotation_line'] = line[2]['is_quotation_line']
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
/** @odoo-module */
|
/** @odoo-module */
|
||||||
|
|
||||||
import { Order, Orderline } from "@point_of_sale/app/store/models";
|
import { PosStore } from "@point_of_sale/app/services/pos_store";
|
||||||
|
import { PosOrderline } from "@point_of_sale/app/models/pos_order_line";
|
||||||
import { patch } from "@web/core/utils/patch";
|
import { patch } from "@web/core/utils/patch";
|
||||||
import { ConfirmPopup } from "@point_of_sale/app/utils/confirm_popup/confirm_popup";
|
import { ConfirmPopup } from "@point_of_sale/app/utils/confirm_popup/confirm_popup";
|
||||||
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";
|
import { ErrorPopup } from "@point_of_sale/app/errors/popups/error_popup";
|
||||||
@ -8,35 +9,38 @@ import { _t } from "@web/core/l10n/translation";
|
|||||||
import { OrderReceipt } from "@point_of_sale/app/screens/receipt_screen/receipt/order_receipt";
|
import { OrderReceipt } from "@point_of_sale/app/screens/receipt_screen/receipt/order_receipt";
|
||||||
import { onError } from "@odoo/owl";
|
import { onError } from "@odoo/owl";
|
||||||
|
|
||||||
patch(Order.prototype, {
|
PosOrderline.extraFields.push("is_quotation_line");
|
||||||
setup() {
|
|
||||||
super.setup(...arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
patch(PosStore.prototype, {
|
||||||
async pay() {
|
async pay() {
|
||||||
|
const order = this.getOrder();
|
||||||
|
if (!order) {
|
||||||
|
return super.pay(...arguments);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if down payment product is in the cart
|
// Check if down payment product is in the cart
|
||||||
const downPaymentProductId = this.pos.config.down_payment_product_id && this.pos.config.down_payment_product_id[0];
|
const downPaymentProductId = this.config.down_payment_product_id && this.config.down_payment_product_id[0];
|
||||||
if (!downPaymentProductId) {
|
if (!downPaymentProductId) {
|
||||||
return super.pay(...arguments);
|
return super.pay(...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = this.get_orderlines();
|
const lines = order.lines;
|
||||||
// Only consider it a "quotation creation" downpayment if it has a positive quantity and price.
|
// Only consider it a "quotation creation" downpayment if it has a positive quantity and price.
|
||||||
// If pos_sale adds it to deduct a downpayment, it will use negative qty or subtotal.
|
// If pos_sale adds it to deduct a downpayment, it will use negative qty or subtotal.
|
||||||
const downPaymentLines = lines.filter(line =>
|
const downPaymentLines = lines.filter(line =>
|
||||||
line.product.id === downPaymentProductId &&
|
line.product_id.id === downPaymentProductId &&
|
||||||
line.get_quantity() > 0 &&
|
line.qty > 0 &&
|
||||||
line.get_unit_price() >= 0
|
line.price_unit >= 0
|
||||||
);
|
);
|
||||||
|
|
||||||
const standardLines = lines.filter(line => line.product.id !== downPaymentProductId);
|
const standardLines = lines.filter(line => line.product_id.id !== downPaymentProductId);
|
||||||
|
|
||||||
// If there is a down payment, we require a customer and automatically
|
// If there is a down payment, we require a customer and automatically
|
||||||
// create a quotation without prompting.
|
// create a quotation without prompting.
|
||||||
const needsQuotation = downPaymentLines.length > 0;
|
const needsQuotation = downPaymentLines.length > 0;
|
||||||
|
|
||||||
if (needsQuotation && !this.is_quotation_line_converted) {
|
if (needsQuotation && !order.is_quotation_line_converted) {
|
||||||
if (!this.get_partner()) {
|
if (!order.partner_id) {
|
||||||
await this.env.services.popup.add(ErrorPopup, {
|
await this.env.services.popup.add(ErrorPopup, {
|
||||||
title: _t("Customer Required"),
|
title: _t("Customer Required"),
|
||||||
body: _t("Please select a customer before creating a quotation with a down payment."),
|
body: _t("Please select a customer before creating a quotation with a down payment."),
|
||||||
@ -47,23 +51,23 @@ patch(Order.prototype, {
|
|||||||
try {
|
try {
|
||||||
// Prepare data for backend
|
// Prepare data for backend
|
||||||
const linesData = standardLines.map(line => ({
|
const linesData = standardLines.map(line => ({
|
||||||
product_id: line.product.id,
|
product_id: line.product_id.id,
|
||||||
qty: line.get_quantity(),
|
qty: line.qty,
|
||||||
price_unit: line.get_unit_price(),
|
price_unit: line.price_unit,
|
||||||
discount: line.get_discount(),
|
discount: line.discount,
|
||||||
tax_ids: line.tax_ids || line.get_product().taxes_id || [],
|
tax_ids: line.tax_ids ? line.tax_ids.map(t => t.id) : [],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Call backend to create sale.order (removed the first empty array for @api.model)
|
// Call backend to create sale.order
|
||||||
const saleOrderResult = await this.env.services.orm.call(
|
const saleOrderResult = await this.env.services.orm.call(
|
||||||
"pos.order",
|
"pos.order",
|
||||||
"create_quotation_from_pos_lines",
|
"create_quotation_from_pos_lines",
|
||||||
[this.get_partner().id, linesData, this.pos.config.id]
|
[order.partner_id.id, linesData, this.config.id]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (saleOrderResult) {
|
if (saleOrderResult) {
|
||||||
// Link the down payment line to the newly created sale order
|
// Link the down payment line to the newly created sale order
|
||||||
const dpLine = lines.find(line => line.product.id === downPaymentProductId);
|
const dpLine = lines.find(line => line.product_id.id === downPaymentProductId);
|
||||||
if (dpLine) {
|
if (dpLine) {
|
||||||
dpLine.sale_order_origin_id = {
|
dpLine.sale_order_origin_id = {
|
||||||
id: saleOrderResult.id,
|
id: saleOrderResult.id,
|
||||||
@ -73,11 +77,11 @@ patch(Order.prototype, {
|
|||||||
|
|
||||||
// Zero out the standard lines to not charge the customer twice
|
// Zero out the standard lines to not charge the customer twice
|
||||||
for (const line of standardLines) {
|
for (const line of standardLines) {
|
||||||
line.set_unit_price(0);
|
line.setUnitPrice(0);
|
||||||
// Set a flag to easily skip stock delivery later if needed
|
// Set a flag to easily skip stock delivery later if needed
|
||||||
line.is_quotation_line = true;
|
line.is_quotation_line = true;
|
||||||
}
|
}
|
||||||
this.is_quotation_line_converted = true;
|
order.is_quotation_line_converted = true;
|
||||||
} else {
|
} else {
|
||||||
await this.env.services.popup.add(ErrorPopup, {
|
await this.env.services.popup.add(ErrorPopup, {
|
||||||
title: _t("Error"),
|
title: _t("Error"),
|
||||||
@ -99,28 +103,20 @@ patch(Order.prototype, {
|
|||||||
|
|
||||||
// Override preparation display / kitchen printing
|
// Override preparation display / kitchen printing
|
||||||
// If we have a down payment, we consider this a quote, not an immediate order for the kitchen
|
// If we have a down payment, we consider this a quote, not an immediate order for the kitchen
|
||||||
async sendChanges(cancelled) {
|
async sendOrderInPreparationUpdateLastChange(order, opts = {}) {
|
||||||
const downPaymentProductId = this.pos.config.down_payment_product_id && this.pos.config.down_payment_product_id[0];
|
const downPaymentProductId = this.config.down_payment_product_id && this.config.down_payment_product_id[0];
|
||||||
// Only block if there's a positive down payment line (indicating quotation creation, not settlement)
|
// Only block if there's a positive down payment line (indicating quotation creation, not settlement)
|
||||||
if (downPaymentProductId && this.get_orderlines().some(line => line.product.id === downPaymentProductId && line.get_quantity() > 0 && line.get_unit_price() > 0)) {
|
if (downPaymentProductId && order.lines.some(line => line.product_id.id === downPaymentProductId && line.qty > 0 && line.price_unit > 0)) {
|
||||||
// It's a quotation line, we don't send it to preparation display
|
// It's a quotation line, we don't send it to preparation display
|
||||||
this.noteHistory = {};
|
order.noteHistory = {};
|
||||||
this.orderlines.forEach(line => line.setHasChange(false));
|
order.lines.forEach(line => {
|
||||||
|
if(line.uiState) {
|
||||||
|
line.uiState.hasChange = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return super.sendChanges(...arguments);
|
return super.sendOrderInPreparationUpdateLastChange(...arguments);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
patch(Orderline.prototype, {
|
|
||||||
init_from_JSON(json) {
|
|
||||||
super.init_from_JSON(...arguments);
|
|
||||||
this.is_quotation_line = json.is_quotation_line || false;
|
|
||||||
},
|
|
||||||
export_as_JSON() {
|
|
||||||
const json = super.export_as_JSON(...arguments);
|
|
||||||
json.is_quotation_line = this.is_quotation_line || false;
|
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user