This commit is contained in:
mohammed-alkhazrji 2025-12-26 01:11:49 +03:00
parent fa01ac0106
commit 8a2020d893
2 changed files with 168 additions and 37 deletions

View File

@ -27,7 +27,7 @@ export class KpiFormulaField extends Component {
onWillStart(async () => {
try {
// Load draggabilly library
await loadJS("kpi_scorecard/static/lib/draggabilly/draggabilly.pkgd.js");
await loadJS("/kpi_scorecard/static/lib/draggabilly/draggabilly.pkgd.js");
await this.loadFormulaData();
} catch (error) {
console.error("Error loading KPI formula:", error);
@ -51,12 +51,14 @@ export class KpiFormulaField extends Component {
async loadFormulaData() {
try {
const fieldValue = this.props.record.data[this.props.name] || "";
if (this.props.readonly) {
// Load formula parts for readonly display
this.state.formulaParts = await this.orm.call(
"kpi.item",
"action_render_formula",
[this.props.value || ""]
[fieldValue]
);
} else {
// Load variables for edit mode
@ -65,13 +67,14 @@ export class KpiFormulaField extends Component {
this.state.variables = await this.orm.call(
"kpi.item",
"action_return_measures",
[[recordId], this.props.value || ""]
[[recordId], fieldValue]
);
}
}
this.state.isLoaded = true;
} catch (error) {
console.error("Error loading formula data:", error);
this.state.isLoaded = true; // Set to true even on error
}
}
@ -128,7 +131,8 @@ export class KpiFormulaField extends Component {
}
});
this.props.update(formula.trim());
// Update using Odoo 18 method
this.props.record.update({ [this.props.name]: formula.trim() });
}
onSearch(ev) {
@ -176,5 +180,7 @@ export class KpiFormulaField extends Component {
}
}
// Register the field widget
registry.category("fields").add("kpi_formula", KpiFormulaField);
// ✅ الطريقة الصحيحة للتسجيل في Odoo 18
registry.category("fields").add("kpi_formula", {
component: KpiFormulaField,
});

View File

@ -2,14 +2,14 @@
<templates>
<t t-name="kpi_scorecard.KpiFormulaField">
<div class="o_field_kpi_formula" t-ref="formula">
<!-- Readonly Mode -->
<t t-if="props.readonly">
<div class="formula-readonly">
<t t-if="state.formulaParts and state.formulaParts.length">
<t t-foreach="state.formulaParts" t-as="part" t-key="part_index">
<span t-att-class="'formula-part ' + (part.type || '').toLowerCase()"
t-att-title="part.name">
<t t-esc="part.name"/>
</span>
t-att-title="part.name"
t-esc="part.name"/>
</t>
</t>
<t t-else="">
@ -17,51 +17,74 @@
</t>
</div>
</t>
<!-- Edit Mode -->
<t t-else="">
<div class="formula-editor" t-if="state.isLoaded">
<!-- Search Input -->
<div class="formula-search mb-2">
<input type="text"
class="kpi-search-input form-control"
placeholder="Search..."
t-on-keyup="onSearch"/>
t-on-input="onSearch"/>
</div>
<div class="row">
<!-- Left Column: Variables and Operators -->
<div class="col-md-6">
<!-- Variables Section -->
<div class="formula-variables" t-if="state.variables">
<t t-foreach="state.variables.sections || []" t-as="section" t-key="section_index">
<div class="variable-section mb-3">
<h6 t-esc="section.name" class="text-primary"/>
<div class="variable-items">
<t t-foreach="section.items || []" t-as="item" t-key="item_index">
<div class="formula-item draggable btn btn-sm btn-outline-secondary m-1"
t-att-data-formula="item.formula"
t-att-data-part-id="item.id">
<span t-esc="item.name"/>
<button class="btn btn-sm btn-danger ms-1"
t-on-click="() => onDeletePart(item.id)"
type="button">
<i class="fa fa-times"/>
</button>
</div>
</t>
<t t-if="state.variables.sections">
<t t-foreach="state.variables.sections" t-as="section" t-key="section_index">
<div class="variable-section mb-3">
<h6 t-esc="section.name" class="text-primary"/>
<div class="variable-items">
<t t-if="section.items">
<t t-foreach="section.items" t-as="item" t-key="item_index">
<div class="formula-item draggable btn btn-sm btn-outline-secondary m-1"
t-att-data-formula="item.formula"
t-att-data-part-id="item.id">
<span t-esc="item.name"/>
<button class="btn btn-sm btn-danger ms-1"
t-on-click.stop="(ev) => this.onDeletePart(item.id)"
type="button">
<i class="fa fa-times"/>
</button>
</div>
</t>
</t>
</div>
</div>
</div>
</t>
</t>
</div>
<!-- Operators Section -->
<div class="formula-operators mb-3">
<h6 class="text-primary">Operators</h6>
<button t-foreach="['+', '-', '*', '/', '(', ')']"
t-as="op"
t-key="op"
class="btn btn-secondary btn-sm m-1"
t-on-click="() => onAddOperator(op)"
type="button">
<t t-esc="op"/>
</button>
<div class="d-flex flex-wrap gap-1">
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator('+')"
type="button">+</button>
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator('-')"
type="button">-</button>
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator('*')"
type="button">*</button>
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator('/')"
type="button">/</button>
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator('(')"
type="button">(</button>
<button class="btn btn-secondary btn-sm"
t-on-click="() => this.onAddOperator(')')"
type="button">)</button>
</div>
</div>
<!-- Number Input Section -->
<div class="formula-number mb-3">
<h6 class="text-primary">Number</h6>
<input type="number"
@ -71,6 +94,7 @@
</div>
</div>
<!-- Right Column: Formula Builder -->
<div class="col-md-6">
<h6 class="text-primary">Formula Builder</h6>
<div class="formula-drop-zone border rounded p-3 mb-3"
@ -82,16 +106,117 @@
<label class="form-label">Current Formula:</label>
<input type="text"
class="form-control"
t-att-value="props.value || ''"
t-att-value="props.record.data[props.name] || ''"
readonly="readonly"/>
</div>
</div>
</div>
</div>
<!-- Loading State -->
<div t-else="" class="text-center text-muted p-3">
<i class="fa fa-spinner fa-spin me-2"/>
Loading formula editor...
</div>
</t>
</div>
</t>
</templates>
<!--<?xml version="1.0" encoding="UTF-8"?>-->
<!--<templates>-->
<!-- <t t-name="kpi_scorecard.KpiFormulaField">-->
<!-- <div class="o_field_kpi_formula" t-ref="formula">-->
<!-- <t t-if="props.readonly">-->
<!-- <div class="formula-readonly">-->
<!-- <t t-if="state.formulaParts and state.formulaParts.length">-->
<!-- <t t-foreach="state.formulaParts" t-as="part" t-key="part_index">-->
<!-- <span t-att-class="'formula-part ' + (part.type || '').toLowerCase()"-->
<!-- t-att-title="part.name">-->
<!-- <t t-esc="part.name"/>-->
<!-- </span>-->
<!-- </t>-->
<!-- </t>-->
<!-- <t t-else="">-->
<!-- <span class="text-muted">No formula defined</span>-->
<!-- </t>-->
<!-- </div>-->
<!-- </t>-->
<!-- <t t-else="">-->
<!-- <div class="formula-editor" t-if="state.isLoaded">-->
<!-- <div class="formula-search mb-2">-->
<!-- <input type="text"-->
<!-- class="kpi-search-input form-control"-->
<!-- placeholder="Search..."-->
<!-- t-on-keyup="onSearch"/>-->
<!-- </div>-->
<!-- <div class="row">-->
<!-- <div class="col-md-6">-->
<!-- <div class="formula-variables" t-if="state.variables">-->
<!-- <t t-foreach="state.variables.sections || []" t-as="section" t-key="section_index">-->
<!-- <div class="variable-section mb-3">-->
<!-- <h6 t-esc="section.name" class="text-primary"/>-->
<!-- <div class="variable-items">-->
<!-- <t t-foreach="section.items || []" t-as="item" t-key="item_index">-->
<!-- <div class="formula-item draggable btn btn-sm btn-outline-secondary m-1"-->
<!-- t-att-data-formula="item.formula"-->
<!-- t-att-data-part-id="item.id">-->
<!-- <span t-esc="item.name"/>-->
<!-- <button class="btn btn-sm btn-danger ms-1"-->
<!-- t-on-click="() => onDeletePart(item.id)"-->
<!-- type="button">-->
<!-- <i class="fa fa-times"/>-->
<!-- </button>-->
<!-- </div>-->
<!-- </t>-->
<!-- </div>-->
<!-- </div>-->
<!-- </t>-->
<!-- </div>-->
<!-- <div class="formula-operators mb-3">-->
<!-- <h6 class="text-primary">Operators</h6>-->
<!-- <button t-foreach="['+', '-', '*', '/', '(', ')']"-->
<!-- t-as="op"-->
<!-- t-key="op"-->
<!-- class="btn btn-secondary btn-sm m-1"-->
<!-- t-on-click="() => onAddOperator(op)"-->
<!-- type="button">-->
<!-- <t t-esc="op"/>-->
<!-- </button>-->
<!-- </div>-->
<!-- <div class="formula-number mb-3">-->
<!-- <h6 class="text-primary">Number</h6>-->
<!-- <input type="number"-->
<!-- class="kpi-number-input form-control"-->
<!-- placeholder="Enter number..."-->
<!-- t-on-change="onChangeNumber"/>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-md-6">-->
<!-- <h6 class="text-primary">Formula Builder</h6>-->
<!-- <div class="formula-drop-zone border rounded p-3 mb-3"-->
<!-- style="min-height: 100px; background-color: #f8f9fa;">-->
<!-- <small class="text-muted">Drag formula parts here</small>-->
<!-- </div>-->
<!-- <div class="current-formula">-->
<!-- <label class="form-label">Current Formula:</label>-->
<!-- <input type="text"-->
<!-- class="form-control"-->
<!-- t-att-value="props.value || ''"-->
<!-- readonly="readonly"/>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div t-else="" class="text-center text-muted p-3">-->
<!-- Loading formula editor...-->
<!-- </div>-->
<!-- </t>-->
<!-- </div>-->
<!-- </t>-->
<!--</templates>-->