Skip to content
Extraits de code Groupes Projets
Valider 50cf7466 rédigé par Benjamin - Le Filament's avatar Benjamin - Le Filament
Parcourir les fichiers

Merge branch '12.0-lm' into '12.0'

12.0 lm

See merge request !1
parents 2f70478a e0f9130a
Aucune branche associée trouvée
Aucune étiquette associée trouvée
1 requête de fusion!112.0 lm
Affichage de
avec 383 ajouts et 69 suppressions
......@@ -3,32 +3,26 @@
:alt: License: AGPL-3
=========================
CG SCOP - Connecteur RIGA
=========================
=============================
CG SCOP - Connecteur Inovatic
=============================
Description
===========
Ce module permet de synchroniser les partenaires (organismes, sociétés, contacts...) Odoo et RIGA.
Ce module hérite le module **cgscop_liste_minitere** pour ajouter les fonctionnalités suivantes :
Il utilise l'API RIGA fournie par la CG SCOP pour créer, mettre à jour ou récupérer les informations présentes dans RIGA. Chaque objet à modifier est mis dans une file d'attente, catte file d'attente est traitée une fois par jour et permet de logguer l'état de traitement de chaque objet.
* Transmission des données de liasse depuis Alfresco vers l'API Inovatic
* Traitement de la réponse sur une adresse de callback
* Possibilité de chargement de la liasse via XML
Usage
=====
Pour configurer ce module, les données suivantes sont à renseigner dans le menu **Configuration > APIs CG Scop > RIGA > Configuration API** :
La configuration de la conneixon se trouve dans le menu **Configuration > APIs CG Scop > Inovatic > Configuration API** :
* *riga_login* : login de connexion à l'API
* *riga_password* : password de connexion à l'API
* *riga_url* : url de l'API
Les données suivantes sont présentes dans la table **ir.config.parameter** :
* *riga_max_try* : nombre max d'essais de connexion
* *riga_token* : token de connexion
* *riga_date_token* : date d'expiration du token de connexion
Il est également nécessaire de configurer la table de correspondance entre les champs Odoo et API Inovatic dans **Configuration > Inovatic > Table de correspondance** :
Credits
......
......@@ -2,3 +2,4 @@
from . import controllers
from . import models
from . import wizard
......@@ -7,13 +7,16 @@
"license": "AGPL-3",
"application": False,
"depends": [
# 'cgscop_liste_ministere',
'cgscop_liste_ministere',
'cmis',
],
"data": [
"security/ir.model.access.csv",
"wizard/load_xml_liasse.xml",
"views/inovatic_connection.xml",
"views/inovatic_field_matching.xml",
"views/inovatic_job_queue.xml",
"views/scop_liste_ministere.xml",
"datas/cron_inovatic.xml",
],
'installable': True,
......
# © 2020 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 datetime
from odoo import http
......@@ -9,26 +8,37 @@ from odoo.http import request
class InovaticController(http.Controller):
@http.route(['/get-liasse/<string:Token>'], type="json", auth="public", website=False, method=['POST'],
csrf=False)
def get_liasse(self, Token, **kwargs):
@http.route(
['/inovatic/auto/<string:token>'], type="json", methods=['POST'],
auth="none", csrf=False)
def inovatic_auto(self, token):
json = request.jsonrequest
job = request.env['inovatic.job.queue'].sudo().search([
("token", "=", Token)])
print(job)
("token", "=", token)])
if job:
if json:
try:
liasse = json.get('Liasses')[0]
job.liasse_fiscale_id.json_matching(liasse)
job.inovatic_liasse_id = liasse.get('LiasseId')
job.date_callback = datetime.now()
job.state = 'done'
job.log = kwargs
print(kwargs)
job.log = json
except Exception as err:
job.log = err.__str__()
job.date_callback = datetime.now()
job.state = 'error'
@http.route(['/get-liasse-manual/<string:Token>'], type="json", auth="public", website=False, method=['POST'],
csrf=False)
def get_liasse(self, Token, **kwargs):
@http.route(
['/inovatic/manual/<string:token>'], type="json", methods=['POST'],
auth="none", csrf=False, cors="*")
def inovatic_manual(self, token, **post):
json = request.jsonrequest
job = request.env['inovatic.job.queue'].sudo().search([
("token", "=", Token)])
print(job)
("token", "=", token)])
if job:
if json:
liasse = json.get('Liasses')[0]
job.inovatic_liasse_id = liasse.get('LiasseId')
job.date_callback = datetime.now()
job.state = 'manual'
job.log = kwargs
print(kwargs)
job.state = 'error'
......@@ -3,4 +3,7 @@
from . import inovatic_api
from . import inovatic_connection
from . import inovatic_field_matching
from . import inovatic_job_queue
from . import scop_liasse_fiscale
from . import scop_liste_ministere
......@@ -27,7 +27,6 @@ class APIInovatic(models.AbstractModel):
:param data: JSON datas
:return: API response.json
"""
_logger.info("Appel Inovatic : %s" % url)
inovatic_param = self.env['inovatic.connection'].sudo().search([
['active', '=', True]])
inovatic_url = inovatic_param.url
......@@ -35,6 +34,7 @@ class APIInovatic(models.AbstractModel):
'Ocp-Apim-Subscription-Key': inovatic_param.api_key,
}
query_url = inovatic_url + url
_logger.info("Appel Inovatic : %s" % query_url)
try:
if call_type == 'get':
response = requests.post(query_url, headers=headers)
......@@ -60,7 +60,7 @@ class APIInovatic(models.AbstractModel):
"- Message : %s" % (
response.url,
response.status_code,
message))
response.text))
return False
return response.json()
......@@ -91,5 +91,3 @@ class APIInovatic(models.AbstractModel):
url='/Inovaclic/Lab/External/extract/batch',
call_type='post',
data=datas)
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
class InovaticFieldMatching(models.Model):
_name = 'inovatic.field.matching'
_description = 'Correspondance champs Inovatic - Odoo'
name = fields.Char('Champ Inovatic')
odoo_field = fields.Char('Champ Odoo')
# ------------------------------------------------------
# Contraintes SQL
# ------------------------------------------------------
# Unicité la liasse fiscale
_sql_constraints = [
('name_unique',
'unique(name)',
"Ce champ est déjà présent dans la table de correspondance"),
]
\ No newline at end of file
......@@ -5,7 +5,7 @@ import random
import logging
import base64
from odoo import fields, models, api
from odoo import fields, models, api, exceptions
_logger = logging.getLogger(__name__)
......@@ -28,15 +28,16 @@ class InovaticJobQueue(models.Model):
_order = 'create_date desc'
liasse_fiscale_id = fields.Many2one(
comodel_name='res.partner',
comodel_name='scop.liasse.fiscale',
string='Liasse',
ondelete='set null',
required=True)
token = fields.Char('Token', compute="_compute_token")
token = fields.Char('Token', compute="_compute_token", store=True)
process_id = fields.Char('Process ID')
date_sync = fields.Datetime('Date envoi')
date_callback = fields.Datetime('Date callback')
log = fields.Text('Log')
inovatic_liasse_id = fields.Char('ID Inovatic')
state = fields.Selection(
selection=[
('waiting', 'En attente'),
......@@ -71,32 +72,55 @@ class InovaticJobQueue(models.Model):
@api.multi
def inovatic_sync(self):
"""
Méthode permettant de synchroniser une liasse fiscale
Méthode permettant de transmettre une liasse fiscale
:return: None
"""
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
for liasse in self:
file = liasse._get_cmis_file()
stream = file.getContentStream()
val = stream.read()
liasse_year = fields.Date.to_string(
self.liasse_fiscale_id.partner_id.first_closeout.replace(
year=int(self.liasse_fiscale_id.year)))
data = {
"callbackCompleted": base_url + "/get-liasse/" + self.token,
"callbackManual": base_url + "/get-liasse-manual/" + self.token,
"callbackCompleted": base_url + "/inovatic/auto/" + self.token,
"callbackManual": base_url + "/inovatic/manual/" + self.token,
"files": [{
"fileName": file.name,
"externalId": self.liasse_fiscale_id.id,
"data": base64.b64decode(stream.read()).decode()
,
"cloture": "2017-12-31T00:00:00Z",
"siren": 'self.liasse_fiscale_id.partner_id.siren'
"data": base64.b64encode(stream.read()).decode('ascii'),
"cloture": liasse_year,
"siren": self.liasse_fiscale_id.partner_id.siren
}]
}
result = liasse.extract_batch(data)
if result:
print(result)
self.state = 'in_process'
self.date_sync = fields.Datetime.now()
self.process_id = result.get('processId')
_logger.info(result)
liasse.state = 'in_process'
liasse.date_sync = fields.Datetime.now()
liasse.process_id = result.get('processId')
@api.multi
def inovatic_get_liasse(self):
"""
Méthode permettant de récupérer les informations par liasseID
:return: None
"""
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
for job in self:
json = job.get_liasses_data(job.inovatic_liasse_id)
if json:
try:
liasse = json.get('liasses')[0]
job.liasse_fiscale_id.json_matching(liasse)
job.inovatic_liasse_id = liasse.get('liasseId')
job.date_callback = fields.Datetime.now()
job.state = 'done'
job.log = json.dumps(liasse)
except Exception as err:
job.log = err.__str__()
job.date_callback = fields.Datetime.now()
job.state = 'error'
# ------------------------------------------------------
# Internal function
......@@ -105,17 +129,18 @@ class InovaticJobQueue(models.Model):
backend = self.env['cmis.backend'].search([])
backend.ensure_one()
cmis_client = backend.get_cmis_client()
doc = cmis_client.getDefaultRepository().query("""
SELECT * FROM cmis:document
WHERE cmis:name='InovaticLFI.pdf'""")
# TODO: suppr section précédente + uncomment section
# doc = cmis_client.query(("""
# SELECT * FROM crm:document as d
# JOIN crm:organisme as o ON d.cmis:objectId = o.cmis:objectId
# WHERE d.cmis:name='Liasse fiscale.pdf'
# AND d.crm:periode = %s
# AND o.crm:id = %s'""",
# (self.liasse_fiscale_id.year, str(self.liasse_fiscale_id.partner_id.id))))
query = ("""
SELECT * FROM crm:document as d
JOIN crm:organisme as o ON d.cmis:objectId = o.cmis:objectId
WHERE d.crm:type='LFI'
AND d.crm:annee = '%s'
AND d.crm:contexte = 'LM'
AND o.crm:id = '%s'""" % (
self.liasse_fiscale_id.year, str(self.liasse_fiscale_id.partner_id.id)))
doc = cmis_client.getDefaultRepository().query(query)
if not doc:
raise exceptions.Warning(
"Il n'y a pas de fichier dans Alfresco pour cette liasse")
return doc[0]
# ------------------------------------------------------
......
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import base64
import xml.etree.ElementTree as ET
from odoo import fields, models, api
class ScopLiasseFiscaleInovatic(models.Model):
_inherit = 'scop.liasse.fiscale'
def json_matching(self, json):
"""
Intègre les datas renvoyées par Inovatic dans Odoo
:param json: objet liasse fiscale du callback
:return:
"""
vals = {
'dureeExercice': json.get('DureeInMonths', 0),
'L2050_DCLO': json.get('ClosingDate', None)
}
MatchTable = self.env['inovatic.field.matching']
for key, value in json.get('DecimalCells').items():
odoo_field = MatchTable.search([('name', '=', key)]).odoo_field
if odoo_field:
vals[odoo_field] = value
self.write(vals)
def parse_xml_liasse(self, file):
"""
Parse les XML Inovatic en JSON au fmême format que celui
renvoyé par l'API pour taitement par la fonction json_matching
:param file: base64 file
:return: dict au format API Inovatic
"""
content = base64.b64decode(file).decode('UTF-8')
tree = ET.fromstring(content)
vals = {}
vals['Siren'] = tree[0][0].text
vals['CompanyName'] = tree[0][1].text
bilan = tree[0][2][0]
vals['LiasseProfil'] = bilan.attrib.get('liasse')
vals['ClosingDate'] = bilan.attrib.get('date')
vals['DureeInMonths'] = int(bilan.attrib.get('duration'))
vals['DecimalCells'] = {}
for child in bilan:
vals['DecimalCells'][child.attrib.get('code')] = int(child.text)
return vals
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, exceptions
class ListeMinistereInovatic(models.Model):
_inherit = 'liste.ministere'
last_job_queue = fields.Many2one(
comodel_name='inovatic.job.queue',
string='Inovatic Job queue'
)
last_job_queue_state = fields.Selection(related='last_job_queue.state')
last_job_queue_date_sync = fields.Datetime(related='last_job_queue.date_sync')
# ------------------------------------------------------
# BUTTON functions
# ------------------------------------------------------
def inovatic_treatment(self):
liasse_id = self.create_liasse_fiscale()
backend = self.env['cmis.backend'].search([])
backend.ensure_one()
cmis_client = backend.get_cmis_client()
query = ("""
SELECT * FROM crm:document as d
JOIN crm:organisme as o ON d.cmis:objectId = o.cmis:objectId
WHERE d.crm:type='LFI'
AND d.crm:contexte = 'LM'
AND d.crm:annee = '%s'
AND o.crm:id = '%s'""" % (
str(self.year), str(self.partner_id.id)))
doc = cmis_client.getDefaultRepository().query(query)
if doc:
job_queue = self.env['inovatic.job.queue'].create({
'liasse_fiscale_id': liasse_id.id
})
self.write({
'last_job_queue': job_queue.id
})
else:
raise exceptions.Warning(
"Il n'y a pas de Liasse correspondante dans Alfresco")
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_inovatic_job_queue,access_inovatic_job_queue,model_inovatic_job_queue,base.group_user,1,1,1,1
access_inovatic_connection,access_inovatic_connection,model_inovatic_connection,base.group_user,1,1,1,1
access_inovatic_field_matching,access_inovatic_field_matching,model_inovatic_field_matching,base.group_user,1,1,1,1
......@@ -67,8 +67,13 @@
name="Inovatic"
parent="base.menu_administration"/>
<menuitem id="cgscop_inovatic_connection_menu"
<menuitem id="inovatic_config_menu"
name="Configuration"
parent="cgscop_inovatic.inovatic_root_menu"
sequence="90"/>
<menuitem id="cgscop_inovatic_connection_menu"
parent="cgscop_inovatic.inovatic_config_menu"
action="action_view_inovatic_connection"
sequence="90"/>
</data>
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="inovatic_field_matching_tree_view" model="ir.ui.view">
<field name="name">inovatic.field.matching.tree</field>
<field name="model">inovatic.field.matching</field>
<field name="arch" type="xml">
<tree string="Correspondance Inovatic - Odoo">
<field name="name"/>
<field name="odoo_field"/>
</tree>
</field>
</record>
<record id="inovatic_field_matching_search_view" model="ir.ui.view">
<field name="name">inovatic.field.matching.search</field>
<field name="model">inovatic.field.matching</field>
<field name="arch" type="xml">
<search string="Correspondance Inovatic - Odoo">
<field name="name"/>
<field name="odoo_field"/>
</search>
</field>
</record>
<record id="inovatic_field_matching_act_window" model="ir.actions.act_window">
<field name="name">Correspondance Inovatic - Odoo</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">inovatic.field.matching</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="inovatic_field_matching_menu"
parent="cgscop_inovatic.inovatic_config_menu"
action="inovatic_field_matching_act_window"
sequence="90"/>
</data>
</odoo>
\ No newline at end of file
......@@ -49,6 +49,7 @@
<form string="Traitement Inovatic">
<header>
<button name="inovatic_sync" type="object" string="Envoyer vers Inovatic" ></button>
<button name="inovatic_get_liasse" type="object" string="Recharger résultats" attrs="{'invisible': [('inovatic_liasse_id', '=', False)]}"></button>
</header>
<sheet>
<group>
......@@ -62,6 +63,7 @@
<field name="date_callback" readonly="1" />
<field name="token" readonly="1" />
<field name="process_id" readonly="1" />
<field name="inovatic_liasse_id" readonly="1" />
</group>
</group>
<group>
......@@ -78,9 +80,13 @@
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_inovatic_log"
parent="cgscop_inovatic.inovatic_root_menu"
name="Logs"
sequence="10"/>
<menuitem id="menu_inovatic_job_queue"
parent="cgscop_inovatic.inovatic_root_menu"
parent="cgscop_inovatic.menu_inovatic_log"
action="action_view_inovatic_job_queue_tree"
name="Logs Inovatic"
sequence="90"/>
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="liste_ministere_form_inherit" model="ir.ui.view">
<field name="name">liste.ministere.form.inovatic</field>
<field name="model">liste.ministere</field>
<field name="inherit_id" ref="cgscop_liste_ministere.view_liste_ministere_form"/>
<field name="priority" eval="8"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='saisir_liasse_fiscale']" position="after">
<button string="Saisie automatique Inovatic" name="inovatic_treatment" type="object" class="oe_highlight m-3" attrs="{'invisible':[('status_liasse_fiscale', '=', 'valide')]}"/>
<button string="Charger un XML" name="%(cgscop_inovatic.load_xml_liasse_act_window)d" type="action" class="m-3" attrs="{'invisible':[('status_liasse_fiscale', '=', 'valide')]}"/>
<field name="last_job_queue" invisible="1"/>
<div class="col-12" attrs="{'invisible': [('last_job_queue', '=', False)]}">
<p class="alert alert-danger" attrs="{'invisible': [('last_job_queue_state', '!=', 'error')]}" role="alert">
Erreur de synchronisation Inovatic. Envoyé le <field name="last_job_queue_date_sync"/>. Statut : <field name="last_job_queue_state"/> | (log : <field name="last_job_queue"/>)
</p>
<p class="text-success" attrs="{'invisible': [('last_job_queue_state', '!=', 'done')]}">
Synchronisation Inovatic du <field name="last_job_queue_date_sync"/> OK. Statut : <field name="last_job_queue_state"/>
</p>
<p class="text-info" attrs="{'invisible': [('last_job_queue_state', 'not in', ('waiting', 'in_process', 'manual'))]}">
Synchronisation Inovatic envoyée le <field name="last_job_queue_date_sync"/>. Statut : <field name="last_job_queue_state"/>
</p>
</div>
</xpath>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import load_xml_liasse
# © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models, api
from odoo.tools.mimetypes import guess_mimetype
class LoadXmlLiasseWizard(models.TransientModel):
_name = 'load.xml.liasse'
_description = 'Load XML Liasse Wizard'
_rec_name = 'liasse_id'
@api.model
def _default_lm_id(self):
return self.env.context.get('active_id')
@api.model
def _default_liasse_id(self):
lm = self.env.context.get('active_id')
return self.env['scop.liasse.fiscale'].search([
('liste_ministere_id', '=', lm)]).id
lm_id = fields.Many2one(
comodel_name='liste.ministere',
string='Liste Ministere',
default=_default_lm_id)
liasse_id = fields.Many2one(
comodel_name='scop.liasse.fiscale',
string='Liasse Fiscale',
default=_default_liasse_id)
file = fields.Binary('Fichier')
filename = fields.Char('Nom')
@api.multi
def load_liasse(self):
"""
Charge les valeurs du XML de la liasse dans l'objet
:return:
"""
this = self
if not self.liasse_id:
self.liasse_id = self.lm_id.create_liasse_fiscale()
data = self.liasse_id.parse_xml_liasse(self.file)
return self.liasse_id.json_matching(data)
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- FORM View-->
<record id="load_xml_liasse_form_view" model="ir.ui.view">
<field name="name">load.xml.liasse.form</field>
<field name="model">load.xml.liasse</field>
<field name="arch" type="xml">
<form string="Charger une Liasse">
<group name="infos">
<field name="liasse_id" readonly="1" />
</group>
<group>
<field name="filename" invisible="1"/>
<field name="file" filename="filename" required="1"/>
</group>
<footer>
<button class="btn btn-sm btn-primary" name="load_liasse" string="Cherger une liasse XML" type="object" confirm="Êtes-vous sûr(e) de vouloir charger ce fichier ?"/>
<button class="btn btn-sm btn-default" special="cancel" string="Fermer"/>
</footer>
</form>
</field>
</record>
<!--ACTION view-->
<record id="load_xml_liasse_act_window" model="ir.actions.act_window">
<field name="name">Charger une Liasse XML</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">load.xml.liasse</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>
\ No newline at end of file
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter