[IMP] hr_expense: Add dashboard for My Expenses
closes odoo/odoo#45659 Taskid: 2198487 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -46,6 +46,7 @@ This module also uses analytic accounting and is compatible with the invoice on
|
||||
'demo': ['data/hr_expense_demo.xml'],
|
||||
'qweb': [
|
||||
"static/src/xml/documents_upload_views.xml",
|
||||
"static/src/xml/expense_dashboard.xml",
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
@@ -504,6 +504,37 @@ class HrExpense(models.Model):
|
||||
self.sheet_id.message_post_with_view('hr_expense.hr_expense_template_refuse_reason',
|
||||
values={'reason': reason, 'is_sheet': False, 'name': self.name})
|
||||
|
||||
@api.model
|
||||
def get_expense_dashbord(self):
|
||||
if not self.env.user.employee_ids:
|
||||
return
|
||||
expenses = self.read_group(
|
||||
[
|
||||
('employee_id', 'in', self.env.user.employee_ids.ids),
|
||||
('payment_mode', '=', 'own_account'),
|
||||
('state', 'in', ['draft', 'reported', 'approved'])
|
||||
], ['total_amount', 'currency_id', 'state'], ['state', 'currency_id'], lazy=False)
|
||||
expense_state = {
|
||||
'draft': {
|
||||
'description': _('to report'),
|
||||
'amount': list(),
|
||||
},
|
||||
'reported': {
|
||||
'description': _('under validation'),
|
||||
'amount': list(),
|
||||
},
|
||||
'approved': {
|
||||
'description': _('to be reimbursed'),
|
||||
'amount': list(),
|
||||
}
|
||||
}
|
||||
for expense in expenses:
|
||||
state = expense['state']
|
||||
currency = expense['currency_id'][0]
|
||||
amount = expense['total_amount']
|
||||
expense_state[state]['amount'].append((currency, amount))
|
||||
return expense_state
|
||||
|
||||
# ----------------------------------------
|
||||
# Mail Thread
|
||||
# ----------------------------------------
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
odoo.define('hr_expense.expenses.tree', function (require) {
|
||||
"use strict";
|
||||
var DocumentUploadMixin = require('hr_expense.documents.upload.mixin');
|
||||
var KanbanController = require('web.KanbanController');
|
||||
var KanbanView = require('web.KanbanView');
|
||||
var ListController = require('web.ListController');
|
||||
var ListView = require('web.ListView');
|
||||
var viewRegistry = require('web.view_registry');
|
||||
|
||||
var ExpensesListController = ListController.extend(DocumentUploadMixin, {
|
||||
buttons_template: 'ExpensesListView.buttons',
|
||||
events: _.extend({}, ListController.prototype.events, {
|
||||
'click .o_button_upload_expense': '_onUpload',
|
||||
'change .o_expense_documents_upload .o_form_binary_form': '_onAddAttachment',
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesListView = ListView.extend({
|
||||
config: _.extend({}, ListView.prototype.config, {
|
||||
Controller: ExpensesListController,
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesKanbanController = KanbanController.extend(DocumentUploadMixin, {
|
||||
buttons_template: 'ExpensesKanbanView.buttons',
|
||||
events: _.extend({}, KanbanController.prototype.events, {
|
||||
'click .o_button_upload_expense': '_onUpload',
|
||||
'change .o_expense_documents_upload .o_form_binary_form': '_onAddAttachment',
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesKanbanView = KanbanView.extend({
|
||||
config: _.extend({}, KanbanView.prototype.config, {
|
||||
Controller: ExpensesKanbanController,
|
||||
}),
|
||||
});
|
||||
|
||||
viewRegistry.add('hr_expense_tree', ExpensesListView);
|
||||
viewRegistry.add('hr_expense_kanban', ExpensesKanbanView);
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
odoo.define('hr_expense.expenses.tree', function (require) {
|
||||
"use strict";
|
||||
var DocumentUploadMixin = require('hr_expense.documents.upload.mixin');
|
||||
var KanbanController = require('web.KanbanController');
|
||||
var KanbanView = require('web.KanbanView');
|
||||
var ListController = require('web.ListController');
|
||||
var ListView = require('web.ListView');
|
||||
var viewRegistry = require('web.view_registry');
|
||||
var core = require('web.core');
|
||||
var ListRenderer = require('web.ListRenderer');
|
||||
var session = require('web.session');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var ExpensesListController = ListController.extend(DocumentUploadMixin, {
|
||||
buttons_template: 'ExpensesListView.buttons',
|
||||
events: _.extend({}, ListController.prototype.events, {
|
||||
'click .o_button_upload_expense': '_onUpload',
|
||||
'change .o_expense_documents_upload .o_form_binary_form': '_onAddAttachment',
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpenseListRenderer = ListRenderer.extend({
|
||||
_render: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
return self._rpc({
|
||||
model: 'hr.expense',
|
||||
method: 'get_expense_dashbord',
|
||||
context: self.context,
|
||||
});
|
||||
}).then(function (result) {
|
||||
self.$el.parent().find('.o_expense_container').remove();
|
||||
var elem = QWeb.render('hr_expense.dashboard_list_header', {
|
||||
expenses: result,
|
||||
render_monetary_field: self.render_monetary_field,
|
||||
});
|
||||
self.$el.before(elem);
|
||||
});
|
||||
},
|
||||
render_monetary_field: function (value, currency_id) {
|
||||
value = value.toFixed(2);
|
||||
var currency = session.get_currency(currency_id);
|
||||
if (currency) {
|
||||
if (currency.position === "after") {
|
||||
value += currency.symbol;
|
||||
} else {
|
||||
value = currency.symbol + value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
var ExpensesListViewDashboardUpload = ListView.extend({
|
||||
config: _.extend({}, ListView.prototype.config, {
|
||||
Renderer: ExpenseListRenderer,
|
||||
Controller: ExpensesListController,
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesListViewDashboard = ListView.extend({
|
||||
config: _.extend({}, ListView.prototype.config, {
|
||||
Renderer: ExpenseListRenderer,
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesKanbanController = KanbanController.extend(DocumentUploadMixin, {
|
||||
buttons_template: 'ExpensesKanbanView.buttons',
|
||||
events: _.extend({}, KanbanController.prototype.events, {
|
||||
'click .o_button_upload_expense': '_onUpload',
|
||||
'change .o_expense_documents_upload .o_form_binary_form': '_onAddAttachment',
|
||||
}),
|
||||
});
|
||||
|
||||
var ExpensesKanbanView = KanbanView.extend({
|
||||
config: _.extend({}, KanbanView.prototype.config, {
|
||||
Controller: ExpensesKanbanController,
|
||||
}),
|
||||
});
|
||||
|
||||
viewRegistry.add('hr_expense_tree_dashboard_upload', ExpensesListViewDashboardUpload);
|
||||
viewRegistry.add('hr_expense_tree_dashboard', ExpensesListViewDashboard);
|
||||
viewRegistry.add('hr_expense_kanban', ExpensesKanbanView);
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
.o_content {
|
||||
.o_expense_card {
|
||||
border-bottom: 1px solid darken($o-control-panel-background-color, 20%);
|
||||
border-right: 1px solid darken($o-control-panel-background-color, 20%);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
.content_center {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
div {
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.o_expense_card_last {
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
.o_expense_purple {
|
||||
color: $o-enterprise-color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates id="template">
|
||||
<t t-name="hr_expense.dashboard_list_header">
|
||||
<div class="o_expense_container d-flex">
|
||||
<div t-foreach="expenses" t-as="expense" t-attf-class="o_expense_card flex-grow-1 d-flex flex-column {{ expense_last ? 'o_expense_card_last' : '' }}">
|
||||
<div class="content_center">
|
||||
<div t-foreach="expenses[expense]['amount']" t-as="amount_currency">
|
||||
<span t-esc="render_monetary_field(amount_currency[1], amount_currency[0])" class="h2 o_expense_purple"/>
|
||||
<div t-if="! amount_currency_last" class="mb-1">+</div>
|
||||
</div>
|
||||
<div t-if="expenses[expense]['amount'].length === 0">
|
||||
<span t-esc="render_monetary_field(0, False)" class="h2 o_expense_purple"/>
|
||||
</div>
|
||||
<b class="m-2"><span t-esc="expenses[expense]['description']"/></b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -3,9 +3,12 @@
|
||||
<data>
|
||||
<template id="assets_backend" name="HR Expense Assets assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/hr_expense/static/src/js/documents_upload.js"/>
|
||||
<script type="text/javascript" src="/hr_expense/static/src/js/expense_views.js"/>
|
||||
<script type="text/javascript" src="/hr_expense/static/src/js/upload_mixin.js"/>
|
||||
</xpath>
|
||||
<xpath expr="link[last()]" position="after">
|
||||
<link rel="stylesheet" type="text/scss" href="/hr_expense/static/src/scss/hr_expense.scss"/>
|
||||
</xpath>
|
||||
</template>
|
||||
<template id="assets_tests" name="HR Expense Assets Tests" inherit_id="web.assets_tests">
|
||||
<xpath expr="." position="inside">
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<field name="name">hr.expense.tree</field>
|
||||
<field name="model">hr.expense</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Expenses" decoration-bf="message_unread == True" class="o_expense_tree" js_class="hr_expense_tree" decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" multi_edit="1">
|
||||
<tree string="Expenses" decoration-bf="message_unread == True" class="o_expense_tree" js_class="hr_expense_tree_dashboard_upload" decoration-info="state == 'draft'" decoration-muted="state == 'cancel'" multi_edit="1">
|
||||
<field name="attachment_number" invisible="True"/>
|
||||
<field name="date" optional="show"/>
|
||||
<field name="name"/>
|
||||
@@ -475,6 +475,18 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_expense_sheet_dashboard_tree" model="ir.ui.view">
|
||||
<field name="name">hr.expense.sheet.dashboard.tree</field>
|
||||
<field name="model">hr.expense.sheet</field>
|
||||
<field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_tree"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="attributes">
|
||||
<attribute name="js_class">hr_expense_tree_dashboard</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_hr_expense_sheet_form" model="ir.ui.view">
|
||||
<field name="name">hr.expense.sheet.form</field>
|
||||
<field name="model">hr.expense.sheet</field>
|
||||
@@ -702,6 +714,7 @@
|
||||
<field name="search_view_id" ref="hr_expense_sheet_view_search"/>
|
||||
<field name="domain">[('employee_id.user_id', '=', uid), ('state', '!=', 'cancel')]</field>
|
||||
<field name="context">{'search_default_my_reports': 1}</field>
|
||||
<field name="view_id" ref="view_hr_expense_sheet_dashboard_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new expense report
|
||||
@@ -718,6 +731,7 @@
|
||||
<field name="search_view_id" ref="hr_expense_sheet_view_search"/>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'search_default_submitted': 1}</field>
|
||||
<field name="view_id" ref="view_hr_expense_sheet_tree"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_empty_folder">
|
||||
No expense reports to approve
|
||||
|
||||
Reference in New Issue
Block a user