summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/hr_expense/__manifest__.py1
-rw-r--r--addons/hr_expense/static/src/js/expense_qr_code_action.js24
-rw-r--r--addons/hr_expense/static/src/js/expense_views.js41
-rw-r--r--addons/hr_expense/static/src/xml/expense_qr_modal_template.xml11
-rw-r--r--addons/hr_expense/views/assets.xml1
-rw-r--r--addons/hr_expense/views/hr_expense_views.xml97
-rw-r--r--addons/hr_expense/views/res_config_settings_views.xml2
-rw-r--r--addons/sale_expense/models/hr_expense.py2
-rw-r--r--addons/sale_expense/models/sale_order.py2
-rw-r--r--addons/sale_expense/views/hr_expense_views.xml4
10 files changed, 152 insertions, 33 deletions
diff --git a/addons/hr_expense/__manifest__.py b/addons/hr_expense/__manifest__.py
index a0b22f423d0..e6690449c94 100644
--- a/addons/hr_expense/__manifest__.py
+++ b/addons/hr_expense/__manifest__.py
@@ -48,6 +48,7 @@ This module also uses analytic accounting and is compatible with the invoice on
'qweb': [
"static/src/xml/documents_upload_views.xml",
"static/src/xml/expense_dashboard.xml",
+ "static/src/xml/expense_qr_modal_template.xml",
],
'installable': True,
'application': True,
diff --git a/addons/hr_expense/static/src/js/expense_qr_code_action.js b/addons/hr_expense/static/src/js/expense_qr_code_action.js
new file mode 100644
index 00000000000..19226545ede
--- /dev/null
+++ b/addons/hr_expense/static/src/js/expense_qr_code_action.js
@@ -0,0 +1,24 @@
+odoo.define('hr_expense.qr_code_action', function (require) {
+"use strict";
+
+const AbstractAction = require('web.AbstractAction');
+const core = require('web.core');
+const config = require('web.config');
+
+const QRModalAction = AbstractAction.extend({
+ template: 'hr_expense_qr_code',
+ xmlDependencies: ['/hr_expense/static/src/xml/expense_qr_modal_template.xml'],
+
+ init: function(parent, action){
+ this._super.apply(this, arguments);
+ const qr_vals = [
+ '002', // Version
+ '1', // Character Set
+ action.params.url, // Download app url
+ ];
+ this.url = _.str.sprintf("/report/barcode/?type=QR&value=%s&width=256&height=256&humanreadable=1", encodeURI(qr_vals.join('\n')));
+ },
+});
+
+core.action_registry.add('expense_qr_code_modal', QRModalAction);
+});
diff --git a/addons/hr_expense/static/src/js/expense_views.js b/addons/hr_expense/static/src/js/expense_views.js
index 5f2b7ad488d..adc9bfdd301 100644
--- a/addons/hr_expense/static/src/js/expense_views.js
+++ b/addons/hr_expense/static/src/js/expense_views.js
@@ -3,13 +3,16 @@ odoo.define('hr_expense.expenses.tree', function (require) {
var DocumentUploadMixin = require('hr_expense.documents.upload.mixin');
var KanbanController = require('web.KanbanController');
var KanbanView = require('web.KanbanView');
+ var PivotView = require('web.PivotView');
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 KanbanRenderer = require('web.KanbanRenderer');
+ var PivotRenderer = require('web.PivotRenderer');
var session = require('web.session');
+ const config = require('web.config');
var QWeb = core.qweb;
@@ -21,6 +24,38 @@ odoo.define('hr_expense.expenses.tree', function (require) {
}),
});
+ const ExpenseQRCodeMixin = {
+ async _renderView() {
+ const self = this;
+ await this._super(...arguments);
+ const google_url = "https://play.google.com/store/apps/details?id=com.odoo.mobile";
+ const apple_url = "https://apps.apple.com/be/app/odoo/id1272543640";
+ const action_desktop = {
+ name: 'Download our App',
+ type: 'ir.actions.client',
+ tag: 'expense_qr_code_modal',
+ params: {'url': "https://apps.apple.com/be/app/odoo/id1272543640"},
+ target: 'new',
+ };
+ this.$el.find('img.o_expense_apple_store').on('click', function(event) {
+ event.preventDefault();
+ if (!config.device.isMobile) {
+ self.do_action(_.extend(action_desktop, {params: {'url': apple_url}}));
+ } else {
+ self.do_action({type: 'ir.actions.act_url', url: apple_url});
+ }
+ });
+ this.$el.find('img.o_expense_google_store').on('click', function(event) {
+ event.preventDefault();
+ if (!config.device.isMobile) {
+ self.do_action(_.extend(action_desktop, {params: {'url': google_url}}));
+ } else {
+ self.do_action({type: 'ir.actions.act_url', url: google_url});
+ }
+ });
+ },
+ };
+
const ExpenseDashboardMixin = {
_render: async function () {
var self = this;
@@ -50,9 +85,9 @@ odoo.define('hr_expense.expenses.tree', function (require) {
}
return value;
}
- }
+ };
- var ExpenseListRenderer = ListRenderer.extend(ExpenseDashboardMixin);
+ var ExpenseListRenderer = ListRenderer.extend(ExpenseDashboardMixin, ExpenseQRCodeMixin);
var ExpensesListViewDashboardUpload = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
@@ -75,7 +110,7 @@ odoo.define('hr_expense.expenses.tree', function (require) {
}),
});
- var ExpenseKanbanRenderer = KanbanRenderer.extend(ExpenseDashboardMixin);
+ var ExpenseKanbanRenderer = KanbanRenderer.extend(ExpenseDashboardMixin, ExpenseQRCodeMixin);
var ExpensesKanbanView = KanbanView.extend({
config: _.extend({}, KanbanView.prototype.config, {
diff --git a/addons/hr_expense/static/src/xml/expense_qr_modal_template.xml b/addons/hr_expense/static/src/xml/expense_qr_modal_template.xml
new file mode 100644
index 00000000000..00a59f418fe
--- /dev/null
+++ b/addons/hr_expense/static/src/xml/expense_qr_modal_template.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates id="template" xml:space="preserve">
+<t t-name="hr_expense_qr_code">
+ <div style="text-align:center;" class="o_expense_modal">
+ <t t-if="widget.url">
+ <h3>Scan this QR code to get the Odoo app:</h3><br/><br/>
+ <img class="border border-dark rounded" t-att-src="widget.url"/>
+ </t>
+ </div>
+</t>
+</templates>
diff --git a/addons/hr_expense/views/assets.xml b/addons/hr_expense/views/assets.xml
index 90c4c0011a9..3cf5e0f6831 100644
--- a/addons/hr_expense/views/assets.xml
+++ b/addons/hr_expense/views/assets.xml
@@ -4,6 +4,7 @@
<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/expense_views.js"/>
+ <script type="text/javascript" src="/hr_expense/static/src/js/expense_qr_code_action.js"/>
<script type="text/javascript" src="/hr_expense/static/src/js/upload_mixin.js"/>
</xpath>
<xpath expr="link[last()]" position="after">
diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml
index 2cae24fbcf9..f681dbe0af2 100644
--- a/addons/hr_expense/views/hr_expense_views.xml
+++ b/addons/hr_expense/views/hr_expense_views.xml
@@ -105,7 +105,7 @@
class="oe_stat_button"
icon="fa-file-text-o"
type="object">
- <field name="attachment_number" widget="statinfo" string="Documents" options="{'reload_on_button': true}"/>
+ <field name="attachment_number" widget="statinfo" string="Receipts" options="{'reload_on_button': true}"/>
</button>
</div>
<div class="oe_title">
@@ -319,7 +319,7 @@
</record>
<record id="hr_expense_actions_my_unsubmitted" model="ir.actions.act_window">
- <field name="name">My Expenses</field>
+ <field name="name">My Expenses to Report</field>
<field name="res_model">hr.expense</field>
<field name="view_mode">tree,kanban,form,graph,pivot,activity</field>
<field name="search_view_id" ref="hr_expense_view_search"/>
@@ -330,12 +330,35 @@
Did you try the mobile app?
</p>
<p>Snap pictures of your receipts and let Odoo<br/> automatically create expenses for you.</p>
- <p class="d-none d-md-block">
+ <p>
<a href="https://apps.apple.com/be/app/odoo/id1272543640" target="_blank">
- <img alt="Apple App Store" class="img img-fluid h-100" src="/hr_expense/static/img/app_store.png"/>
+ <img alt="Apple App Store" class="img img-fluid h-100 o_expense_apple_store" src="/hr_expense/static/img/app_store.png"/>
</a>
- <a href="https://play.google.com/store/apps/details?id=com.odoo.mobile" target="_blank">
- <img alt="Google Play Store" class="img img-fluid h-100" src="/hr_expense/static/img/play_store.png"/>
+ <a href="https://play.google.com/store/apps/details?id=com.odoo.mobile" target="_blank" class="o_expense_google_store">
+ <img alt="Google Play Store" class="img img-fluid h-100 o_expense_google_store" src="/hr_expense/static/img/play_store.png"/>
+ </a>
+ </p>
+ </field>
+ </record>
+
+ <record id="hr_expense_actions_my_all" model="ir.actions.act_window">
+ <field name="name">All My Expenses</field>
+ <field name="res_model">hr.expense</field>
+ <field name="view_mode">tree,kanban,form,graph,pivot,activity</field>
+ <field name="search_view_id" ref="hr_expense_view_search"/>
+ <field name="view_id" ref="view_my_expenses_tree"/>
+ <field name="context">{'search_default_my_expenses': 1}</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_expense_receipt">
+ Did you try the mobile app?
+ </p>
+ <p>Snap pictures of your receipts and let Odoo<br/> automatically create expenses for you.</p>
+ <p>
+ <a href="https://apps.apple.com/be/app/odoo/id1272543640" target="_blank">
+ <img alt="Apple App Store" class="img img-fluid h-100 o_expense_apple_store" src="/hr_expense/static/img/app_store.png"/>
+ </a>
+ <a href="https://play.google.com/store/apps/details?id=com.odoo.mobile" target="_blank" class="o_expense_google_store">
+ <img alt="Google Play Store" class="img img-fluid h-100 o_expense_google_store" src="/hr_expense/static/img/play_store.png"/>
</a>
</p>
</field>
@@ -378,7 +401,7 @@
<group name="product_details">
<group string="General Information">
<field name="active" invisible="1"/>
- <field name="type"/>
+ <field name="type" invisible="1"/>
<field name="list_price"/>
<field name="standard_price"/>
<field name="uom_id" groups="uom.group_uom" options="{'no_create': True}"/>
@@ -426,7 +449,9 @@
<field name="domain">[('can_be_expensed', '=', True)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new expense product
+ No expense products found.
+ </p><p>
+ Let's create one! Expense products can be reinvoiced to your customers.
</p>
</field>
</record>
@@ -455,17 +480,17 @@
<field name="model">hr.expense.sheet</field>
<field name="arch" type="xml">
<tree string="Expense Reports" sample="1">
+ <field name="employee_id" widget="many2one_avatar_employee"/>
<field name="accounting_date" optional="show" groups="account.group_account_manager"/>
<field name="create_date" optional="hide"/>
<field name="name" string="Expense Report"/>
- <field name="employee_id" widget="many2one_avatar_employee"/>
- <field name="user_id" optional="show" widget="many2one_avatar_user"/>
+ <field name="user_id" optional="hide" widget="many2one_avatar_user"/>
<field name="company_id" optional="show" groups="base.group_multi_company"/>
+ <field name="activity_ids" widget="list_activity" optional="show"/>
<field name="total_amount" optional="show" sum="Total Amount" decoration-bf="True"/>
<field name="currency_id" optional="hide"/>
<field name="journal_id" optional="hide"/>
<field name="state" optional="show" decoration-info="state == 'draft'" decoration-success="state in ['submit', 'approve', 'post', 'done']" decoration-danger="state == 'cancel'" widget="badge"/>
- <field name="activity_ids" widget="list_activity" optional="show"/>
<field name="message_unread" invisible="1"/>
</tree>
</field>
@@ -513,6 +538,7 @@
<field name="state" widget="statusbar" statusbar_visible="draft,submit,approve,post,done"/>
</header>
<sheet>
+ <widget name="web_ribbon" title="Paid" bg_color="bg-success" attrs="{'invisible': [('state', '!=', 'done')]}"/>
<div class="oe_button_box" name="button_box">
<button name="action_get_attachment_view"
class="oe_stat_button"
@@ -530,8 +556,8 @@
<group>
<group name="employee_details">
<field name="employee_id" context="{'default_company_id': company_id}" widget="many2one_avatar_employee"/>
- <field name="payment_mode"/>
<field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
+ <field name="payment_mode"/>
<field name="address_id" invisible="1" context="{'default_company_id': company_id}"/>
<field name="department_id" invisible="1" context="{'default_company_id': company_id}"/>
<field name="company_id" groups="base.group_multi_company"/>
@@ -722,7 +748,7 @@
</record>
<record id="action_hr_expense_sheet_my_all" model="ir.actions.act_window">
- <field name="name">My Expense Reports</field>
+ <field name="name">My Reports</field>
<field name="res_model">hr.expense.sheet</field>
<field name="view_mode">tree,kanban,form,pivot,graph,activity</field>
<field name="search_view_id" ref="hr_expense_sheet_view_search"/>
@@ -731,9 +757,9 @@
<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
+ No expense report found.
</p><p>
- Once you have created your expense, submit it to your manager who will validate it.
+ Let's create one! Once you have created your expense, submit it to your manager who will validate it.
</p>
</field>
</record>
@@ -748,7 +774,9 @@
<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
+ No expense reports found.
+ </p><p>
+ Approve the new expense reports submitted by the employees you manage.
</p>
</field>
</record>
@@ -762,9 +790,9 @@
<field name="context">{'search_default_to_post': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new expense report
+ No expense reports found.
</p><p>
- Once you have created your expense, submit it to your manager who will validate it.
+ Post the journal entries of the new expense reports approved by the employees' manager.
</p>
</field>
</record>
@@ -778,9 +806,23 @@
<field name="context">{'search_default_approved': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
- Create a new expense report
+ No expense reports found.
</p><p>
- Once you have created your expense, submit it to your manager who will validate it.
+ Reimburse the employees who incurred these costs or simply register the corresponding payments.
+ </p>
+ </field>
+ </record>
+
+ <record id="action_hr_expense_sheet_all" model="ir.actions.act_window">
+ <field name="name">All Expense Reports</field>
+ <field name="res_model">hr.expense.sheet</field>
+ <field name="view_mode">tree,kanban,form,pivot,graph</field>
+ <field name="search_view_id" ref="hr_expense_sheet_view_search"/>
+ <field name="domain">[]</field>
+ <field name="context">{}</field>
+ <field name="help" type="html">
+ <p class="o_view_nocontent_smiling_face">
+ No expense reports found.
</p>
</field>
</record>
@@ -905,22 +947,27 @@ if records:
<menuitem id="menu_hr_expense_root" name="Expenses" sequence="100" web_icon="hr_expense,static/description/icon.png"/>
<menuitem id="menu_hr_expense_my_expenses" name="My Expenses" sequence="1" parent="menu_hr_expense_root" groups="base.group_user"/>
- <menuitem id="menu_hr_expense_my_expenses_to_submit" sequence="1" parent="menu_hr_expense_my_expenses" action="hr_expense_actions_my_unsubmitted"/>
- <menuitem id="menu_hr_expense_sheet_my_reports" sequence="3" parent="menu_hr_expense_my_expenses" action="action_hr_expense_sheet_my_all"/>
+ <menuitem id="menu_hr_expense_my_expenses_to_submit" sequence="1" parent="menu_hr_expense_my_expenses" action="hr_expense_actions_my_unsubmitted" name="My Expenses to Report"/>
+ <menuitem id="menu_hr_expense_my_expenses_all" sequence="2" parent="menu_hr_expense_my_expenses" action="hr_expense_actions_my_all" name="All My Expenses"/>
+ <menuitem id="menu_hr_expense_sheet_my_reports" sequence="3" parent="menu_hr_expense_my_expenses" action="action_hr_expense_sheet_my_all" name="My Reports"/>
<menuitem id="menu_hr_expense_report" name="Expense Reports" sequence="2" parent="menu_hr_expense_root"/>
<menuitem id="menu_hr_expense_sheet_all_to_approve"
- name="To Approve" sequence="1" parent="menu_hr_expense_report"
+ name="Reports to Approve" sequence="1" parent="menu_hr_expense_report"
action="action_hr_expense_sheet_all_to_approve"
groups="hr_expense.group_hr_expense_team_approver"/>
<menuitem id="menu_hr_expense_sheet_all_to_post"
- name="To Post" sequence="2" parent="menu_hr_expense_report"
+ name="Reports to Post" sequence="2" parent="menu_hr_expense_report"
action="action_hr_expense_sheet_all_to_post"
groups="account.group_account_invoice,hr_expense.group_hr_expense_manager"/>
<menuitem id="menu_hr_expense_sheet_all_to_pay"
- name="To Pay" sequence="3" parent="menu_hr_expense_report"
+ name="Reports to Pay" sequence="3" parent="menu_hr_expense_report"
action="action_hr_expense_sheet_all_to_pay"
groups="account.group_account_invoice,hr_expense.group_hr_expense_manager"/>
+ <menuitem id="menu_hr_expense_sheet_all"
+ name="All Reports" sequence="4" parent="menu_hr_expense_report"
+ action="action_hr_expense_sheet_all"
+ groups="account.group_account_invoice,hr_expense.group_hr_expense_manager"/>
<menuitem id="menu_hr_expense_reports" name="Reporting" sequence="4" parent="menu_hr_expense_root" groups="hr_expense.group_hr_expense_manager"/>
<menuitem id="menu_hr_expense_all_expenses" name="Expenses Analysis" sequence="0" parent="menu_hr_expense_reports" action="hr_expense_actions_all"/>
diff --git a/addons/hr_expense/views/res_config_settings_views.xml b/addons/hr_expense/views/res_config_settings_views.xml
index ee47164eaad..39d4e47bbf2 100644
--- a/addons/hr_expense/views/res_config_settings_views.xml
+++ b/addons/hr_expense/views/res_config_settings_views.xml
@@ -44,7 +44,7 @@
<div class="o_setting_right_pane">
<label for="module_hr_payroll_expense" string="Reimburse in Payslip"/>
<div class="text-muted">
- Expenses can be reimbursed in payslips.
+ Reimburse expenses in payslips
</div>
</div>
</div>
diff --git a/addons/sale_expense/models/hr_expense.py b/addons/sale_expense/models/hr_expense.py
index 8a6d2c0c351..fc88dcbbff1 100644
--- a/addons/sale_expense/models/hr_expense.py
+++ b/addons/sale_expense/models/hr_expense.py
@@ -7,7 +7,7 @@ from odoo import api, fields, models
class Expense(models.Model):
_inherit = "hr.expense"
- sale_order_id = fields.Many2one('sale.order', compute='_compute_sale_order_id', store=True, string='Reinvoice Customer', readonly=False, tracking=True,
+ sale_order_id = fields.Many2one('sale.order', compute='_compute_sale_order_id', store=True, string='Customer to Reinvoice', readonly=False, tracking=True,
states={'approved': [('readonly', True)], 'done': [('readonly', True)], 'refused': [('readonly', True)]},
# NOTE: only confirmed SO can be selected, but this domain in activated throught the name search with the `sale_expense_all_order`
# context key. So, this domain is not the one applied.
diff --git a/addons/sale_expense/models/sale_order.py b/addons/sale_expense/models/sale_order.py
index ccd3c1d1627..fef55214523 100644
--- a/addons/sale_expense/models/sale_order.py
+++ b/addons/sale_expense/models/sale_order.py
@@ -22,7 +22,7 @@ class SaleOrder(models.Model):
@api.depends('expense_ids')
def _compute_expense_count(self):
- expense_data = self.env['hr.expense'].read_group([('sale_order_id', 'in', self.ids), ('state', '=', 'done')], ['sale_order_id'], ['sale_order_id'])
+ expense_data = self.env['hr.expense'].read_group([('sale_order_id', 'in', self.ids)], ['sale_order_id'], ['sale_order_id'])
mapped_data = dict([(item['sale_order_id'][0], item['sale_order_id_count']) for item in expense_data])
for sale_order in self:
sale_order.expense_count = mapped_data.get(sale_order.id, 0)
diff --git a/addons/sale_expense/views/hr_expense_views.xml b/addons/sale_expense/views/hr_expense_views.xml
index 68f442b7455..022c0cf9ac2 100644
--- a/addons/sale_expense/views/hr_expense_views.xml
+++ b/addons/sale_expense/views/hr_expense_views.xml
@@ -18,7 +18,7 @@
<field name="inherit_id" ref="hr_expense.view_expenses_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='reference']" position="after">
- <field name="sale_order_id" optional="show" attrs="{'invisible': [('can_be_reinvoiced', '=', False)]}" options="{'no_create_edit': True, 'no_create': True, 'no_open': True}" context="{'sale_show_partner_name': True, 'sale_expense_all_order': True}" readonly="1"/>
+ <field name="sale_order_id" optional="hide" attrs="{'invisible': [('can_be_reinvoiced', '=', False)]}" options="{'no_create_edit': True, 'no_create': True, 'no_open': True}" context="{'sale_show_partner_name': True, 'sale_expense_all_order': True}" readonly="1"/>
<field name="can_be_reinvoiced" invisible="1" readonly="1"/>
</xpath>
</field>
@@ -64,7 +64,7 @@
<field name="name">Expenses</field>
<field name="res_model">hr.expense</field>
<field name="view_mode">tree,form</field>
- <field name="domain">[('sale_order_id', '=', active_id), ('state', '=', 'done')]</field>
+ <field name="domain">[('sale_order_id', '=', active_id)]</field>
<field name="context">{'default_sale_order_id': active_id}</field>
</record>