feat: add functionality to display recent submitted expense reports in the kiosk interface

This commit is contained in:
Suherdy Yacob 2026-04-21 11:25:14 +07:00
parent 8aa595ad32
commit 6fe3b042b9
3 changed files with 82 additions and 0 deletions

View File

@ -79,6 +79,35 @@ class HrExpenseKioskController(http.Controller):
return [] return []
return request.env['hr.expense.realization'].sudo().get_pending_realizations(employee_id) return request.env['hr.expense.realization'].sudo().get_pending_realizations(employee_id)
@http.route('/hr_expense/kiosk_get_submitted/<string:token>', type='json', auth='public')
def get_submitted(self, token, employee_id):
""" Returns submitted expense reports for the employee. """
if not self._check_token(token):
return []
sheets = request.env['hr.expense.sheet'].sudo().search([
('employee_id', '=', employee_id),
('state', 'not in', ['draft', 'cancel'])
], order='create_date desc', limit=10)
result = []
state_selection = dict(request.env['hr.expense.sheet']._fields['state']._description_selection(request.env))
payment_selection = dict(request.env['hr.expense.sheet']._fields['payment_state']._description_selection(request.env))
for sheet in sheets:
result.append({
'id': sheet.id,
'name': sheet.name,
'sequences': sheet.expense_sequences or '',
'date': sheet.create_date.strftime('%Y-%m-%d'),
'total_amount': sheet.currency_id.symbol + " " + "{:,.2f}".format(sheet.total_amount),
'state': state_selection.get(sheet.state),
'state_raw': sheet.state,
'payment_status': payment_selection.get(sheet.payment_state),
'payment_state_raw': sheet.payment_state,
})
return result
@http.route('/hr_expense/kiosk_submit_realization/<string:token>', type='json', auth='public') @http.route('/hr_expense/kiosk_submit_realization/<string:token>', type='json', auth='public')
def submit_realization(self, token, employee_id, expense_id, lines=None): def submit_realization(self, token, employee_id, expense_id, lines=None):
""" Creates a realization report from the kiosk. """ """ Creates a realization report from the kiosk. """

View File

@ -20,6 +20,7 @@ class ExpenseKioskApp extends Component {
selectedCategory: null, selectedCategory: null,
enteredPin: "", enteredPin: "",
pendingRealizations: [], pendingRealizations: [],
submittedExpenses: [],
selectedAction: null, selectedAction: null,
selectedPaymentMode: null, selectedPaymentMode: null,
selectedExpense: null, selectedExpense: null,
@ -88,6 +89,7 @@ class ExpenseKioskApp extends Component {
if (result.status === 'ok') { if (result.status === 'ok') {
await this.loadPendingRealizations(); await this.loadPendingRealizations();
await this.loadSubmittedExpenses();
this.state.screen = 'action_selection'; this.state.screen = 'action_selection';
} else { } else {
this.notification.add(result.message, { type: 'danger' }); this.notification.add(result.message, { type: 'danger' });
@ -102,6 +104,13 @@ class ExpenseKioskApp extends Component {
this.state.pendingRealizations = data; this.state.pendingRealizations = data;
} }
async loadSubmittedExpenses() {
const data = await this.rpc(`/hr_expense/kiosk_get_submitted/${this.token}`, {
employee_id: this.state.selectedEmployee.id,
});
this.state.submittedExpenses = data;
}
// Action Selection // Action Selection
selectAction(action) { selectAction(action) {
this.state.selectedAction = action; this.state.selectedAction = action;
@ -237,6 +246,8 @@ class ExpenseKioskApp extends Component {
if (result.status === 'ok') { if (result.status === 'ok') {
this.state.screen = 'success'; this.state.screen = 'success';
await this.loadPendingRealizations();
await this.loadSubmittedExpenses();
setTimeout(() => { setTimeout(() => {
this.backToSelection(); this.backToSelection();
}, 3000); }, 3000);

View File

@ -79,6 +79,48 @@
<p class="text-muted small">Submit a new reimbursement request</p> <p class="text-muted small">Submit a new reimbursement request</p>
</div> </div>
</div> </div>
<!-- SUBMITTED EXPENSES LIST -->
<div t-if="state.submittedExpenses.length > 0" class="mt-5 w-100 animate-fade-in" style="max-width: 800px;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="m-0 text-dark">Your Recent Submissions</h4>
<span class="badge bg-secondary" t-esc="state.submittedExpenses.length"/>
</div>
<div class="card shadow-sm border-0 overflow-hidden">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">Report Name</th>
<th>Expense Sequences</th>
<th>Date</th>
<th>Total</th>
<th class="text-center">Report Status</th>
<th class="text-center">Payment Status</th>
</tr>
</thead>
<tbody>
<tr t-foreach="state.submittedExpenses" t-as="sheet" t-key="sheet.id">
<td class="ps-4">
<div class="fw-bold" t-esc="sheet.name"/>
</td>
<td>
<small class="text-muted" t-esc="sheet.sequences"/>
</td>
<td class="text-muted" t-esc="sheet.date"/>
<td class="fw-bold text-primary" t-esc="sheet.total_amount"/>
<td class="text-center">
<span t-attf-class="badge rounded-pill #{sheet.state_raw === 'approve' ? 'bg-info' : (sheet.state_raw === 'post' ? 'bg-primary' : (sheet.state_raw === 'done' ? 'bg-success' : (sheet.state_raw === 'cancel' ? 'bg-danger' : 'bg-warning')))}" t-esc="sheet.state"/>
</td>
<td class="text-center">
<span t-attf-class="badge rounded-pill #{sheet.payment_state_raw === 'paid' ? 'bg-success' : (sheet.payment_state_raw === 'in_payment' ? 'bg-info' : (sheet.payment_state_raw === 'not_paid' ? 'bg-secondary' : 'bg-warning'))}" t-esc="sheet.payment_status"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div> </div>
<!-- PAYMENT MODE SELECTION --> <!-- PAYMENT MODE SELECTION -->