From dd27a52a85155bfaaf662e6c467ce70549dc37a6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 19 Nov 2016 16:08:27 +0100 Subject: [PATCH] Fix several problems on new REST API on project/tasks --- htdocs/adherents/class/api_members.class.php | 1 + .../class/api_subscriptions.class.php | 1 + htdocs/api/class/api.class.php | 8 + htdocs/api/index.php | 3 + .../categories/class/api_categories.class.php | 1 + .../class/api_deprecated_category.class.php | 1 + .../action/class/api_agendaevents.class.php | 1 + .../comm/propal/class/api_proposals.class.php | 1 + .../class/api_deprecated_commande.class.php | 1 + htdocs/commande/class/api_orders.class.php | 1 + .../bank/class/api_bankaccounts.class.php | 1 + .../class/api_deprecated_invoice.class.php | 1 + .../facture/class/api_invoices.class.php | 1 + .../class/api_expensereports.class.php | 1 + .../class/api_deprecated_product.class.php | 1 + htdocs/product/class/api_products.class.php | 1 + .../stock/class/api_stockmovements.class.php | 1 + .../stock/class/api_warehouses.class.php | 1 + htdocs/projet/class/api_projects.class.php | 161 +++-- htdocs/projet/class/api_tasks.class.php | 615 ++++++++++++++++++ htdocs/projet/class/project.class.php | 9 +- htdocs/projet/class/task.class.php | 55 +- htdocs/societe/class/api_contacts.class.php | 3 +- .../class/api_deprecated_contact.class.php | 3 +- .../class/api_deprecated_thirdparty.class.php | 1 + .../societe/class/api_thirdparties.class.php | 1 + .../user/class/api_deprecated_user.class.php | 3 +- htdocs/user/class/api_users.class.php | 3 +- 28 files changed, 793 insertions(+), 88 deletions(-) create mode 100644 htdocs/projet/class/api_tasks.class.php diff --git a/htdocs/adherents/class/api_members.class.php b/htdocs/adherents/class/api_members.class.php index 548b5728b1a..59d52094515 100644 --- a/htdocs/adherents/class/api_members.class.php +++ b/htdocs/adherents/class/api_members.class.php @@ -200,6 +200,7 @@ class Members extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; // Process the status separately because it must be updated using // the validate() and resiliate() methods of the class Adherent. if ($field == 'statut') { diff --git a/htdocs/adherents/class/api_subscriptions.class.php b/htdocs/adherents/class/api_subscriptions.class.php index 2dd2a609e63..10f25e88e42 100644 --- a/htdocs/adherents/class/api_subscriptions.class.php +++ b/htdocs/adherents/class/api_subscriptions.class.php @@ -188,6 +188,7 @@ class Subscriptions extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $subscription->$field = $value; } diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index b41bf1cb271..75c814860a3 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -106,6 +106,14 @@ class DolibarrApi unset($object->projet); // Should be fk_project unset($object->project); // Should be fk_project unset($object->author); // Should be fk_user_author + unset($object->timespent_old_duration); + unset($object->timespent_id); + unset($object->timespent_duration); + unset($object->timespent_date); + unset($object->timespent_datehour); + unset($object->timespent_withhour); + unset($object->timespent_fk_user); + unset($object->timespent_note); unset($object->statuts); unset($object->statuts_short); diff --git a/htdocs/api/index.php b/htdocs/api/index.php index eca1a8a6cf1..410d2e38673 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -109,6 +109,9 @@ foreach ($modulesdir as $dir) elseif ($module == 'project') { $moduledirforclass = 'projet'; } + elseif ($module == 'task') { + $moduledirforclass = 'projet'; + } elseif ($module == 'stock') { $moduledirforclass = 'product/stock'; } diff --git a/htdocs/categories/class/api_categories.class.php b/htdocs/categories/class/api_categories.class.php index d775fd9eff1..3394c2abf53 100644 --- a/htdocs/categories/class/api_categories.class.php +++ b/htdocs/categories/class/api_categories.class.php @@ -298,6 +298,7 @@ class Categories extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->category->$field = $value; } diff --git a/htdocs/categories/class/api_deprecated_category.class.php b/htdocs/categories/class/api_deprecated_category.class.php index a329710939d..7bff4d16082 100644 --- a/htdocs/categories/class/api_deprecated_category.class.php +++ b/htdocs/categories/class/api_deprecated_category.class.php @@ -425,6 +425,7 @@ class CategoryApi extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->category->$field = $value; } diff --git a/htdocs/comm/action/class/api_agendaevents.class.php b/htdocs/comm/action/class/api_agendaevents.class.php index 2965d07f29c..3c2f84b4700 100644 --- a/htdocs/comm/action/class/api_agendaevents.class.php +++ b/htdocs/comm/action/class/api_agendaevents.class.php @@ -223,6 +223,7 @@ class AgendaEvents extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->expensereport->$field = $value; } diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 84a7a1a1a1c..00850fc7adf 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -396,6 +396,7 @@ class Proposals extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->propal->$field = $value; } diff --git a/htdocs/commande/class/api_deprecated_commande.class.php b/htdocs/commande/class/api_deprecated_commande.class.php index 06da6fa874a..16e37cc6235 100644 --- a/htdocs/commande/class/api_deprecated_commande.class.php +++ b/htdocs/commande/class/api_deprecated_commande.class.php @@ -432,6 +432,7 @@ class CommandeApi extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->commande->$field = $value; } diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index c9931ac6f2a..646e9ead270 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -399,6 +399,7 @@ class Orders extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->commande->$field = $value; } diff --git a/htdocs/compta/bank/class/api_bankaccounts.class.php b/htdocs/compta/bank/class/api_bankaccounts.class.php index a3c7e3e9a3e..d6fb3515c81 100644 --- a/htdocs/compta/bank/class/api_bankaccounts.class.php +++ b/htdocs/compta/bank/class/api_bankaccounts.class.php @@ -185,6 +185,7 @@ class BankAccounts extends DolibarrApi } foreach ($request_data as $field => $value) { + if ($field == 'id') continue; $account->$field = $value; } diff --git a/htdocs/compta/facture/class/api_deprecated_invoice.class.php b/htdocs/compta/facture/class/api_deprecated_invoice.class.php index 51e047e4412..0b2949ca9bb 100644 --- a/htdocs/compta/facture/class/api_deprecated_invoice.class.php +++ b/htdocs/compta/facture/class/api_deprecated_invoice.class.php @@ -232,6 +232,7 @@ class InvoiceApi extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->invoice->$field = $value; } diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 0b2b7f58781..e0a2e12695a 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -229,6 +229,7 @@ class Invoices extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->invoice->$field = $value; } diff --git a/htdocs/expensereport/class/api_expensereports.class.php b/htdocs/expensereport/class/api_expensereports.class.php index 1e4a3d50008..ce7ce544f12 100644 --- a/htdocs/expensereport/class/api_expensereports.class.php +++ b/htdocs/expensereport/class/api_expensereports.class.php @@ -398,6 +398,7 @@ class ExpenseReports extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->expensereport->$field = $value; } diff --git a/htdocs/product/class/api_deprecated_product.class.php b/htdocs/product/class/api_deprecated_product.class.php index d4ad8335f54..66f34fbd9c3 100644 --- a/htdocs/product/class/api_deprecated_product.class.php +++ b/htdocs/product/class/api_deprecated_product.class.php @@ -307,6 +307,7 @@ class ProductApi extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->product->$field = $value; } diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index 290d011d09c..0c08fb0dc35 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -213,6 +213,7 @@ class Products extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->product->$field = $value; } diff --git a/htdocs/product/stock/class/api_stockmovements.class.php b/htdocs/product/stock/class/api_stockmovements.class.php index b3b1f8bd3a5..b453c2b7d30 100644 --- a/htdocs/product/stock/class/api_stockmovements.class.php +++ b/htdocs/product/stock/class/api_stockmovements.class.php @@ -227,6 +227,7 @@ class StockMovements extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->stockmovement->$field = $value; } diff --git a/htdocs/product/stock/class/api_warehouses.class.php b/htdocs/product/stock/class/api_warehouses.class.php index 072b4a2d5c2..f280111a385 100644 --- a/htdocs/product/stock/class/api_warehouses.class.php +++ b/htdocs/product/stock/class/api_warehouses.class.php @@ -198,6 +198,7 @@ class Warehouses extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->warehouse->$field = $value; } diff --git a/htdocs/projet/class/api_projects.class.php b/htdocs/projet/class/api_projects.class.php index 74650407f87..50c40a85dc3 100644 --- a/htdocs/projet/class/api_projects.class.php +++ b/htdocs/projet/class/api_projects.class.php @@ -19,6 +19,7 @@ use Luracast\Restler\RestException; require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; /** * API class for projects @@ -50,6 +51,7 @@ class Projects extends DolibarrApi global $db, $conf; $this->db = $db; $this->project = new Project($this->db); + $this->task = new Task($this->db); } /** @@ -154,7 +156,7 @@ class Projects extends DolibarrApi $obj = $db->fetch_object($result); $project_static = new Project($db); if($project_static->fetch($obj->rowid)) { - $obj_ret[] = parent::_cleanObjectDatas($project_static); + $obj_ret[] = $this->_cleanObjectDatas($project_static); } $i++; } @@ -203,13 +205,13 @@ class Projects extends DolibarrApi /** * Get tasks of a project * - * @param int $id Id of project + * @param int $id Id of project + * @param int $includetimespent 0=Return only list of tasks. 1=Include a summary of time spent, 2=Include details of time spent lines (2 is no implemented yet) + * @return int * * @url GET {id}/tasks - * - * @return int */ - function getLines($id) { + function getLines($id, $includetimespent=0) { if(! DolibarrApiAccess::$user->rights->projet->lire) { throw new RestException(401); } @@ -224,23 +226,36 @@ class Projects extends DolibarrApi } $this->project->getLinesArray(DolibarrApiAccess::$user); $result = array(); - foreach ($this->project->lines as $line) { - array_push($result,$this->_cleanObjectDatas($line)); + foreach ($this->project->lines as $line) // $line is a task + { + if ($includetimespent == 1) + { + $timespent = $line->getSummaryOfTimeSpent(0); + } + if ($includetimespent == 1) + { + // TODO + // Add class for timespent records and loop and fill $line->lines with records of timespent + } + array_push($result,$this->_cleanObjectDatas($line)); } return $result; } /** - * Get users and roles assigned to a project + * Get roles a user is assigned to a project with * - * @param int $id Id of project + * @param int $id Id of project + * @param int $userid Id of user (0 = connected user) * * @url GET {id}/roles * * @return int */ - function getRoles($id) { + function getRoles($id, $userid=0) { + global $db; + if(! DolibarrApiAccess::$user->rights->projet->lire) { throw new RestException(401); } @@ -256,7 +271,13 @@ class Projects extends DolibarrApi require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; $taskstatic=new Task($this->db); - $this->project->roles = $taskstatic->getUserRolesForProjectsOrTasks(DolibarrApiAccess::$user, 0, $id, 0); + $userp = DolibarrApiAccess::$user; + if ($userid > 0) + { + $userp = new User($this->db); + $userp->fetch($userid); + } + $this->project->roles = $taskstatic->getUserRolesForProjectsOrTasks($userp, 0, $id, 0); $result = array(); foreach ($this->project->roles as $line) { array_push($result,$this->_cleanObjectDatas($line)); @@ -330,10 +351,10 @@ class Projects extends DolibarrApi * Update a task to given project * * @param int $id Id of project to update - * @param int $lineid Id of line to update + * @param int $taskid Id of task to update * @param array $request_data Projectline data * - * @url PUT {id}/tasks/{lineid} + * @url PUT {id}/tasks/{taskid} * * @return object */ @@ -385,52 +406,6 @@ class Projects extends DolibarrApi }*/ - /** - * Delete a tasks of given project - * - * - * @param int $id Id of project to update - * @param int $taskid Id of task to delete - * - * @url DELETE {id}/tasks/{taskid} - * - * @return int - */ - function delLine($id, $taskid) { - if(! DolibarrApiAccess::$user->rights->projet->creer) { - throw new RestException(401); - } - - $result = $this->project->fetch($id); - if( ! ($result > 0) ) { - throw new RestException(404, 'Project not found'); - } - - if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - $taskstatic=new Task($this->db); - $result = $taskstatic->fetch($taskid); - if( ! ($result > 0) ) { - throw new RestException(404, 'Task not found'); - } - - $deleteRes = $taskstatic->delete(DolibarrApiAccess::$user); - - if( ! ($deleteRes > 0)) { - throw new RestException(500, 'Error when delete tasks : '.$taskstatic->error); - } - - return array( - 'success' => array( - 'code' => 200, - 'message' => 'Task deleted' - ) - ); - } - /** * Update project general fields (won't touch lines of project) @@ -446,7 +421,7 @@ class Projects extends DolibarrApi } $result = $this->project->fetch($id); - if( ! $result ) { + if ($result <= 0) { throw new RestException(404, 'Project not found'); } @@ -454,12 +429,18 @@ class Projects extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->project->$field = $value; } - if($this->project->update(DolibarrApiAccess::$user, 0)) + if($this->project->update(DolibarrApiAccess::$user, 0) > 0) + { return $this->get($id); - + } + else + { + throw new RestException(500, $this->project->error); + } return false; } @@ -498,8 +479,10 @@ class Projects extends DolibarrApi } /** - * Validate a project - * + * Validate a project. + * You can test this API with the following input message + * { "notrigger": 0 } + * * @param int $id Project ID * @param int $notrigger 1=Does not execute triggers, 0= execute triggers * @@ -543,6 +526,56 @@ class Projects extends DolibarrApi ); } + + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + * + * @todo use an array for properties to clean + * + */ + function _cleanObjectDatas($object) { + + $object = parent::_cleanObjectDatas($object); + + unset($object->barcode_type); + unset($object->barcode_type_code); + unset($object->barcode_type_label); + unset($object->barcode_type_coder); + unset($object->cond_reglement_id); + unset($object->cond_reglement); + unset($object->fk_delivery_address); + unset($object->shipping_method_id); + unset($object->fk_account); + unset($object->note); + unset($object->fk_incoterms); + unset($object->libelle_incoterms); + unset($object->location_incoterms); + unset($object->name); + unset($object->lastname); + unset($object->firstname); + unset($object->civility_id); + unset($object->mode_reglement_id); + unset($object->country); + unset($object->country_id); + unset($object->country_code); + + unset($object->weekWorkLoad); + unset($object->weekWorkLoad); + + //unset($object->lines); // for task we use timespent_lines, but for project we use lines + + unset($object->total_ht); + unset($object->total_tva); + unset($object->total_localtax1); + unset($object->total_localtax2); + unset($object->total_ttc); + + return $object; + } + /** * Validate fields before create or update object * diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php new file mode 100644 index 00000000000..735b830e9d5 --- /dev/null +++ b/htdocs/projet/class/api_tasks.class.php @@ -0,0 +1,615 @@ + + * Copyright (C) 2016 Laurent Destailleur + * + * 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 . + */ + + use Luracast\Restler\RestException; + + require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; + +/** + * API class for projects + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class Tasks extends DolibarrApi +{ + + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'ref', + 'label' + ); + + /** + * @var Task $task {@type Task} + */ + public $task; + + /** + * Constructor + */ + function __construct() + { + global $db, $conf; + $this->db = $db; + $this->task = new Task($this->db); + } + + /** + * Get properties of a task object + * + * Return an array with task informations + * + * @param int $id ID of task + * @param int $includetimespent 0=Return only task. 1=Include a summary of time spent, 2=Include details of time spent lines (2 is no implemented yet) + * @return array|mixed data without useless information + * + * @throws RestException + */ + function get($id, $includetimespent=0) + { + if(! DolibarrApiAccess::$user->rights->projet->lire) { + throw new RestException(401); + } + + $result = $this->task->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Task not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('task',$this->task->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if ($includetimespent == 1) + { + $timespent = $this->task->getSummaryOfTimeSpent(0); + } + if ($includetimespent == 1) + { + // TODO + // Add class for timespent records and loop and fill $line->lines with records of timespent + } + + return $this->_cleanObjectDatas($this->task); + } + + + + /** + * List tasks + * + * Get a list of tasks + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + * @return array Array of project objects + */ + function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '') { + global $db, $conf; + + $obj_ret = array(); + // case of external user, $thirdpartyid param is ignored and replaced by user's socid + $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids; + + // If the internal user must only see his customers, force searching by him + if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id; + + $sql = "SELECT t.rowid"; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects) + $sql.= " FROM ".MAIN_DB_PREFIX."projet_task as t"; + + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale + + $sql.= ' WHERE t.entity IN ('.getEntity('project', 1).')'; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc"; + if ($socids) $sql.= " AND t.fk_soc IN (".$socids.")"; + if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale + // Insert sale filter + if ($search_sale > 0) + { + $sql .= " AND sc.fk_user = ".$search_sale; + } + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + $sql.= $db->order($sortfield, $sortorder); + if ($limit) { + if ($page < 0) + { + $page = 0; + } + $offset = $limit * $page; + + $sql.= $db->plimit($limit + 1, $offset); + } + + dol_syslog("API Rest request"); + $result = $db->query($sql); + + if ($result) + { + $num = $db->num_rows($result); + while ($i < min($num, ($limit <= 0 ? $num : $limit))) + { + $obj = $db->fetch_object($result); + $task_static = new Task($db); + if($task_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($task_static); + } + $i++; + } + } + else { + throw new RestException(503, 'Error when retrieve task list'); + } + if( ! count($obj_ret)) { + throw new RestException(404, 'No task found'); + } + return $obj_ret; + } + + /** + * Create task object + * + * @param array $request_data Request data + * @return int ID of project + */ + function post($request_data = NULL) + { + if(! DolibarrApiAccess::$user->rights->projet->creer) { + throw new RestException(401, "Insuffisant rights"); + } + // Check mandatory fields + $result = $this->_validate($request_data); + + foreach($request_data as $field => $value) { + $this->task->$field = $value; + } + /*if (isset($request_data["lines"])) { + $lines = array(); + foreach ($request_data["lines"] as $line) { + array_push($lines, (object) $line); + } + $this->project->lines = $lines; + }*/ + if ($this->task->create(DolibarrApiAccess::$user) <= 0) { + $errormsg = $this->task->error; + throw new RestException(500, $errormsg ? $errormsg : "Error while creating task"); + } + + return $this->task->id; + } + + /** + * Get time spent of a task + * + * @param int $id Id of task + * @return int + * + * @url GET {id}/tasks + */ + /* + function getLines($id, $includetimespent=0) { + if(! DolibarrApiAccess::$user->rights->projet->lire) { + throw new RestException(401); + } + + $result = $this->project->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Project not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $this->project->getLinesArray(DolibarrApiAccess::$user); + $result = array(); + foreach ($this->project->lines as $line) // $line is a task + { + if ($includetimespent == 1) + { + $timespent = $line->getSummaryOfTimeSpent(0); + } + if ($includetimespent == 1) + { + // TODO + // Add class for timespent records and loop and fill $line->lines with records of timespent + } + array_push($result,$this->_cleanObjectDatas($line)); + } + return $result; + } + */ + + /** + * Get roles a user is assigned to a task with + * + * @param int $id Id of task + * @param int $userid Id of user (0 = connected user) + * + * @url GET {id}/roles + * + * @return int + */ + function getRoles($id, $userid=0) { + global $db; + + if(! DolibarrApiAccess::$user->rights->projet->lire) { + throw new RestException(401); + } + + $result = $this->task->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Task not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('task',$this->task->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $usert = DolibarrApiAccess::$user; + if ($userid > 0) + { + $usert = new User($this->db); + $usert->fetch($userid); + } + $this->task->roles = $this->task->getUserRolesForProjectsOrTasks(0, $usert, 0, $id); + $result = array(); + foreach ($this->task->roles as $line) { + array_push($result,$this->_cleanObjectDatas($line)); + } + return $result; + } + + + /** + * Add a task to given project + * + * @param int $id Id of project to update + * @param array $request_data Projectline data + * + * @url POST {id}/tasks + * + * @return int + */ + /* + function postLine($id, $request_data = NULL) { + if(! DolibarrApiAccess::$user->rights->projet->creer) { + throw new RestException(401); + } + + $result = $this->project->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Project not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $request_data = (object) $request_data; + $updateRes = $this->project->addline( + $request_data->desc, + $request_data->subprice, + $request_data->qty, + $request_data->tva_tx, + $request_data->localtax1_tx, + $request_data->localtax2_tx, + $request_data->fk_product, + $request_data->remise_percent, + $request_data->info_bits, + $request_data->fk_remise_except, + 'HT', + 0, + $request_data->date_start, + $request_data->date_end, + $request_data->product_type, + $request_data->rang, + $request_data->special_code, + $fk_parent_line, + $request_data->fk_fournprice, + $request_data->pa_ht, + $request_data->label, + $request_data->array_options, + $request_data->fk_unit, + $this->element, + $request_data->id + ); + + if ($updateRes > 0) { + return $this->get($id)->line->rowid; + + } + return false; + } + */ + + /** + * Update a task to given project + * + * @param int $id Id of project to update + * @param int $taskid Id of task to update + * @param array $request_data Projectline data + * + * @url PUT {id}/tasks/{taskid} + * + * @return object + */ + /* + function putLine($id, $lineid, $request_data = NULL) { + if(! DolibarrApiAccess::$user->rights->projet->creer) { + throw new RestException(401); + } + + $result = $this->project->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Project not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $request_data = (object) $request_data; + $updateRes = $this->project->updateline( + $lineid, + $request_data->desc, + $request_data->subprice, + $request_data->qty, + $request_data->remise_percent, + $request_data->tva_tx, + $request_data->localtax1_tx, + $request_data->localtax2_tx, + 'HT', + $request_data->info_bits, + $request_data->date_start, + $request_data->date_end, + $request_data->product_type, + $request_data->fk_parent_line, + 0, + $request_data->fk_fournprice, + $request_data->pa_ht, + $request_data->label, + $request_data->special_code, + $request_data->array_options, + $request_data->fk_unit + ); + + if ($updateRes > 0) { + $result = $this->get($id); + unset($result->line); + return $this->_cleanObjectDatas($result); + } + return false; + }*/ + + + /** + * Update task general fields (won't touch time spent of task) + * + * @param int $id Id of task to update + * @param array $request_data Datas + * + * @return int + */ + function put($id, $request_data = NULL) { + if(! DolibarrApiAccess::$user->rights->projet->creer) { + throw new RestException(401); + } + + $result = $this->task->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Task not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('task',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + foreach($request_data as $field => $value) { + if ($field == 'id') continue; + $this->task->$field = $value; + } + + if($this->task->update(DolibarrApiAccess::$user, 0) > 0) + { + return $this->get($id); + } + else + { + throw new RestException(500, $this->task->error); + } + + return false; + } + + /** + * Delete task + * + * @param int $id Task ID + * + * @return array + */ + function delete($id) + { + if(! DolibarrApiAccess::$user->rights->projet->supprimer) { + throw new RestException(401); + } + $result = $this->task->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Task not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('task',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if( ! $this->task->delete(DolibarrApiAccess::$user)) { + throw new RestException(500, 'Error when delete task : '.$this->task->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Task deleted' + ) + ); + + } + + + /** + * Add time spent to a task of a project. + * You can test this API with the following input message + * { "date": "2016-12-31 23:15:00", "duration": 1800, "user_id": 1, "note": "My time test" } + * + * @param int $id Task ID + * @param datetime $date Date (YYYY-MM-DD HH:MI:SS in GMT) + * @param int $duration Duration in seconds (3600 = 1h) + * @param int $user_id User (Use 0 for connected user) + * @param string $note Note + * + * @url POST {id}/addtimespent + * + * @return array + */ + function addTimeSpent($id, $date, $duration, $user_id=0, $note='') + { + if(! DolibarrApiAccess::$user->rights->projet->creer) { + throw new RestException(401); + } + $result = $this->task->fetch($id); + if ($result <= 0) { + throw new RestException(404, 'Task not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('project',$this->project->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $uid = $user_id; + if (empty($uid)) $uid = DolibarrApiAccess::$user->id; + + $newdate = dol_stringtotime($date, 1); + $this->task->timespent_date = $newdate; + $this->task->timespent_datehour = $newdate; + $this->task->timespent_withhour = 1; + $this->task->timespent_duration = $duration; + $this->task->timespent_fk_user = $user_id; + $this->task->timespent_note = $note; + + $result = $this->task->addTimeSpent(DolibarrApiAccess::$user, 0); + if ($result == 0) { + throw new RestException(500, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when adding time: '.$this->task->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Time spent added' + ) + ); + } + + + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + * + * @todo use an array for properties to clean + * + */ + function _cleanObjectDatas($object) { + + $object = parent::_cleanObjectDatas($object); + + unset($object->barcode_type); + unset($object->barcode_type_code); + unset($object->barcode_type_label); + unset($object->barcode_type_coder); + unset($object->cond_reglement_id); + unset($object->cond_reglement); + unset($object->fk_delivery_address); + unset($object->shipping_method_id); + unset($object->fk_account); + unset($object->note); + unset($object->fk_incoterms); + unset($object->libelle_incoterms); + unset($object->location_incoterms); + unset($object->name); + unset($object->lastname); + unset($object->firstname); + unset($object->civility_id); + unset($object->mode_reglement_id); + unset($object->country); + unset($object->country_id); + unset($object->country_code); + + unset($object->weekWorkLoad); + unset($object->weekWorkLoad); + + //unset($object->lines); // for task we use timespent_lines, but for project we use lines + + unset($object->total_ht); + unset($object->total_tva); + unset($object->total_localtax1); + unset($object->total_localtax2); + unset($object->total_ttc); + + return $object; + } + + /** + * Validate fields before create or update object + * + * @param array $data Array with data to verify + * @return array + * @throws RestException + */ + function _validate($data) + { + $object = array(); + foreach (self::$FIELDS as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $object[$field] = $data[$field]; + + } + return $object; + } + + + // TODO + // getSummaryOfTimeSpent +} diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index cdddccbf432..7a88fc3112c 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -97,6 +97,11 @@ class Project extends CommonObject */ public $date_m; + /** + * @var Task[] + */ + public $lines; + /** * Constructor @@ -228,7 +233,7 @@ class Project extends CommonObject * * @param User $user User object of making update * @param int $notrigger 1=Disable all triggers - * @return int + * @return int <=0 if KO, >0 if OK */ function update($user, $notrigger=0) { @@ -346,7 +351,7 @@ class Project extends CommonObject } /** - * Get object and lines from database + * Get object from database * * @param int $id Id of object to load * @param string $ref Ref of project diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 1f6d472b2c9..31dcb04d032 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -52,6 +52,15 @@ class Task extends CommonObject var $fk_user_valid; var $rang; + var $timespent_min_date; + var $timespent_max_date; + var $timespent_total_duration; + var $timespent_total_amount; + var $timespent_nblinesnull; + var $timespent_nblines; + // For detail of lines of timespent record, there is the property ->lines in common + + // Var used to call method addTimeSpent(). Bad practice. var $timespent_id; var $timespent_duration; var $timespent_old_duration; @@ -261,7 +270,7 @@ class Task extends CommonObject * * @param User $user User that modify * @param int $notrigger 0=launch triggers after, 1=disable triggers - * @return int <0 if KO, >0 if OK + * @return int <=0 if KO, >0 if OK */ function update($user=null, $notrigger=0) { @@ -595,7 +604,7 @@ class Task extends CommonObject $this->fk_projet=''; $this->ref='TK01'; $this->fk_task_parent=''; - $this->title='Specimen task TK01'; + $this->label='Specimen task TK01'; $this->duration_effective=''; $this->fk_user_creat=''; $this->progress='25'; @@ -768,7 +777,7 @@ class Task extends CommonObject * Return list of roles for a user for each projects or each tasks (or a particular project or a particular task). * * @param User $userp Return roles on project for this internal user. If set, usert and taskid must not be defined. - * @param User $usert Return roles on task for this internal user. If set userp must not be defined. -1 means no filter. + * @param User $usert Return roles on task for this internal user. If set userp must NOT be defined. -1 means no filter. * @param int $projectid Project id list separated with , to filter on project * @param int $taskid Task id to filter on a task * @param string $filteronprojstatus Filter on project status if userp is set. Not used if userp not defined. @@ -795,7 +804,8 @@ class Task extends CommonObject /* Liste des taches et role sur les projets ou taches */ $sql = "SELECT pt.rowid as pid, ec.element_id, ctc.code, ctc.source"; if ($userp) $sql.= " FROM ".MAIN_DB_PREFIX."projet as pt"; - if ($usert) $sql.= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."projet_task as pt"; + if ($usert && $filteronprojstatus > -1) $sql.= " FROM ".MAIN_DB_PREFIX."projet as p, ".MAIN_DB_PREFIX."projet_task as pt"; + if ($usert && $filteronprojstatus <= -1) $sql.= " FROM ".MAIN_DB_PREFIX."projet_task as pt"; $sql.= ", ".MAIN_DB_PREFIX."element_contact as ec"; $sql.= ", ".MAIN_DB_PREFIX."c_type_contact as ctc"; $sql.= " WHERE pt.rowid = ec.element_id"; @@ -820,7 +830,7 @@ class Task extends CommonObject } //print $sql; - dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks", LOG_DEBUG); + dol_syslog(get_class($this)."::getUserRolesForProjectsOrTasks execute request", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { @@ -872,7 +882,7 @@ class Task extends CommonObject * * @param User $user User object * @param int $notrigger 0=launch triggers after, 1=disable triggers - * @return void + * @return int <=0 if KO, >0 if OK */ function addTimeSpent($user, $notrigger=0) { @@ -934,7 +944,7 @@ class Task extends CommonObject $ret = -1; } - if ($ret >= 0) + if ($ret > 0) { // Recalculate amount of time spent for task and update denormalized field $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task"; @@ -961,7 +971,7 @@ class Task extends CommonObject } } - if ($ret >=0) + if ($ret >0) { $this->db->commit(); } @@ -976,7 +986,7 @@ class Task extends CommonObject * Calculate total of time spent for task * * @param int $userid Filter on user id. 0=No filter - * @return array Array of info for task array('min_date', 'max_date', 'total_duration') + * @return array Array of info for task array('min_date', 'max_date', 'total_duration', 'total_amount', 'nblines', 'nblinesnull') */ function getSummaryOfTimeSpent($userid=0) { @@ -994,7 +1004,10 @@ class Task extends CommonObject $sql = "SELECT"; $sql.= " MIN(t.task_datehour) as min_date,"; $sql.= " MAX(t.task_datehour) as max_date,"; - $sql.= " SUM(t.task_duration) as total_duration"; + $sql.= " SUM(t.task_duration) as total_duration,"; + $sql.= " SUM(t.task_duration / 3600 * ".$this->db->ifsql("t.thm IS NULL", 0, "t.thm").") as total_amount,"; + $sql.= " COUNT(t.rowid) as nblines,"; + $sql.= " SUM(".$this->db->ifsql("t.thm IS NULL", 1, 0).") as nblinesnull"; $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time as t"; $sql.= " WHERE t.fk_task = ".$id; if ($userid > 0) $sql.=" AND t.fk_user = ".$userid; @@ -1005,22 +1018,28 @@ class Task extends CommonObject { $obj = $this->db->fetch_object($resql); - $result['min_date'] = $obj->min_date; - $result['max_date'] = $obj->max_date; - $result['total_duration'] = $obj->total_duration; - + $result['min_date'] = $obj->min_date; // deprecated. use the ->timespent_xxx instead + $result['max_date'] = $obj->max_date; // deprecated. use the ->timespent_xxx instead + $result['total_duration'] = $obj->total_duration; // deprecated. use the ->timespent_xxx instead + + $this->timespent_min_date=$this->db->jdate($obj->min_date); + $this->timespent_max_date=$this->db->jdate($obj->max_date); + $this->timespent_total_duration=$obj->total_duration; + $this->timespent_total_amount=$obj->total_amount; + $this->timespent_nblinesnull=($obj->nblinesnull?$obj->nblinesnull:0); + $this->timespent_nblines=($obj->nblines?$obj->nblines:0); + $this->db->free($resql); - return $result; } else { dol_print_error($this->db); - return $result; } + return $result; } /** - * Calculate vamue of time consumed using the thm (hourly amount value of work for user entering time) + * Calculate value of time consumed using the thm (hourly amount value of work for user entering time) * * @param User $fuser Filter on a dedicated user * @param string $dates Start date (ex 00:00:00) @@ -1075,7 +1094,7 @@ class Task extends CommonObject } /** - * Load object in memory from database + * Load one record of time spent * * @param int $id Id object * @return int <0 if KO, >0 if OK diff --git a/htdocs/societe/class/api_contacts.class.php b/htdocs/societe/class/api_contacts.class.php index 0c205a7f34b..775d9d48cf4 100644 --- a/htdocs/societe/class/api_contacts.class.php +++ b/htdocs/societe/class/api_contacts.class.php @@ -222,7 +222,8 @@ class Contacts extends DolibarrApi foreach ($request_data as $field => $value) { - $this->contact->$field = $value; + if ($field == 'id') continue; + $this->contact->$field = $value; } if ($this->contact->update($id, DolibarrApiAccess::$user, 1, '', '', 'update')) diff --git a/htdocs/societe/class/api_deprecated_contact.class.php b/htdocs/societe/class/api_deprecated_contact.class.php index 201c800a898..65f361de23a 100644 --- a/htdocs/societe/class/api_deprecated_contact.class.php +++ b/htdocs/societe/class/api_deprecated_contact.class.php @@ -239,7 +239,8 @@ class ContactApi extends DolibarrApi foreach ($request_data as $field => $value) { - $this->contact->$field = $value; + if ($field == 'id') continue; + $this->contact->$field = $value; } if ($this->contact->update($id, DolibarrApiAccess::$user, 1, '', '', 'update')) diff --git a/htdocs/societe/class/api_deprecated_thirdparty.class.php b/htdocs/societe/class/api_deprecated_thirdparty.class.php index 3179cb697ce..61c9c1cc013 100644 --- a/htdocs/societe/class/api_deprecated_thirdparty.class.php +++ b/htdocs/societe/class/api_deprecated_thirdparty.class.php @@ -328,6 +328,7 @@ class ThirdpartyApi extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->company->$field = $value; } diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index de21e4fbbe0..13f28aea705 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -216,6 +216,7 @@ class Thirdparties extends DolibarrApi } foreach($request_data as $field => $value) { + if ($field == 'id') continue; $this->company->$field = $value; } diff --git a/htdocs/user/class/api_deprecated_user.class.php b/htdocs/user/class/api_deprecated_user.class.php index f080e8a3b45..278ce766878 100644 --- a/htdocs/user/class/api_deprecated_user.class.php +++ b/htdocs/user/class/api_deprecated_user.class.php @@ -191,7 +191,8 @@ class UserApi extends DolibarrApi foreach ($request_data as $field => $value) { - $this->useraccount->$field = $value; + if ($field == 'id') continue; + $this->useraccount->$field = $value; } if ($this->useraccount->update($id, DolibarrApiAccess::$user, 1, '', '', 'update')) diff --git a/htdocs/user/class/api_users.class.php b/htdocs/user/class/api_users.class.php index e177b4d52ec..db18bea229a 100644 --- a/htdocs/user/class/api_users.class.php +++ b/htdocs/user/class/api_users.class.php @@ -214,7 +214,8 @@ class Users extends DolibarrApi foreach ($request_data as $field => $value) { - $this->useraccount->$field = $value; + if ($field == 'id') continue; + $this->useraccount->$field = $value; } if ($this->useraccount->update(DolibarrApiAccess::$user, 1))