feat: add history view for recent expense submissions to kiosk dashboard
This commit is contained in:
parent
a981456e93
commit
07b70336c6
@ -79,6 +79,37 @@ 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 expenses for the employee. """
|
||||||
|
if not self._check_token(token):
|
||||||
|
return []
|
||||||
|
|
||||||
|
expenses = request.env['hr.expense'].sudo().search([
|
||||||
|
('employee_id', '=', employee_id),
|
||||||
|
('state', 'not in', ['draft', 'refused'])
|
||||||
|
], order='date desc, id desc', limit=15)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
state_selection = dict(request.env['hr.expense']._fields['state']._description_selection(request.env))
|
||||||
|
# Get payment state labels from account.move if possible
|
||||||
|
payment_selection = dict(request.env['account.move']._fields['payment_state']._description_selection(request.env))
|
||||||
|
|
||||||
|
for exp in expenses:
|
||||||
|
payment_state = exp.account_move_id.payment_state if exp.account_move_id else 'not_paid'
|
||||||
|
result.append({
|
||||||
|
'id': exp.id,
|
||||||
|
'name': exp.name,
|
||||||
|
'sequences': exp.sequence_name or '',
|
||||||
|
'date': exp.date.strftime('%Y-%m-%d') if exp.date else '',
|
||||||
|
'total_amount': exp.currency_id.symbol + " " + "{:,.2f}".format(exp.total_amount),
|
||||||
|
'state': state_selection.get(exp.state),
|
||||||
|
'state_raw': exp.state,
|
||||||
|
'payment_status': payment_selection.get(payment_state, _("Not Paid")),
|
||||||
|
'payment_state_raw': 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. """
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -79,6 +79,45 @@
|
|||||||
<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>
|
||||||
|
|
||||||
|
<!-- Recent Submissions List -->
|
||||||
|
<div class="mt-5 w-100 px-3" t-if="state.submittedExpenses.length > 0">
|
||||||
|
<h4 class="mb-3 text-start"><i class="fa fa-history me-2"></i>Your Recent Submissions</h4>
|
||||||
|
<div class="table-responsive rounded shadow-sm bg-white">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th class="ps-3">Reference / Description</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th class="text-end">Total</th>
|
||||||
|
<th class="text-center">Status</th>
|
||||||
|
<th class="text-center pe-3">Payment</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-foreach="state.submittedExpenses" t-as="exp" t-key="exp.id">
|
||||||
|
<tr>
|
||||||
|
<td class="ps-3">
|
||||||
|
<div class="fw-bold text-primary" t-esc="exp.sequences"/>
|
||||||
|
<div class="small text-muted" t-esc="exp.name"/>
|
||||||
|
</td>
|
||||||
|
<td t-esc="exp.date"/>
|
||||||
|
<td class="text-end fw-bold" t-esc="exp.total_amount"/>
|
||||||
|
<td class="text-center">
|
||||||
|
<span t-attf-class="badge rounded-pill #{['approved', 'paid', 'posted'].includes(exp.state_raw) ? 'bg-success' : (['submitted', 'reported'].includes(exp.state_raw) ? 'bg-info' : (exp.state_raw === 'refused' ? 'bg-danger' : 'bg-warning'))}" t-esc="exp.state"/>
|
||||||
|
</td>
|
||||||
|
<td class="text-center pe-3">
|
||||||
|
<span t-attf-class="badge rounded-pill #{exp.payment_state_raw === 'paid' ? 'bg-success' : (exp.payment_state_raw === 'in_payment' ? 'bg-info' : (exp.payment_state_raw === 'not_paid' ? 'bg-secondary' : 'bg-warning'))}" t-esc="exp.payment_status"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted small mt-2 text-start">
|
||||||
|
<i class="fa fa-info-circle me-1"></i> Showing your last 15 submissions.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PAYMENT MODE SELECTION -->
|
<!-- PAYMENT MODE SELECTION -->
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user