diff --git a/__manifest__.py b/__manifest__.py
index e94acb035285e8635b361d4c532223a1d68db95a..bae454ae4167a10b5ec338e49ae2238d661d3907 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -19,12 +19,14 @@
'security/ir.model.access.csv',
'datas/adefpat_archi_dossier_datas.xml',
'wizard/upload_file_wizard.xml',
+ "wizard/adefpat_project_justif_zip_wizard.xml",
'views/project_views.xml',
'views/project_task_views.xml',
'views/adefpat_list_type_doc_views.xml',
'views/hr_timesheet_views.xml',
'views/hr_expense_views.xml',
'views/res_company.xml',
+ 'views/account_views.xml',
],
}
\ No newline at end of file
diff --git a/models/__init__.py b/models/__init__.py
index 33cba6ae53e3b77bd02007ec2c94c4ac78eae3e3..7f6fb42173d401be7161d7e564640f160579c499 100644
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2020 Le Filament (<http://www.le-filament.com>)
+# Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import project
@@ -6,4 +6,5 @@ from . import project_task
from . import adefpat_list_type_doc
from . import hr_expense
from . import hr_timesheet
-from . import res_company
\ No newline at end of file
+from . import res_company
+from . import account
\ No newline at end of file
diff --git a/models/account.py b/models/account.py
new file mode 100644
index 0000000000000000000000000000000000000000..7bb4d72a6d8aa313d28a12204aab958cdccc5e82
--- /dev/null
+++ b/models/account.py
@@ -0,0 +1,83 @@
+# Copyright 2020-2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+from datetime import date
+
+from odoo import api, models, fields
+from odoo.exceptions import UserError
+
+
+class AccountInvoice(models.Model):
+ _inherit = 'account.invoice'
+
+ proof_file = fields.Char("Facture fournisseur")
+
+ # ------------------------------------------------------
+ # Override ORM
+ # ------------------------------------------------------
+ @api.multi
+ def unlink(self):
+ for line in self:
+ if line.proof_file:
+ raise UserError(
+ "Un document est attaché à cette ligne, "
+ "veuillez le supprimer avant de supprimer la ligne.")
+ return super(AccountInvoice, self).unlink()
+
+ # ------------------------------------------------------
+ # Button Function
+ # ------------------------------------------------------
+ @api.multi
+ def get_content_details_url(self):
+ # TODO: Refaire la fonction sans le type CMIS Folder
+ """
+ Ouvre une nouvelle fenêtre avec le fichier
+ :return: ir.actions.act_url
+ """
+ backend = self.env['cmis.backend'].search([], limit=1)
+ for pp in self:
+ if pp.proof_file:
+ properties = backend.get_cmis_repository().getFolder(
+ pp.proof_file).getProperties()
+ url = backend.get_content_details_url_from_props(properties)
+ return {
+ 'type': 'ir.actions.act_url',
+ 'url': url,
+ 'target': 'new',
+ }
+
+ def delete_file(self):
+ backend = self.env['cmis.backend'].search([], limit=1)
+ try:
+ file = backend.get_cmis_repository().getObject(
+ self.proof_file
+ )
+ file.delete()
+ self.proof_file = False
+ except:
+ self.proof_file = False
+
+ # ------------------------------------------------------
+ # Common Function
+ # ------------------------------------------------------
+ def get_file_properties(self):
+ """
+ Ajoute les propriétés au dossier lors de la création dans Alfresco
+ """
+ if self.task_ids:
+ task_start = self.task_ids.sorted(key=lambda r: r.date_deadline)[0].date_deadline
+ task_end = self.task_ids.sorted(key=lambda r: r.date_deadline, reverse=True)[0].date_deadline
+ return {
+ 'cmis:secondaryObjectTypeIds': ['P:adefpat:facture'],
+ 'adefpat:factureStartDate': fields.Datetime.to_datetime(task_start).isoformat(),
+ 'adefpat:factureEndDate': fields.Datetime.to_datetime(task_end).isoformat(),
+ 'adefpat:factureTypeConvention': self.type_convention_id.name or "",
+ }
+ else:
+ return {
+ 'cmis:secondaryObjectTypeIds': ['P:adefpat:facture'],
+ 'adefpat:factureStartDate': fields.Datetime.to_datetime(
+ self.date_invoice).isoformat(),
+ 'adefpat:factureTypeConvention': self.type_convention_id.name or "",
+ }
+
diff --git a/models/res_company.py b/models/res_company.py
index 48cb2357fac274c4a6f1e50d69b6349a7585a67d..d0bfcc37e7213b748dc99e9dfbbd775453e95ee7 100644
--- a/models/res_company.py
+++ b/models/res_company.py
@@ -9,3 +9,6 @@ class ResCompanyAlfodoo(models.Model):
project_cmis = fields.Char("NodeRef Projets")
proof_cmis = fields.Char("NodeRef Justificatifs")
+ proof_invoice_cmis = fields.Char("NodeRef Justificatifs Facture Fournisseur")
+ proof_invoice_customer_cmis = fields.Char("NodeRef Justificatifs Facture Client")
+ proof_justif_cmis = fields.Char("NodeRef Dossiers pour JSON")
diff --git a/views/account_views.xml b/views/account_views.xml
index 2aad9988154457b69894a9a4d758fba9dad14073..28b2d8a90477e5336732ff1161f5288bf2dc8e3c 100644
--- a/views/account_views.xml
+++ b/views/account_views.xml
@@ -1,8 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
-
- $END$
-
+
+ <record id="invoice_supplier_form" model="ir.ui.view">
+ <field name="name">account.invoice.supplier.form.inherit</field>
+ <field name="model">account.invoice</field>
+ <field name="inherit_id" ref="account.invoice_supplier_form"/>
+ <field name="arch" type="xml">
+ <header position="inside">
+ <field name="proof_file" invisible="1"/>
+ <button name="%(adefpat_alfodoo.upload_file_wizard_action)d"
+ string="Charger le justificatif"
+ type="action"
+ class="oe_highlight"
+ attrs="{'invisible': [('proof_file', '!=', False)]}"
+ />
+ <button
+ name="delete_file"
+ string="Supprimer le fichier"
+ type="object"
+ attrs="{'invisible': [('proof_file', '=', False)]}"
+ />
+ <button
+ name="get_content_details_url"
+ string="Voir le fichier dans Alfresco"
+ type="object"
+ attrs="{'invisible': [('proof_file', '=', False)]}"
+ />
+ </header>
+ </field>
+ </record>
+
+ <record id="invoice_form" model="ir.ui.view">
+ <field name="name">adefpat.invoice_form.form.alfodoo</field>
+ <field name="model">account.invoice</field>
+ <field name="inherit_id" ref="account.invoice_form"/>
+ <field name="arch" type="xml">
+ <header position="inside">
+ <field name="proof_file" invisible="1"/>
+ <button name="%(adefpat_alfodoo.upload_file_wizard_action)d"
+ string="Charger le justificatif"
+ type="action"
+ class="oe_highlight"
+ attrs="{'invisible': [('proof_file', '!=', False)]}"
+ />
+ <button
+ name="delete_file"
+ string="Supprimer le fichier"
+ type="object"
+ attrs="{'invisible': [('proof_file', '=', False)]}"
+ />
+ <button
+ name="get_content_details_url"
+ string="Voir le fichier dans Alfresco"
+ type="object"
+ attrs="{'invisible': [('proof_file', '=', False)]}"
+ />
+ </header>
+ </field>
+ </record>
</data>
</odoo>
\ No newline at end of file
diff --git a/views/res_company.xml b/views/res_company.xml
index f9f7a2fc33e2b9762882a641daa319aa1738a9b7..a6e8d804cd5e6e03113af54e031fe28fa2568280 100644
--- a/views/res_company.xml
+++ b/views/res_company.xml
@@ -15,6 +15,9 @@
<group>
<field name="project_cmis"/>
<field name="proof_cmis"/>
+ <field name="proof_invoice_cmis"/>
+ <field name="proof_invoice_customer_cmis"/>
+ <field name="proof_justif_cmis"/>
</group>
</group>
</page>
diff --git a/wizard/__init__.py b/wizard/__init__.py
index eb1ffab4f53eeb4bf641982d70390d62d949cf63..3d23381f6e383e6647db22ae2bbacfc83ee8a1cb 100644
--- a/wizard/__init__.py
+++ b/wizard/__init__.py
@@ -2,3 +2,4 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import upload_file_wizard
+from . import adefpat_project_justif_zip_wizard
diff --git a/wizard/adefpat_project_justif_zip_wizard.py b/wizard/adefpat_project_justif_zip_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..de55af7405234aac16f6cfdca4b0223301a4f588
--- /dev/null
+++ b/wizard/adefpat_project_justif_zip_wizard.py
@@ -0,0 +1,223 @@
+# Copyright 2022 Le Filament (<http://www.le-filament.com>)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+import json
+
+from datetime import date
+from odoo import api, fields, models
+
+from odoo.exceptions import UserError
+
+
+class AdefpatProjectJustifZip(models.TransientModel):
+ _name = "adefpat.project.justif.zip.wizard"
+ _description = "Wizard justifs zip projets"
+
+ period_start = fields.Date("Début de période", required=True)
+ period_end = fields.Date(
+ "Fin de période", required=True, default=fields.Date.today()
+ )
+ type_convention_id = fields.Many2one(
+ "adefpat.type.convention",
+ domain=[
+ "|",
+ ("date_end_validity", ">=", fields.Date.today()),
+ ("date_end_validity", "=", False),
+ ],
+ string="Type de convention de financement",
+ )
+
+ # function will trigger from the show report button
+ @api.multi
+ def build_folder(self):
+ # Get Projects with at least 1 task on period
+ project_ids = self.env["project.task"].search([
+ ("date_deadline", "<=", self.period_end),
+ ("date_deadline", ">=", self.period_start),
+ ]).mapped("project_id")
+
+ if self.type_convention_id:
+ project_ids = project_ids.filtered(
+ lambda p: p.type_convention_id == self.type_convention_id)
+
+ compteur = 0
+ json_file = []
+ for project in project_ids:
+ compteur += 1
+ path = "PATH:'/app:company_home/st:sites/cm:odoo/cm:documentLibrary/cm:Projets/" + project.name
+ # virtual_json["nodes"]["nodes"].append({
+ json_file.append({
+ "id": "1" + str(compteur),
+ "name": project.name,
+ "description": project.name,
+ "nodes":[
+ {
+ "id": "1" + str(compteur) + "1",
+ "name": "CR séance",
+ "description": "Compte-Rendus des séances d’accompagnement",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:seances//*'" + " AND =adefpat:typeDocument:'compte rendu'",
+ }
+ },
+ {
+ "id": "1" + str(compteur) + "2",
+ "name": "GAP",
+ "description": "Compte-Rendus des séances de GAP",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:gap//*'" + " AND =adefpat:typeDocument:'compte rendu'",
+ },
+ },
+ {
+ "id": "1" + str(compteur) + "3",
+ "name": "Evaluation CF",
+ "description": "Evaluation finale du consultant formateur",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:seances//*'" + " AND =adefpat:typeDocument:'évaluation du formateur'",
+ },
+ },
+ {
+ "id": "1" + str(compteur) + "4",
+ "name": "Evaluation stagiaire",
+ "description": "Questionnaire de satisfaction de chaque stagiaire",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:beneficiaires//*'" + " AND =adefpat:typeDocument:'questionnaire de satisfaction'",
+ },
+ },
+ {
+ "id": "1" + str(compteur) + "5",
+ "name": "Consultations",
+ "description": "Consultations",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:consultation//*'",
+ },
+ },
+ {
+ "id": "1" + str(compteur) + "6",
+ "name": "Conventions",
+ "description": "Conventions",
+ "search": {
+ "language": "fts-alfresco",
+ "query": path + "/cm:admin//*'" + " AND (=adefpat:typeDocument:'convention d'accompagnement' OR =adefpat:typeDocument:'convention d'objectif')",
+ },
+ },
+ ]})
+
+ virtual_json = {
+ "name": "Justificatifs Projets",
+ "nodes": [{
+ "id": "1",
+ "name": "Justificatifs Projets",
+ "description": "Justificatifs Projets",
+ "nodes": json_file,
+ }]
+ }
+
+ js = json.dumps(virtual_json, indent=4)
+ prop = {
+ 'cmis:secondaryObjectTypeIds': ['P:adefpat:justificatif'],
+ }
+ # 'adefpat:financementConvention': str(self.type_convention_id.name),
+ backend = self.env['cmis.backend'].search([], limit=1)
+ json_file_cmis = self.env.user.company_id.proof_justif_cmis
+ repo = backend.get_cmis_repository().getObject(json_file_cmis)
+ try:
+ file = repo.createDocument(
+ name="justifs_projets_"+ str(date.today()) +".json",
+ properties=prop,
+ contentFile=js,
+ contentType="application/json"
+ )
+ except Exception as e:
+ raise UserError(json.loads(e.details).get('message'))
+
+ @api.multi
+ def build_facture_fournisseur(self):
+
+ virtual_json = {
+ "name" : "Factures fournisseurs",
+ "nodes" : [{
+ "id" : "1",
+ "name" : "Factures fournisseurs",
+ "description" : "Factures fournisseurs",
+ "search" : {
+ "language" : "fts-alfresco",
+ "query" : "(PATH:'/app:company_home/st:sites/cm:odootest/cm:documentLibrary/cm:Factures_x0020_Justifs//*') AND (+adefpat:factureEndDate:['" + str(self.period_start) + "' TO '" + str(self.period_end) +"'] OR +adefpat:factureSartDate:['" + str(self.period_start) + "' TO '" + str(self.period_end) +"'])",
+ }
+ },
+ ]
+ }
+
+ js = json.dumps(virtual_json, indent=4)
+ prop = {
+ 'cmis:secondaryObjectTypeIds': ['P:adefpat:justificatif'],
+ }
+
+ backend = self.env['cmis.backend'].search([], limit=1)
+ json_file_cmis = self.env.user.company_id.proof_justif_cmis
+ repo = backend.get_cmis_repository().getObject(json_file_cmis)
+ try:
+ file = repo.createDocument(
+ name="justifs_factures_fournisseurs_"+ str(date.today()) +".json",
+ properties=prop,
+ contentFile=js,
+ contentType="application/json"
+ )
+ except Exception as e:
+ raise UserError(json.loads(e.details).get('message'))
+
+ @api.multi
+ def build_facture_client(self):
+
+ if self.type_convention_id:
+ virtual_json = {
+ "name":"Factures clients",
+ "nodes":[{
+ "id":"1",
+ "name":"Factures clients",
+ "description":"Factures clients",
+ "search":{
+ "language":"fts-alfresco",
+ "query":"(PATH:'/app:company_home/st:sites/cm:odootest/cm:documentLibrary/cm:Factures_x0020_clients_x0020_Justifs//*') AND (+adefpat:factureStartDate:['" + str(self.period_start) + "' TO '" + str(self.period_end) +"']) AND =adefpat:factureTypeConvention:'"+ self.type_convention_id.name +"'",
+ }
+ },
+ ]
+ }
+ else:
+ virtual_json = {
+ "name": "Factures clients",
+ "nodes": [{
+ "id": "1",
+ "name": "Factures clients",
+ "description": "Factures clients",
+ "search": {
+ "language": "fts-alfresco",
+ "query": "(PATH:'/app:company_home/st:sites/cm:odootest/cm:documentLibrary/cm:Factures_x0020_clients_x0020_Justifs//*') AND (+adefpat:factureStartDate:['" + str(
+ self.period_start) + "' TO '" + str(
+ self.period_end) + "'])",
+ }
+ },
+ ]
+ }
+
+ js = json.dumps(virtual_json, indent=4)
+ prop = {
+ 'cmis:secondaryObjectTypeIds': ['P:adefpat:justificatif'],
+ }
+
+ backend = self.env['cmis.backend'].search([], limit=1)
+ json_file_cmis = self.env.user.company_id.proof_justif_cmis
+ repo = backend.get_cmis_repository().getObject(json_file_cmis)
+ try:
+ file = repo.createDocument(
+ name="justifs_factures_clients_"+ str(date.today()) +".json",
+ properties=prop,
+ contentFile=js,
+ contentType="application/json"
+ )
+ except Exception as e:
+ raise UserError(json.loads(e.details).get('message'))
diff --git a/wizard/adefpat_project_justif_zip_wizard.xml b/wizard/adefpat_project_justif_zip_wizard.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d886017c0ce3474574fb6a3852a6964c25932956
--- /dev/null
+++ b/wizard/adefpat_project_justif_zip_wizard.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- Copyright 2022 Le Filament
+ License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
+<odoo>
+ <record id="adefpat_project_justif_zip_wizard_form" model="ir.ui.view">
+ <field name="name">adefpat.project.justif.zip.wizard.form</field>
+ <field name="model">adefpat.project.justif.zip.wizard</field>
+ <field name="arch" type="xml">
+ <form string="Génération des justifs ZIP">
+ <group>
+ <group>
+ <field name="period_start" />
+ <field name="period_end" />
+ <field name="type_convention_id" />
+ </group>
+ </group>
+ <footer>
+ <button
+ class="btn btn-sm btn-primary"
+ name="build_folder"
+ string="Justifs par dossier"
+ type="object"
+ />
+ <button
+ class="btn btn-sm btn-primary"
+ name="build_facture_fournisseur"
+ string="Justifs factures fournisseurs"
+ type="object"
+ />
+ <button
+ class="btn btn-sm btn-primary"
+ name="build_facture_client"
+ string="Justifs factures client"
+ type="object"
+ />
+ <button
+ class="btn btn-sm btn-default"
+ special="cancel"
+ string="Fermer"
+ />
+ </footer>
+ </form>
+ </field>
+ </record>
+
+ <record id="adefpat_project_justif_zip_action" model="ir.actions.act_window">
+ <field name="name">Génération des justifs ZIP</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">adefpat.project.justif.zip.wizard</field>
+ <field name="view_id" ref="adefpat_project_justif_zip_wizard_form" />
+ <field name="target">new</field>
+ </record>
+
+ <menuitem
+ id="adefpat_project.menu_generate_zip"
+ name="Génération des justifs ZIP"
+ parent="project.menu_project_report"
+ action="adefpat_project_justif_zip_action"
+ sequence="30"
+ />
+</odoo>
diff --git a/wizard/upload_file_wizard.py b/wizard/upload_file_wizard.py
index 9b63d288b6adccca2c7c3eac083666010bd6d7c3..f7eb67e462f90a7bf7c4112134b57de1993127d7 100644
--- a/wizard/upload_file_wizard.py
+++ b/wizard/upload_file_wizard.py
@@ -26,8 +26,15 @@ class UploadFileWizard(models.TransientModel):
Ajoute un fichier sur la GED Alfresco
@return: fonction get_partner_files() de res.partner
"""
- # Get proof folder nodeRef
- proof_folder = self.env.user.company_id.proof_cmis
+ if self.env.context["active_model"] == "account.invoice":
+ account_id = self.env["account.invoice"].browse(self.env.context["active_id"])
+ if account_id.type == "in_invoice":
+ proof_folder = self.env.user.company_id.proof_invoice_cmis
+ else:
+ proof_folder = self.env.user.company_id.proof_invoice_customer_cmis
+ else:
+ # Get proof folder nodeRef
+ proof_folder = self.env.user.company_id.proof_cmis
if not proof_folder:
raise UserError("Le dossier des justificatifs n'est pas configuré")
@@ -51,9 +58,14 @@ class UploadFileWizard(models.TransientModel):
print("--- (self.file) ---", str(self.file))
if not obj.proof_file:
try:
- filename = (fields.Date.to_string(obj.date).replace('-', '') +
+ if self.env.context["active_model"] == "account.invoice":
+ filename = (fields.Date.to_string(obj.date_invoice).replace('-', '') +
+ '-' + str(obj.id) + ' - ' + self.filename)
+ else:
+ filename = (fields.Date.to_string(obj.date).replace('-', '') +
'-' + str(obj.id) + ' - ' +
obj.employee_id.user_id.name + ' - ' + self.filename)
+
file = repo.createDocument(
name=filename,
properties=obj.get_file_properties(),