新增主生产计划模块
This commit is contained in:
22
mrp_mps/static/src/search/group_menu.js
Normal file
22
mrp_mps/static/src/search/group_menu.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
export class GroupMenu extends Component {
|
||||
get items() {
|
||||
return this.props.items;
|
||||
}
|
||||
|
||||
_toggle_group(group) {
|
||||
const value = {};
|
||||
value[group] = !this.props.items[group];
|
||||
this.env.model._saveCompanySettings(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GroupMenu.template = "mrp_mps.GroupMenu";
|
||||
GroupMenu.components = { Dropdown, DropdownItem };
|
||||
73
mrp_mps/static/src/search/group_menu.xml
Normal file
73
mrp_mps/static/src/search/group_menu.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mrp_mps.GroupMenu" owl="1">
|
||||
<Dropdown togglerClass="'btn btn-light'">
|
||||
<t t-set-slot="toggler">
|
||||
<i class="me-1" t-att-class="icon"/>
|
||||
<span class="dropdown-toggle o_dropdown_title">Rows</span>
|
||||
</t>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_starting_inventory }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_starting_inventory')">
|
||||
Starting Inventory
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_demand_forecast }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_demand_forecast')">
|
||||
Demand Forecast
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_actual_demand }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_actual_demand')">
|
||||
Actual Demand
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_actual_demand_year_minus_1 }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_actual_demand_year_minus_1')">
|
||||
Actual Demand Y-1
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_actual_demand_year_minus_2 }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_actual_demand_year_minus_2')">
|
||||
Actual Demand Y-2
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_indirect_demand }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_indirect_demand')">
|
||||
Indirect Demand Forecast
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_to_replenish }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_to_replenish')">
|
||||
To Replenish
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_actual_replenishment }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_actual_replenishment')">
|
||||
Actual Replenishment
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_safety_stock }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_safety_stock')">
|
||||
Forecasted Stock
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
class="{ o_menu_item: true, selected: items.mrp_mps_show_available_to_promise }"
|
||||
parentClosingMode="'none'"
|
||||
onSelected="() => this._toggle_group('mrp_mps_show_available_to_promise')">
|
||||
Available to Promise
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
13
mrp_mps/static/src/search/import_records.js
Normal file
13
mrp_mps/static/src/search/import_records.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ImportRecords } from "@base_import/import_records/import_records";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
const favoriteMenuRegistry = registry.category("favoriteMenu");
|
||||
const mpsImportRecordsItem = {
|
||||
Component: ImportRecords,
|
||||
groupNumber: 4,
|
||||
isDisplayed: ({ config }) =>
|
||||
config.mpsImportRecords
|
||||
};
|
||||
favoriteMenuRegistry.add("mps-import-records-menu", mpsImportRecordsItem, { sequence: 1 });
|
||||
139
mrp_mps/static/src/search/mrp_mps_control_panel.js
Normal file
139
mrp_mps/static/src/search/mrp_mps_control_panel.js
Normal file
@@ -0,0 +1,139 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { GroupMenu } from "./group_menu";
|
||||
import { download } from "@web/core/network/download";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { ActionMenus } from "@web/search/action_menus/action_menus";
|
||||
import { ControlPanel } from "@web/search/control_panel/control_panel";
|
||||
import { ExportDataDialog } from "@web/views/view_dialogs/export_data_dialog";
|
||||
|
||||
|
||||
export class MrpMpsControlPanel extends ControlPanel {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.rpc = useService("rpc");
|
||||
this.dialogService = useService("dialog");
|
||||
}
|
||||
|
||||
get model() {
|
||||
return this.env.model;
|
||||
}
|
||||
|
||||
get groups() {
|
||||
return this.env.model.data.groups[0];
|
||||
}
|
||||
|
||||
get isRecordSelected() {
|
||||
return this.model.selectedRecords.size > 0;
|
||||
}
|
||||
|
||||
getActionMenuItems() {
|
||||
return Object.assign({}, {
|
||||
other: [{
|
||||
key: "export",
|
||||
description: this.env._t("Export"),
|
||||
callback: () => this.onExportData(),
|
||||
}, {
|
||||
key: "delete",
|
||||
description: this.env._t("Delete"),
|
||||
callback: () => this.unlinkSelectedRecord(),
|
||||
}, {
|
||||
key: "replenish",
|
||||
description: this.env._t("Replenish"),
|
||||
callback: () => this.replenishSelectedRecords(),
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the click on replenish button. It will call action_replenish with
|
||||
* all the Ids present in the view.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onClickReplenish(ev) {
|
||||
this.env.model.replenishAll();
|
||||
}
|
||||
|
||||
_onMouseOverReplenish(ev) {
|
||||
this.model.mouseOverReplenish()
|
||||
}
|
||||
|
||||
_onMouseOutReplenish(ev) {
|
||||
this.model.mouseOutReplenish()
|
||||
}
|
||||
|
||||
_onClickCreate(ev) {
|
||||
this.env.model._createProduct();
|
||||
}
|
||||
|
||||
replenishSelectedRecords() {
|
||||
this.env.model.replenishSelectedRecords();
|
||||
}
|
||||
|
||||
unlinkSelectedRecord() {
|
||||
this.env.model.unlinkSelectedRecord();
|
||||
}
|
||||
|
||||
async getExportedFields(model, import_compat, parentParams) {
|
||||
return await this.rpc("/web/export/get_fields", {
|
||||
...parentParams,
|
||||
model,
|
||||
import_compat,
|
||||
});
|
||||
}
|
||||
|
||||
async downloadExport(fields, import_compat, format) {
|
||||
const resIds = Array.from(this.model.selectedRecords);
|
||||
const exportedFields = fields.map((field) => ({
|
||||
name: field.name || field.id,
|
||||
label: field.label || field.string,
|
||||
store: field.store,
|
||||
type: field.field_type,
|
||||
}));
|
||||
if (import_compat) {
|
||||
exportedFields.unshift({ name: "id", label: this.env._t("External ID") });
|
||||
}
|
||||
await download({
|
||||
data: {
|
||||
data: JSON.stringify({
|
||||
import_compat,
|
||||
context: this.props.context,
|
||||
domain: this.model.domain,
|
||||
fields: exportedFields,
|
||||
ids: resIds.length > 0 && resIds,
|
||||
model: "mrp.production.schedule",
|
||||
}),
|
||||
},
|
||||
url: `/web/export/${format}`,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Export Dialog
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
onExportData() {
|
||||
const resIds = Array.from(this.model.selectedRecords);
|
||||
const dialogProps = {
|
||||
resIds,
|
||||
context: this.props.context,
|
||||
download: this.downloadExport.bind(this),
|
||||
getExportedFields: this.getExportedFields.bind(this),
|
||||
root: {
|
||||
resModel: "mrp.production.schedule",
|
||||
activeFields: [],
|
||||
},
|
||||
};
|
||||
this.dialogService.add(ExportDataDialog, dialogProps);
|
||||
}
|
||||
}
|
||||
|
||||
MrpMpsControlPanel.template = "mrp_mps.MrpMpsControlPanel";
|
||||
MrpMpsControlPanel.components = {
|
||||
...ControlPanel.components,
|
||||
ActionMenus,
|
||||
GroupMenu,
|
||||
};
|
||||
37
mrp_mps/static/src/search/mrp_mps_control_panel.xml
Normal file
37
mrp_mps/static/src/search/mrp_mps_control_panel.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="mrp_mps.MrpMpsControlPanel.Regular" t-inherit="web.ControlPanel.Regular" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//t[@t-slot='control-panel-bottom-left']" position="replace">
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
t-on-click.stop="_onClickReplenish"
|
||||
t-on-mouseover.stop="_onMouseOverReplenish"
|
||||
t-on-mouseout.stop="_onMouseOutReplenish">Replenish</button>
|
||||
<button
|
||||
type="button"
|
||||
class='btn btn-secondary'
|
||||
t-on-click.stop="_onClickCreate">Add a Product</button>
|
||||
</div>
|
||||
<ActionMenus t-if="isRecordSelected"
|
||||
getActiveIds="() => Array.from(model.selectedRecords)"
|
||||
context="{}"
|
||||
domain="model.domain"
|
||||
items="getActionMenuItems()"
|
||||
isDomainSelected="model.isDomainSelected"
|
||||
resModel="'mrp.production.schedule'"/>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-foreach='searchMenus']" position="before">
|
||||
<GroupMenu items="groups"/>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="mrp_mps.MrpMpsControlPanel" t-inherit="web.ControlPanel" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//t[@t-call='web.ControlPanel.Regular']" position="replace">
|
||||
<t t-call="mrp_mps.MrpMpsControlPanel.Regular"/>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
28
mrp_mps/static/src/search/mrp_mps_search_model.js
Normal file
28
mrp_mps/static/src/search/mrp_mps_search_model.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { SearchModel } from "@web/search/search_model";
|
||||
|
||||
export class MrpMpsSearchModel extends SearchModel {
|
||||
/**
|
||||
* When search with field bom_id, also show components of that bom
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_getFieldDomain(field, autocompleteValues) {
|
||||
let domain = super._getFieldDomain(...arguments);
|
||||
if (field.fieldName === "bom_id") {
|
||||
const additionalDomain = [
|
||||
"|",
|
||||
["product_id.bom_line_ids.bom_id", "ilike", autocompleteValues[0].value],
|
||||
"|",
|
||||
["product_id.variant_bom_ids", "ilike", autocompleteValues[0].value],
|
||||
"&",
|
||||
["product_tmpl_id.bom_ids.product_id", "=", false],
|
||||
["product_tmpl_id.bom_ids", "ilike", autocompleteValues[0].value],
|
||||
];
|
||||
domain = Domain.or([additionalDomain, domain.toList()]);
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user