PC SOFT

PROFESSIONAL NEWSGROUPS
WINDEVWEBDEV and WINDEV Mobile

Home → WINDEV 2024 → Windev et Odoo
Windev et Odoo
Started by Vincent DUBREIL, Feb., 17 2020 10:10 AM - 10 replies
Posted on February, 17 2020 - 10:10 AM
Bonjour à tous,

j'essaye actuellement de connecter un projet windev (ou webdev) à une base postgresql Odoo hébergée sur Odoo.sh

Est-ce quelqu'un a déjà fait cela et si oui, par quel moyen ? :(

J'ai trouvé dans la LST 112, un code permettant d'exploiter via Windev, du code python qui va utiliser l'API odoo pour interroger la base. Après un test, cela marche, mais j'aurais préféré trouver un moyen plus direct afin de ne pas avoir à écrire du python.

Par moyen direct, j'entends soit de pouvoir envoyer des requêtes SQL par exemples et en récupérer le résultat ou à défaut, de générer moi-même le XML à utiliser avec du HTTPRequete mais pas moyen de trouver la syntaxe du XML attendu par Odoo.

Si vous avez des infos, d'autres idées qui pourraient m'aider, car voilà plus d'une semaine que je cherche et toujours rien. ;(

Merci de m'avoir lu :merci:

Bonne journée et bonne semaine 8)

Vincent
Registered member
449 messages
Popularité : +31 (43 votes)
Posted on February, 17 2020 - 12:15 PM
Bonjour

J'avais écrit une réponse à ce sujet voici le lien : https://forum.pcsoft.fr/fr-FR/pcsoft.fr.windevmobile/37831-connect-directement-erp-odoo-postgressql-avec-windev-mobile/read.awp…

vous y trouverez un exemple de connection de windev à odoo et ma procedure call qui permet d'interroger une API et de récupérer le résultat en json

Par contre il va vous falloir vous mettre à python pour pouvoir faire communiquer votre application windev avec la base de donnée postgres.

Je vous rajoute en code ci dessous un exemple d'appel dans windev et une api ecrit en python dans odoo

Dans la procédure ci dessous j'appelle odoo:call vous trouverez la procédure dans le lien au dessus

**************************************************************************************************************************
code windev d'appel de l'api dans odoo
//procedure qui permet de recuperer la cadence en fonction d'un poste et de pouvoir l'appliquer aux écrans atelier
// on transmet donc un numéro de poste et la procedure rempli des membre de la classe CvarGlobal
Procedure Recuperation_cadence(sPoste_Atelier est une chaîne) <métier>
odoo:var = Null
odoo:var.filtre = "('name','=','"+ SansEspace(sPoste_Atelier) +"'),"
SI odoo:call("wpa.posteateliers","api_v1_wpa_posteateliers_cadence_get") ALORS
VarGlobal:__Cadence = odoo:res_data[1].cadence
VarGlobal:__Nbr_Cadence_Default = odoo:res_data[1].nb_cadence_default
VarGlobal:__Nbre_Cadence = odoo:res_data[1].nb_cadence
RENVOYER Vrai
SINON
RENVOYER Faux
FIN



*****************************************************************************************************
code dans odoo en langage python
# -*- coding: utf-8 -*-

import odoo
from odoo import tools, models, fields, api, _
from datetime import date, time, datetime
import base64
import json
import encodings

class wpa_posteateliers(models.Model):
_name = 'wpa.posteateliers'
_inherit = 'wpa.posteateliers'
_model = 'wpa.posteateliers'
_description = 'Package header'

#API qui permet de renvoyer juste les informations de cadence en fonction d'un poste envoyer en valeur de filtre en amont
@api.model
def api_v1_wpa_posteateliers_cadence_get(self, company_id, var):
data = []
filter = []

filter = [('company_id', '=', company_id)]
if var != None:
if 'filtre' in var:
filter += eval(var['filtre'])
posteateliers = self.env['wpa.posteateliers'].search(filter)
for element in posteateliers:
dict = {}
dict['cadence'] = element.cadence
dict['nb_cadence'] = element.nb_cadence
dict['nb_cadence_default'] = element.nb_cadence_default

data.append(dict)

if data:
return json.dumps(data)

return False

J'espère que cela vous aidera

Bon courage

Cordialement
DG
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 18 2020 - 3:33 PM
Bonjour DG,

Merci pour ton retour, je vais regarde cela de plus près.

Par contre, de ce que j'ai pu lire à droite à gauche, le fait de ne pas utiliser l'API propriétaire d'Odoo, on risque quelques incohérences dans la base car , en passant par leur API, le fait d'écrire dans la table A, ne va pas forcément faire qu'écrire dans la table A
Par exemple, si tu écris un enregistrement dans la table sale.order, cela va automatiquement écrire dans la table des messages pour tracer l'historique.
Cet exemple n'est pas le plus embêtant mais, à moins de connaître toutes ces subtilités, ne risque-t'on pas au final de passer à côté de certaines choses ?

Vincent

--
______________________________________
Vincent DUBREIL
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 18 2020 - 3:40 PM
DG,

J'en profite pour te demander si tu n'avais pas déjà essayé de te connecter à odoo.sh via un tunnel SSH afin de passer des requêtes directement sur la base (pour faire des select par exemple) ?

--
______________________________________
Vincent DUBREIL
Registered member
449 messages
Popularité : +31 (43 votes)
Posted on February, 18 2020 - 5:22 PM
Vincent DUBREIL a écrit :
Bonjour DG,

Merci pour ton retour, je vais regarde cela de plus près.

Par contre, de ce que j'ai pu lire à droite à gauche, le fait de ne pas utiliser l'API propriétaire d'Odoo, on risque quelques incohérences dans la base car , en passant par leur API, le fait d'écrire dans la table A, ne va pas forcément faire qu'écrire dans la table A
Par exemple, si tu écris un enregistrement dans la table sale.order, cela va automatiquement écrire dans la table des messages pour tracer l'historique.
Cet exemple n'est pas le plus embêtant mais, à moins de connaître toutes ces subtilités, ne risque-t'on pas au final de passer à côté de certaines choses ?

Vincent

--
______________________________________
Vincent DUBREIL



Franchement cela fait à peu près 2 ans que nous sommes passez sur odoo, on travail avec une société qui s'appelle "sudokeys", qui elle s'occupe de mettre à jour les module compta et nous à former au développement sur odoo.
Par contre pour le reste on écrit nous même nos api pour faire communiquer notre logiciel de prod avec les bases de odoo et on a pas de souci d’incohérence.

Sinon, je n'ai pas tester le tunnel ssh, pour les requêtes, on écrit une api, notre logiciel de prod(en windev) appel l'api , l'api nous retourne un résultat en json que je traite.

Au cas ou voici un exemple d'api avec requête :

#===================================================================================================
#API requete pour compter....
@api.model
def api_v1_wpa_tracking_distinct_counter(self, company_id, var):

if var is None: return False

data = []
sql = "SELECT DISTINCT wpa_tracking.post_workshop, wpa_posteateliers.description, wpa_tracking.user_login "
sql = sql + "FROM wpa_tracking, wpa_posteateliers "
sql = sql + "WHERE wpa_tracking.company_id = %i AND " %(company_id)
sql = sql + "wpa_posteateliers.name = wpa_tracking.post_workshop AND "
if 'production' in var:
sql = sql + "wpa_posteateliers.production IN (%s) AND " %(var['production'])
sql = sql + "wpa_posteateliers.company_id = wpa_tracking.company_id AND "
sql = sql + "wpa_tracking.date_scan BETWEEN '%s' and '%s' AND " %(var['date_scan_begin'],var['date_scan_end'])
sql = sql + "wpa_tracking.archive = False "
sql = sql + "order by wpa_tracking.post_workshop,wpa_tracking.user_login"

self.env.cr.execute(sql)
resultreq = self.env.cr.fetchall()

for post_workshop,description,user_login in resultreq:
dict = {}
dict['post_workshop'] = post_workshop
dict['description'] = description
dict['user_login'] = user_login

data.append(dict)

if data:
return json.dumps(data)

return False


Cordialement

DImitri
Message modified, February, 18 2020 - 5:25 PM
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 19 2020 - 8:42 AM
Bonjour Dimitri,

ok bien noté cela me rassure pour les incohérences.
Merci pour tous ces éléments qui devrait bien m'aider :merci:

Bonne journée 8)

--
______________________________________
Vincent DUBREIL
Registered member
449 messages
Popularité : +31 (43 votes)
Posted on February, 19 2020 - 10:04 AM
Bonjour Vincent

N’hésitez pas si vous avez d'autres questions je reste abonné à ce post au cas où.

Bonne journée également

cdlt

Dimitri
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 19 2020 - 2:31 PM
Justement j'allais te poser une autre question

J'essaye plusieurs solutions en parallèle avant de décider laquelle sera retenue.
J'étais à essayer l'exemple WD Python de la LST 112

J'ai codé en python la fonction de lecture qui fait un read et doit renvoyer la liste des données (n champs de n enregistrements)
Dans le code de l'exemple windev, on récupère la réponse en spécifiant le type en retour (entier, etc...)
Pour ce cas, j'utilise un type dédié wlPythonObject qui est déclaré dans une classe rattachée au projet.

Sais-tu comment on peut ensuite lire ce genre de variable pour en récupérer les différents élements (par exemple client 1 (nom, prénom, tel), Client 2 (nom, prénom, tel),....) ?

Je te mets un bout de code si c'est plus parlant











--
______________________________________
Vincent DUBREIL
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 19 2020 - 2:58 PM
Dimitri,

C'est bon j'ai trouvé, il y avait bien une procédure dans la classe pour faire cela, j'étais passé trop vite!!! :)

--
______________________________________
Vincent DUBREIL
Registered member
67 messages
Popularité : +1 (1 vote)
Posted on February, 20 2020 - 4:19 PM
Bonjour Dimitri,

J'ai à nouveau besoin de tes lumières

J'ai une fonction python "read_data" (celle que tu peux voir dans mon post au-dessus) à laquelle je passe un filtre tel que [[('name','=','toto')]]
Ça marche bien si je passe ce filtre en paramètre depuis une autre fonction python
Par contre si je veux appeler directement cette fonction depuis Windev, je n'arrive pas à passer le paramètre car ce n'est pas juste une chaine ou un numérique.
Sais-tu comment passer ce genre de paramètre ?

Cordialement

--
______________________________________
Vincent DUBREIL
Registered member
449 messages
Popularité : +31 (43 votes)
Posted on February, 20 2020 - 5:12 PM
Bonjour vincent

mon passage de paramètre je le fais comme ceci lors de l'appel de ma procedure call le filtre est traité à la ligne => :demande_request.params.args[2] = :var

EXEMPLE de filtre odoo
Procedure Supprimer_tracking(nNum_Indice est un entier) <métier>

odoo:var = Null
odoo:var.filtre = "('id','=','" + nNum_Indice + "'),"

SI odoo:call("wpa.tracking","api_v1_wpa_tracking_delete") ALORS
RENVOYER Vrai
SINON
RENVOYER Faux
FIN




Ma procedure call
Procedure call(p_model="",p_method="" )

SI :IDFichier<>-1 ALORS
ChronoDébut()
FIN

:MaRequeteRequest..ContentType = typeMimeJSON

:MaRequeteRequest..Entête["Cookie"] = :cReponseRequest.Entête["Set-Cookie"]
:MaRequeteRequest..URL = "http://"+:p_ipserveur+"/web/dataset/call_kw"
:MaRequeteRequest..DuréeNonRéponse = :p_timeout
:demande_request.jsonrpc = "2.0"
:demande_request.method = "call"

SI p_model<>"" ALORS :demande_request.params.model = p_model
SI p_model<>"" ALORS :demande_request.params.method = p_method

:demande_request.params.context.lang = :result_connexion.user_context.lang
:demande_request.params.context.tz = :result_connexion.user_context.tz
:demande_request.params.context.uid = :result_connexion.user_context.uid

:demande_request.params.kwargs.tmp = ""
SupprimeTout(:demande_request.params.kwargs..Membre)

:demande_request.params.args[1] = :result_connexion.Company_id
:demande_request.params.args[2] = :var

:MaRequeteRequest.Contenu = :demande_request..FormatJSON
cMaReponsedata est un restRéponse = RESTEnvoie(:MaRequeteRequest)

SI ErreurDétectée ALORS
Erreur(ErreurInfo(errComplet))
SINON

SI cMaReponsedata..CodeEtat<>200 ALORS
// Trace("Erreur HTTP "+cMaReponsedata.CodeEtat)
// Trace("Erreur HTTP description "+cMaReponsedata.DescriptionCodeEtat)
Erreur("Erreur HTTP "+cMaReponsedata.CodeEtat,AnsiVersUnicode(cMaReponsedata..Contenu))
// Trace("Envoyé : "+AnsiVersUnicode(:MaRequeteRequest.Contenu))
RENVOYER Faux
SINON
// trace(cMaReponsedata..Contenu)
:res_data = cMaReponsedata..Contenu
SI :res_data.RESULT = Faux ALORS RENVOYER False
:res_data = :res_data.RESULT


SI :IDFichier<>-1 ALORS

DureeMaFonction = ChronoFin()
:log_write(DuréeVersChaîne(DureeMaFonction,"HH-MM-SS-LLL")+";"+p_model+";"+NetAdresseIP+";"+p_method)

FIN



RENVOYER Vrai
FIN
FIN


J'espère que cela t'aidera

Cordialement

Dimitri