[IMP] sale_stock: adapt product_catalog for stock module
When the stock module is installed some conditions changes in the sale orders Here's the list and the implementation made to help this Patched the kanban_record so that the asked_qty of a product cannot go below the delivered_qty the delivered_qty is added in the productCatalogData of the record through the _get_catalog_info() hook in the following PR: https://github.com/odoo/odoo/pull/132341/commits Patched the sale_order_line xml to disabled removeProduct and decreaseProduct buttons when the quantity is equal to the delivered quantity if the user tries to remove an already delivered product it'll set to the delivered quantity instead of 0 if the user tries to set a quantity that is below the delivered quantity it'll set it to the delivered quantity Added action action_product_forecast_report to the menuitem of the products Task-3343547 closes odoo/odoo#127161 Related: odoo/enterprise#43469 Related: odoo/upgrade#4887 Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
This commit is contained in:
@@ -38,7 +38,7 @@ class CatalogController(Controller):
|
||||
product_ids.remove(product.id)
|
||||
|
||||
default_data = request.env['sale.order.line']._get_catalog_info()
|
||||
default_data['readOnly'] = order._is_readonly()
|
||||
default_data['readOnly'] = order._is_readonly() if order else False
|
||||
|
||||
sale_order_line_info.update({
|
||||
id: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { KanbanController } from "@web/views/kanban/kanban_controller";
|
||||
import { onWillStart } from "@odoo/owl";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
|
||||
export class ProductCatalogKanbanController extends KanbanController {
|
||||
static template = "sale.ProductCatalogKanbanController";
|
||||
@@ -14,14 +14,7 @@ export class ProductCatalogKanbanController extends KanbanController {
|
||||
this.orm = useService("orm");
|
||||
this.orderId = this.props.context.order_id;
|
||||
|
||||
onWillStart(async () => {
|
||||
// Define the content of the button.
|
||||
const orderStateInfo = await this.orm.searchRead(
|
||||
"sale.order", [["id", "=", this.orderId]], ["state"]
|
||||
);
|
||||
const orderIsQuotation = ["draft", "sent"].includes(orderStateInfo[0].state);
|
||||
this.buttonString = `Back to ${orderIsQuotation ? "Quotation" : "Order"}`
|
||||
})
|
||||
onWillStart(async () => this._defineButtonContent());
|
||||
}
|
||||
|
||||
// Force the slot for the "Back to Quotation" button to always be shown.
|
||||
@@ -29,6 +22,19 @@ export class ProductCatalogKanbanController extends KanbanController {
|
||||
return true;
|
||||
}
|
||||
|
||||
async _defineButtonContent() {
|
||||
// Define the content of the button.
|
||||
const orderStateInfo = await this.orm.searchRead(
|
||||
"sale.order", [["id", "=", this.orderId]], ["state"]
|
||||
);
|
||||
const orderIsQuotation = ["draft", "sent"].includes(orderStateInfo[0].state);
|
||||
if (orderIsQuotation) {
|
||||
this.buttonString = _t("Back to Quotation");
|
||||
} else {
|
||||
this.buttonString = _t("Back to Order");
|
||||
}
|
||||
}
|
||||
|
||||
async backToQuotation() {
|
||||
// Restore the last form view from the breadcrumbs if breadcrumbs are available.
|
||||
// If, for some weird reason, the user reloads the page then the breadcrumbs are
|
||||
|
||||
@@ -5,12 +5,11 @@ import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
import { ProductCatalogKanbanRecord } from "./kanban_record";
|
||||
|
||||
|
||||
export class ProductCatalogKanbanRenderer extends KanbanRenderer {
|
||||
static template = "sale.ProductCatalogKanbanRenderer";
|
||||
static components = {
|
||||
...KanbanRenderer.components,
|
||||
KanbanRecord: ProductCatalogKanbanRecord
|
||||
KanbanRecord: ProductCatalogKanbanRecord,
|
||||
};
|
||||
|
||||
setup() {
|
||||
@@ -18,13 +17,23 @@ export class ProductCatalogKanbanRenderer extends KanbanRenderer {
|
||||
this.action = useService("action");
|
||||
}
|
||||
|
||||
get createProductContext() {
|
||||
return {};
|
||||
}
|
||||
|
||||
async createProduct() {
|
||||
await this.action.doAction({
|
||||
type: "ir.actions.act_window",
|
||||
res_model: "product.product",
|
||||
target: "new",
|
||||
views: [[false, "form"]],
|
||||
view_mode: "form",
|
||||
});
|
||||
await this.action.doAction(
|
||||
{
|
||||
type: "ir.actions.act_window",
|
||||
res_model: "product.product",
|
||||
target: "new",
|
||||
views: [[false, "form"]],
|
||||
view_mode: "form",
|
||||
context: this.createProductContext,
|
||||
},
|
||||
{
|
||||
onClose: () => this.props.list.model.load(),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,14 @@ export class ProductCatalogSOL extends Component {
|
||||
return this.props.quantity !== 0;
|
||||
}
|
||||
|
||||
get disableRemove() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get disabledButtonTooltip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
get price() {
|
||||
return formatMonetary(this.props.price, { currencyId: this.env.currencyId, digits: this.env.digits });
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
<div t-if="isInSaleOrder()"
|
||||
class="input-group o_sale_product_catalog_quantity o_sale_product_catalog_cancel_global_click w-50">
|
||||
<button class="btn btn-primary border"
|
||||
t-on-click="this.env.decreaseQuantity">
|
||||
t-on-click="this.env.decreaseQuantity"
|
||||
t-att-disabled="disableRemove"
|
||||
t-att-data-tooltip="disabledButtonTooltip">
|
||||
<i class="fa fa-minus center"/>
|
||||
</button>
|
||||
<input class="o_input form-control border text-center text-bg-light"
|
||||
@@ -32,12 +34,14 @@
|
||||
<i class="fa fa-shopping-cart"/>
|
||||
Add
|
||||
</button>
|
||||
<button t-else=""
|
||||
t-on-click="this.env.removeProduct"
|
||||
class="btn btn-light border">
|
||||
<i class="fa fa-trash"/>
|
||||
Remove
|
||||
</button>
|
||||
<div t-else="" class="o_tooltip_div_remove" t-att-data-tooltip="this.disabledButtonTooltip">
|
||||
<button t-on-click="this.env.removeProduct"
|
||||
t-att-disabled="disableRemove"
|
||||
class="btn btn-light border">
|
||||
<i class="fa fa-trash"/>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/** @odoo-module */
|
||||
import { ProductCatalogKanbanRecord } from "@sale/js/product_catalog/kanban_record";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(ProductCatalogKanbanRecord.prototype, {
|
||||
updateQuantity(quantity) {
|
||||
if (
|
||||
this.productCatalogData.quantity === this.productCatalogData.deliveredQty &&
|
||||
quantity < this.productCatalogData.quantity
|
||||
) {
|
||||
// This condition is triggered on the following specific condition that the product was already at the minimum quantity possible,
|
||||
// as stated in the sale_stock module, then the user inputs a quantity lower than this limit, in this case we need the record to forcefully update
|
||||
// the record
|
||||
this.props.record.load();
|
||||
this.props.record.model.notify();
|
||||
} else {
|
||||
super.updateQuantity(Math.max(quantity, this.productCatalogData.deliveredQty));
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { ProductCatalogSOL } from "@sale/js/product_catalog/sale_order_line/sale_order_line";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
|
||||
patch(ProductCatalogSOL, {
|
||||
props: {
|
||||
@@ -9,3 +10,15 @@ patch(ProductCatalogSOL, {
|
||||
deliveredQty: Number,
|
||||
},
|
||||
});
|
||||
|
||||
patch(ProductCatalogSOL.prototype, {
|
||||
get disableRemove() {
|
||||
return this.props.quantity === this.props.deliveredQty;
|
||||
},
|
||||
get disabledButtonTooltip() {
|
||||
if (this.disableRemove) {
|
||||
return _t("The ordered quantity cannot be decreased below the amount already delivered. Instead, create a return in your inventory.");
|
||||
}
|
||||
return super.disabledButtonTooltip;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
<field name="qty_available"/>
|
||||
</div>
|
||||
</div>
|
||||
<a role="menuitem" type="edit" position="after">
|
||||
<a role="menuitem" type="object" name="action_product_forecast_report" class="dropdown-item border-top-0">View Availability</a>
|
||||
</a>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user