employee_kpi/views/kpi_portal_templates.xml
2026-02-05 18:45:49 +07:00

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 &amp;&amp; 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>