diff --git a/htdocs/webservices/demo_wsclient_project.php-NORUN b/htdocs/webservices/demo_wsclient_project.php-NORUN
new file mode 100644
index 0000000000000000000000000000000000000000..ef39673976dcf23aba78debe4a7d5135da1d5b85
--- /dev/null
+++ b/htdocs/webservices/demo_wsclient_project.php-NORUN
@@ -0,0 +1,154 @@
+<?php
+/* Copyright (C) 2006-2010 Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2016 Ion Agorria <ion@agorria.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file htdocs/webservices/demo_wsclient_project.php
+ * \brief Demo page to make a client call to Dolibarr WebServices "server_project"
+ */
+
+// This is to make Dolibarr working with Plesk
+set_include_path($_SERVER['DOCUMENT_ROOT'].'/htdocs');
+
+require_once '../master.inc.php';
+require_once NUSOAP_PATH.'/nusoap.php'; // Include SOAP
+
+$WS_DOL_URL = DOL_MAIN_URL_ROOT.'/webservices/server_project.php';
+//$WS_DOL_URL = 'http://localhost:8080/'; // To test with Soapui mock. If not a page, should end with /
+$WS_METHOD1 = 'createProject';
+$WS_METHOD2 = 'getProject';
+$ns='http://www.dolibarr.org/ns/';
+
+
+// Set the WebService URL
+dol_syslog("Create nusoap_client for URL=".$WS_DOL_URL);
+$soapclient = new nusoap_client($WS_DOL_URL);
+if ($soapclient)
+{
+ $soapclient->soap_defencoding='UTF-8';
+ $soapclient->decodeUTF8(false);
+}
+
+
+// Call the WebService method and store its result in $result.
+$authentication=array(
+ 'dolibarrkey'=>$conf->global->WEBSERVICES_KEY,
+ 'sourceapplication'=>'DEMO',
+ 'login'=>'admin',
+ 'password'=>'changeme',
+ 'entity'=>'');
+
+
+// Test url 1
+if ($WS_METHOD1)
+{
+ $parameters = array(
+ 'authentication'=>$authentication,
+ 'project'=>array(
+ 'ref'=>'REF_TEST_WS',
+ 'label'=>'LABEL_WS',
+ 'thirdparty_id'=>'1234',
+ 'public'=>'1',
+ 'status'=>'0',
+ 'date_start'=>'2016-04-07T21:24:19Z',
+ 'date_end'=>'2016-04-08T08:13:42Z',
+ 'budget'=>'1234',
+ 'description'=>'DESCRIPTION_WS',
+ )
+ );
+ dol_syslog("Call method ".$WS_METHOD1);
+ $result1 = $soapclient->call($WS_METHOD1,$parameters,$ns,'');
+ if (! $result1)
+ {
+ print $soapclient->error_str;
+ print "<br>\n\n";
+ print $soapclient->request;
+ print "<br>\n\n";
+ print $soapclient->response;
+ exit;
+ }
+}
+
+// Test url 2
+if ($WS_METHOD2)
+{
+ $parameters = array(
+ 'authentication'=>$authentication,
+ 'id'=>'',
+ 'ref'=>'REF_TEST_WS'
+ );
+ dol_syslog("Call method ".$WS_METHOD2);
+ $result2 = $soapclient->call($WS_METHOD2,$parameters,$ns,'');
+ if (! $result2)
+ {
+ print $soapclient->error_str;
+ print "<br>\n\n";
+ print $soapclient->request;
+ print "<br>\n\n";
+ print $soapclient->response;
+ exit;
+ }
+}
+
+
+/*
+ * View
+ */
+
+header("Content-type: text/html; charset=utf8");
+print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'."\n";
+echo '<html>'."\n";
+echo '<head>';
+echo '<title>WebService Test: '.$WS_METHOD1.'</title>';
+echo '</head>'."\n";
+
+echo '<body>'."\n";
+echo 'NUSOAP_PATH='.NUSOAP_PATH.'<br>';
+
+echo "<h2>Request:</h2>";
+echo '<h4>Function</h4>';
+echo $WS_METHOD1;
+echo '<h4>SOAP Message</h4>';
+echo '<pre>' . htmlspecialchars($soapclient1->request, ENT_QUOTES) . '</pre>';
+//echo '<hr>';
+echo "<h2>Response:</h2>";
+echo '<h4>Result</h4>';
+echo '<pre>';
+print_r($result1);
+echo '</pre>';
+echo '<h4>SOAP Message</h4>';
+echo '<pre>' . htmlspecialchars($soapclient1->response, ENT_QUOTES) . '</pre>';
+
+print '<hr>';
+
+echo "<h2>Request:</h2>";
+echo '<h4>Function</h4>';
+echo $WS_METHOD2;
+echo '<h4>SOAP Message</h4>';
+echo '<pre>' . htmlspecialchars($soapclient2->request, ENT_QUOTES) . '</pre>';
+//echo '<hr>';
+echo "<h2>Response:</h2>";
+echo '<h4>Result</h4>';
+echo '<pre>';
+print_r($result2);
+echo '</pre>';
+echo '<h4>SOAP Message</h4>';
+echo '<pre>' . htmlspecialchars($soapclient2->response, ENT_QUOTES) . '</pre>';
+
+echo '</body>'."\n";
+echo '</html>'."\n";
+?>
diff --git a/htdocs/webservices/server_project.php b/htdocs/webservices/server_project.php
new file mode 100644
index 0000000000000000000000000000000000000000..078295e2ac9e779a2e295867c29fa5470a7422d2
--- /dev/null
+++ b/htdocs/webservices/server_project.php
@@ -0,0 +1,433 @@
+<?php
+/* Copyright (C) 2006-2010 Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2016 Ion Agorria <ion@agorria.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file htdocs/webservices/server_project.php
+ * \brief File that is entry point to call Dolibarr WebServices
+ */
+
+// This is to make Dolibarr working with Plesk
+set_include_path($_SERVER['DOCUMENT_ROOT'].'/htdocs');
+
+require_once '../master.inc.php';
+require_once NUSOAP_PATH.'/nusoap.php'; // Include SOAP
+require_once DOL_DOCUMENT_ROOT.'/core/lib/ws.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
+require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
+
+
+dol_syslog("Call Dolibarr webservices interfaces");
+
+$langs->load("main");
+
+// Enable and test if module web services is enabled
+if (empty($conf->global->MAIN_MODULE_WEBSERVICES))
+{
+ $langs->load("admin");
+ dol_syslog("Call Dolibarr webservices interfaces with module webservices disabled");
+ print $langs->trans("WarningModuleNotActive",'WebServices').'.<br><br>';
+ print $langs->trans("ToActivateModule");
+ exit;
+}
+
+// Create associated types array, with each table
+$listofreferent=array(
+ 'propal' => 'propal',
+ 'order' => 'commande',
+ 'invoice' => 'facture',
+ 'invoice_predefined' => 'facture_rec',
+ 'proposal_supplier' => 'commande_fournisseur',
+ 'order_supplier' => 'commande_fournisseur',
+ 'invoice_supplier' => 'facture_fourn',
+ 'contract' => 'contrat',
+ 'intervention' => 'fichinter',
+ 'trip' => 'deplacement',
+ 'expensereport' => 'expensereport_det',
+ 'donation' => 'don',
+ 'agenda' => 'actioncomm',
+ 'project_task' => 'projet_task',
+);
+
+// Create the soap Object
+$server = new nusoap_server();
+$server->soap_defencoding='UTF-8';
+$server->decode_utf8=false;
+$ns='http://www.dolibarr.org/ns/';
+$server->configureWSDL('WebServicesDolibarrOther',$ns);
+$server->wsdl->schemaTargetNamespace=$ns;
+
+// Define WSDL Authentication object
+$server->wsdl->addComplexType(
+ 'authentication',
+ 'complexType',
+ 'struct',
+ 'all',
+ '',
+ array(
+ 'dolibarrkey' => array('name'=>'dolibarrkey','type'=>'xsd:string'),
+ 'sourceapplication' => array('name'=>'sourceapplication','type'=>'xsd:string'),
+ 'login' => array('name'=>'login','type'=>'xsd:string'),
+ 'password' => array('name'=>'password','type'=>'xsd:string'),
+ 'entity' => array('name'=>'entity','type'=>'xsd:string'),
+ )
+);
+
+// Define WSDL Return object
+$server->wsdl->addComplexType(
+ 'result',
+ 'complexType',
+ 'struct',
+ 'all',
+ '',
+ array(
+ 'result_code' => array('name'=>'result_code','type'=>'xsd:string'),
+ 'result_label' => array('name'=>'result_label','type'=>'xsd:string'),
+ )
+);
+
+// Define other specific objects
+$server->wsdl->addComplexType(
+ 'element',
+ 'complexType',
+ 'struct',
+ 'all',
+ '',
+ array(
+ 'id' => array('name'=>'id','type'=>'xsd:int'),
+ 'user' => array('name'=>'user','type'=>'xsd:int'),
+ )
+);
+
+$server->wsdl->addComplexType(
+ 'elementsArray',
+ 'complexType',
+ 'array',
+ 'sequence',
+ '',
+ array(
+ 'elements' => array(
+ 'name' => 'elementsArray',
+ 'type' => 'tns:element',
+ 'minOccurs' => '0',
+ 'maxOccurs' => 'unbounded'
+ )
+ )
+);
+
+$project_elements = array();
+foreach($listofreferent as $key => $_)
+{
+ $project_elements[$key] = array('name'=>$key,'type'=>'tns:elementsArray');
+}
+$server->wsdl->addComplexType(
+ 'elements',
+ 'complexType',
+ 'struct',
+ 'all',
+ '',
+ $project_elements
+);
+
+// Define project
+$project_fields = array(
+ 'id' => array('name'=>'id','type'=>'xsd:string'),
+ 'ref' => array('name'=>'ref','type'=>'xsd:string'),
+ 'label' => array('name'=>'label','type'=>'xsd:string'),
+ 'thirdparty_id' => array('name'=>'thirdparty_id','type'=>'xsd:int'),
+ 'public' => array('name'=>'public','type'=>'xsd:int'),
+ 'status' => array('name'=>'status','type'=>'xsd:int'),
+ 'date_start' => array('name'=>'date_start','type'=>'xsd:date'),
+ 'date_end' => array('name'=>'date_end','type'=>'xsd:date'),
+ 'budget' => array('name'=>'budget','type'=>'xsd:int'),
+ 'description' => array('name'=>'description','type'=>'xsd:string'),
+ 'elements' => array('name'=>'elements','type'=>'tns:elements')
+);
+
+//Retreive all extrafield for thirdsparty
+// fetch optionals attributes and labels
+$extrafields=new ExtraFields($db);
+$extralabels=$extrafields->fetch_name_optionals_label('project',true);
+if (count($extrafields)>0) {
+ $extrafield_array = array();
+}
+foreach($extrafields->attribute_label as $key=>$label)
+{
+ //$value=$object->array_options["options_".$key];
+ $type =$extrafields->attribute_type[$key];
+ if ($type=='date' || $type=='datetime') {$type='xsd:dateTime';}
+ else {$type='xsd:string';}
+ $extrafield_array['options_'.$key]=array('name'=>'options_'.$key,'type'=>$type);
+}
+$project_fields=array_merge($project_fields,$extrafield_array);
+
+$server->wsdl->addComplexType(
+ 'project',
+ 'complexType',
+ 'struct',
+ 'all',
+ '',
+ $project_fields
+);
+
+// 5 styles: RPC/encoded, RPC/literal, Document/encoded (not WS-I compliant), Document/literal, Document/literal wrapped
+// Style merely dictates how to translate a WSDL binding to a SOAP message. Nothing more. You can use either style with any programming model.
+// http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
+$styledoc='rpc'; // rpc/document (document is an extend into SOAP 1.0 to support unstructured messages)
+$styleuse='encoded'; // encoded/literal/literal wrapped
+// Better choice is document/literal wrapped but literal wrapped not supported by nusoap.
+
+// Register WSDL
+$server->register(
+ 'createProject',
+ // Entry values
+ array('authentication'=>'tns:authentication','project'=>'tns:project'),
+ // Exit values
+ array('result'=>'tns:result','id'=>'xsd:string','ref'=>'xsd:string'),
+ $ns,
+ $ns.'#createProject',
+ $styledoc,
+ $styleuse,
+ 'WS to create project'
+);
+
+// Register WSDL
+$server->register(
+ 'getProject',
+ // Entry values
+ array('authentication'=>'tns:authentication','id'=>'xsd:string','ref'=>'xsd:string'),
+ // Exit values
+ array('result'=>'tns:result','project'=>'tns:project'),
+ $ns,
+ $ns.'#getProject',
+ $styledoc,
+ $styleuse,
+ 'WS to get project'
+);
+
+// Full methods code
+/**
+ * Create project
+ *
+ * @param array $authentication Array of authentication information
+ * @param array $project Project info
+ * @return int Id of new order
+ */
+function createProject($authentication, $project)
+{
+ global $db,$conf;
+
+ dol_syslog("Function: createProject login=".$authentication['login']);
+
+ if ($authentication['entity']) $conf->entity=$authentication['entity'];
+
+ // Init and check authentication
+ $objectresp=array();
+ $errorcode='';$errorlabel='';
+ $error=0;
+ $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
+ // Check parameters
+ if (empty($project['ref']))
+ {
+ $error++; $errorcode='KO'; $errorlabel="Name is mandatory.";
+ }
+
+
+ if (! $error)
+ {
+ $fuser->getrights();
+
+ if ($fuser->rights->projet->creer)
+ {
+ $newobject=new Project($db);
+ $newobject->ref=$project['ref'];
+ $newobject->title=$project['label'];
+ $newobject->socid=$project['thirdparty_id'];
+ $newobject->public=$project['public'];
+ $newobject->statut=$project['status'];
+ $newobject->date_start=dol_stringtotime($project['date_start'],'dayrfc');
+ $newobject->date_end=dol_stringtotime($project['date_end'],'dayrfc');
+ $newobject->budget_amount=$project['budget'];
+ $newobject->description=$project['description'];
+
+ // Retrieve all extrafields for project
+ // fetch optionals attributes and labels
+ $extrafields=new ExtraFields($db);
+ $extralabels=$extrafields->fetch_name_optionals_label('project',true);
+ foreach($extrafields->attribute_label as $key=>$label)
+ {
+ $key='options_'.$key;
+ $newobject->array_options[$key]=$project[$key];
+ }
+
+ $db->begin();
+
+ $result = $newobject->create($fuser);
+ if (! $error && $result > 0)
+ {
+ // Add myself as project leader
+ $result = $newobject->add_contact($fuser->id, 'PROJECTLEADER', 'internal');
+ if ($result < 0)
+ {
+ $error++;
+ }
+ }
+ else
+ {
+ $error++;
+ }
+
+ if (! $error)
+ {
+ $db->commit();
+ $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref);
+ }
+ else
+ {
+ $db->rollback();
+ $error++;
+ $errorcode='KO';
+ $errorlabel=$newobject->error;
+ }
+ }
+ else
+ {
+ $error++;
+ $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request';
+ }
+ }
+
+ if ($error)
+ {
+ $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
+ }
+
+ return $objectresp;
+}
+
+/**
+ * Get a project
+ *
+ * @param array $authentication Array of authentication information
+ * @param string $id internal id
+ * @param string $ref internal reference
+ * @return array Array result
+ */
+function getProject($authentication,$id='',$ref='')
+{
+ global $db,$conf,$langs;
+
+ dol_syslog("Function: getProject login=".$authentication['login']." id=".$id." ref=".$ref);
+
+ if ($authentication['entity']) $conf->entity=$authentication['entity'];
+
+ // Init and check authentication
+ $objectresp=array();
+ $errorcode='';$errorlabel='';
+ $error=0;
+ $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
+ // Check parameters
+ if (! $error && (($id && $ref)))
+ {
+ $error++;
+ $errorcode='BAD_PARAMETERS'; $errorlabel="Parameter id and ref can't be both provided. You must choose one or other but not both.";
+ }
+
+ if (! $error)
+ {
+ $fuser->getrights();
+
+ if ($fuser->rights->projet->lire)
+ {
+ $project=new Project($db);
+ $result=$project->fetch($id,$ref);
+ if ($result > 0)
+ {
+ $project_result_fields=array(
+ 'id' => $project->id,
+ 'ref' => $project->ref,
+ 'label' => $project->title,
+ 'thirdparty_id' => $project->socid,
+ 'public' => $project->public,
+ 'status' => $project->statut,
+ 'date_start' => $project->date_start ? dol_print_date($project->date_start, 'dayrfc') : '',
+ 'date_end' => $project->date_end ? dol_print_date($project->date_end, 'dayrfc') : '',
+ 'budget' => $project->budget_amount,
+ 'description' => $project->description,
+ );
+
+ //Retrieve all extrafields for project
+ $extrafields=new ExtraFields($db);
+ $extralabels=$extrafields->fetch_name_optionals_label('societe',true);
+
+ //Get extrafield values
+ $project->fetch_optionals($project->id,$extralabels);
+ foreach($extrafields->attribute_label as $key=>$label)
+ {
+ $project_result_fields=array_merge($project_result_fields,array('options_'.$key => $project->array_options['options_'.$key]));
+ }
+
+ //Get linked elements
+ global $listofreferent;
+ $elements = array();
+ foreach ($listofreferent as $key => $tablename)
+ {
+ $elements[$key] = array();
+ $element_array = $project->get_element_list($key, $tablename);
+ if (count($element_array) > 0 && is_array($element_array))
+ {
+ foreach ($element_array as $element)
+ {
+ $tmp = explode('_', $element);
+ $idofelement = count($tmp) > 0? $tmp[0] : "";
+ $idofelementuser = count($tmp) > 1? $tmp[1] : "";
+ $elements[$key][] = array('id' => $idofelement, 'user' => $idofelementuser);
+ }
+ }
+ }
+ $project_result_fields['elements'] = $elements;
+
+ //Result
+ $objectresp = array(
+ 'result'=>array('result_code'=>'OK', 'result_label'=>''),
+ 'project'=>$project_result_fields
+ );
+ }
+ else
+ {
+ $error++;
+ $errorcode='NOT_FOUND'; $errorlabel='Object not found for id='.$id.' nor ref='.$ref;
+ }
+ }
+ else
+ {
+ $error++;
+ $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request';
+ }
+ }
+
+ if ($error)
+ {
+ $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
+ }
+
+ return $objectresp;
+}
+
+// Return the results.
+$server->service(file_get_contents("php://input"));