Intégration sur l'API d'un module fait maison

Bonjour,

Je suis en train de créer un module Dolibarr (en utilisant le Générateur de Module et Application) pour un client permettant de lier des données de leur Dolibarr avec leur site PrestaShop.
Je souhaite ajouter mon module sur l’API afin de pouvoir y effectuer des actions (Exemple : Création, récupération de données, etc.).
J’ai découvert qu’il était possible via l’onglet « Object » du Générateur de Module de générer automatiquement la classe PHP de l’API, ce que j’ai effectué.
Je suis donc sur « Dolibarr REST API Explorer », je teste la méthode de création de mon module mais malheureusement cela ne fonctionne pas. Voici l’erreur retournée par la méthode :

{
  "error": {
    "code": 401,
    "message": "Unauthorized"
  },
  "debug": {
    "source": "api_synchrop.class.php:197 at call stage",
    "stages": {
      "success": [
        "get",
        "route",
        "negotiate",
        "authenticate",
        "validate"
      ],
      "failure": [
        "call",
        "message"
      ]
    }
  }
}

Pour information, voici le code concerné par l’erreur :

/**
	 * Create synchrof object
	 *
	 * @param array $request_data   Request datas
	 * @return int  ID of synchrof
	 *
	 * @throws RestException
	 *
	 * @url	POST synchrof/
	 */
	public function post($request_data = null)
	{
		if (!DolibarrApiAccess::$user->rights->synchrop->write) {
			throw new RestException(401);
		}
		// Check mandatory fields
		$result = $this->_validate($request_data);

		foreach ($request_data as $field => $value) {
			$this->synchrof->$field = $value;
		}
		if (!$this->synchrof->create(DolibarrApiAccess::$user)) {
			throw new RestException(500, "Error creating SynchroF", array_merge(array($this->synchrof->error), $this->synchrof->errors));
		}
		return $this->synchrof->id;
	}

La ligne 197, correspond à :
if (!DolibarrApiAccess::$user->rights->synchrop->write) { throw new RestException(401); }

Avez-vous une idée pour résoudre ce problème ?
J’ai besoin de vous, car je désespère !

Bonsoir,
et sinon ça n’existerait pas déjà ?

https://www.dolistore.com/fr/recherche?controller=search&orderby=position&orderway=desc&tag=&search_query=prestashop&submit_search=

parfois pour quelques (centaines) d’euros ça ne vaut pas trop le coup de réinventer la roue …

Bonjour @erics,
Merci pour votre réponse.
En effet un module existe déjà, mon client l’utilise déjà mais pour des raisons personnelles, ils souhaitent que le partage de certaines données soit effectuées d’une autre manière.
Bien cordialement.

Ok,
pour votre problème c’est une question de droits d’accès, la clé d’API que vous utilisez est liée à un utilisateur dolibarr. Cet utilisateur doit avoir les droits « synchrop->write » pour pouvoir accéder à la ressource demandée.

Vérifiez donc bien dans dolibarr / gestion des utilisateurs / droits que ce droit est bien associé pour cet utilisateur …

Bonjour @erics

Merci pour votre aide, en effet c’était un problème de droit d’accès.

Ce problème résolu, j’ai voulu tester de supprimer un élément grâce à la méthode « delete » de mon module (toujours en testant grâce au REST API Explorer).
La requête est la suivante : (8 = Id de la ligne à supprimer)

https://[LIEN_SITE]/api/index.php/synchropapi/synchrof/8

La réponse retournée est la suivante :

{
  "error": {
    "code": 401,
    "message": "Unauthorized: Access to instance id=8 of object not allowed for login XXX"
  },
  "debug": {
    "source": "api_synchrop.class.php:273 at call stage",
    "stages": {
      "success": [
        "get",
        "route",
        "negotiate",
        "authenticate",
        "validate"
      ],
      "failure": [
        "call",
        "message"
      ]
    }
  }
}

Pourtant l’utilisateur possède bien tous les accès à ce module (read, write et delete).
La ligne 273 correspond à :

if (!DolibarrApi::_checkAccessToResource('synchrof', $this->synchrof->id, 'synchrop_synchrof')) {
			throw new RestException(401, 'Access to instance id='.$this->synchrof->id.' of object not allowed for login '.DolibarrApiAccess::$user->login);
		}

Après avoir passé une partie de l’après-midi hier à chercher une solution qui n’est toujours pas trouvée, j’ai besoin de votre aide !

Merci par avance.

Le message laisse suggérer que le login utilisé n’a pas le droit d’accéder à l’objet en question …

Unauthorized: Access to instance id=8 of object not allowed for login XXX

Dans dolibarr - hors API - est-ce que votre utilisateur a le droit d’aller supprimer cet objet ? par exemple si c’est une facture est-ce que avec mon compte XXX je peux aller sur la facture id=8 et cliquer sur le bouton supprimer ?

@erics

En effet lorsque je vais sur la fiche de la ligne que je souhaite supprimer et que je clique sur le bouton supprimer, voici ce qu’il me retourne :

Identifier name ‹ llx_synchrop_synchrof_extrafields › is too long

Cette table n’est pas créée, elle ne m’est pas utile.

Voici le code de la fonction delete de la class de mon object :

/**
	 * Delete object in database
	 *
	 * @param User $user       User that deletes
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
	 * @return int             <0 if KO, >0 if OK
	 */
	public function delete(User $user, $notrigger = false)
	{
		return $this->deleteCommon($user, $notrigger);
		//return $this->deleteCommon($user, $notrigger, 1);
	}

Avez-vous une idée pour retirer l’appel à cette table qui ne sert à rien dans mon cas ?
Merci par avance !

Une petite recherche « llx_synchrop_synchrof_extrafields » sur l’ensemble du code de votre plugin devrait donner qqchose … reste à voir ensuite comment s’en dépatouiller.

Je suis surpris par le double « synchrop » « synchrop » …

Et sinon via le module builder il est normalement possible de supprimer les tables / champs extrafields pour l’objet souhaité … et en complément de désactiver les extrafields pour un objet (voir la définition de la l’objet/classe) (tips: extrafields managed)

J’ai modifié le code de la fonction « delete » de ma class comme ceci :

/**
	 * Delete object in database
	 *
	 * @param User $user       User that deletes
	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
	 * @return int             <0 if KO, >0 if OK
	 */
	public function delete(User $user, $notrigger = false)
	{
		global $conf, $langs;
		include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';

		$error = 0;

		// Check parameters
		if (empty($this->id)) {
			$this->error = "Object must be fetched before calling delete";
			return -1;
		}
		if (empty($user->rights->synchrop->synchrof->delete)) {
			$this->error = "ErrorForbidden";
			return 0;
		}

		// $objectisused = $this->isObjectUsed($this->id);
		$objectisused = "";
		if (empty($objectisused)) {
			$this->db->begin();

			// Delete product
			if (!$error) {
				$sqlz = "DELETE FROM ".MAIN_DB_PREFIX."synchrop_synchrof";
				$sqlz .= " WHERE rowid = ".(int) $this->id;
				
				$resultz = $this->db->query($sqlz);
				
				if (!$resultz) {
					$error++;
					$this->errors[] = $this->db->lasterror();
				}
			}
			
			if (!$error) {
				$this->db->commit();
				return 1;
			} else {
				foreach ($this->errors as $errmsg)
				{
					dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
					$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
				}
				$this->db->rollback();
				return -$error;
			}
		} else {
			$this->error = "ErrorRecordIsUsedCantDelete";
			return 0;
		}
	}

Sur Dolibarr lorsque je suis sur le listing, je coche l’élément que je souhaite supprimer, je confirme la suppression et cela fonctionne !
Par contre lorsque je suis sur la fiche de l’élément que je souhaite supprimer, je clique sur le bouton « Supprimer », cela me retourne bien 1 mais la fonction suivante ne me renvoie pas sur la page du listing.

// Delete a product
	if ($action == 'confirm_delete' && $confirm != 'yes') { $action = ''; }

	if ($action == 'confirm_delete' && $confirm == 'yes'/* && $usercandelete*/)
	{
		$object = new SynchronisationFournisseur($db);
		$object->fetch($id);
		$result = $object->delete($user);
		// echo $result;
		if ($result > 0)
		{ 
			header('Location: '.DOL_URL_ROOT.'custom/synchronisationprestashop/Synchronisationprestashop_fournisseurList.php');
			exit;
		} else {
			setEventMessages($langs->trans($object->error), null, 'errors');
			$reload = 0;
			$action = '';
		}
	}

Je ne comprends vraiment pas pourquoi !
une idée ?

Bonjour @erics

Après réflexion, la partie suppression n’est pas urgente voir même inutile, je mets donc cela en suspend pour le moment.

Pour mon module, j’ai ajouté une nouvelle table, un nouveau objet nommé synchronisationprestashop et une classe correspondante.

Je suis en train d’ajouter des fonctions sur l’API de mon module dont l’ajout de donnée.
Lorsque je teste cette méthode, cela me retourne une erreur 500 et je ne comprends pas d’où cela peux provenir.
Avez-vous une idée ?

Erreur 500 c’est « fatal » donc direction error.log si vous avez votre dolibarr sur un apache.

Bonjour tout le monde,
J’ai repris le code de A à Z concernant la class API de mon module et cela à résolu mon erreur 500.
Merci en tout cas @erics pour votre aide.

1 « J'aime »