181 lines
9.6 KiB
XML
181 lines
9.6 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data>
|
|
|
|
<!-- Portal Home Menu Item -->
|
|
<template id="portal_my_home_menu_kpi" name="Portal layout : KPI menu entries" inherit_id="portal.portal_breadcrumbs" priority="30">
|
|
<xpath expr="//ol[hasclass('o_portal_submenu')]" position="inside">
|
|
<li t-if="page_name == 'kpi' or kpi" class="breadcrumb-item col-12 col-md-auto" t-att-class="{'active': not kpi}">
|
|
<a t-if="kpi" t-attf-href="/my/kpi">KPIs</a>
|
|
<span t-else="">KPIs</span>
|
|
</li>
|
|
<li t-if="kpi" class="breadcrumb-item active">
|
|
<span t-field="kpi.name"/>
|
|
</li>
|
|
</xpath>
|
|
</template>
|
|
|
|
<template id="portal_my_home_kpi" name="Show KPI" inherit_id="portal.portal_my_home" priority="30">
|
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
|
|
<t t-call="portal.portal_docs_entry">
|
|
<t t-set="title">KPIs</t>
|
|
<t t-set="url" t-value="'/my/kpi'"/>
|
|
<t t-set="placeholder_count" t-value="'kpi_count'"/>
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- KPI List View -->
|
|
<template id="portal_my_kpis" name="My KPIs">
|
|
<t t-call="portal.portal_layout">
|
|
<t t-set="breadcrumbs_searchbar" t-value="True"/>
|
|
|
|
<t t-call="portal.portal_table">
|
|
<thead>
|
|
<tr class="active">
|
|
<th>Reference</th>
|
|
<th>Period</th>
|
|
<th>Status</th>
|
|
<th>Total Score</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<t t-foreach="kpis" t-as="kpi">
|
|
<tr>
|
|
<td><a t-attf-href="/my/kpi/#{kpi.id}"><t t-esc="kpi.name"/></a></td>
|
|
<td><span t-field="kpi.period"/></td>
|
|
<td><span t-field="kpi.state"/></td>
|
|
<td><span t-field="kpi.total_score"/></td>
|
|
</tr>
|
|
</t>
|
|
</tbody>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- KPI Detail View -->
|
|
<template id="portal_my_kpi" name="My KPI Detail">
|
|
<t t-call="portal.portal_layout">
|
|
<t t-set="o_portal_fullwidth_alert" groups="employee_kpi.group_kpi_manager">
|
|
<t t-call="portal.portal_back_in_edit_mode">
|
|
<t t-set="backend_url" t-value="'/nav/to/record/kpi.kpi/' + str(kpi.id)"/>
|
|
</t>
|
|
</t>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header">
|
|
<div class="row">
|
|
<div class="col-8">
|
|
<h4>
|
|
<span t-field="kpi.name"/>
|
|
</h4>
|
|
</div>
|
|
<div class="col-4 text-end">
|
|
<span t-field="kpi.state" class="badge bg-secondary"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<strong>Employee:</strong> <span t-field="kpi.employee_id"/><br/>
|
|
<strong>Department:</strong> <span t-field="kpi.department_id"/><br/>
|
|
<strong>Job:</strong> <span t-field="kpi.job_id"/>
|
|
</div>
|
|
<div class="col-md-6 text-end">
|
|
<strong>Period:</strong> <span t-field="kpi.period"/><br/>
|
|
<strong>Total Score:</strong> <span t-field="kpi.total_score" id="kpi_total_score"/>
|
|
</div>
|
|
</div>
|
|
|
|
<h5>KPI Details</h5>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Code</th>
|
|
<th>KPI</th>
|
|
<th>Weight</th>
|
|
<th>Target (YTD)</th>
|
|
<th>Realization</th>
|
|
<th>Score</th>
|
|
<th>Final Score</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr t-foreach="kpi.line_ids" t-as="line">
|
|
<td><span t-field="line.code"/></td>
|
|
<td>
|
|
<span t-field="line.name"/>
|
|
<br/>
|
|
<small class="text-muted"><span t-field="line.perspective"/></small>
|
|
</td>
|
|
<td><span t-field="line.weight"/></td>
|
|
<td><span t-field="line.target_ytd"/></td>
|
|
<td>
|
|
<input type="number" step="any" class="form-control form-control-sm kpi-realization-input"
|
|
t-att-data-line-id="line.id"
|
|
t-att-value="line.realization"/>
|
|
</td>
|
|
<td><span t-field="line.score" t-att-id="'score_' + str(line.id)"/></td>
|
|
<td><span t-field="line.final_score" t-att-id="'final_score_' + str(line.id)"/></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Simple Inline script to handle updates -->
|
|
<script type="text/javascript">
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var inputs = document.querySelectorAll('.kpi-realization-input');
|
|
inputs.forEach(function(input) {
|
|
input.addEventListener('change', function() {
|
|
var lineId = this.getAttribute('data-line-id');
|
|
var value = this.value;
|
|
|
|
odoo.define('employee_kpi.update', [], function(require){
|
|
var ajax = require('web.ajax'); // Odoo 16/17 style, might differ in 19 but 'jsonRpc' is standard-ish
|
|
// In Odoo 19, 'jsonRpc' might be direct fetch or via core `rpc` service if available.
|
|
// Using fetch for generic web compatibility if 'odoo' object available.
|
|
|
|
// Let's use standard fetch to the controller route which is safer across versions if simple JSON
|
|
fetch('/my/kpi/save_line', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
params: {
|
|
line_id: parseInt(lineId),
|
|
realization: value
|
|
}
|
|
})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.result && data.result.success) {
|
|
// Update DOM
|
|
document.getElementById('score_' + lineId).innerText = data.result.new_score.toFixed(2);
|
|
document.getElementById('final_score_' + lineId).innerText = data.result.new_final_score.toFixed(4);
|
|
document.getElementById('kpi_total_score').innerText = data.result.kpi_total_score.toFixed(2);
|
|
|
|
// Optional: Green flash effect
|
|
input.classList.add('is-valid');
|
|
setTimeout(() => input.classList.remove('is-valid'), 1000);
|
|
} else {
|
|
alert('Error saving data');
|
|
}
|
|
})
|
|
.catch(error => console.error('Error:', error));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
</t>
|
|
</template>
|
|
</data>
|
|
</odoo>
|