[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:
jbm-odoo
2020-02-28 10:36:52 +00:00
parent f348621e0b
commit b2414b118d
8 changed files with 179 additions and 42 deletions
+1
View File
@@ -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,
+31
View File
@@ -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>
+4 -1
View File
@@ -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">
+15 -1
View File
@@ -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