first push message

This commit is contained in:
2026-07-01 14:41:49 +07:00
parent 6667dec2bf
commit 58b5f46cc4
2951 changed files with 316619 additions and 0 deletions
+274
View File
@@ -0,0 +1,274 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="cpp_dashboard" name="CPP Election Dashboard">
<t t-call="portal.portal_layout">
<div class="container-fluid mt-4">
<!-- Auto-refresh meta tag -->
<meta http-equiv="refresh" content="3600"/>
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card bg-primary text-white shadow-sm">
<div class="card-body py-3">
<div class="row align-items-center">
<div class="col-md-8">
<h3 class="mb-0 fw-bold">
<i class="fa fa-chart-line me-2"/>
លទ្ធផលដំណើរការបោះឆ្នោត
</h3>
<small>Dashboard - Election Process Results</small>
</div>
<div class="col-md-4 text-md-end">
<h4 class="mb-0 fw-bold">
<i class="fa fa-clock me-2"/>
ម៉ោង: <t t-esc="current_dt.strftime('%H:%M')"/>
</h4>
<small>ថ្ងៃ: <t t-esc="current_dt.strftime('%d/%m/%Y')"/></small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ✅ UPDATED FILTERS SECTION -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<form method="get" action="/my/cpp_entries/dashboard" class="row g-2">
<!-- 1. Province Filter -->
<div class="col-md-2">
<label class="form-label fw-bold small">រាជធានី/ខេត្ដ</label>
<select name="province_id" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="provinces" t-as="prov">
<option t-att-value="prov.id" t-att-selected="sel_province == str(prov.id)">
<t t-esc="prov.location_name"/>
</option>
</t>
</select>
</div>
<!-- 2. District Filter -->
<div class="col-md-2">
<label class="form-label fw-bold small">ស្រុក/ខណ្ឌ</label>
<select name="district_id" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="districts" t-as="dist">
<option t-att-value="dist.id" t-att-selected="sel_district == str(dist.id)">
<t t-esc="dist.location_name"/>
</option>
</t>
</select>
</div>
<!-- 3. Commune Filter -->
<div class="col-md-2">
<label class="form-label fw-bold small">ឃុំ/សង្កាត់</label>
<select name="commune_id" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="communes" t-as="com">
<option t-att-value="com.id" t-att-selected="sel_commune == str(com.id)">
<t t-esc="com.location_name"/>
</option>
</t>
</select>
</div>
<!-- 4. Al Office Filter (Text Input) -->
<div class="col-md-3">
<label class="form-label fw-bold small">ការិយាល័យបោះឆ្នោត</label>
<input type="text" name="al_office" class="form-control form-control-sm"
placeholder="ស្វែងរកការិយាល័យ..."
t-att-value="sel_al_office or ''"/>
</div>
<!-- 5. Company Filter -->
<div class="col-md-2">
<label class="form-label fw-bold small">ក្រុមហ៊ុន</label>
<select name="company_id" class="form-select form-select-sm">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="companies" t-as="comp">
<option t-att-value="comp.id" t-att-selected="sel_company == str(comp.id)">
<t t-esc="comp.name"/>
</option>
</t>
</select>
</div>
<!-- 6. Action Buttons -->
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary btn-sm w-100" title="តម្រង">
<i class="fa fa-filter"/>
</button>
</div>
<!-- Reset Button (Full width below or separate) -->
<div class="col-12 mt-2 text-end">
<a href="/my/cpp_entries/dashboard" class="btn btn-outline-secondary btn-sm">
<i class="fa fa-refresh me-1"/> រីផ្រេស (Reset)
</a>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Overall Statistics Cards -->
<div class="row mb-4">
<div class="col-12">
<h4 class="text-primary mb-3">
<i class="fa fa-chart-pie me-2"/> លទ្ធផលទូទាំងស្រុក
</h4>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-info text-white h-100 shadow-sm">
<div class="card-body text-center">
<h6 class="card-title">ចំនួនអ្នកបោះឆ្នោតសរុប</h6>
<h2 class="display-6 fw-bold"><t t-esc="totals['voters']"/></h2>
<p class="mb-0 small">នាក់</p>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-success text-white h-100 shadow-sm">
<div class="card-body text-center">
<h6 class="card-title">បោះឆ្នោតរួច</h6>
<h2 class="display-6 fw-bold"><t t-esc="totals['voted']"/></h2>
<p class="mb-0 small"><t t-esc="'%.2f' % overall_pct"/>%</p>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-warning text-dark h-100 shadow-sm">
<div class="card-body text-center">
<h6 class="card-title">សមាជិក</h6>
<h3 class="fw-bold"><t t-esc="totals['members_voted']"/> / <t t-esc="totals['members']"/></h3>
<p class="mb-0 small"><t t-esc="'%.2f' % totals.get('members_pct', 0)"/>%</p>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-danger text-white h-100 shadow-sm">
<div class="card-body text-center">
<h6 class="card-title">មិនមែនសមាជិក</h6>
<h3 class="fw-bold"><t t-esc="totals['non_members_voted']"/> / <t t-esc="totals['non_members']"/></h3>
<p class="mb-0 small"><t t-esc="'%.2f' % totals.get('non_members_pct', 0)"/>%</p>
</div>
</div>
</div>
</div>
<!-- Hourly Progress Table -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="fa fa-clock me-2"/> តារាងម៉ោងបោះឆ្នោត</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped mb-0 text-center align-middle">
<thead class="table-light">
<tr>
<th class="text-start ps-3">ឃុំ/សង្កាត់</th>
<th t-foreach="hours" t-as="hour" class="text-center"><t t-esc="hour"/>:00</th>
<th class="text-center bg-warning text-dark">សរុប</th>
<th class="text-center bg-primary text-white">ភាគរយ</th>
</tr>
</thead>
<tbody>
<t t-foreach="commune_data.items()" t-as="commune">
<tr>
<td class="text-start fw-bold ps-3"><t t-esc="commune[0]"/></td>
<t t-foreach="hours" t-as="hour">
<td>
<t t-if="commune[1]['hourly'][hour]['count'] > 0">
<span class="badge bg-success"><t t-esc="commune[1]['hourly'][hour]['count']"/></span>
</t>
<t t-else="">-</t>
</td>
</t>
<td class="fw-bold"><t t-esc="commune[1]['voted']"/> / <t t-esc="commune[1]['total']"/></td>
<td><span class="badge bg-primary"><t t-esc="'%.2f' % commune[1]['pct']"/>%</span></td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Detailed Statistics Table -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0"><i class="fa fa-table me-2"/> តារាងស្ថិតិលម្អិត</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-hover mb-0 text-center align-middle">
<thead class="table-light">
<tr>
<th rowspan="2" class="align-middle">ល.រ</th>
<th rowspan="2" class="align-middle text-start ps-3">ឃុំ/សង្កាត់</th>
<th colspan="3" class="bg-warning bg-opacity-25">សមាជិកគណបក្ស</th>
<th colspan="3" class="bg-danger bg-opacity-25">មិនមែនសមាជិក</th>
<th rowspan="2" class="align-middle">សរុប</th>
<th rowspan="2" class="align-middle">ភាគរយ</th>
</tr>
<tr>
<th>សរុប</th><th>បោះឆ្នោតរួច</th><th>%</th>
<th>សរុប</th><th>បោះឆ្នោតរួច</th><th>%</th>
</tr>
</thead>
<tbody>
<t t-foreach="commune_data.items()" t-as="commune">
<tr>
<td><t t-esc="commune_index + 1"/></td>
<td class="text-start fw-bold ps-3"><t t-esc="commune[0]"/></td>
<td><t t-esc="commune[1]['members']"/></td>
<td class="text-success fw-bold"><t t-esc="commune[1]['members_voted']"/></td>
<td><t t-esc="'%.2f' % commune[1]['members_pct']"/>%</td>
<td><t t-esc="commune[1]['non_members']"/></td>
<td class="text-success fw-bold"><t t-esc="commune[1]['non_members_voted']"/></td>
<td><t t-esc="'%.2f' % commune[1]['non_members_pct']"/>%</td>
<td class="fw-bold"><t t-esc="commune[1]['voted']"/> / <t t-esc="commune[1]['total']"/></td>
<td>
<div class="progress" style="height: 20px;">
<div class="progress-bar bg-success" t-attf-style="width: {{commune[1]['pct']}}%">
<t t-esc="'%.1f' % commune[1]['pct']"/>%
</div>
</div>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Footer Info -->
<div class="row">
<div class="col-12">
<div class="alert alert-light border text-center small">
<i class="fa fa-info-circle text-primary me-1"/>
ទិន្នន័យនឹងធ្វើបចចុប្បន្នភាពដោយស្វ័យប្រវត្តិរងរាល់ ១ ម៉ោងម្តង |
ព័ត៌មានចុងក្រោយ: <t t-esc="current_dt.strftime('%d/%m/%Y %H:%M:%S')"/>
</div>
</div>
</div>
</div>
</t>
</template>
</odoo>
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="id_party_views" model="ir.ui.view">
<field name="name">Party View</field>
<field name="model">person.member</field>
<field name="arch" type="xml">
<list editable="bottom">
<field name="name"/>
<field name="short_name"/>
</list>
</field>
</record>
<record model="ir.actions.act_window" id="party_name_action">
<field name="name">ឈ្មោះគណបក្ស</field>
<field name="res_model">person.member</field>
<field name="view_mode">list</field>
</record>
<menuitem name="Party Name" id="party_name_menu" action="party_name_action" parent="youth_and_scholarship.cpp_setting"/>
</odoo>
+193
View File
@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="party_list" name="Party Voter Statistics">
<t t-call="portal.portal_layout">
<div class="container-fluid mt-4">
<!-- Auto-refresh -->
<meta http-equiv="refresh" content="3600"/>
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card bg-primary text-white shadow-sm">
<div class="card-body py-3">
<div class="row align-items-center">
<div class="col-md-8">
<h3 class="mb-0 fw-bold">
<i class="fa fa-users me-2"/>
ទម្រង់បញ្ជីតាមការវិភាគលើគណបក្សនយោបាយ
</h3>
<small>(មានប្រភេទសមាជិកគណបក្សនយោបាយ)</small>
</div>
<div class="col-md-4 text-md-end">
<h4 class="mb-0 fw-bold">
<i class="fa fa-clock me-2"/>
ម៉ោង: <t t-esc="current_dt.strftime('%H:%M')"/>
</h4>
<small>ថ្ងៃ: <t t-esc="current_dt.strftime('%d/%m/%Y')"/></small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<form method="get" action="/my/cpp_entries/party_list" class="row g-3">
<div class="col-md-4">
<label class="form-label fw-bold">ស្រុក/ខណ្ឌ</label>
<select name="district_id" class="form-select" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="districts" t-as="district">
<option t-att-value="district.id" t-att-selected="sel_district == str(district.id)">
<t t-esc="district.location_name"/>
</option>
</t>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">ឃុំ/សង្កាត់</label>
<select name="commune_id" class="form-select" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="communes" t-as="commune">
<option t-att-value="commune.id" t-att-selected="sel_commune == str(commune.id)">
<t t-esc="commune.location_name"/>
</option>
</t>
</select>
</div>
<div class="col-md-4 d-flex align-items-end">
<a href="/my/cpp_entries/party_list" class="btn btn-outline-primary w-100">
<i class="fa fa-refresh me-1"/> រីផ្រេស
</a>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Info Box -->
<div class="alert alert-info mb-4">
<i class="fa fa-info-circle me-2"/>
<strong>ការព្រមាន:</strong> បញ្ជីនេះបង្ហាញពីចំនួនអ្នកបោះឆ្នោតតាមគណបក្សនយោបាយ។
ចុចលើឈ្មោះគណបក្ស ដើម្បីមើលបញ្ជីឈ្មោះអ្នកបោះឆ្នោតនីមួយៗ។
</div>
<!-- Party Statistics Table -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0">
<i class="fa fa-chart-bar me-2"/>
ទម្រង់បញ្ជីលទ្ធផលរាប់សន្លឹកឆ្នោត
</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-hover mb-0">
<thead class="table-light">
<tr>
<th class="text-center" style="width: 10%;">ល.រ.</th>
<th class="text-center" style="width: 60%;">ឈ្មោះគណបក្សនយោបាយ</th>
<th class="text-center" style="width: 15%;">សម្គាល់</th>
<th class="text-center" style="width: 15%;">សកម្មភាព</th>
</tr>
</thead>
<tbody>
<t t-foreach="party_stats.items()" t-as="party">
<tr class="table-hover" style="cursor: pointer;">
<td class="text-center fw-bold"><t t-esc="party_index + 1"/></td>
<td class="fw-bold text-primary">
<a t-attf-href="/my/cpp_entries/party_voters/#{party[0]}"
class="text-decoration-none"
style="color: inherit;">
<i class="fa fa-users me-2"/>
<t t-esc="party[1]['name']"/>
</a>
</td>
<td class="text-center">
<span class="badge bg-primary fs-6">
<t t-esc="party[1]['total']"/> នាក់
</span>
</td>
<td class="text-center">
<a t-attf-href="/my/cpp_entries/party_voters/#{party[0]}"
class="btn btn-sm btn-primary">
<i class="fa fa-eye"/> មើលលម្អិត
</a>
</td>
</tr>
</t>
<tr class="table-primary fw-bold">
<td class="text-center" colspan="2">សរុបទាំងអស់</td>
<td class="text-center">
<span class="badge bg-success fs-6">
<t t-esc="total_voters"/> នាក់
</span>
</td>
<td/>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Summary Cards -->
<div class="row mb-4">
<t t-foreach="party_stats.items()" t-as="party">
<div class="col-md-4 mb-3">
<div class="card h-100 shadow-sm border-primary">
<div class="card-header bg-primary text-white">
<h6 class="mb-0"><t t-esc="party[1]['name']"/></h6>
</div>
<div class="card-body">
<div class="row text-center">
<div class="col-6 mb-2">
<h4 class="text-primary"><t t-esc="party[1]['total']"/></h4>
<small class="text-muted">សរុប</small>
</div>
<div class="col-6 mb-2">
<h4 class="text-success"><t t-esc="party[1]['voted']"/></h4>
<small class="text-muted">បានបោះឆ្នោត</small>
</div>
<div class="col-6">
<small>ប្រុស: <strong><t t-esc="party[1]['male']"/></strong></small>
</div>
<div class="col-6">
<small>ស្រី: <strong><t t-esc="party[1]['female']"/></strong></small>
</div>
</div>
</div>
<div class="card-footer bg-white">
<a t-attf-href="/my/cpp_entries/party_voters/#{party[0]}"
class="btn btn-sm btn-outline-primary w-100">
<i class="fa fa-list me-1"/> មើលបញ្ជី
</a>
</div>
</div>
</div>
</t>
</div>
<!-- Back to Dashboard -->
<div class="row">
<div class="col-12">
<a href="/my/cpp_entries/dashboard" class="btn btn-secondary">
<i class="fa fa-arrow-left me-1"/> ត្រឡប់ទៅ Dashboard
</a>
</div>
</div>
</div>
</t>
</template>
</odoo>
+200
View File
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="party_voters_detail" name="Party Voters Detail">
<t t-call="portal.portal_layout">
<div class="container-fluid mt-4">
<!-- Auto-refresh -->
<meta http-equiv="refresh" content="3600"/>
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card bg-success text-white shadow-sm">
<div class="card-body py-3">
<div class="row align-items-center">
<div class="col-md-8">
<h3 class="mb-0 fw-bold">
<i class="fa fa-users me-2"/>
<t t-esc="party_name"/>
</h3>
<small>បញ្ជី្មោះអនកបោះឆនោត</small>
</div>
<div class="col-md-4 text-md-end">
<h4 class="mb-0 fw-bold">
<i class="fa fa-clock me-2"/>
ម៉ោង: <t t-esc="current_dt.strftime('%H:%M')"/>
</h4>
<small>ថ្ងៃ: <t t-esc="current_dt.strftime('%d/%m/%Y')"/></small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<form method="get" t-attf-action="/my/cpp_entries/party_voters/#{party_key}" class="row g-3">
<div class="col-md-4">
<label class="form-label fw-bold">ស្រុក/ខណ្ឌ</label>
<select name="district_id" class="form-select" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="districts" t-as="district">
<option t-att-value="district.id" t-att-selected="sel_district == str(district.id)">
<t t-esc="district.location_name"/>
</option>
</t>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">ឃុំ/សង្កាត់</label>
<select name="commune_id" class="form-select" onchange="this.form.submit()">
<option value="">-- ទាំងអស់ --</option>
<t t-foreach="communes" t-as="commune">
<option t-att-value="commune.id" t-att-selected="sel_commune == str(commune.id)">
<t t-esc="commune.location_name"/>
</option>
</t>
</select>
</div>
<div class="col-md-4 d-flex align-items-end">
<a t-attf-href="/my/cpp_entries/party_voters/#{party_key}" class="btn btn-outline-primary w-100">
<i class="fa fa-refresh me-1"/> រីផ្រេស
</a>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Statistics Summary -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card bg-primary text-white h-100">
<div class="card-body text-center">
<h5>សរុប</h5>
<h2 class="display-4 fw-bold"><t t-esc="total"/></h2>
<small>នាក់</small>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-success text-white h-100">
<div class="card-body text-center">
<h5>បានបោះឆ្ោត</h5>
<h2 class="display-4 fw-bold"><t t-esc="voted"/></h2>
<small><t t-esc="'%.1f' % (voted/total*100 if total > 0 else 0)"/>%</small>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-info text-white h-100">
<div class="card-body text-center">
<h5>ប្រុស</h5>
<h2 class="display-4 fw-bold"><t t-esc="male"/></h2>
<small>នាក់</small>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card bg-danger text-white h-100">
<div class="card-body text-center">
<h5>ស្រី</h5>
<h2 class="display-4 fw-bold"><t t-esc="female"/></h2>
<small>នាក់</small>
</div>
</div>
</div>
</div>
<!-- Voters List Table -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fa fa-list me-2"/>
បញ្ជីឈ្មោះអ្នកបោះឆ្នោត
</h5>
<span class="badge bg-light text-primary">
<t t-esc="total"/> នាក់
</span>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped mb-0">
<thead class="table-light">
<tr>
<th class="text-center">ល.រ.</th>
<th>ឈ្មោះ</th>
<th class="text-center">ភេទ</th>
<th>ថ្ងៃខែឆ្នាំកំណើត</th>
<th>លេខទូរស័ព្ទ</th>
<th>ឃុំ/សង្កាត់</th>
<th>ស្រុក/ខណ្ឌ</th>
<th class="text-center">ស្ថានភាព</th>
</tr>
</thead>
<tbody>
<t t-foreach="voters_list" t-as="voter">
<tr>
<td class="text-center"><t t-esc="voter_index + 1"/></td>
<td class="fw-bold"><t t-esc="voter['name']"/></td>
<td class="text-center">
<t t-if="voter['gender'] == 'ប្រុស'">
<span class="badge bg-info"><t t-esc="voter['gender']"/></span>
</t>
<t t-else="">
<span class="badge bg-danger"><t t-esc="voter['gender']"/></span>
</t>
</td>
<td><t t-esc="voter['dob'] or '-'"/></td>
<td><t t-esc="voter['phone'] or ' '"/></td>
<td><t t-esc="voter['commune']"/></td>
<td><t t-esc="voter['district']"/></td>
<td class="text-center">
<t t-if="voter['status_vote']">
<span class="badge bg-success">បានបោះឆ្នោត</span>
</t>
<t t-else="">
<span class="badge bg-warning text-dark">មិនទាន់</span>
</t>
</td>
</tr>
</t>
<t t-if="not voters_list">
<tr>
<td colspan="8" class="text-center text-muted py-4">
<i class="fa fa-info-circle me-2"/>
មិនមានទិន្ននយ
</td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Navigation Buttons -->
<div class="row">
<div class="col-12">
<a href="/my/cpp_entries/party_list" class="btn btn-secondary me-2">
<i class="fa fa-arrow-left me-1"/> ត្រឡប់ទៅបញ្ជីគណបក្ស
</a>
<a href="/my/cpp_entries/dashboard" class="btn btn-outline-primary">
<i class="fa fa-chart-line me-1"/> ទៅ Dashboard
</a>
</div>
</div>
</div>
</t>
</template>
</odoo>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Add CPP Entries link to portal home dashboard -->
<template id="portal_my_home_cpp" inherit_id="portal.portal_my_home" name="CPP Entries Link" priority="30">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">CPP Entries</t>
<t t-set="url" t-value="'/my/cpp_entries'"/>
<t t-set="placeholder_count" t-value="'cpp_entries_count'"/>
<t t-set="icon" t-value="'fa fa-list-alt'"/>
</t>
</xpath>
</template>
</odoo>
+434
View File
@@ -0,0 +1,434 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- =======================================================
TEMPLATE: List of CPP Entries
======================================================= -->
<template id="portal_my_cpp_entries" name="My CPP Entries">
<t t-call="portal.portal_layout">
<div class="container mt-4 khmer-text">
<!-- Error Alert -->
<t t-if="error">
<div class="alert alert-danger alert-dismissible fade show">
<i class="fa fa-exclamation-triangle me-2"/>
<strong>Error:</strong> <t t-esc="error"/>
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
</div>
</t>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="fa fa-list-alt me-2"/>បញ្ជី</h2>
<a href="/my/cpp_entries/new" class="btn btn-primary">
<i class="fa fa-plus me-1"/>បង្កើតថ្មី
</a>
</div>
<t t-if="entries">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th>ថ្ងៃបង្កើត</th>
<th>រាជធានី/ខេត្ដ</th>
<th>ស្រុក/ខណ្ឌ</th>
<th>ឃុំ/សង្កាត់</th>
<th>ការិយាល័យបោះឆ្នោត</th>
<th class="text-center">អ្នកបោះឆ្នោត</th>
<th class="text-center">មិនទាន់បោះឆ្នោត</th>
<th class="text-end">សកម្មភាព</th>
</tr>
</thead>
<tbody>
<t t-foreach="entries" t-as="entry">
<tr>
<td><t t-esc="entry.create_date.strftime('%d/%m/%Y') if entry.create_date else '-'"/></td>
<td><t t-esc="entry.province_id.location_name or '-'"/></td>
<td><t t-esc="entry.district_id.location_name or '-'"/></td>
<td><t t-esc="entry.commune_id.location_name or '-'"/></td>
<td><t t-esc="entry.al_office or '-'"/></td>
<td class="text-center"><span class="badge bg-success"><t t-esc="entry.voter_count or 0"/></span></td>
<td class="text-center"><span class="badge bg-warning text-dark"><t t-esc="entry.non_voter_count or 0"/></span></td>
<td class="text-end">
<a t-attf-href="/my/cpp_entries/#{entry.id}" class="btn btn-sm btn-outline-primary">
<i class="fa fa-eye"/> មើល
</a>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
<t t-else="">
<div class="alert alert-info text-center">
<i class="fa fa-info-circle me-2"/>
មិនទាន់មានទិន្នន័យ។ <a href="/my/cpp_entries/new">ចុចទីនេះ</a> ដើម្បីបង្កើតថ្មី។
</div>
</t>
</div>
</t>
</template>
<!-- =======================================================
TEMPLATE: Main CPP Entry Form
======================================================= -->
<template id="portal_cpp_form" name="CPP Entry Form">
<t t-call="portal.portal_layout">
<div class="container mt-4 o_portal_cpp_form">
<!-- Error Alert -->
<t t-if="error">
<div class="alert alert-danger alert-dismissible fade show">
<i class="fa fa-exclamation-triangle me-2"/>
<strong>Error:</strong> <t t-esc="error"/>
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
</div>
</t>
<h2 class="mb-4 text-primary">
<i class="fa fa-edit me-2"/>
<t t-if="entry.id">កែបញ្ជីឈ្មោះ</t>
<t t-else="">បង្កើតបញ្ជីឈ្មោះថ្មី</t>
</h2>
<form t-attf-action="/my/cpp_entries/submit" method="post" class="bg-white p-4 rounded shadow-sm border">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="entry_id" t-att-value="entry.id or 0"/>
<!-- Location Section -->
<div class="row mb-4 p-3 bg-light rounded">
<div class="col-12 mb-2"><h5 class="fw-bold text-secondary">📍 ព័ត៌មានទីតាំង</h5></div>
<!-- Province -->
<div class="col-md-4 mb-3">
<label class="form-label fw-bold">រាជធានី/ខេត្ដ <span class="text-danger">*</span></label>
<select name="province_id" class="form-select" required="1" id="province_select">
<option value="">-- ជ្រើសរើសរាជធានី/ខេត្ដ --</option>
<t t-foreach="provinces" t-as="prov">
<option t-att-value="prov.id" t-att-selected="entry.province_id.id == prov.id">
<t t-esc="prov.location_name"/>
</option>
</t>
</select>
</div>
<!-- District -->
<div class="col-md-4 mb-3">
<label class="form-label fw-bold">ស្រុក/ខណ្ឌ</label>
<select name="district_id" class="form-select" id="district_select">
<option value="">-- ជ្រើសរើសស្រុក/ខណ្ឌ --</option>
<t t-if="entry.district_id">
<option t-att-value="entry.district_id.id" selected="selected">
<t t-esc="entry.district_id.location_name"/>
</option>
</t>
</select>
</div>
<!-- Commune -->
<div class="col-md-4 mb-3">
<label class="form-label fw-bold">ឃុំ/សង្កាត់</label>
<select name="commune_id" class="form-select" id="commune_select">
<option value="">-- ជ្រើសរើសឃុំ/សង្កាត់ --</option>
<t t-if="entry.commune_id">
<option t-att-value="entry.commune_id.id" selected="selected">
<t t-esc="entry.commune_id.location_name"/>
</option>
</t>
</select>
</div>
<div class="col-md-4 mb-3">
<label class="form-label fw-bold">លេខការិយាល័យ</label>
<input name="al_office" class="form-control form-control-lg" placeholder="លេខការិយាល័យ" t-att-value="entry.al_office or ''"/>
</div>
</div>
<!-- ✅ CONDITIONAL: Only show tables/buttons IF Entry is Saved -->
<t t-if="entry.id">
<!-- Table 1: Non-Voters List (Pink/Red) -->
<div class="card mb-4 border-danger">
<div class="card-header bg-danger text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0">📋 បញ្ជីឈ្មោះអ្នកមិនទាន់បោះឆ្នោត</h5>
<span class="badge bg-light text-danger fs-6">
<t t-esc="len(entry.info_ids.filtered(lambda r: not r.status_vote))"/> នាក់
</span>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped mb-0 align-middle">
<thead class="table-light">
<tr>
<th style="width:5%" class="text-center">ល.រ.</th>
<th style="width:8%">ភេទ</th>
<th style="width:20%">ឈ្មោះ</th>
<th style="width:12%">ថ្ងៃកំណើត</th>
<th style="width:25%">អាសយដ្ឋាន</th>
<!-- <th style="width:10%" class="text-center">ទូរសព្ទ</th>-->
<th style="width:10%" class="text-center">ជាសមាជិក</th>
<th style="width:12%" class="text-center">ស្ថានភាព</th>
<th style="width:12%" class="text-center">សកម្មភាព</th>
<th style="width:8%" class="text-center">រូប</th>
</tr>
</thead>
<tbody>
<t t-if="entry.info_ids.filtered(lambda r: not r.status_vote)">
<t t-foreach="entry.info_ids.filtered(lambda r: not r.status_vote)" t-as="voter">
<tr>
<td class="text-center fw-bold"><t t-esc="voter_index + 1"/></td>
<td>
<span t-if="voter.gender" t-attf-class="badge bg-#{'info' if voter.gender.name == 'ប្រុស' else 'danger'}">
<t t-esc="voter.gender.name or '-'"/>
</span>
<span t-else="" class="text-muted">-</span>
</td>
<td class="fw-medium"><t t-esc="voter.name or ''"/></td>
<td><t t-esc="voter.dob or '-'"/></td>
<td><t t-esc="voter.address or '-'"/></td>
<!-- <td class="text-center"><t t-esc="voter.phone or '-'"/></td>-->
<td><t t-esc="voter.cpp_member or '-'"/> </td>
<td class="text-center">
<span class="badge bg-warning text-dark">មិនទាន់បោះឆ្នោត</span>
</td>
<td class="text-center">
<!-- ✅ TOGGLE BUTTON: Mark as Voted -->
<a t-attf-href="/my/cpp_entries/voter/#{voter.id}/toggle_vote?csrf_token=#{request.csrf_token()}"
class="btn btn-sm btn-success py-0 me-1"
title="កំណត់ថាបានបោះឆ្នោត">
<i class="fa fa-check"/> បានបោះរួច
</a>
<a t-attf-href="/my/cpp_entries/voter/#{voter.id}/edit" class="btn btn-sm btn-outline-primary py-0 me-1"><i class="fa fa-pencil"/></a>
<!-- <a t-attf-href="/my/cpp_entries/voter/#{voter.id}/delete?csrf_token=#{request.csrf_token()}" class="btn btn-sm btn-outline-danger py-0" onclick="return confirm('តើអ្នកពិតជាចង់លុកឈ្មោះនេះមែនទេ?');"><i class="fa fa-trash"/></a>-->
</td>
<td class="text-center">
<t t-if="voter.photo">
<img t-att-src="image_data_uri(voter.photo)" class="rounded" style="width:40px;height:40px;object-fit:cover;" alt="Photo"/>
</t>
<t t-else=""><span class="text-muted small"></span></t>
</td>
</tr>
</t>
</t>
<t t-else="">
<tr><td colspan="9" class="text-center text-muted py-4"><i class="fa fa-info-circle me-1"/> មិនទាន់មានទិន្នន័យ</td></tr>
</t>
</tbody>
</table>
</div>
</div>
<div class="card-footer bg-white">
<a t-attf-href="/my/cpp_entries/voter/new?entry_id=#{entry.id}&amp;status_vote=0" class="btn btn-success btn-sm">
<i class="fa fa-plus me-1"/> បន្ថែមអ្នកមិនទាន់បោះឆ្នោត
</a>
</div>
</div>
<!-- Table 2: Voters List (Green) -->
<div class="card mb-4 border-success">
<div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0">✅ បញ្ជីឈ្មោះអនកបានបោះឆ្នោត</h5>
<span class="badge bg-light text-success fs-6">
<t t-esc="len(entry.info_ids.filtered(lambda r: r.status_vote))"/> នាក់
</span>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-bordered table-striped mb-0 align-middle">
<thead class="table-light">
<tr>
<th style="width:5%" class="text-center">ល.រ.</th>
<th style="width:8%">ភេទ</th>
<th style="width:20%">ឈ្មោះ</th>
<th style="width:12%">ថ្ងៃកំណើត</th>
<th style="width:25%">អាសយដ្ឋាន</th>
<!-- <th style="width:10%" class="text-center">ទូរស័ព្ទ</th>-->
<th style="width:12%" class="text-center">ស្ថានភាព</th>
<th style="width:12%" class="text-center">សកម្មភាព</th>
<th style="width:8%" class="text-center">រូប</th>
</tr>
</thead>
<tbody>
<t t-if="entry.info_ids.filtered(lambda r: r.status_vote)">
<t t-foreach="entry.info_ids.filtered(lambda r: r.status_vote)" t-as="voter">
<tr>
<td class="text-center fw-bold"><t t-esc="voter_index + 1"/></td>
<td>
<span t-if="voter.gender" t-attf-class="badge bg-#{'info' if voter.gender.name == 'ប្រុស' else 'danger'}">
<t t-esc="voter.gender.name or '-'"/>
</span>
<span t-else="" class="text-muted">-</span>
</td>
<td class="fw-medium"><t t-esc="voter.name or ''"/></td>
<td><t t-esc="voter.dob or '-'"/></td>
<td><t t-esc="voter.address or '-'"/></td>
<!-- <td class="text-center"><t t-esc="voter.phone or '-'"/></td>-->
<td class="text-center">
<span class="badge bg-success">បោះឆ្នោតរួច</span>
</td>
<td class="text-center">
<!-- ✅ TOGGLE BUTTON: Mark as Not Voted -->
<a t-attf-href="/my/cpp_entries/voter/#{voter.id}/toggle_vote?csrf_token=#{request.csrf_token()}"
class="btn btn-sm btn-warning py-0 me-1"
title="កំណត់ថាមិនទាន់បោះឆ្នោត">
<i class="fa fa-undo"/> មិនទាន់បោះឆ្នោត
</a>
<a t-attf-href="/my/cpp_entries/voter/#{voter.id}/edit" class="btn btn-sm btn-outline-primary py-0 me-1"><i class="fa fa-pencil"/></a>
<a t-attf-href="/my/cpp_entries/voter/#{voter.id}/delete?csrf_token=#{request.csrf_token()}" class="btn btn-sm btn-outline-danger py-0" onclick="return confirm('តើអ្នកពិតជាចង់លុកឈ្មោះនេះមែនទេ?');"><i class="fa fa-trash"/></a>
</td>
<td class="text-center">
<t t-if="voter.photo">
<img t-att-src="image_data_uri(voter.photo)" class="rounded" style="width:40px;height:40px;object-fit:cover;" alt="Photo"/>
</t>
<t t-else=""><span class="text-muted small"></span></t>
</td>
</tr>
</t>
</t>
<t t-else="">
<tr><td colspan="9" class="text-center text-muted py-4"><i class="fa fa-info-circle me-1"/> មិនទាន់មានទិន្នន័យ</td></tr>
</t>
</tbody>
</table>
</div>
</div>
<!-- <div class="card-footer bg-white">-->
<!-- <a t-attf-href="/my/cpp_entries/voter/new?entry_id=#{entry.id}&amp;status_vote=1" class="btn btn-success btn-sm">-->
<!-- <i class="fa fa-plus me-1"/> បន្ថែមអ្នកបានបោះឆ្នោត-->
<!-- </a>-->
<!-- </div>-->
</div>
</t>
<t t-else="">
<!-- ✅ Info Message if entry is NOT saved yet -->
<div class="alert alert-info">
<i class="fa fa-info-circle me-2"/>
<strong>ចំណាំ:</strong> សូមចុច <b>"រក្សាទុក"</b> ដើម្បីបង្កើតបញ្ជីជាមុនសិន ទើបអាចបន្ថែមអ្នកបោះឆ្នោតបាន។
</div>
</t>
<!-- Action Buttons -->
<div class="d-flex justify-content-between mt-4 pt-3 border-top">
<a href="/my/cpp_entries" class="btn btn-outline-secondary px-4">
<i class="fa fa-arrow-left me-1"/> ត្រប់
</a>
<div>
<button type="submit" class="btn btn-primary px-5">
<i class="fa fa-save me-1"/> រក្សាទុកព័ត៌មាន
</button>
</div>
</div>
</form>
</div>
</t>
</template>
<!-- =======================================================
TEMPLATE: Voter Add/Edit Form
======================================================= -->
<template id="portal_voter_form" name="Voter Information Form">
<t t-call="portal.portal_layout">
<div class="container mt-4" style="max-width: 750px;">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/my">ផ្ទាំងគ្រប់គ្រង</a></li>
<li class="breadcrumb-item"><a href="/my/cpp_entries">CPP Entries</a></li>
<li class="breadcrumb-item"><a t-attf-href="/my/cpp_entries/#{entry.id}">បញ្ជី</a></li>
<li class="breadcrumb-item active">
<t t-if="voter.id">កែព័ត៌មាន</t>
<t t-else="">បន្ថែមថ្មី</t>
</li>
</ol>
</nav>
<div class="card shadow-sm border-0">
<div class="card-header bg-primary text-white">
<h4 class="mb-0"><i class="fa fa-user me-2"/>
<t t-if="voter.id">កែព័ត៌មានអ្នកបោះឆ្នោត</t>
<t t-else="">បន្ថែមអ្នកបោះឆ្នោតថ្មី</t>
</h4>
</div>
<form t-attf-action="/my/cpp_entries/voter/submit" method="post" enctype="multipart/form-data" class="card-body">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<!-- ✅ Hidden Fields for ID tracking -->
<input type="hidden" name="entry_id" t-att-value="entry.id"/>
<input type="hidden" name="voter_id" t-att-value="voter.id or 0"/>
<!-- Photo Upload Section -->
<div class="photo-upload-container text-center mb-4">
<div class="position-relative d-inline-block">
<!-- ✅ Show existing photo if available -->
<t t-if="voter.photo">
<img t-att-src="image_data_uri(voter.photo)"
id="photo_preview"
class="rounded-circle border border-3 border-light shadow"
style="width:120px;height:120px;object-fit:cover;display:block;"
alt="Profile Photo"/>
</t>
<!-- ✅ Show placeholder if no photo -->
<t t-else="">
<div class="photo-placeholder rounded-circle bg-light d-flex align-items-center justify-content-center border border-3 border-light shadow"
style="width:120px;height:120px;">
<i class="fa fa-user fa-3x text-muted"/>
</div>
</t>
<!-- ✅ Camera button with file input -->
<label for="photo_upload"
class="position-absolute bottom-0 end-0 btn btn-sm btn-primary rounded-circle shadow"
style="width:36px;height:36px;padding:0;line-height:36px;text-align:center;cursor:pointer;z-index:10;">
<i class="fa fa-camera" style="font-size:14px;"/>
<input type="file"
name="photo"
id="photo_upload"
class="d-none"
accept="image/*"/>
</label>
</div>
<small class="text-muted d-block mt-2">រូបថត (JPEG, PNG - អតិបរមា 2MB)</small>
</div>
<!-- Personal Info -->
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">ឈ្មោះ <span class="text-danger">*</span></label>
<input type="text" name="name" class="form-control form-control-lg" required="1" placeholder="បញ្ចូល្មោះពេញ" t-att-value="voter.name or ''"/>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">ភេទ</label>
<select name="gender" class="form-select form-select-lg">
<option value="">-- ជ្រើសរើសភេទ --</option>
<t t-foreach="genders" t-as="g">
<option t-att-value="g.id" t-att-selected="voter.gender.id == g.id"><t t-esc="g.name"/></option>
</t>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">ថ្ងៃខែឆ្នាំកំណើត</label>
<input type="date" name="dob" class="form-control form-control-lg" t-att-value="voter.dob"/>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">លេខទូរស័ព្ទ</label>
<input type="tel" name="phone" class="form-control form-control-lg" placeholder="012 345 678" t-att-value="voter.phone or ''"/>
</div>
<div class="col-12 mb-3">
<label class="form-label fw-bold">អាសយដ្ឋាន</label>
<textarea name="address" class="form-control" rows="3" placeholder="បញ្ចូលអាសយដ្ឋានពេញ" t-esc="voter.address or ''"/>
</div>
<div class="col-12 mb-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="status_vote" id="status_vote" t-att-checked="'checked' if status_vote == 1 else None"/>
<label class="form-check-label fw-bold" for="status_vote">✅ បោះឆ្នោតរួច</label>
</div>
</div>
</div>
<div class="d-flex justify-content-between mt-4 pt-3 border-top">
<a t-attf-href="/my/cpp_entries/#{entry.id}" class="btn btn-outline-secondary px-4"><i class="fa fa-times me-1"/> បោះបង់</a>
<button type="submit" class="btn btn-primary px-5">
<i class="fa fa-save me-1"/> <t t-if="voter.id">កែប្រែ</t><t t-else="">បន្ថែម</t>
</button>
</div>
</form>
</div>
</div>
</t>
</template>
</odoo>