From 50d9f1f7eba3d124a315e8cb30e673a137b3e14b Mon Sep 17 00:00:00 2001
From: Remi <remi@le-filament.com>
Date: Fri, 26 Apr 2019 16:14:39 +0200
Subject: [PATCH] Fix coding according to standards and licenses

---
 LICENSE                                    |  27 -
 __init__.py                                |   3 +-
 __manifest__.py                            |  14 +-
 data/ir_module_category.xml                |   2 +
 models/__init__.py                         |   8 +-
 models/hr_employee.py                      |   7 +-
 models/lefilament_tdb.py                   | 674 +++++++++++++--------
 models/res_company.py                      |  40 +-
 security/lefilament_dashboard_security.xml |   2 +
 static/description/icon_menu.png           | Bin 0 -> 7169 bytes
 static/description/icon_menu.svg           |  23 +
 static/src/js/dashboard_year.js            |   1 -
 static/src/js/tresorerie.js                |   1 -
 static/src/xml/lefilament_tdb.xml          |   2 +
 static/src/xml/lefilament_treso.xml        |   2 +
 views/assets.xml                           |   2 +
 views/schedule.xml                         |   4 +-
 views/views.xml                            |   2 +
 18 files changed, 500 insertions(+), 314 deletions(-)
 create mode 100644 static/description/icon_menu.png
 create mode 100644 static/description/icon_menu.svg

diff --git a/LICENSE b/LICENSE
index 7e5dad2..33aa54e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -201,30 +201,3 @@ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY C
 If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
 
 END OF TERMS AND CONDITIONS
-
-How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
-
-To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Affero General Public License as
-    published by the Free Software Foundation, either version 3 of the
-    License, or (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Affero General Public License for more details.
-
-    You should have received a copy of the GNU Affero General Public License
-    along with this program.  If not, see <https://www.gnu.org/licenses/>.
-Also add information on how to contact you by electronic and paper mail.
-
-If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
-
-You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <https://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/__init__.py b/__init__.py
index 268881c..b44d765 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,3 +1,4 @@
 # -*- coding: utf-8 -*-
-import models
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
 
+from . import models
diff --git a/__manifest__.py b/__manifest__.py
index a575350..52f5bba 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
 {
     'name': "Le Filament - Tableau de Bord",
 
@@ -8,27 +9,26 @@
     'description': """
         Tableaux de Bord Le Filament
 
-        Affichage de tableaux de bord : 
+        Affichage de tableaux de bord :
          - suivi annuel Factures/Commandes/Pipe et Trésorerie
          - tableau des performances mensuelles
          - graphe de la tésorerie sur 1 an glissant
          - prévisionnel de la trésorerie sur 6 mois
-         
+
     """,
     'author': "LE FILAMENT",
     'category': 'dashboard',
-    'website': "http://www.le-filament.com",
-    'version': '10.0.1',
+    'website': "https://le-filament.com",
+    'version': '10.0.1.0.0',
     'license': 'AGPL-3',
-    'depends': ['crm','account','hr_expense'],
+    'depends': ['account', 'crm', 'hr_expense', 'sale'],
     'data': [
         'security/lefilament_dashboard_security.xml',
         'security/ir.model.access.csv',
         'views/assets.xml',
         'views/views.xml',
-        # 'views/account_invoice.xml',
         'views/schedule.xml',
-	    'data/ir_module_category.xml'
+        'data/ir_module_category.xml'
     ],
     'qweb': [
         'static/src/xml/*.xml',
diff --git a/data/ir_module_category.xml b/data/ir_module_category.xml
index c7e4878..f772ab7 100644
--- a/data/ir_module_category.xml
+++ b/data/ir_module_category.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <odoo>
 	<data>
 	  <record model="ir.module.category" id="module_category_dashboard">
diff --git a/models/__init__.py b/models/__init__.py
index 5cc4332..3c98179 100644
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
 
-import lefilament_tdb
-import res_company
-import hr_employee
-# import account_invoice
+from . import lefilament_tdb
+from . import res_company
+from . import hr_employee
diff --git a/models/hr_employee.py b/models/hr_employee.py
index a1075b5..2af3611 100644
--- a/models/hr_employee.py
+++ b/models/hr_employee.py
@@ -5,8 +5,9 @@
 
 from odoo import models, fields
 
+
 class hr_employee(models.Model):
-	_name = "hr.employee"
-	_inherit = "hr.employee"
+    _name = "hr.employee"
+    _inherit = "hr.employee"
 
-	capital = fields.Float( "Apport Capital Social" )
+    capital = fields.Float("Apport Capital Social")
diff --git a/models/lefilament_tdb.py b/models/lefilament_tdb.py
index 9b6c739..b27846b 100644
--- a/models/lefilament_tdb.py
+++ b/models/lefilament_tdb.py
@@ -3,263 +3,433 @@
 # © 2017 Le Filament (<http://www.le-filament.com>)
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
-from datetime import datetime, timedelta
+from datetime import datetime
 from dateutil.relativedelta import relativedelta
 
 from odoo import models, fields, api
-from odoo import tools
 
 from odoo.fields import Date
 
 
 class LeFilamentTdb(models.Model):
-	_name = "lefilament.dashboard"
-	_description = "Le Filament Dashboard"
-	_order = "date_tdb desc"
-
-	name = fields.Char( 'Mois', compute='get_month')
-	date_tdb = fields.Date( 'Date', required=True, default=datetime.today().strftime('%Y-%m-%d'),)
-
-	ca_mois = fields.Float( 'Facturé', compute="dashboard_values", store=True)
-
-	cmd_mois = fields.Float( 'Commandes', compute="dashboard_values", store=True)	
-
-	pipe_mois = fields.Float( 'Pipe', compute="dashboard_values", store=True )
-
-	
-	treso = fields.Float( 'Trésorerie', compute="dashboard_values", store=True )
-	variation = fields.Float( 'Variation', compute="dashboard_values", store=True )
-	charges = fields.Float( 'Décaissé', compute="dashboard_values", store=True )
-	encaisse = fields.Float( 'Encaissé', compute="dashboard_values", store=True )
-	charges_fixes = fields.Float( 'Charges Fixes', default=10000 )
-	runway = fields.Float( 'Runway', compute="runway_value", )
-
-	@api.multi
-	@api.depends('date_tdb')
-	def dashboard_values(self):
-		for record in self:
-			if record.date_tdb :
-				date_tdb = datetime.strptime(record.date_tdb, '%Y-%m-%d')
-				
-				##############    CA    ################
-				# FACTURÉ
-				self.env.cr.execute("select sum(amount_untaxed_signed) from account_invoice where state!='draft' and (type='out_invoice' or type='out_refund') and date >= date_trunc('month', %s) and date < date_trunc('month', %s + interval '1' month);", (date_tdb, date_tdb) )
-				ca_mois = self.env.cr.fetchone()[0]
-
-				##############    COMMANDES    ################
-				# TOTAL
-				self.env.cr.execute("select sum(amount_untaxed) from sale_order where invoice_status='to invoice' and date_order >= date_trunc('month', %s) and date_order < date_trunc('month', %s + interval '1' month);", (date_tdb, date_tdb) )
-				cmd_mois = self.env.cr.fetchone()[0]
-
-				##############    TRESO   ################
-				# Trésorerie
-				self.env.cr.execute("select sum(amount) from account_bank_statement_line where date < date_trunc('month', %s + interval '1' month);", (date_tdb, ) )
-				treso_total = self.env.cr.fetchone()[0]
-				# CHARGES
-				self.env.cr.execute("select sum(amount) from account_bank_statement_line where amount < 0 and date >= date_trunc('month', %s) and date < date_trunc('month', %s + interval '1' month);", (date_tdb, date_tdb) )
-				charges = self.env.cr.fetchone()[0]
-				# ENCAISSE
-				self.env.cr.execute("select sum(amount) from account_bank_statement_line where amount > 0 and date >= date_trunc('month', %s) and date < date_trunc('month', %s + interval '1' month);", (date_tdb, date_tdb) )
-				encaisse = self.env.cr.fetchone()[0]
-
-				##############    CHARGES   ################
-				self.env.cr.execute("select charges_fixes from res_company" )
-				charges_fixes = self.env.cr.fetchone()[0]
-
-				##############    PIPE    ################
-				# TOTAL
-				self.env.cr.execute("select sum(planned_revenue*probability/100) from crm_lead where active=True;")
-				pipe = self.env.cr.fetchone()[0]
-
-				if not encaisse:
-					encaisse = 0
-				if not charges:
-					charges = 0
-
-				record.ca_mois = ca_mois
-				record.cmd_mois = cmd_mois
-				record.treso = treso_total
-				record.charges = charges * (-1.0)
-				record.encaisse = encaisse
-				record.variation = encaisse + charges
-				record.charges_fixes = charges_fixes
-				record.pipe_mois = pipe
-
-
-	@api.multi
-	@api.depends('charges_fixes','treso')
-	def runway_value(self):
-		for record in self:
-			if record.charges_fixes :
-				record.runway = record.treso / record.charges_fixes
-
-	@api.one
-	def get_month(self):
-		months = ['Janv', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sept', 'Oct', 'Nov', 'Dec']
-		date_tdb = self.date_tdb
-		month = int(date_tdb[5:7])
-		year = date_tdb[2:4]
-		self.name = months[month-1] + " " + year
-
-
-	@api.model
-	def new_data(self):
-		self.create({ 'date_tdb': str(datetime.now()) })
-
-	@api.model
-	def retrieve_datas_dashboard(self):
-		## Get fiscal years
-		fiscal_date = datetime(datetime.now().year, self.env.user.company_id.fiscalyear_last_month, self.env.user.company_id.fiscalyear_last_day)	
-		if datetime.now() > fiscal_date:
-			fiscal_year = "'" + Date.to_string(fiscal_date) + "'"
-			fiscal_year_next = "'" + Date.to_string(fiscal_date+relativedelta(years=1)) + "'"
-		else:
-			fiscal_year = "'" + Date.to_string(fiscal_date-relativedelta(years=1)) + "'"
-			fiscal_year_next = "'" + Date.to_string(fiscal_date) + "'"
-
-		## Prepare values
-		res = {
-			'facture': 0,
-			'commandes': 0,
-			'pipe': 0,
-			'pipe_win': 0,
-			'pipe_to_win': 0,
-			'pipe_n1': 0,
-			'tresorerie': 0,
-			'entree': 0,
-			'sortie': 0,
-			'variation': 0,
-			'target': 0,
-			'cca': 0,
-			'capital': 0,
-			'date_maj': 0,
-			'a_encaisser': 0,
-			'a_payer': 0,
-			'fiscal_year': fiscal_year,
-			'fiscal_year_next': fiscal_year_next,
-		}
-
-		self._cr.execute("""
-			SELECT
-            	(select count(*) from account_invoice) as id,
-            	(select sum(amount_untaxed_signed) from account_invoice where state!='draft' and (type='out_invoice' or type='out_refund') and date > %s and date <= %s ) as facture, 
-            	(select sum(residual_company_signed) from account_invoice where state!='draft' and type='out_invoice' ) as a_encaisser, 
-            	(select sum(residual_company_signed) from account_invoice where state!='draft' and type='in_invoice' ) as a_payer, 
-            	(select sum(planned_revenue*probability/100) from crm_lead where active=True and (date_deadline <= %s or date_deadline is null) ) as pipe, 
-            	(select sum(planned_revenue*probability/100) from crm_lead where active=True and date_deadline > %s ) as pipe_n1, 
-            	(select sum(planned_revenue*probability/100) from crm_lead where active=True and probability=100  and (date_deadline <= %s or date_deadline is null) ) as pipe_win, 
-            	(select sum(planned_revenue*probability/100) from crm_lead where active=True and probability!=100  and (date_deadline < %s or date_deadline is null) ) as pipe_to_win,
-            	(select date from account_bank_statement ORDER BY ID DESC LIMIT 1) as date_maj,
-            	(select sum(amount) from account_bank_statement_line ) as tresorerie,
-            	(select sum(amount) from account_bank_statement_line where amount > 0 and date > %s ) as entree,
-            	(select sum(amount) from account_bank_statement_line where amount < 0 and date > %s ) as sortie,
-            	(select sum(amount) from account_bank_statement_line where date > %s ) as variation,
-            	(select sum(e.total_amount) from hr_expense_sheet es, hr_expense e where es.id = e.sheet_id and e.payment_mode='own_account' and es.state!='done' ) as cca,
-            	(select sum(price_subtotal-qty_invoiced*price_unit) from sale_order_line where invoice_status='to invoice') as commandes; """
-            	% (fiscal_year, fiscal_year_next, fiscal_year_next, fiscal_year_next, fiscal_year_next, fiscal_year_next, fiscal_year, fiscal_year, fiscal_year) )
-		datas = self._cr.dictfetchall()
-
-		self._cr.execute("select ca_target from res_company;")
-		ca_target = self._cr.dictfetchall()
-
-		self._cr.execute("select sum(capital) as capital from hr_employee;")
-		capital = self._cr.dictfetchall()
-
-		if datas[0]['facture']:
-			res['facture'] =+ datas[0]['facture']
-		if datas[0]['a_encaisser']:
-			res['a_encaisser'] =+ datas[0]['a_encaisser']
-		if datas[0]['a_payer']:
-			res['a_payer'] =+ datas[0]['a_payer']
-		if datas[0]['pipe']:
-			res['pipe'] =+ datas[0]['pipe']
-		if datas[0]['pipe_win']:
-			res['pipe_win'] =+ datas[0]['pipe_win']
-		if datas[0]['pipe_to_win']:
-			res['pipe_to_win'] =+ datas[0]['pipe_to_win']
-		if datas[0]['pipe_n1']:
-			res['pipe_n1'] =+ datas[0]['pipe_n1']
-		if datas[0]['tresorerie']:
-			res['tresorerie'] =+ datas[0]['tresorerie']
-		if datas[0]['date_maj']:
-			res['date_maj'] = datas[0]['date_maj']
-		if datas[0]['entree']:
-			res['entree'] =+ datas[0]['entree']
-		if datas[0]['sortie']:
-			res['sortie'] =+ datas[0]['sortie']
-		if datas[0]['variation']:
-			res['variation'] =+ datas[0]['variation']
-		if datas[0]['commandes']:
-			res['commandes'] =+ datas[0]['commandes']
-		if datas[0]['cca']:
-			res['cca'] =+ datas[0]['cca']
-		if ca_target[0]['ca_target']:
-			res['target'] =+ ca_target[0]['ca_target']
-		if capital[0]['capital']:	
-			res['capital'] =+ capital[0]['capital']
-
-		return res
-
-	@api.model
-	def tresorerie(self):
-		self._cr.execute("""SELECT to_char(date_trunc('month', date),'YYYY-MM') as mois, 
-					sum(case when amount > 0 then amount else 0 end ) as entree,
-					sum(case when amount < 0 then amount else 0 end ) as sortie,
-					sum(amount) as variation
-					from account_bank_statement_line 
-					group by date_trunc('month', date) 
-					order by date_trunc('month', date);""")
-		tresorerie = self._cr.dictfetchall()
-
-		self._cr.execute("""SELECT 
-					(select sum(e.total_amount) as fonds_propres from hr_expense_sheet es, hr_expense e where es.id = e.sheet_id and e.payment_mode='own_account' and es.state!='done') as cca,
-					(select sum(capital) as capital from hr_employee) as capital;""")
-		fonds_propres = self._cr.dictfetchall()[0]
-
-		if not fonds_propres['cca']:
-			fonds_propres['cca'] = 0
-
-		return { 'tresorerie': tresorerie, 'fonds_propres': fonds_propres }
-
-	@api.model
-	def previ_tresorerie(self):
-		self._cr.execute("""SELECT to_char(date_trunc('month', date),'YYYY-MM') as mois, sum(sum(amount))
-						over ( order by date_trunc('month', date) ) as treso
-						from account_bank_statement_line
-						group by date_trunc('month', date)
-						order by date_trunc('month', date) desc limit 6;""")
-		tresorerie = self._cr.dictfetchall()
-
-		self._cr.execute("""SELECT 
-					(select sum(e.total_amount) as fonds_propres from hr_expense_sheet es, hr_expense e where es.id = e.sheet_id and e.payment_mode='own_account' and es.state!='done') as cca,
-					(select sum(capital) as capital from hr_employee) as capital;""")
-		fonds_propres = self._cr.dictfetchall()[0]
-
-		self._cr.execute("""SELECT to_char(date_trunc('month', date_due),'YYYY-MM') as mois, 
-					sum(case when type='in_invoice' then residual_company_signed else 0 end ) as f_fournisseur,
-					sum(case when type='out_invoice' then residual_company_signed else 0 end ) as f_client
-					from account_invoice
-					where state!='draft' and state!='paid'
-					group by date_trunc('month', date_due)
-					order by date_trunc('month', date_due);""")
-		factures = self._cr.dictfetchall()
-
-		self._cr.execute("""SELECT periode,
-					sum(montant)
-					from previ_treso
-					where periode != 1
-					group by periode
-					order by periode;""")
-		charges_periode = self._cr.dictfetchall()
-
-		self._cr.execute("""SELECT to_char(date_trunc('month', date),'YYYY-MM') as mois, 
-					sum(montant)
-					from previ_treso
-					where periode = 1
-					group by date_trunc('month', date);""")
-		charges_fixes = self._cr.dictfetchall()
-
-		if not fonds_propres['cca']:
-			fonds_propres['cca'] = 0
-
-		return { 'tresorerie': tresorerie, 'fonds_propres': fonds_propres, 'factures': factures, 'charges_fixes': charges_fixes, 'charges_periode':charges_periode, }
+    _name = "lefilament.dashboard"
+    _description = "Le Filament Dashboard"
+    _order = "date_tdb desc"
+
+    name = fields.Char('Mois', compute='get_month')
+    date_tdb = fields.Date('Date',
+                           required=True,
+                           default=datetime.today().strftime('%Y-%m-%d'),)
+    ca_mois = fields.Float('Facturé', compute="dashboard_values", store=True)
+    cmd_mois = fields.Float('Commandes',
+                            compute="dashboard_values",
+                            store=True)
+    pipe_mois = fields.Float('Pipe', compute="dashboard_values", store=True)
+    treso = fields.Float('Trésorerie', compute="dashboard_values", store=True)
+    variation = fields.Float('Variation',
+                             compute="dashboard_values",
+                             store=True)
+    charges = fields.Float('Décaissé', compute="dashboard_values", store=True)
+    encaisse = fields.Float('Encaissé', compute="dashboard_values", store=True)
+    charges_fixes = fields.Float('Charges Fixes', default=10000)
+    runway = fields.Float('Runway', compute="runway_value")
+
+    @api.multi
+    @api.depends('date_tdb')
+    def dashboard_values(self):
+        for record in self:
+            if record.date_tdb:
+                date_tdb = datetime.strptime(record.date_tdb, '%Y-%m-%d')
+
+                # FACTURÉ
+                self.env.cr.execute(
+                    "SELECT SUM(amount_untaxed_signed) \
+                    FROM account_invoice \
+                    WHERE state != 'draft' \
+                    AND (type = 'out_invoice' OR type = 'out_refund') \
+                    AND date >= date_trunc('month', %s) \
+                    AND date < date_trunc('month', %s + interval '1' month);",
+                    (date_tdb, date_tdb)
+                    )
+                ca_mois = self.env.cr.fetchone()[0]
+
+                # COMMANDES TOTAL
+                self.env.cr.execute(
+                    "SELECT SUM(amount_untaxed) \
+                    FROM sale_order \
+                    WHERE invoice_status = 'to invoice' \
+                    AND date_order >= date_trunc('month', %s) \
+                    AND date_order < date_trunc('month', %s \
+                    + interval '1' month);",
+                    (date_tdb, date_tdb)
+                    )
+                cmd_mois = self.env.cr.fetchone()[0]
+
+                # Trésorerie
+                self.env.cr.execute(
+                    "SELECT SUM(amount) \
+                    FROM account_bank_statement_line \
+                    WHERE date < date_trunc('month', %s \
+                    + interval '1' month);",
+                    (date_tdb)
+                    )
+                treso_total = self.env.cr.fetchone()[0]
+                # CHARGES
+                self.env.cr.execute(
+                    "SELECT SUM(amount) \
+                    FROM account_bank_statement_line \
+                    WHERE amount < 0 \
+                    AND date >= date_trunc('month', %s) \
+                    AND date < date_trunc('month', %s + interval '1' month);",
+                    (date_tdb, date_tdb)
+                    )
+                charges = self.env.cr.fetchone()[0]
+                # ENCAISSE
+                self.env.cr.execute(
+                    "SELECT SUM(amount) \
+                    FROM account_bank_statement_line \
+                    WHERE amount > 0 \
+                    AND date >= date_trunc('month', %s) \
+                    AND date < date_trunc('month', %s + interval '1' month);",
+                    (date_tdb, date_tdb)
+                    )
+                encaisse = self.env.cr.fetchone()[0]
+
+                # CHARGES FIXES
+                self.env.cr.execute(
+                    "SELECT charges_fixes \
+                    FROM res_company"
+                    )
+                charges_fixes = self.env.cr.fetchone()[0]
+
+                # PIPE
+                self.env.cr.execute(
+                    "SELECT SUM(planned_revenue * probability / 100) \
+                    FROM crm_lead \
+                    WHERE active = True"
+                    )
+                pipe = self.env.cr.fetchone()[0]
+
+                if not encaisse:
+                    encaisse = 0
+                if not charges:
+                    charges = 0
+
+                record.ca_mois = ca_mois
+                record.cmd_mois = cmd_mois
+                record.treso = treso_total
+                record.charges = charges * (-1.0)
+                record.encaisse = encaisse
+                record.variation = encaisse + charges
+                record.charges_fixes = charges_fixes
+                record.pipe_mois = pipe
+
+    @api.multi
+    @api.depends('charges_fixes', 'treso')
+    def runway_value(self):
+        for record in self:
+            if record.charges_fixes:
+                record.runway = record.treso / record.charges_fixes
+
+    @api.multi
+    @api.depends('date_tdb')
+    def get_month(self):
+        for record in self:
+            months = ['Janv',
+                      'Fév',
+                      'Mars',
+                      'Avr',
+                      'Mai',
+                      'Juin',
+                      'Juil',
+                      'Août',
+                      'Sept',
+                      'Oct',
+                      'Nov',
+                      'Dec']
+            date_tdb = record.date_tdb
+            month = int(date_tdb[5:7])
+            year = date_tdb[2:4]
+            record.name = months[month-1] + " " + year
+
+    @api.model
+    def new_data(self):
+        self.create({'date_tdb': str(datetime.now())})
+
+    @api.model
+    def retrieve_datas_dashboard(self):
+        # Get fiscal years
+        fiscal_date = datetime(
+            datetime.now().year,
+            self.env.user.company_id.fiscalyear_last_month,
+            self.env.user.company_id.fiscalyear_last_day
+            )
+        if datetime.now() > fiscal_date:
+            fiscal_year = "'" + Date.to_string(fiscal_date) + "'"
+            fiscal_year_next = "'" + Date.to_string(
+                fiscal_date + relativedelta(years=1)) + "'"
+        else:
+            fiscal_year = "'" + Date.to_string(fiscal_date - relativedelta(
+                years=1)) + "'"
+            fiscal_year_next = "'" + Date.to_string(fiscal_date) + "'"
+
+        # Prepare values
+        res = {
+            'facture': 0,
+            'commandes': 0,
+            'pipe': 0,
+            'pipe_win': 0,
+            'pipe_to_win': 0,
+            'pipe_n1': 0,
+            'tresorerie': 0,
+            'entree': 0,
+            'sortie': 0,
+            'variation': 0,
+            'target': 0,
+            'cca': 0,
+            'capital': 0,
+            'date_maj': 0,
+            'a_encaisser': 0,
+            'a_payer': 0,
+            'fiscal_year': fiscal_year,
+            'fiscal_year_next': fiscal_year_next,
+        }
+
+        self._cr.execute(
+            """
+            SELECT
+                (SELECT COUNT(*)
+                    FROM account_invoice
+                ) AS id,
+                (SELECT SUM(amount_untaxed_signed)
+                    FROM account_invoice
+                    WHERE state!='draft'
+                        AND (type='out_invoice' OR type='out_refund')
+                        AND date > %s AND date <= %s
+                ) AS facture,
+                (SELECT SUM(residual_company_signed)
+                    FROM account_invoice
+                    WHERE state!='draft' AND type='out_invoice'
+                ) AS a_encaisser,
+                (SELECT SUM(residual_company_signed)
+                    FROM account_invoice
+                    WHERE state!='draft' AND type='in_invoice'
+                ) AS a_payer,
+                (SELECT SUM(planned_revenue * probability / 100)
+                    FROM crm_lead
+                    WHERE active=True
+                        AND (date_deadline <= %s OR date_deadline is NULL)
+                ) AS pipe,
+                (SELECT SUM(planned_revenue * probability / 100)
+                    FROM crm_lead WHERE active=True AND date_deadline > %s
+                ) AS pipe_n1,
+                (SELECT SUM(planned_revenue * probability / 100)
+                    FROM crm_lead
+                    WHERE active=True
+                        AND probability = 100
+                        AND (date_deadline <= %s OR date_deadline is NULL)
+                ) AS pipe_win,
+                (SELECT SUM(planned_revenue * probability / 100)
+                    FROM crm_lead
+                    WHERE active=True
+                        AND probability != 100
+                        AND (date_deadline < %s OR date_deadline is NULL)
+                ) AS pipe_to_win,
+                (SELECT date
+                    FROM account_bank_statement
+                    ORDER BY ID DESC LIMIT 1
+                ) AS date_maj,
+                (SELECT SUM(amount)
+                    FROM account_bank_statement_line
+                ) AS tresorerie,
+                (SELECT SUM(amount)
+                    FROM account_bank_statement_line
+                    WHERE amount > 0 AND date > %s
+                ) AS entree,
+                (SELECT SUM(amount)
+                    FROM account_bank_statement_line
+                    WHERE amount < 0 AND date > %s
+                ) AS sortie,
+                (SELECT SUM(amount)
+                    FROM account_bank_statement_line
+                    WHERE date > %s
+                ) AS variation,
+                (SELECT SUM(e.total_amount)
+                    FROM hr_expense_sheet es, hr_expense e
+                    WHERE es.id = e.sheet_id
+                        AND e.payment_mode = 'own_account'
+                        AND es.state != 'done'
+                ) AS cca,
+                (SELECT SUM(price_subtotal - qty_invoiced * price_unit)
+                    FROM sale_order_line
+                    WHERE invoice_status = 'to invoice'
+                ) AS commandes;
+            """
+            % (fiscal_year,
+               fiscal_year_next,
+               fiscal_year_next,
+               fiscal_year_next,
+               fiscal_year_next,
+               fiscal_year_next,
+               fiscal_year,
+               fiscal_year,
+               fiscal_year)
+            )
+        datas = self._cr.dictfetchall()
+
+        self._cr.execute("SELECT ca_target FROM res_company;")
+        ca_target = self._cr.dictfetchall()
+
+        self._cr.execute("SELECT sum(capital) AS capital FROM hr_employee;")
+        capital = self._cr.dictfetchall()
+
+        if datas[0]['facture']:
+            res['facture'] += datas[0]['facture']
+        if datas[0]['a_encaisser']:
+            res['a_encaisser'] += datas[0]['a_encaisser']
+        if datas[0]['a_payer']:
+            res['a_payer'] += datas[0]['a_payer']
+        if datas[0]['pipe']:
+            res['pipe'] += datas[0]['pipe']
+        if datas[0]['pipe_win']:
+            res['pipe_win'] += datas[0]['pipe_win']
+        if datas[0]['pipe_to_win']:
+            res['pipe_to_win'] += datas[0]['pipe_to_win']
+        if datas[0]['pipe_n1']:
+            res['pipe_n1'] += datas[0]['pipe_n1']
+        if datas[0]['tresorerie']:
+            res['tresorerie'] += datas[0]['tresorerie']
+        if datas[0]['date_maj']:
+            res['date_maj'] = datas[0]['date_maj']
+        if datas[0]['entree']:
+            res['entree'] += datas[0]['entree']
+        if datas[0]['sortie']:
+            res['sortie'] += datas[0]['sortie']
+        if datas[0]['variation']:
+            res['variation'] += datas[0]['variation']
+        if datas[0]['commandes']:
+            res['commandes'] += datas[0]['commandes']
+        if datas[0]['cca']:
+            res['cca'] += datas[0]['cca']
+        if ca_target[0]['ca_target']:
+            res['target'] += ca_target[0]['ca_target']
+        if capital[0]['capital']:
+            res['capital'] += capital[0]['capital']
+
+        return res
+
+    @api.model
+    def tresorerie(self):
+        self._cr.execute(
+            """
+            SELECT to_char(date_trunc('month', date),'YYYY-MM') AS mois,
+                SUM(CASE WHEN amount > 0 THEN amount ELSE 0 END) AS entree,
+                SUM(CASE WHEN amount < 0 THEN amount ELSE 0 END) AS sortie,
+                SUM(amount) AS variation
+            FROM account_bank_statement_line
+            GROUP BY date_trunc('month', date)
+            ORDER BY date_trunc('month', date);
+            """
+            )
+        tresorerie = self._cr.dictfetchall()
+
+        self._cr.execute(
+            """
+            SELECT
+                (SELECT SUM(e.total_amount) AS fonds_propres
+                    FROM hr_expense_sheet es, hr_expense e
+                    WHERE es.id = e.sheet_id
+                        AND e.payment_mode = 'own_account'
+                        AND es.state != 'done'
+                ) AS cca,
+                (SELECT SUM(capital) AS capital FROM hr_employee) AS capital;
+            """
+            )
+        fonds_propres = self._cr.dictfetchall()[0]
+
+        if not fonds_propres['cca']:
+            fonds_propres['cca'] = 0
+
+        return {'tresorerie': tresorerie, 'fonds_propres': fonds_propres}
+
+    @api.model
+    def previ_tresorerie(self):
+        self._cr.execute(
+            """
+            SELECT to_char(date_trunc('month', date),'YYYY-MM') AS mois,
+                SUM(SUM(amount)) OVER (
+                    ORDER BY date_trunc('month', date)
+                ) AS treso
+            FROM account_bank_statement_line
+            GROUP BY date_trunc('month', date)
+            ORDER BY date_trunc('month', date) DESC LIMIT 6;
+            """
+            )
+        tresorerie = self._cr.dictfetchall()
+
+        self._cr.execute(
+            """
+            SELECT
+                (SELECT SUM(e.total_amount) AS fonds_propres
+                    FROM hr_expense_sheet es, hr_expense e
+                    WHERE es.id = e.sheet_id
+                        AND e.payment_mode = 'own_account'
+                        AND es.state != 'done'
+                ) as cca,
+                (SELECT SUM(capital) AS capital FROM hr_employee) AS capital;
+            """
+            )
+        fonds_propres = self._cr.dictfetchall()[0]
+
+        self._cr.execute(
+            """
+            SELECT to_char(date_trunc('month', date_due),'YYYY-MM') AS mois,
+                SUM(CASE WHEN type = 'in_invoice'
+                    THEN residual_company_signed
+                    ELSE 0 END
+                    ) AS f_fournisseur,
+                SUM(CASE WHEN type = 'out_invoice'
+                    THEN residual_company_signed
+                    ELSE 0 END
+                    ) AS f_client
+            FROM account_invoice
+            WHERE state != 'draft' AND state != 'paid'
+            GROUP BY date_trunc('month', date_due)
+            ORDER BY date_trunc('month', date_due);
+            """
+            )
+        factures = self._cr.dictfetchall()
+
+        self._cr.execute(
+            """
+            SELECT periode,
+                SUM(montant)
+            FROM previ_treso
+            WHERE periode != 1
+            GROUP BY periode
+            ORDER BY periode;
+            """
+            )
+        charges_periode = self._cr.dictfetchall()
+
+        self._cr.execute(
+            """
+            SELECT to_char(date_trunc('month', date), 'YYYY-MM') as mois,
+                SUM(montant)
+            FROM previ_treso
+            WHERE periode = 1
+            GROUP BY date_trunc('month', date);
+            """
+            )
+        charges_fixes = self._cr.dictfetchall()
+
+        if not fonds_propres['cca']:
+            fonds_propres['cca'] = 0
+
+        return {
+            'tresorerie': tresorerie,
+            'fonds_propres': fonds_propres,
+            'factures': factures,
+            'charges_fixes': charges_fixes,
+            'charges_periode': charges_periode,
+            }
diff --git a/models/res_company.py b/models/res_company.py
index 5ae5e39..74128d9 100644
--- a/models/res_company.py
+++ b/models/res_company.py
@@ -1,27 +1,33 @@
 # -*- coding: utf-8 -*-
-
 # © 2017 Le Filament (<http://www.le-filament.com>)
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
-from odoo import models, fields, api
+from odoo import models, fields
 
-class res_company(models.Model):
-	_name = "res.company"
-	_inherit = "res.company"
 
-	ca_target = fields.Integer( "Objectif Chiffre d'Affaire" )
-	charges_fixes = fields.Integer( 'Charges Fixes' )
-	previ_treso_ids = fields.One2many('previ.treso', 'company_id', 'Prévisionnel')
+class res_company(models.Model):
+    _inherit = "res.company"
 
+    ca_target = fields.Integer("Objectif Chiffre d'Affaire")
+    charges_fixes = fields.Integer('Charges Fixes')
+    previ_treso_ids = fields.One2many('previ.treso',
+                                      'company_id',
+                                      'Prévisionnel')
 
 
 class previ_treso(models.Model):
-	_name = "previ.treso"
-	_description = "Previsionnel de tresorerie"
-	_order = 'name'
-
-	company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.user.company_id.id )
-	name = fields.Char('Nom')
-	periode = fields.Selection([(12,'Mensuel'),(3,'Trimestriel'),(1,'Annuel')], srting='Période')
-	date = fields.Date('Date')
-	montant = fields.Float('Montant')
\ No newline at end of file
+    _name = "previ.treso"
+    _description = "Previsionnel de tresorerie"
+    _order = 'name'
+
+    company_id = fields.Many2one(
+        'res.company',
+        'Company',
+        default=lambda self: self.env.user.company_id.id)
+    name = fields.Char('Nom')
+    periode = fields.Selection(
+        [(12, 'Mensuel'), (3, 'Trimestriel'), (1, 'Annuel')],
+        srting='Période'
+        )
+    date = fields.Date('Date')
+    montant = fields.Float('Montant')
diff --git a/security/lefilament_dashboard_security.xml b/security/lefilament_dashboard_security.xml
index de335ff..5aeff45 100644
--- a/security/lefilament_dashboard_security.xml
+++ b/security/lefilament_dashboard_security.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <odoo>
 	<data noupdate="0">
 
diff --git a/static/description/icon_menu.png b/static/description/icon_menu.png
new file mode 100644
index 0000000000000000000000000000000000000000..6591b91a04ae5274382d55080290ba0d41372825
GIT binary patch
literal 7169
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

literal 0
HcmV?d00001

diff --git a/static/description/icon_menu.svg b/static/description/icon_menu.svg
new file mode 100644
index 0000000..10e163b
--- /dev/null
+++ b/static/description/icon_menu.svg
@@ -0,0 +1,23 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70" viewBox="0 0 70 70">
+    <defs>
+        <path id="icon-a" d="M4,5.35309892e-14 C36.4160122,9.87060235e-15 58.0836068,-3.97961823e-14 65,5.07020818e-14 C69,6.733808e-14 70,1 70,5 C70,43.0488877 70,62.4235458 70,65 C70,69 69,70 65,70 C61,70 9,70 4,70 C1,70 7.10542736e-15,69 7.10542736e-15,65 C7.25721566e-15,62.4676575 3.83358709e-14,41.8005206 3.60818146e-14,5 C-1.13686838e-13,1 1,5.75716207e-14 4,5.35309892e-14 Z"/>
+        <linearGradient id="icon-c" x1="100%" x2="0%" y1="0%" y2="100%">
+            <stop offset="0%" stop-color="#36DABE"/>
+            <stop offset="100%" stop-color="#00B495"/>
+        </linearGradient>
+        <path id="icon-d" d="M18.0450069,57.225 C16.6239398,57.2249541 15.319401,56.4292666 14.6550625,55.1573449 C12.9601701,51.9125391 12,48.2137078 12,44.2875 C12,31.4261695 22.2974514,21 35,21 C47.7025486,21 58,31.4261695 58,44.2875 C58,48.2137078 57.0398299,51.9125391 55.3449375,55.1573449 C54.6806259,56.4292924 53.3760701,57.2249902 51.9549931,57.225 L18.0450069,57.225 Z M52.8888889,41.7 C51.4775035,41.7 50.3333333,42.8584723 50.3333333,44.2875 C50.3333333,45.7165277 51.4775035,46.875 52.8888889,46.875 C54.3002743,46.875 55.4444444,45.7165277 55.4444444,44.2875 C55.4444444,42.8584723 54.3002743,41.7 52.8888889,41.7 Z M35,28.7625 C36.4113854,28.7625 37.5555556,27.6040277 37.5555556,26.175 C37.5555556,24.7459723 36.4113854,23.5875 35,23.5875 C33.5886146,23.5875 32.4444444,24.7459723 32.4444444,26.175 C32.4444444,27.6040277 33.5886146,28.7625 35,28.7625 Z M17.1111111,41.7 C15.6997257,41.7 14.5555556,42.8584723 14.5555556,44.2875 C14.5555556,45.7165277 15.6997257,46.875 17.1111111,46.875 C18.5224965,46.875 19.6666667,45.7165277 19.6666667,44.2875 C19.6666667,42.8584723 18.5224965,41.7 17.1111111,41.7 Z M22.3506389,28.8925219 C20.9392535,28.8925219 19.7950833,30.0509941 19.7950833,31.4800219 C19.7950833,32.9090496 20.9392535,34.0675219 22.3506389,34.0675219 C23.7620243,34.0675219 24.9061944,32.9090496 24.9061944,31.4800219 C24.9061944,30.0509941 23.7620243,28.8925219 22.3506389,28.8925219 Z M47.6493611,28.8925219 C46.2379757,28.8925219 45.0938056,30.0509941 45.0938056,31.4800219 C45.0938056,32.9090496 46.2379757,34.0675219 47.6493611,34.0675219 C49.0607465,34.0675219 50.2049167,32.9090496 50.2049167,31.4800219 C50.2049167,30.0509941 49.0607465,28.8925219 47.6493611,28.8925219 Z M40.6952153,31.4423414 C39.686809,31.1156695 38.6082049,31.6784508 38.285566,32.6992195 L34.6181042,44.3034293 C31.9739028,44.501373 29.8888889,46.7346281 29.8888889,49.4625 C29.8888889,52.3205555 32.1772292,54.6375 35,54.6375 C37.8227708,54.6375 40.1111111,52.3205555 40.1111111,49.4625 C40.1111111,47.8636676 39.3946771,46.434559 38.269434,45.4852699 L41.9365764,33.8821113 C42.2591354,32.8612617 41.7033819,31.7690133 40.6952153,31.4423414 Z"/>
+    </defs>
+    <g fill="none" fill-rule="evenodd">
+        <mask id="icon-b" fill="#fff">
+            <use xlink:href="#icon-a"/>
+        </mask>
+        <g mask="url(#icon-b)">
+            <rect width="70" height="70" fill="url(#icon-c)"/>
+            <path fill="#FFF" fill-opacity=".383" d="M4,1.8 L65,1.8 C67.6666667,1.8 69.3333333,1.13333333 70,-0.2 C70,2.46666667 70,3.46666667 70,2.8 L1.10547097e-14,2.8 C-1.65952376e-14,3.46666667 -2.9161925e-14,2.46666667 -2.66453526e-14,-0.2 C0.666666667,1.13333333 2,1.8 4,1.8 Z" transform="matrix(1 0 0 -1 0 2.8)"/>
+            <path fill="#393939" d="M4,50 C2,50 -7.10542736e-15,49.851312 0,45.8367347 L0,26.3942795 L16.3536575,8.86200565 C29.4512192,-0.488174988 39.6666667,-2.3877551 47,3.16326531 C54.3333333,8.71428571 58,14.9591837 58,21.8979592 C55.8677728,29.7827578 54.7719047,33.7755585 54.7123959,33.8763613 C54.6528871,33.9771642 49.9857922,39.3517104 40.7111111,50 L4,50 Z" opacity=".324" transform="translate(0 20)"/>
+            <path fill="#000" fill-opacity=".383" d="M4,4 L65,4 C67.6666667,4 69.3333333,3 70,1 C70,3.66666667 70,5 70,5 L1.77635684e-15,5 C1.77635684e-15,5 1.77635684e-15,3.66666667 1.77635684e-15,1 C0.666666667,3 2,4 4,4 Z" transform="translate(0 65)"/>
+            <use fill="#000" fill-rule="nonzero" opacity=".3" xlink:href="#icon-d"/>
+            <path fill="#FFF" fill-rule="nonzero" d="M18.0450069,55.225 C16.6239398,55.2249541 15.319401,54.4292666 14.6550625,53.1573449 C12.9601701,49.9125391 12,46.2137078 12,42.2875 C12,29.4261695 22.2974514,19 35,19 C47.7025486,19 58,29.4261695 58,42.2875 C58,46.2137078 57.0398299,49.9125391 55.3449375,53.1573449 C54.6806259,54.4292924 53.3760701,55.2249902 51.9549931,55.225 L18.0450069,55.225 Z M52.8888889,39.7 C51.4775035,39.7 50.3333333,40.8584723 50.3333333,42.2875 C50.3333333,43.7165277 51.4775035,44.875 52.8888889,44.875 C54.3002743,44.875 55.4444444,43.7165277 55.4444444,42.2875 C55.4444444,40.8584723 54.3002743,39.7 52.8888889,39.7 Z M35,26.7625 C36.4113854,26.7625 37.5555556,25.6040277 37.5555556,24.175 C37.5555556,22.7459723 36.4113854,21.5875 35,21.5875 C33.5886146,21.5875 32.4444444,22.7459723 32.4444444,24.175 C32.4444444,25.6040277 33.5886146,26.7625 35,26.7625 Z M17.1111111,39.7 C15.6997257,39.7 14.5555556,40.8584723 14.5555556,42.2875 C14.5555556,43.7165277 15.6997257,44.875 17.1111111,44.875 C18.5224965,44.875 19.6666667,43.7165277 19.6666667,42.2875 C19.6666667,40.8584723 18.5224965,39.7 17.1111111,39.7 Z M22.3506389,26.8925219 C20.9392535,26.8925219 19.7950833,28.0509941 19.7950833,29.4800219 C19.7950833,30.9090496 20.9392535,32.0675219 22.3506389,32.0675219 C23.7620243,32.0675219 24.9061944,30.9090496 24.9061944,29.4800219 C24.9061944,28.0509941 23.7620243,26.8925219 22.3506389,26.8925219 Z M47.6493611,26.8925219 C46.2379757,26.8925219 45.0938056,28.0509941 45.0938056,29.4800219 C45.0938056,30.9090496 46.2379757,32.0675219 47.6493611,32.0675219 C49.0607465,32.0675219 50.2049167,30.9090496 50.2049167,29.4800219 C50.2049167,28.0509941 49.0607465,26.8925219 47.6493611,26.8925219 Z M40.6952153,29.4423414 C39.686809,29.1156695 38.6082049,29.6784508 38.285566,30.6992195 L34.6181042,42.3034293 C31.9739028,42.501373 29.8888889,44.7346281 29.8888889,47.4625 C29.8888889,50.3205555 32.1772292,52.6375 35,52.6375 C37.8227708,52.6375 40.1111111,50.3205555 40.1111111,47.4625 C40.1111111,45.8636676 39.3946771,44.434559 38.269434,43.4852699 L41.9365764,31.8821113 C42.2591354,30.8612617 41.7033819,29.7690133 40.6952153,29.4423414 Z"/>
+        </g>
+    </g>
+</svg>
diff --git a/static/src/js/dashboard_year.js b/static/src/js/dashboard_year.js
index af8c52a..e1b1c7a 100644
--- a/static/src/js/dashboard_year.js
+++ b/static/src/js/dashboard_year.js
@@ -1,4 +1,3 @@
-
  // © 2017 Le Filament (<http://www.le-filament.com>)
  // License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
diff --git a/static/src/js/tresorerie.js b/static/src/js/tresorerie.js
index 7b563c5..eddcb39 100644
--- a/static/src/js/tresorerie.js
+++ b/static/src/js/tresorerie.js
@@ -1,4 +1,3 @@
-
 // © 2017 Le Filament (<http://www.le-filament.com>)
 // License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
 
diff --git a/static/src/xml/lefilament_tdb.xml b/static/src/xml/lefilament_tdb.xml
index 1a32d32..c4e9486 100644
--- a/static/src/xml/lefilament_tdb.xml
+++ b/static/src/xml/lefilament_tdb.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <templates xml:space="preserve">
 
 	<t t-name="Dashboard">
diff --git a/static/src/xml/lefilament_treso.xml b/static/src/xml/lefilament_treso.xml
index 936d14c..3f16f1a 100644
--- a/static/src/xml/lefilament_treso.xml
+++ b/static/src/xml/lefilament_treso.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <templates xml:space="preserve">
 
 
diff --git a/views/assets.xml b/views/assets.xml
index 6355aa0..d4363a1 100644
--- a/views/assets.xml
+++ b/views/assets.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <odoo>
     <data>
         
diff --git a/views/schedule.xml b/views/schedule.xml
index 748bcb5..6afdedd 100644
--- a/views/schedule.xml
+++ b/views/schedule.xml
@@ -1,6 +1,8 @@
 <odoo>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
     <data noupdate="1">
-        <record id="ir_cron_sapova_tdb" model="ir.cron">
+        <record id="ir_cron_lefilament_tdb" model="ir.cron">
             <field name="name">Tableau de Bord - Le Filament</field>
             <field name="active" eval="True" />
             <field name="user_id" ref="base.user_root" />
diff --git a/views/views.xml b/views/views.xml
index 7b3ee33..00250c6 100644
--- a/views/views.xml
+++ b/views/views.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>)
+     License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <odoo>
     <data>
         
-- 
GitLab