--- /tmp/dsg/dolibarr/htdocs/contrat/class/github_api_contracts.class.php +++ /tmp/dsg/dolibarr/htdocs/contrat/class/client_api_contracts.class.php @@ -1,7 +1,7 @@ - * Copyright (C) 2016 Laurent Destailleur - * Copyright (C) 2018-2020 Frédéric France +/* Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2016 Laurent Destailleur + * Copyright (C) 2018 Frédéric France * * 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 @@ -30,647 +30,653 @@ class Contracts extends DolibarrApi { - /** - * @var array $FIELDS Mandatory fields, checked when create and update object - */ - static $FIELDS = array( - 'socid', - 'date_contrat', - 'commercial_signature_id', - 'commercial_suivi_id' - ); - - /** - * @var Contrat $contract {@type Contrat} - */ - public $contract; - - /** - * Constructor - */ - public function __construct() - { - global $db, $conf; - $this->db = $db; - $this->contract = new Contrat($this->db); - } - - /** - * Get properties of a contract object - * - * Return an array with contract informations - * - * @param int $id ID of contract - * @return array|mixed data without useless information - * - * @throws RestException - */ - public function get($id) - { - if (!DolibarrApiAccess::$user->rights->contrat->lire) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - $this->contract->fetchObjectLinked(); - return $this->_cleanObjectDatas($this->contract); - } - - - - /** - * List contracts - * - * Get a list of contracts - * - * @param string $sortfield Sort field - * @param string $sortorder Sort order - * @param int $limit Limit for list - * @param int $page Page number - * @param string $thirdparty_ids Thirdparty ids to filter contracts of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i} - * @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 contract objects - * - * @throws RestException 404 Not found - * @throws RestException 503 Error - */ - public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '') - { - global $db, $conf; - - $obj_ret = array(); - - // case of external user, $thirdparty_ids param is ignored and replaced by user's socid - $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids; - - // If the internal user must only see his customers, force searching by him - $search_sale = 0; - 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."contrat 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('contrat').')'; - 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 .= $this->db->order($sortfield, $sortorder); - if ($limit) { - if ($page < 0) - { - $page = 0; - } - $offset = $limit * $page; - - $sql .= $this->db->plimit($limit + 1, $offset); - } - - dol_syslog("API Rest request"); - $result = $this->db->query($sql); - - if ($result) - { - $num = $this->db->num_rows($result); - $min = min($num, ($limit <= 0 ? $num : $limit)); - $i = 0; - while ($i < $min) - { - $obj = $this->db->fetch_object($result); - $contrat_static = new Contrat($this->db); - if ($contrat_static->fetch($obj->rowid)) { - $obj_ret[] = $this->_cleanObjectDatas($contrat_static); - } - $i++; - } - } else { - throw new RestException(503, 'Error when retrieve contrat list : '.$this->db->lasterror()); - } - if (!count($obj_ret)) { - throw new RestException(404, 'No contract found'); - } - return $obj_ret; - } - - /** - * Create contract object - * - * @param array $request_data Request data - * @return int ID of contrat - */ - public function post($request_data = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401, "Insufficient rights"); - } - // Check mandatory fields - $result = $this->_validate($request_data); - - foreach ($request_data as $field => $value) { - $this->contract->$field = $value; - } - /*if (isset($request_data["lines"])) { + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'socid', + 'date_contrat', + 'commercial_signature_id', + 'commercial_suivi_id' + ); + + /** + * @var Contrat $contract {@type Contrat} + */ + public $contract; + + /** + * Constructor + */ + public function __construct() + { + global $db, $conf; + $this->db = $db; + $this->contract = new Contrat($this->db); + } + + /** + * Get properties of a contract object + * + * Return an array with contract informations + * + * @param int $id ID of contract + * @return array|mixed data without useless information + * + * @throws RestException + */ + public function get($id) + { + if (!DolibarrApiAccess::$user->rights->contrat->lire) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $this->contract->fetchObjectLinked(); + return $this->_cleanObjectDatas($this->contract); + } + + + + /** + * List contracts + * + * Get a list of contracts + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $thirdparty_ids Thirdparty ids to filter contracts of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i} + * @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 contract objects + * + * @throws RestException 404 Not found + * @throws RestException 503 Error + */ + public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '') + { + global $db, $conf; + + $obj_ret = array(); + + // case of external user, $thirdparty_ids param is ignored and replaced by user's socid + $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids; + + // If the internal user must only see his customers, force searching by him + $search_sale = 0; + 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."contrat 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('contrat').')'; + 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); + $min = min($num, ($limit <= 0 ? $num : $limit)); + $i = 0; + while ($i < $min) + { + $obj = $db->fetch_object($result); + $contrat_static = new Contrat($db); + if ($contrat_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($contrat_static); + } + $i++; + } + } + else { + throw new RestException(503, 'Error when retrieve contrat list : '.$db->lasterror()); + } + if (!count($obj_ret)) { + throw new RestException(404, 'No contract found'); + } + return $obj_ret; + } + + /** + * Create contract object + * + * @param array $request_data Request data + * @return int ID of contrat + */ + public function post($request_data = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401, "Insufficient rights"); + } + // Check mandatory fields + $result = $this->_validate($request_data); + + foreach ($request_data as $field => $value) { + $this->contract->$field = $value; + } + /*if (isset($request_data["lines"])) { $lines = array(); foreach ($request_data["lines"] as $line) { array_push($lines, (object) $line); } $this->contract->lines = $lines; }*/ - if ($this->contract->create(DolibarrApiAccess::$user) < 0) { - throw new RestException(500, "Error creating contract", array_merge(array($this->contract->error), $this->contract->errors)); - } - - return $this->contract->id; - } - - /** - * Get lines of a contract - * - * @param int $id Id of contract - * - * @url GET {id}/lines - * - * @return array - */ - public function getLines($id) - { - if (!DolibarrApiAccess::$user->rights->contrat->lire) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - $this->contract->getLinesArray(); - $result = array(); - foreach ($this->contract->lines as $line) { - array_push($result, $this->_cleanObjectDatas($line)); - } - return $result; - } - - /** - * Add a line to given contract - * - * @param int $id Id of contrat to update - * @param array $request_data Contractline data - * - * @url POST {id}/lines - * - * @return int|bool - */ - public function postLine($id, $request_data = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - $request_data = (object) $request_data; - $updateRes = $this->contract->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->date_start, // date_start = date planned start, date ouverture = date_start_real - $request_data->date_end, // date_end = date planned end, date_cloture = date_end_real - $request_data->HT, - $request_data->subprice_excl_tax, - $request_data->info_bits, - $request_data->fk_fournprice, - $request_data->pa_ht, - $request_data->array_options, - $request_data->fk_unit, - $request_data->rang - ); - - if ($updateRes > 0) { - return $updateRes; - } - return false; - } - - /** - * Update a line to given contract - * - * @param int $id Id of contrat to update - * @param int $lineid Id of line to update - * @param array $request_data Contractline data - * - * @url PUT {id}/lines/{lineid} - * - * @return Object|bool - */ - public function putLine($id, $lineid, $request_data = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contrat not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - $request_data = (object) $request_data; - - $updateRes = $this->contract->updateline( - $lineid, - $request_data->desc, - $request_data->subprice, - $request_data->qty, - $request_data->remise_percent, - $request_data->date_ouveture_prevue, - $request_data->date_fin_validite, - $request_data->tva_tx, - $request_data->localtax1_tx, - $request_data->localtax2_tx, - $request_data->date_ouverture, - $request_data->date_cloture, - 'HT', - $request_data->info_bits, - $request_data->fk_fourn_price, - $request_data->pa_ht, - $request_data->array_options, - $request_data->fk_unit - ); - - if ($updateRes > 0) { - $result = $this->get($id); - unset($result->line); - return $this->_cleanObjectDatas($result); - } - - return false; - } - - /** - * Activate a service line of a given contract - * - * @param int $id Id of contract to activate - * @param int $lineid Id of line to activate - * @param string $datestart {@from body} Date start {@type timestamp} - * @param string $dateend {@from body} Date end {@type timestamp} - * @param string $comment {@from body} Comment - * - * @url PUT {id}/lines/{lineid}/activate - * - * @return Object|bool - */ - public function activateLine($id, $lineid, $datestart, $dateend = null, $comment = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contrat not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - $updateRes = $this->contract->active_line(DolibarrApiAccess::$user, $lineid, $datestart, $dateend, $comment); - - if ($updateRes > 0) { - $result = $this->get($id); - unset($result->line); - return $this->_cleanObjectDatas($result); - } - - return false; - } - - /** - * Unactivate a service line of a given contract - * - * @param int $id Id of contract to activate - * @param int $lineid Id of line to activate - * @param string $datestart {@from body} Date start {@type timestamp} - * @param string $comment {@from body} Comment - * - * @url PUT {id}/lines/{lineid}/unactivate - * - * @return Object|bool - */ - public function unactivateLine($id, $lineid, $datestart, $comment = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contrat not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - // $request_data = (object) $request_data; - - $updateRes = $this->contract->close_line(DolibarrApiAccess::$user, $lineid, $datestart, $comment); - - if ($updateRes > 0) { - $result = $this->get($id); - unset($result->line); - return $this->_cleanObjectDatas($result); - } - - return false; - } - - /** - * Delete a line to given contract - * - * - * @param int $id Id of contract to update - * @param int $lineid Id of line to delete - * - * @url DELETE {id}/lines/{lineid} - * - * @return array|mixed - * - * @throws RestException 401 - * @throws RestException 404 - */ - public function deleteLine($id, $lineid) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contrat not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - // TODO Check the lineid $lineid is a line of object - - $updateRes = $this->contract->deleteline($lineid, DolibarrApiAccess::$user); - if ($updateRes > 0) { - return $this->get($id); - } else { - throw new RestException(405, $this->contract->error); - } - } - - /** - * Update contract general fields (won't touch lines of contract) - * - * @param int $id Id of contract to update - * @param array $request_data Datas - * - * @return array|mixed - */ - public function put($id, $request_data = null) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contrat not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - foreach ($request_data as $field => $value) { - if ($field == 'id') continue; - $this->contract->$field = $value; - } - - if ($this->contract->update(DolibarrApiAccess::$user) > 0) { - return $this->get($id); - } else { - throw new RestException(500, $this->contract->error); - } - } - - /** - * Delete contract - * - * @param int $id Contract ID - * - * @return array - */ - public function delete($id) - { - if (!DolibarrApiAccess::$user->rights->contrat->supprimer) { - throw new RestException(401); - } - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - if (!$this->contract->delete(DolibarrApiAccess::$user)) { - throw new RestException(500, 'Error when delete contract : '.$this->contract->error); - } - - return array( - 'success' => array( - 'code' => 200, - 'message' => 'Contract deleted' - ) - ); - } - - /** - * Validate a contract - * - * @param int $id Contract ID - * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * - * @url POST {id}/validate - * - * @return array - * FIXME An error 403 is returned if the request has an empty body. - * Error message: "Forbidden: Content type `text/plain` is not supported." - * Workaround: send this in the body - * { - * "notrigger": 0 - * } - */ - public function validate($id, $notrigger = 0) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - $result = $this->contract->validate(DolibarrApiAccess::$user, '', $notrigger); - if ($result == 0) { - throw new RestException(304, 'Error nothing done. May be object is already validated'); - } - if ($result < 0) { - throw new RestException(500, 'Error when validating Contract: '.$this->contract->error); - } - - return array( - 'success' => array( - 'code' => 200, - 'message' => 'Contract validated (Ref='.$this->contract->ref.')' - ) - ); - } - - /** - * Close all services of a contract - * - * @param int $id Contract ID - * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * - * @url POST {id}/close - * - * @return array - * FIXME An error 403 is returned if the request has an empty body. - * Error message: "Forbidden: Content type `text/plain` is not supported." - * Workaround: send this in the body - * { - * "notrigger": 0 - * } - */ - public function close($id, $notrigger = 0) - { - if (!DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401); - } - $result = $this->contract->fetch($id); - if (!$result) { - throw new RestException(404, 'Contract not found'); - } - - if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { - throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); - } - - $result = $this->contract->closeAll(DolibarrApiAccess::$user, $notrigger); - if ($result == 0) { - throw new RestException(304, 'Error nothing done. May be object is already close'); - } - if ($result < 0) { - throw new RestException(500, 'Error when closing Contract: '.$this->contract->error); - } - - return array( - 'success' => array( - 'code' => 200, - 'message' => 'Contract closed (Ref='.$this->contract->ref.'). All services were closed.' - ) - ); - } - - - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore - /** - * Clean sensible object datas - * - * @param Object $object Object to clean - * @return Object Object with cleaned properties - */ - protected function _cleanObjectDatas($object) - { - // phpcs:enable - $object = parent::_cleanObjectDatas($object); - - unset($object->address); - - unset($object->date_ouverture_prevue); - unset($object->date_ouverture); - unset($object->date_fin_validite); - unset($object->date_cloture); - unset($object->date_debut_prevue); - unset($object->date_debut_reel); - unset($object->date_fin_prevue); - unset($object->date_fin_reel); - unset($object->civility_id); - - return $object; - } - - /** - * Validate fields before create or update object - * - * @param array $data Array with data to verify - * @return array - * @throws RestException - */ - private function _validate($data) - { - $contrat = array(); - foreach (Contracts::$FIELDS as $field) { - if (!isset($data[$field])) - throw new RestException(400, "$field field missing"); - $contrat[$field] = $data[$field]; - } - return $contrat; - } + if ($this->contract->create(DolibarrApiAccess::$user) < 0) { + throw new RestException(500, "Error creating contract", array_merge(array($this->contract->error), $this->contract->errors)); + } + + return $this->contract->id; + } + + /** + * Get lines of a contract + * + * @param int $id Id of contract + * + * @url GET {id}/lines + * + * @return array + */ + public function getLines($id) + { + if (!DolibarrApiAccess::$user->rights->contrat->lire) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $this->contract->getLinesArray(); + $result = array(); + foreach ($this->contract->lines as $line) { + array_push($result, $this->_cleanObjectDatas($line)); + } + return $result; + } + + /** + * Add a line to given contract + * + * @param int $id Id of contrat to update + * @param array $request_data Contractline data + * + * @url POST {id}/lines + * + * @return int|bool + */ + public function postLine($id, $request_data = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + $request_data = (object) $request_data; + $updateRes = $this->contract->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->date_start, // date_start = date planned start, date ouverture = date_start_real + $request_data->date_end, // date_end = date planned end, date_cloture = date_end_real + $request_data->HT, + $request_data->subprice_excl_tax, + $request_data->info_bits, + $request_data->fk_fournprice, + $request_data->pa_ht, + $request_data->array_options, + $request_data->fk_unit, + $request_data->rang + ); + + if ($updateRes > 0) { + return $updateRes; + } + return false; + } + + /** + * Update a line to given contract + * + * @param int $id Id of contrat to update + * @param int $lineid Id of line to update + * @param array $request_data Contractline data + * + * @url PUT {id}/lines/{lineid} + * + * @return array|bool + */ + public function putLine($id, $lineid, $request_data = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contrat not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $request_data = (object) $request_data; + + $updateRes = $this->contract->updateline( + $lineid, + $request_data->desc, + $request_data->subprice, + $request_data->qty, + $request_data->remise_percent, + $request_data->date_ouveture_prevue, + $request_data->date_fin_validite, + $request_data->tva_tx, + $request_data->localtax1_tx, + $request_data->localtax2_tx, + $request_data->date_ouverture, + $request_data->date_cloture, + 'HT', + $request_data->info_bits, + $request_data->fk_fourn_price, + $request_data->pa_ht, + $request_data->array_options, + $request_data->fk_unit + ); + + if ($updateRes > 0) { + $result = $this->get($id); + unset($result->line); + return $this->_cleanObjectDatas($result); + } + + return false; + } + + /** + * Activate a service line of a given contract + * + * @param int $id Id of contract to activate + * @param int $lineid Id of line to activate + * @param string $datestart {@from body} Date start {@type timestamp} + * @param string $dateend {@from body} Date end {@type timestamp} + * @param string $comment {@from body} Comment + * + * @url PUT {id}/lines/{lineid}/activate + * + * @return array|bool + */ + public function activateLine($id, $lineid, $datestart, $dateend = null, $comment = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contrat not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $updateRes = $this->contract->active_line(DolibarrApiAccess::$user, $lineid, $datestart, $dateend, $comment); + + if ($updateRes > 0) { + $result = $this->get($id); + unset($result->line); + return $this->_cleanObjectDatas($result); + } + + return false; + } + + /** + * Unactivate a service line of a given contract + * + * @param int $id Id of contract to activate + * @param int $lineid Id of line to activate + * @param string $datestart {@from body} Date start {@type timestamp} + * @param string $comment {@from body} Comment + * + * @url PUT {id}/lines/{lineid}/unactivate + * + * @return array|bool + */ + public function unactivateLine($id, $lineid, $datestart, $comment = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contrat not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $request_data = (object) $request_data; + + $updateRes = $this->contract->close_line(DolibarrApiAccess::$user, $lineid, $datestart, $comment); + + if ($updateRes > 0) { + $result = $this->get($id); + unset($result->line); + return $this->_cleanObjectDatas($result); + } + + return false; + } + + /** + * Delete a line to given contract + * + * + * @param int $id Id of contract to update + * @param int $lineid Id of line to delete + * + * @url DELETE {id}/lines/{lineid} + * + * @return int + * + * @throws RestException 401 + * @throws RestException 404 + */ + public function deleteLine($id, $lineid) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contrat not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + // TODO Check the lineid $lineid is a line of object + + $updateRes = $this->contract->deleteline($lineid, DolibarrApiAccess::$user); + if ($updateRes > 0) { + return $this->get($id); + } + else + { + throw new RestException(405, $this->contract->error); + } + } + + /** + * Update contract general fields (won't touch lines of contract) + * + * @param int $id Id of contract to update + * @param array $request_data Datas + * + * @return int + */ + public function put($id, $request_data = null) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contrat not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + foreach ($request_data as $field => $value) { + if ($field == 'id') continue; + $this->contract->$field = $value; + } + + if ($this->contract->update(DolibarrApiAccess::$user) > 0) + { + return $this->get($id); + } + else + { + throw new RestException(500, $this->contract->error); + } + } + + /** + * Delete contract + * + * @param int $id Contract ID + * + * @return array + */ + public function delete($id) + { + if (!DolibarrApiAccess::$user->rights->contrat->supprimer) { + throw new RestException(401); + } + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (!$this->contract->delete(DolibarrApiAccess::$user)) { + throw new RestException(500, 'Error when delete contract : '.$this->contract->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Contract deleted' + ) + ); + } + + /** + * Validate a contract + * + * @param int $id Contract ID + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * + * @url POST {id}/validate + * + * @return array + * FIXME An error 403 is returned if the request has an empty body. + * Error message: "Forbidden: Content type `text/plain` is not supported." + * Workaround: send this in the body + * { + * "notrigger": 0 + * } + */ + public function validate($id, $notrigger = 0) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->contract->validate(DolibarrApiAccess::$user, '', $notrigger); + if ($result == 0) { + throw new RestException(304, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when validating Contract: '.$this->contract->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Contract validated (Ref='.$this->contract->ref.')' + ) + ); + } + + /** + * Close all services of a contract + * + * @param int $id Contract ID + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * + * @url POST {id}/close + * + * @return array + * FIXME An error 403 is returned if the request has an empty body. + * Error message: "Forbidden: Content type `text/plain` is not supported." + * Workaround: send this in the body + * { + * "notrigger": 0 + * } + */ + public function close($id, $notrigger = 0) + { + if (!DolibarrApiAccess::$user->rights->contrat->creer) { + throw new RestException(401); + } + $result = $this->contract->fetch($id); + if (!$result) { + throw new RestException(404, 'Contract not found'); + } + + if (!DolibarrApi::_checkAccessToResource('contrat', $this->contract->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->contract->closeAll(DolibarrApiAccess::$user, $notrigger); + if ($result == 0) { + throw new RestException(304, 'Error nothing done. May be object is already close'); + } + if ($result < 0) { + throw new RestException(500, 'Error when closing Contract: '.$this->contract->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Contract closed (Ref='.$this->contract->ref.'). All services were closed.' + ) + ); + } + + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + */ + protected function _cleanObjectDatas($object) + { + // phpcs:enable + $object = parent::_cleanObjectDatas($object); + + unset($object->address); + + unset($object->date_ouverture_prevue); + unset($object->date_ouverture); + unset($object->date_fin_validite); + unset($object->date_cloture); + unset($object->date_debut_prevue); + unset($object->date_debut_reel); + unset($object->date_fin_prevue); + unset($object->date_fin_reel); + unset($object->civility_id); + + return $object; + } + + /** + * Validate fields before create or update object + * + * @param array $data Array with data to verify + * @return array + * @throws RestException + */ + private function _validate($data) + { + $contrat = array(); + foreach (Contracts::$FIELDS as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $contrat[$field] = $data[$field]; + } + return $contrat; + } } --- /tmp/dsg/dolibarr/htdocs/contrat/class/github_contrat.class.php +++ /tmp/dsg/dolibarr/htdocs/contrat/class/client_contrat.class.php @@ -53,36 +53,36 @@ public $table_element = 'contrat'; /** - * @var string Name of subtable line + * @var int Name of subtable line */ public $table_element_line = 'contratdet'; /** - * @var string Fieldname with ID of parent key if this field has a parent + * @var int Field with ID of parent key if this field has a parent */ public $fk_element = 'fk_contrat'; - /** + /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png */ public $picto = 'contract'; - /** - * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe - * @var int - */ - public $ismultientitymanaged = 1; - - /** - * @var int Does object support extrafields ? 0=No, 1=Yes - */ - public $isextrafieldmanaged = 1; - - /** - * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user - * @var integer - */ - public $restrictiononfksoc = 1; + /** + * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + * @var int + */ + public $ismultientitymanaged = 1; + + /** + * @var int Does object support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user + * @var integer + */ + public $restrictiononfksoc = 1; /** * {@inheritdoc} @@ -101,11 +101,11 @@ */ public $ref_supplier; - /** - * Entity of the contract - * @var int - */ - public $entity; + /** + * Entity of the contract + * @var int + */ + public $entity; /** * Client id linked to the contract @@ -298,19 +298,23 @@ if ($numref != "") { return $numref; - } else { + } + else + { $this->error = $obj->error; dol_print_error($db, get_class($this)."::getNextValue ".$obj->error); return ""; } - } else { + } + else + { $langs->load("errors"); print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("Contract")); return ""; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Activate a contract line * @@ -323,7 +327,7 @@ */ public function active_line($user, $line_id, $date, $date_end = '', $comment = '') { - // phpcs:enable + // phpcs:enable $result = $this->lines[$this->lines_id_index_mapper[$line_id]]->active_line($user, $date, $date_end, $comment); if ($result < 0) { @@ -334,7 +338,7 @@ } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Close a contract line * @@ -346,7 +350,7 @@ */ public function close_line($user, $line_id, $date_end, $comment = '') { - // phpcs:enable + // phpcs:enable $result = $this->lines[$this->lines_id_index_mapper[$line_id]]->close_line($user, $date_end, $comment); if ($result < 0) { @@ -362,8 +366,8 @@ * * @param User $user Object User making action * @param int|string $date_start Date start (now if empty) - * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers - * @param string $comment Comment + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @param string $comment Comment * @return int <0 if KO, >0 if OK * @see () */ @@ -406,7 +410,9 @@ { $this->db->commit(); return 1; - } else { + } + else + { $this->db->rollback(); return -1; } @@ -416,8 +422,8 @@ * Close all lines of a contract * * @param User $user Object User making action - * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers - * @param string $comment Comment + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @param string $comment Comment * @return int <0 if KO, >0 if OK * @see activateAll() */ @@ -436,7 +442,7 @@ { // Close lines not already closed if ($contratline->statut != ContratLigne::STATUS_CLOSED) - { + { $contratline->date_cloture = $now; $contratline->fk_user_cloture = $user->id; $contratline->statut = ContratLigne::STATUS_CLOSED; @@ -448,7 +454,7 @@ $this->errors = $contratline->errors; break; } - } + } } if (!$error && $this->statut == 0) @@ -457,14 +463,16 @@ if ($result < 0) $error++; } - if (!$error) - { - $this->db->commit(); - return 1; - } else { - $this->db->rollback(); - return -1; - } + if (!$error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } } /** @@ -472,7 +480,7 @@ * * @param User $user Objet User * @param string $force_number Reference to force on contract (not implemented yet) - * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers * @return int <0 if KO, >0 if OK */ public function validate(User $user, $force_number = '', $notrigger = 0) @@ -500,17 +508,20 @@ if ($force_number) { $num = $force_number; - } elseif (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life + } + elseif (!$error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life { $num = $this->getNextNumRef($this->thirdparty); - } else { + } + else + { $num = $this->ref; } - $this->newref = dol_sanitizeFileName($num); + $this->newref = dol_sanitizeFileName($num); if ($num) { - $sql = "UPDATE ".MAIN_DB_PREFIX."contrat SET ref = '".$this->db->escape($num)."', statut = 1"; + $sql = "UPDATE ".MAIN_DB_PREFIX."contrat SET ref = '".$num."', statut = 1"; //$sql.= ", fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'"; $sql .= " WHERE rowid = ".$this->id." AND statut = 0"; @@ -526,15 +537,15 @@ // Trigger calls if (!$error && !$notrigger) { - // Call trigger - $result = $this->call_trigger('CONTRACT_VALIDATE', $user); - if ($result < 0) { $error++; } - // End call triggers + // Call trigger + $result = $this->call_trigger('CONTRACT_VALIDATE', $user); + if ($result < 0) { $error++; } + // End call triggers } if (!$error) { - $this->oldref = $this->ref; + $this->oldref = $this->ref; // Rename directory if dir was a temporary ref if (preg_match('/^[\(]?PROV/i', $this->ref)) @@ -557,16 +568,16 @@ if (@rename($dirsource, $dirdest)) { dol_syslog("Rename ok"); - // Rename docs starting with $oldref with $newref - $listoffiles = dol_dir_list($conf->contract->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); - foreach ($listoffiles as $fileentry) - { - $dirsource = $fileentry['name']; - $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); - $dirsource = $fileentry['path'].'/'.$dirsource; - $dirdest = $fileentry['path'].'/'.$dirdest; - @rename($dirsource, $dirdest); - } + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->contract->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/')); + foreach ($listoffiles as $fileentry) + { + $dirsource = $fileentry['name']; + $dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource); + $dirsource = $fileentry['path'].'/'.$dirsource; + $dirdest = $fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } } } } @@ -580,7 +591,9 @@ $this->brouillon = 0; $this->date_validation = $now; } - } else { + } + else + { $error++; } @@ -588,7 +601,9 @@ { $this->db->commit(); return 1; - } else { + } + else + { $this->db->rollback(); return -1; } @@ -598,7 +613,7 @@ * Unvalidate a contract * * @param User $user Object User - * @param int $notrigger 1=Does not execute triggers, 0=execute triggers + * @param int $notrigger 1=Does not execute triggers, 0=execute triggers * @return int <0 if KO, >0 if OK */ public function reopen($user, $notrigger = 0) @@ -651,7 +666,9 @@ { $this->db->commit(); return 1; - } else { + } + else + { $this->db->rollback(); return -1; } @@ -671,7 +688,7 @@ $sql = "SELECT rowid, statut, ref, fk_soc,"; $sql .= " ref_supplier, ref_customer,"; $sql .= " ref_ext,"; - $sql .= " entity,"; + $sql .= " entity,"; $sql .= " date_contrat as datecontrat,"; $sql .= " fk_user_author,"; $sql .= " fk_projet as fk_project,"; @@ -703,7 +720,8 @@ $this->error = 'Fetch found several records.'; dol_syslog($this->error, LOG_ERR); $result = -2; - } elseif ($num) // $num = 1 + } + elseif ($num) // $num = 1 { $obj = $this->db->fetch_object($resql); if ($obj) @@ -713,7 +731,7 @@ $this->ref_customer = $obj->ref_customer; $this->ref_supplier = $obj->ref_supplier; $this->ref_ext = $obj->ref_ext; - $this->entity = $obj->entity; + $this->entity = $obj->entity; $this->statut = $obj->statut; $this->date_contrat = $this->db->jdate($obj->datecontrat); @@ -726,8 +744,7 @@ $this->note_private = $obj->note_private; $this->note_public = $obj->note_public; - $this->model_pdf = $obj->model_pdf; - $this->modelpdf = $obj->model_pdf; // deprecated + $this->modelpdf = $obj->model_pdf; $this->fk_projet = $obj->fk_project; // deprecated $this->fk_project = $obj->fk_project; @@ -753,19 +770,23 @@ return $this->id; } - } else { + } + else + { dol_syslog(get_class($this)."::fetch Contract not found"); $this->error = "Contract not found"; return 0; } - } else { + } + else + { dol_syslog(get_class($this)."::fetch Error searching contract"); $this->error = $this->db->error(); return -1; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Load lines array into this->lines. * This set also nbofserviceswait, nbofservicesopened, nbofservicesexpired and nbofservicesclosed @@ -801,10 +822,10 @@ $extrafields->fetch_name_optionals_label($line->table_element, true); $this->lines = array(); - $pos = 0; + $pos = 0; // Selects contract lines related to a product - $sql = "SELECT p.label as product_label, p.description as product_desc, p.ref as product_ref, p.fk_product_type as product_type,"; + $sql = "SELECT p.label as product_label, p.description as product_desc, p.ref as product_ref,"; $sql .= " d.rowid, d.fk_contrat, d.statut, d.description, d.price_ht, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.localtax1_type, d.localtax2_type, d.qty, d.remise_percent, d.subprice, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht,"; $sql .= " d.total_ht,"; $sql .= " d.total_tva,"; @@ -817,8 +838,7 @@ $sql .= " d.fk_user_author,"; $sql .= " d.fk_user_ouverture,"; $sql .= " d.fk_user_cloture,"; - $sql .= " d.fk_unit,"; - $sql .= " d.product_type as type"; + $sql .= " d.fk_unit"; $sql .= " FROM ".MAIN_DB_PREFIX."contratdet as d LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid"; $sql .= " WHERE d.fk_contrat = ".$this->id; $sql .= " ORDER by d.rowid ASC"; @@ -858,7 +878,6 @@ $line->total_ttc = $objp->total_ttc; $line->fk_product = (($objp->fk_product > 0) ? $objp->fk_product : 0); $line->info_bits = $objp->info_bits; - $line->type = $objp->type; $line->fk_fournprice = $objp->fk_fournprice; $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); @@ -871,7 +890,6 @@ $line->ref = $objp->product_ref; // deprecated $line->product_ref = $objp->product_ref; // Product Ref - $line->product_type = $objp->product_type; // Product Type $line->product_desc = $objp->product_desc; // Product Description $line->product_label = $objp->product_label; // Product Label @@ -891,16 +909,16 @@ $line->date_fin_prevue = $this->db->jdate($objp->date_fin_validite); $line->date_fin_reel = $this->db->jdate($objp->date_cloture); - // Retrieve all extrafields for contract + // Retreive all extrafields for contract // fetch optionals attributes and labels $line->fetch_optionals(); // multilangs - if (!empty($conf->global->MAIN_MULTILANGS) && !empty($objp->fk_product) && !empty($loadalsotranslation)) { - $line = new Product($this->db); - $line->fetch($objp->fk_product); - $line->getMultiLangs(); - } + if (!empty($conf->global->MAIN_MULTILANGS) && !empty($objp->fk_product) && !empty($loadalsotranslation)) { + $line = new Product($this->db); + $line->fetch($objp->fk_product); + $line->getMultiLangs(); + } $this->lines[$pos] = $line; $this->lines_id_index_mapper[$line->id] = $pos; @@ -914,22 +932,24 @@ if ($line->statut == ContratLigne::STATUS_CLOSED) $this->nbofservicesclosed++; $total_ttc += $objp->total_ttc; // TODO Not saved into database - $total_vat += $objp->total_tva; - $total_ht += $objp->total_ht; + $total_vat += $objp->total_tva; + $total_ht += $objp->total_ht; $i++; $pos++; } $this->db->free($result); - } else { + } + else + { dol_syslog(get_class($this)."::Fetch Error when reading lines of contracts linked to products"); return -3; } $this->nbofservices = count($this->lines); - $this->total_ttc = price2num($total_ttc); // TODO For the moment value is false as value is not stored in database for line linked to products - $this->total_tva = price2num($total_vat); // TODO For the moment value is false as value is not stored in database for line linked to products - $this->total_ht = price2num($total_ht); // TODO For the moment value is false as value is not stored in database for line linked to products + $this->total_ttc = price2num($total_ttc); // TODO For the moment value is false as value is not stored in database for line linked to products + $this->total_vat = price2num($total_vat); // TODO For the moment value is false as value is not stored in database for line linked to products + $this->total_ht = price2num($total_ht); // TODO For the moment value is false as value is not stored in database for line linked to products return $this->lines; } @@ -1027,112 +1047,122 @@ // Insert business contacts ('SALESREPSIGN','contrat') if (!$error) { - $result = $this->add_contact($this->commercial_signature_id, 'SALESREPSIGN', 'internal'); - if ($result < 0) $error++; + $result = $this->add_contact($this->commercial_signature_id, 'SALESREPSIGN', 'internal'); + if ($result < 0) $error++; } // Insert business contacts ('SALESREPFOLL','contrat') - if (!$error) { - $result = $this->add_contact($this->commercial_suivi_id, 'SALESREPFOLL', 'internal'); - if ($result < 0) $error++; - } - - if (!$error) { + if (!$error) + { + $result = $this->add_contact($this->commercial_suivi_id, 'SALESREPFOLL', 'internal'); + if ($result < 0) $error++; + } + + if (!$error) + { if (!empty($this->linkedObjectsIds) && empty($this->linked_objects)) // To use new linkedObjectsIds instead of old linked_objects { $this->linked_objects = $this->linkedObjectsIds; // TODO Replace linked_objects with linkedObjectsIds } // Add object linked - if (!$error && $this->id && !empty($this->linked_objects) && is_array($this->linked_objects)) - { - foreach ($this->linked_objects as $origin => $tmp_origin_id) - { - if (is_array($tmp_origin_id)) // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...)) - { - foreach ($tmp_origin_id as $origin_id) - { - $ret = $this->add_object_linked($origin, $origin_id); - if (!$ret) - { - $this->error = $this->db->lasterror(); - $error++; - } - } - } else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1)) - { - $origin_id = $tmp_origin_id; - $ret = $this->add_object_linked($origin, $origin_id); - if (!$ret) - { - $this->error = $this->db->lasterror(); - $error++; - } - } - } - } - - if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) // Get contact from origin object - { - $originforcontact = $this->origin; - $originidforcontact = $this->origin_id; - if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order - { - require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; - $exp = new Expedition($this->db); - $exp->fetch($this->origin_id); - $exp->fetchObjectLinked(); - if (count($exp->linkedObjectsIds['commande']) > 0) - { - foreach ($exp->linkedObjectsIds['commande'] as $key => $value) - { - $originforcontact = 'commande'; - $originidforcontact = $value->id; - break; // We take first one - } - } - } - - $sqlcontact = "SELECT ctc.code, ctc.source, ec.fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc"; - $sqlcontact .= " WHERE element_id = ".$originidforcontact." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$this->db->escape($originforcontact)."'"; - - $resqlcontact = $this->db->query($sqlcontact); - if ($resqlcontact) - { - while ($objcontact = $this->db->fetch_object($resqlcontact)) - { - if ($objcontact->source == 'internal' && in_array($objcontact->code, array('SALESREPSIGN', 'SALESREPFOLL'))) continue; // ignore this, already forced previously - - //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n"; - $this->add_contact($objcontact->fk_socpeople, $objcontact->code, $objcontact->source); // May failed because of duplicate key or because code of contact type does not exists for new object - } - } else dol_print_error($resqlcontact); - } + if (!$error && $this->id && is_array($this->linked_objects) && !empty($this->linked_objects)) + { + foreach ($this->linked_objects as $origin => $tmp_origin_id) + { + if (is_array($tmp_origin_id)) // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...)) + { + foreach ($tmp_origin_id as $origin_id) + { + $ret = $this->add_object_linked($origin, $origin_id); + if (!$ret) + { + $this->error = $this->db->lasterror(); + $error++; + } + } + } + else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1)) + { + $origin_id = $tmp_origin_id; + $ret = $this->add_object_linked($origin, $origin_id); + if (!$ret) + { + $this->error = $this->db->lasterror(); + $error++; + } + } + } + } + + if (!$error && $this->id && !empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN) && !empty($this->origin) && !empty($this->origin_id)) // Get contact from origin object + { + $originforcontact = $this->origin; + $originidforcontact = $this->origin_id; + if ($originforcontact == 'shipping') // shipment and order share the same contacts. If creating from shipment we take data of order + { + require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; + $exp = new Expedition($this->db); + $exp->fetch($this->origin_id); + $exp->fetchObjectLinked(); + if (count($exp->linkedObjectsIds['commande']) > 0) + { + foreach ($exp->linkedObjectsIds['commande'] as $key => $value) + { + $originforcontact = 'commande'; + $originidforcontact = $value->id; + break; // We take first one + } + } + } + + $sqlcontact = "SELECT ctc.code, ctc.source, ec.fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc"; + $sqlcontact .= " WHERE element_id = ".$originidforcontact." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$originforcontact."'"; + + $resqlcontact = $this->db->query($sqlcontact); + if ($resqlcontact) + { + while ($objcontact = $this->db->fetch_object($resqlcontact)) + { + if ($objcontact->source == 'internal' && in_array($objcontact->code, array('SALESREPSIGN', 'SALESREPFOLL'))) continue; // ignore this, already forced previously + + //print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n"; + $this->add_contact($objcontact->fk_socpeople, $objcontact->code, $objcontact->source); // May failed because of duplicate key or because code of contact type does not exists for new object + } + } + else dol_print_error($resqlcontact); + } } if (!$error) { - // Call trigger - $result = $this->call_trigger('CONTRACT_CREATE', $user); - if ($result < 0) { $error++; } - // End call triggers + // Call trigger + $result = $this->call_trigger('CONTRACT_CREATE', $user); + if ($result < 0) { $error++; } + // End call triggers if (!$error) { $this->db->commit(); return $this->id; - } else { + } + else + { dol_syslog(get_class($this)."::create - 30 - ".$this->error, LOG_ERR); $this->db->rollback(); return -3; } - } else { + } + else + { $this->error = "Failed to add contract"; dol_syslog(get_class($this)."::create - 20 - ".$this->error, LOG_ERR); $this->db->rollback(); return -2; } - } else { + } + else + { $this->error = $langs->trans("UnknownError: ".$this->db->error()." -", LOG_DEBUG); $this->db->rollback(); @@ -1142,10 +1172,10 @@ /** - * Delete object - * - * @param User $user User that deletes - * @return int < 0 if KO, > 0 if OK + * Supprime l'objet de la base + * + * @param User $user Utilisateur qui supprime + * @return int < 0 si erreur, > 0 si ok */ public function delete($user) { @@ -1156,10 +1186,10 @@ $this->db->begin(); - // Call trigger - $result = $this->call_trigger('CONTRACT_DELETE', $user); - if ($result < 0) { $error++; } - // End call triggers + // Call trigger + $result = $this->call_trigger('CONTRACT_DELETE', $user); + if ($result < 0) { $error++; } + // End call triggers if (!$error) { @@ -1222,8 +1252,8 @@ } } - // Delete lines - if (!$error) { + if (!$error) + { // Delete contratdet extrafields $main = MAIN_DB_PREFIX.'contratdet'; $ef = $main."_extrafields"; @@ -1253,21 +1283,9 @@ } } - // Delete llx_ecm_files - if (!$error) { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX."ecm_files WHERE src_object_type = '".$this->db->escape($this->table_element.(empty($this->module) ? '' : '@'.$this->module))."' AND src_object_id = ".$this->id; - $resql = $this->db->query($sql); - if (!$resql) - { - $this->error = $this->db->lasterror(); - $this->errors[] = $this->error; - $error++; - } - } - - // Delete contract if (!$error) { + // Delete contrat $sql = "DELETE FROM ".MAIN_DB_PREFIX."contrat"; $sql .= " WHERE rowid=".$this->id; @@ -1296,7 +1314,7 @@ $ref = dol_sanitizeFileName($this->ref); if ($conf->contrat->dir_output) { - $dir = $conf->contrat->multidir_output[$this->entity]."/".$ref; + $dir = $conf->contrat->dir_output."/".$ref; if (file_exists($dir)) { $res = @dol_delete_dir_recursive($dir); @@ -1313,7 +1331,9 @@ { $this->db->commit(); return 1; - } else { + } + else + { $this->error = $this->db->lasterror(); $this->db->rollback(); return -1; @@ -1356,7 +1376,7 @@ // Put here code to add a control on parameters values // Update request - $sql = "UPDATE ".MAIN_DB_PREFIX."contrat SET"; + $sql = "UPDATE ".MAIN_DB_PREFIX."contrat SET"; $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").","; $sql .= " ref_customer=".(isset($this->ref_customer) ? "'".$this->db->escape($this->ref_customer)."'" : "null").","; $sql .= " ref_supplier=".(isset($this->ref_supplier) ? "'".$this->db->escape($this->ref_supplier)."'" : "null").","; @@ -1406,7 +1426,9 @@ } $this->db->rollback(); return -1 * $error; - } else { + } + else + { $this->db->commit(); return 1; } @@ -1465,10 +1487,11 @@ $vat_src_code = $reg[1]; $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. } + $txtva = price2num($txtva); + $txlocaltax1 = price2num($txlocaltax1); $txlocaltax2 = price2num($txlocaltax2); - $remise_percent = price2num($remise_percent); $qty = price2num($qty); if (empty($qty)) $qty = 1; @@ -1477,12 +1500,14 @@ if (empty($pu_ttc)) $pu_ttc = 0; if (empty($txtva) || !is_numeric($txtva)) $txtva = 0; if (empty($txlocaltax1) || !is_numeric($txlocaltax1)) $txlocaltax1 = 0; - if (empty($txlocaltax2) || !is_numeric($txlocaltax2)) $txlocaltax2 = 0; + if (empty($txlocaltax2) || !is_numeric($txlocaltax2)) $txlocaltax2 = 0; if ($price_base_type == 'HT') { $pu = $pu_ht; - } else { + } + else + { $pu = $pu_ttc; } @@ -1524,7 +1549,7 @@ $price = $pu_ht - $remise; } - if (empty($pa_ht)) $pa_ht = 0; + if (empty($pa_ht)) $pa_ht = 0; // if buy price not defined, define buyprice as configured in margin admin @@ -1533,7 +1558,9 @@ if (($result = $this->defineBuyPrice($pu_ht, $remise_percent, $fk_product)) < 0) { return $result; - } else { + } + else + { $pa_ht = $result; } } @@ -1553,15 +1580,15 @@ $sql .= ($fk_product > 0 ? $fk_product : "null").","; $sql .= " ".$qty.","; $sql .= " ".$txtva.","; - $sql .= " ".($vat_src_code ? "'".$this->db->escape($vat_src_code)."'" : "null").","; + $sql .= " ".($vat_src_code ? "'".$vat_src_code."'" : "null").","; $sql .= " ".$txlocaltax1.","; $sql .= " ".$txlocaltax2.","; - $sql .= " '".$this->db->escape($localtax1_type)."',"; - $sql .= " '".$this->db->escape($localtax2_type)."',"; + $sql .= " '".$localtax1_type."',"; + $sql .= " '".$localtax2_type."',"; $sql .= " ".price2num($remise_percent).","; $sql .= " ".price2num($pu_ht).","; $sql .= " ".price2num($total_ht).",".price2num($total_tva).",".price2num($total_localtax1).",".price2num($total_localtax2).",".price2num($total_ttc).","; - $sql .= " '".$this->db->escape($info_bits)."',"; + $sql .= " '".$info_bits."',"; $sql .= " ".price2num($price).",".price2num($remise).","; if (isset($fk_fournprice)) $sql .= ' '.$fk_fournprice.','; else $sql .= ' null,'; @@ -1591,29 +1618,35 @@ } if (empty($error)) { - // Call trigger - $result = $this->call_trigger('LINECONTRACT_INSERT', $user); - if ($result < 0) - { - $error++; - } - // End call triggers + // Call trigger + $result = $this->call_trigger('LINECONTRACT_INSERT', $user); + if ($result < 0) + { + $error++; + } + // End call triggers } if ($error) { $this->db->rollback(); return -1; - } else { + } + else + { $this->db->commit(); return $contractlineid; } - } else { + } + else + { $this->db->rollback(); $this->error = $this->db->error()." sql=".$sql; return -1; } - } else { + } + else + { dol_syslog(get_class($this)."::addline ErrorTryToAddLineOnValidatedContract", LOG_ERR); return -2; } @@ -1665,7 +1698,9 @@ { $remise = round(($pu * $remise_percent / 100), 2); $price = $pu - $remise; - } else { + } + else + { $remise_percent = 0; } @@ -1703,11 +1738,11 @@ $price = price2num(round($pu, 2)); if (dol_strlen($remise_percent) > 0) { - $remise = round(($pu * $remise_percent / 100), 2); - $price = $pu - $remise; - } - - if (empty($pa_ht)) $pa_ht = 0; + $remise = round(($pu * $remise_percent / 100), 2); + $price = $pu - $remise; + } + + if (empty($pa_ht)) $pa_ht = 0; // if buy price not defined, define buyprice as configured in margin admin if ($this->pa_ht == 0) @@ -1715,7 +1750,9 @@ if (($result = $this->defineBuyPrice($pu, $remise_percent)) < 0) { return $result; - } else { + } + else + { $pa_ht = $result; } } @@ -1729,8 +1766,8 @@ $sql .= ",tva_tx='".price2num($tvatx)."'"; $sql .= ",localtax1_tx='".price2num($localtax1tx)."'"; $sql .= ",localtax2_tx='".price2num($localtax2tx)."'"; - $sql .= ",localtax1_type='".$this->db->escape($localtax1_type)."'"; - $sql .= ",localtax2_type='".$this->db->escape($localtax2_type)."'"; + $sql .= ",localtax1_type='".$localtax1_type."'"; + $sql .= ",localtax2_type='".$localtax2_type."'"; $sql .= ", total_ht='".price2num($total_ht)."'"; $sql .= ", total_tva='".price2num($total_tva)."'"; $sql .= ", total_localtax1='".price2num($total_localtax1)."'"; @@ -1738,10 +1775,14 @@ $sql .= ", total_ttc='".price2num($total_ttc)."'"; $sql .= ", fk_product_fournisseur_price=".($fk_fournprice > 0 ? $fk_fournprice : "null"); $sql .= ", buy_price_ht='".price2num($pa_ht)."'"; - if ($date_start > 0) { $sql .= ",date_ouverture_prevue='".$this->db->idate($date_start)."'"; } else { $sql .= ",date_ouverture_prevue=null"; } - if ($date_end > 0) { $sql .= ",date_fin_validite='".$this->db->idate($date_end)."'"; } else { $sql .= ",date_fin_validite=null"; } - if ($date_debut_reel > 0) { $sql .= ",date_ouverture='".$this->db->idate($date_debut_reel)."'"; } else { $sql .= ",date_ouverture=null"; } - if ($date_fin_reel > 0) { $sql .= ",date_cloture='".$this->db->idate($date_fin_reel)."'"; } else { $sql .= ",date_cloture=null"; } + if ($date_start > 0) { $sql .= ",date_ouverture_prevue='".$this->db->idate($date_start)."'"; } + else { $sql .= ",date_ouverture_prevue=null"; } + if ($date_end > 0) { $sql .= ",date_fin_validite='".$this->db->idate($date_end)."'"; } + else { $sql .= ",date_fin_validite=null"; } + if ($date_debut_reel > 0) { $sql .= ",date_ouverture='".$this->db->idate($date_debut_reel)."'"; } + else { $sql .= ",date_ouverture=null"; } + if ($date_fin_reel > 0) { $sql .= ",date_cloture='".$this->db->idate($date_fin_reel)."'"; } + else { $sql .= ",date_cloture=null"; } $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape($fk_unit)."'" : "null"); $sql .= " WHERE rowid = ".$rowid; @@ -1772,24 +1813,28 @@ } if (empty($error)) { - // Call trigger - $result = $this->call_trigger('LINECONTRACT_UPDATE', $user); - if ($result < 0) - { - $this->db->rollback(); - return -3; - } - // End call triggers + // Call trigger + $result = $this->call_trigger('LINECONTRACT_UPDATE', $user); + if ($result < 0) + { + $this->db->rollback(); + return -3; + } + // End call triggers $this->db->commit(); return 1; } - } else { + } + else + { $this->db->rollback(); dol_syslog(get_class($this)."::updateline Erreur -2"); return -2; } - } else { + } + else + { $this->db->rollback(); $this->error = $this->db->error(); dol_syslog(get_class($this)."::updateline Erreur -1"); @@ -1812,14 +1857,14 @@ if ($this->statut >= 0) { - // Call trigger - $result = $this->call_trigger('LINECONTRACT_DELETE', $user); - if ($result < 0) return -1; - // End call triggers - - $this->db->begin(); - - $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element_line; + // Call trigger + $result = $this->call_trigger('LINECONTRACT_DELETE', $user); + if ($result < 0) return -1; + // End call triggers + + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX.$this->table_element_line; $sql .= " WHERE rowid=".$idline; dol_syslog(get_class($this)."::deleteline", LOG_DEBUG); @@ -1850,14 +1895,16 @@ $this->db->rollback(); return -1; } - } else { + } + else + { $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; return -2; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Update statut of contract according to services * @@ -1867,7 +1914,7 @@ */ public function update_statut($user) { - // phpcs:enable + // phpcs:enable dol_syslog(__METHOD__." is deprecated", LOG_WARNING); // If draft, we keep it (should not happen) @@ -1876,11 +1923,11 @@ // Load $this->lines array // $this->fetch_lines(); - // $newstatut=1; - // foreach($this->lines as $key => $contractline) - // { - // // if ($contractline) // Loop on each service - // } + // $newstatut=1; + // foreach($this->lines as $key => $contractline) + // { + // // if ($contractline) // Loop on each service + // } return 1; } @@ -1897,7 +1944,7 @@ return $this->LibStatut($this->statut, $mode); } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Renvoi label of a given contrat status * @@ -1907,22 +1954,23 @@ */ public function LibStatut($status, $mode) { - // phpcs:enable + // phpcs:enable global $langs; if (empty($this->labelStatus) || empty($this->labelStatusShort)) { global $langs; $langs->load("contracts"); - $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('ContractStatusDraft'); - $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ContractStatusValidated'); - $this->labelStatus[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('ContractStatusClosed'); - $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('ContractStatusDraft'); - $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('ContractStatusValidated'); - $this->labelStatusShort[self::STATUS_CLOSED] = $langs->transnoentitiesnoconv('ContractStatusClosed'); + $this->labelStatus[self::STATUS_DRAFT] = $langs->trans('ContractStatusDraft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->trans('ContractStatusValidated'); + $this->labelStatus[self::STATUS_CLOSED] = $langs->trans('ContractStatusClosed'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->trans('ContractStatusDraft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->trans('ContractStatusValidated'); + $this->labelStatusShort[self::STATUS_CLOSED] = $langs->trans('ContractStatusClosed'); } $statusType = 'status'.$status; + if ($status == self::STATUS_VALIDATED) $statusType = 'status4'; if ($status == self::STATUS_VALIDATED) $statusType = 'status6'; if ($mode == 4 || $mode == 6 || $mode == 7) @@ -1945,7 +1993,9 @@ $text .= ($mode != 7 || $this->nbofservicesclosed > 0) ? ($this->nbofservicesclosed.ContratLigne::LibStatut(5, 3, -1, 'class="marginleft2"')) : ''; $text .= ($mode == 7 ? '' : ''); return $text; - } else { + } + else + { return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); } } @@ -1956,11 +2006,11 @@ * * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto * @param int $maxlength Max length of ref - * @param int $notooltip 1=Disable tooltip - * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @param int $notooltip 1=Disable tooltip + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking * @return string Chaine avec URL */ - public function getNomUrl($withpicto = 0, $maxlength = 0, $notooltip = 0, $save_lastsearch_value = -1) + public function getNomUrl($withpicto = 0, $maxlength = 0, $notooltip = 0, $save_lastsearch_value = -1) { global $conf, $langs, $user, $hookmanager; @@ -1976,39 +2026,35 @@ if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1'; //} - $label = ''; - - if ($user->rights->contrat->lire) { - $label = img_picto('', $this->picto).' '.$langs->trans("Contract").''; - /* Status of a contract is status of all services, so disabled - if (isset($this->statut)) { - $label .= ' '.$this->getLibStatut(5); - }*/ - $label .= '
'.$langs->trans('Ref').': '.($this->ref ? $this->ref : $this->id); - $label .= '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); - $label .= '
'.$langs->trans('RefSupplier').': '.$this->ref_supplier; - if (!empty($this->total_ht)) { - $label .= '
'.$langs->trans('AmountHT').': '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); - } - if (!empty($this->total_tva)) { - $label .= '
'.$langs->trans('VAT').': '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency); - } - if (!empty($this->total_ttc)) { - $label .= '
'.$langs->trans('AmountTTC').': '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency); - } - } - - $linkclose = ''; - if (empty($notooltip) && $user->rights->contrat->lire) - { - if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) - { - $label = $langs->trans("ShowOrder"); - $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; - } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="classfortooltip"'; - } + $label = ''; + + if ($user->rights->contrat->lire) { + $label = ''.$langs->trans("ShowContract").''; + $label .= '
'.$langs->trans('Ref').': '.($this->ref ? $this->ref : $this->id); + $label .= '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); + $label .= '
'.$langs->trans('RefSupplier').': '.$this->ref_supplier; + if (!empty($this->total_ht)) { + $label .= '
'.$langs->trans('AmountHT').': '.price($this->total_ht, 0, $langs, 0, -1, -1, $conf->currency); + } + if (!empty($this->total_tva)) { + $label .= '
'.$langs->trans('VAT').': '.price($this->total_tva, 0, $langs, 0, -1, -1, $conf->currency); + } + if (!empty($this->total_ttc)) { + $label .= '
'.$langs->trans('AmountTTC').': '.price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency); + } + } + + $linkclose = ''; + if (empty($notooltip) && $user->rights->contrat->lire) + { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label = $langs->trans("ShowOrder"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip"'; + } $linkstart = ''; @@ -2044,7 +2090,7 @@ $sql .= " c.tms as date_modification,"; $sql .= " fk_user_author"; $sql .= " FROM ".MAIN_DB_PREFIX."contrat as c"; - $sql .= " WHERE c.rowid = ".((int) $id); + $sql .= " WHERE c.rowid = ".$id; $result = $this->db->query($sql); if ($result) @@ -2067,12 +2113,14 @@ } $this->db->free($result); - } else { + } + else + { dol_print_error($this->db); } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return list of line rowid * @@ -2081,7 +2129,7 @@ */ public function array_detail($status = -1) { - // phpcs:enable + // phpcs:enable $tab = array(); $sql = "SELECT cd.rowid"; @@ -2102,7 +2150,9 @@ $i++; } return $tab; - } else { + } + else + { $this->error = $this->db->error(); return -1; } @@ -2138,24 +2188,26 @@ $i++; } return $tab; - } else { + } + else + { $this->error = $this->db->error(); return -1; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Load indicators for dashboard (this->nbtodo and this->nbtodolate) - * - * @param User $user Objet user - * @param string $mode "inactive" pour services a activer, "expired" pour services expires - * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK - */ - public function load_board($user, $mode) - { - // phpcs:enable + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Objet user + * @param string $mode "inactive" pour services a activer, "expired" pour services expires + * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK + */ + public function load_board($user, $mode) + { + // phpcs:enable global $conf, $langs; $this->from = " FROM ".MAIN_DB_PREFIX."contrat as c"; @@ -2170,7 +2222,8 @@ $sql .= " WHERE c.statut = 1"; $sql .= " AND c.rowid = cd.fk_contrat"; $sql .= " AND cd.statut = 0"; - } elseif ($mode == 'expired') + } + elseif ($mode == 'expired') { $sql = "SELECT cd.rowid, cd.date_fin_validite as datefin"; $sql .= $this->from; @@ -2178,15 +2231,16 @@ $sql .= " AND c.rowid = cd.fk_contrat"; $sql .= " AND cd.statut = 4"; $sql .= " AND cd.date_fin_validite < '".$this->db->idate(dol_now())."'"; - } elseif ($mode == 'active') - { - $sql = "SELECT cd.rowid, cd.date_fin_validite as datefin"; - $sql .= $this->from; - $sql .= " WHERE c.statut = 1"; - $sql .= " AND c.rowid = cd.fk_contrat"; - $sql .= " AND cd.statut = 4"; - //$datetouse = dol_now(); - //$sql.= " AND cd.date_fin_validite < '".$this->db->idate($datetouse)."'"; + } + elseif ($mode == 'active') + { + $sql = "SELECT cd.rowid, cd.date_fin_validite as datefin"; + $sql .= $this->from; + $sql .= " WHERE c.statut = 1"; + $sql .= " AND c.rowid = cd.fk_contrat"; + $sql .= " AND cd.statut = 4"; + //$datetouse = dol_now(); + //$sql.= " AND cd.date_fin_validite < '".$this->db->idate($datetouse)."'"; } $sql .= " AND c.fk_soc = s.rowid"; $sql .= " AND c.entity = ".$conf->entity; @@ -2204,11 +2258,12 @@ $label = $langs->trans("BoardNotActivatedServices"); $labelShort = $langs->trans("BoardNotActivatedServicesShort"); $url = DOL_URL_ROOT.'/contrat/services_list.php?mainmenu=commercial&leftmenu=contracts&mode=0&sortfield=cd.date_fin_validite&sortorder=asc'; - } elseif ($mode == 'expired') { - $warning_delay = $conf->contrat->services->expires->warning_delay; - $url = DOL_URL_ROOT.'/contrat/services_list.php?mainmenu=commercial&leftmenu=contracts&mode=4&filter=expired&sortfield=cd.date_fin_validite&sortorder=asc'; - $label = $langs->trans("BoardExpiredServices"); - $labelShort = $langs->trans("BoardExpiredServicesShort"); + } + elseif ($mode == 'expired') { + $warning_delay = $conf->contrat->services->expires->warning_delay; + $url = DOL_URL_ROOT.'/contrat/services_list.php?mainmenu=commercial&leftmenu=contracts&mode=4&filter=expired&sortfield=cd.date_fin_validite&sortorder=asc'; + $label = $langs->trans("BoardExpiredServices"); + $labelShort = $langs->trans("BoardExpiredServicesShort"); } else { $warning_delay = $conf->contrat->services->expires->warning_delay; $url = DOL_URL_ROOT.'/contrat/services_list.php?mainmenu=commercial&leftmenu=contracts&mode=4&sortfield=cd.date_fin_validite&sortorder=asc'; @@ -2235,14 +2290,16 @@ } return $response; - } else { + } + else + { dol_print_error($this->db); $this->error = $this->db->error(); return -1; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Charge indicateurs this->nb de tableau de bord * @@ -2250,7 +2307,7 @@ */ public function load_state_board() { - // phpcs:enable + // phpcs:enable global $conf, $user; $this->nb = array(); @@ -2272,11 +2329,13 @@ { while ($obj = $this->db->fetch_object($resql)) { - $this->nb["contracts"] = $obj->nb; - } - $this->db->free($resql); + $this->nb["Contracts"] = $obj->nb; + } + $this->db->free($resql); return 1; - } else { + } + else + { dol_print_error($this->db); $this->error = $this->db->error(); return -1; @@ -2308,25 +2367,23 @@ /** - * Initialise an instance with random values. - * Used to build previews or test instances. - * id must be 0 if object instance is a specimen. - * - * @return void - */ - public function initAsSpecimen() - { + * Initialise an instance with random values. + * Used to build previews or test instances. + * id must be 0 if object instance is a specimen. + * + * @return void + */ + public function initAsSpecimen() + { global $user, $langs, $conf; - // Load array of products prodids + // Load array of products prodids $num_prods = 0; $prodids = array(); $sql = "SELECT rowid"; $sql .= " FROM ".MAIN_DB_PREFIX."product"; $sql .= " WHERE entity IN (".getEntity('product').")"; $sql .= " AND tosell = 1"; - $sql .= $this->db->plimit(100); - $resql = $this->db->query($sql); if ($resql) { @@ -2375,10 +2432,10 @@ $line->date_end = dol_now() + 500000; $line->date_end_real = dol_now() - 100000; if ($num_prods > 0) - { + { $prodid = mt_rand(1, $num_prods); $line->fk_product = $prodids[$prodid]; - } + } $this->lines[$xnbp] = $line; $xnbp++; } @@ -2403,7 +2460,7 @@ * @param int $hidedetails Hide details of lines * @param int $hidedesc Hide description * @param int $hideref Hide ref - * @param null|array $moreparams Array to provide more information + * @param null|array $moreparams Array to provide more information * @return int 0 if KO, 1 if OK */ public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) @@ -2411,14 +2468,11 @@ global $conf, $langs; $langs->load("contracts"); - $outputlangs->load("products"); if (!dol_strlen($modele)) { $modele = 'strato'; - if (!empty($this->model_pdf)) { - $modele = $this->model_pdf; - } elseif (!empty($this->modelpdf)) { // deprecated + if ($this->modelpdf) { $modele = $this->modelpdf; } elseif (!empty($conf->global->CONTRACT_ADDON_PDF)) { $modele = $conf->global->CONTRACT_ADDON_PDF; @@ -2455,8 +2509,8 @@ * @param int $notrigger 1=Does not execute triggers, 0= execute triggers * @return int New id of clone */ - public function createFromClone(User $user, $socid = 0, $notrigger = 0) - { + public function createFromClone(User $user, $socid = 0, $notrigger = 0) + { global $db, $langs, $conf, $hookmanager, $extrafields; dol_include_once('/projet/class/project.class.php'); @@ -2467,7 +2521,7 @@ // Load dest object $clonedObj = clone $this; - $clonedObj->socid = $socid; + $clonedObj->socid = $socid; $this->db->begin(); @@ -2518,13 +2572,13 @@ $this->error = $clonedObj->error; $this->errors[] = $clonedObj->error; } else { - // copy external contacts if same company - if ($this->socid == $clonedObj->socid) { - if ($clonedObj->copy_linked_contact($this, 'external') < 0) { - $error++; - } - } - } + // copy external contacts if same company + if ($this->socid == $clonedObj->socid) { + if ($clonedObj->copy_linked_contact($this, 'external') < 0) { + $error++; + } + } + } if (!$error) { foreach ($this->lines as $line) { @@ -2570,12 +2624,12 @@ */ class ContratLigne extends CommonObjectLine { - /** + /** * @var string ID to identify managed object */ public $element = 'contratdet'; - /** + /** * @var string Name of table without prefix where object is stored */ public $table_element = 'contratdet'; @@ -2593,13 +2647,13 @@ public $tms; /** - * @var int ID - */ + * @var int ID + */ public $fk_contrat; /** - * @var int ID - */ + * @var int ID + */ public $fk_product; public $statut; // 0 inactive, 4 active, 5 closed @@ -2622,7 +2676,6 @@ */ public $description; - public $product_type; // 0 for product, 1 for service public $product_ref; public $product_label; @@ -2647,8 +2700,8 @@ public $remise; /** - * @var int ID - */ + * @var int ID + */ public $fk_remise_except; public $subprice; // Unit price HT @@ -2669,8 +2722,8 @@ public $total_ttc; /** - * @var int ID - */ + * @var int ID + */ public $fk_fournprice; public $pa_ht; @@ -2678,18 +2731,18 @@ public $info_bits; /** - * @var int ID - */ + * @var int ID + */ public $fk_user_author; /** - * @var int ID - */ + * @var int ID + */ public $fk_user_ouverture; /** - * @var int ID - */ + * @var int ID + */ public $fk_user_cloture; public $commentaire; @@ -2701,9 +2754,9 @@ /** - * Constructor - * - * @param DoliDb $db Database handler + * Constructor + * + * @param DoliDb $db Database handler */ public function __construct($db) { @@ -2722,7 +2775,7 @@ return $this->LibStatut($this->statut, $mode, ((!empty($this->date_fin_validite)) ? ($this->date_fin_validite < dol_now() ? 1 : 0) : -1)); } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return label of a contract line status * @@ -2734,26 +2787,15 @@ */ public static function LibStatut($status, $mode, $expired = -1, $moreatt = '') { - // phpcs:enable + // phpcs:enable global $langs; $langs->load("contracts"); - if ($status == self::STATUS_INITIAL) { - $labelStatus = $langs->trans("ServiceStatusInitial"); - $labelStatusShort = $langs->trans("ServiceStatusInitial"); - } elseif ($status == self::STATUS_OPEN && $expired == -1) { - $labelStatus = $langs->trans("ServiceStatusRunning"); - $labelStatusShort = $langs->trans("ServiceStatusRunning"); - } elseif ($status == self::STATUS_OPEN && $expired == 0) { - $labelStatus = $langs->trans("ServiceStatusNotLate"); - $labelStatusShort = $langs->trans("ServiceStatusNotLateShort"); - } elseif ($status == self::STATUS_OPEN && $expired == 1) { - $labelStatus = $langs->trans("ServiceStatusLate"); - $labelStatusShort = $langs->trans("ServiceStatusLateShort"); - } elseif ($status == self::STATUS_CLOSED) { - $labelStatus = $langs->trans("ServiceStatusClosed"); - $labelStatusShort = $langs->trans("ServiceStatusClosed"); - } + if ($status == self::STATUS_INITIAL) { $labelStatus = $langs->trans("ServiceStatusInitial"); $labelStatusShort = $langs->trans("ServiceStatusInitial"); } + elseif ($status == self::STATUS_OPEN && $expired == -1) { $labelStatus = $langs->trans("ServiceStatusRunning"); $labelStatusShort = $langs->trans("ServiceStatusRunning"); } + elseif ($status == self::STATUS_OPEN && $expired == 0) { $labelStatus = $langs->trans("ServiceStatusNotLate"); $labelStatusShort = $langs->trans("ServiceStatusNotLateShort"); } + elseif ($status == self::STATUS_OPEN && $expired == 1) { $labelStatus = $langs->trans("ServiceStatusLate"); $labelStatusShort = $langs->trans("ServiceStatusLateShort"); } + elseif ($status == self::STATUS_CLOSED) { $labelStatus = $langs->trans("ServiceStatusClosed"); $labelStatusShort = $langs->trans("ServiceStatusClosed"); } $statusType = 'status'.$status; if ($status == self::STATUS_OPEN && $expired == 1) $statusType = 'status1'; @@ -2773,22 +2815,22 @@ * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto * @param int $maxlength Max length * @return string Chaine avec URL - */ - public function getNomUrl($withpicto = 0, $maxlength = 0) + */ + public function getNomUrl($withpicto = 0, $maxlength = 0) { global $langs; $result = ''; - $label = $langs->trans("ShowContractOfService").': '.$this->label; - if (empty($label)) $label = $this->description; - - $link = ''; + $label = $langs->trans("ShowContractOfService").': '.$this->label; + if (empty($label)) $label = $this->description; + + $link = ''; $linkend = ''; $picto = 'service'; if ($this->type == 0) $picto = 'product'; - if ($withpicto) $result .= ($link.img_object($label, $picto, 'class="classfortooltip"').$linkend); + if ($withpicto) $result .= ($link.img_object($label, $picto, 'class="classfortooltip"').$linkend); if ($withpicto && $withpicto != 2) $result .= ' '; if ($withpicto != 2) $result .= $link.($this->product_ref ? $this->product_ref.' ' : '').($this->label ? $this->label : $this->description).$linkend; return $result; @@ -2798,16 +2840,18 @@ * Load object in memory from database * * @param int $id Id object - * @param string $ref Ref of contract line + * @param string $ref Ref of contract * @return int <0 if KO, >0 if OK */ - public function fetch($id, $ref = '') - { + public function fetch($id, $ref = '') + { + // Check parameters if (empty($id) && empty($ref)) return -1; $sql = "SELECT"; $sql .= " t.rowid,"; + $sql .= " t.tms,"; $sql .= " t.fk_contrat,"; $sql .= " t.fk_product,"; @@ -2908,18 +2952,16 @@ $this->fk_user_cloture = $obj->fk_user_cloture; $this->commentaire = $obj->commentaire; $this->fk_fournprice = $obj->fk_fournprice; - $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->fk_fournprice, $obj->pa_ht); $this->pa_ht = $marginInfos[0]; $this->fk_unit = $obj->fk_unit; - - $this->fetch_optionals(); - } - + } $this->db->free($resql); return 1; - } else { + } + else + { $this->error = "Error ".$this->db->lasterror(); return -1; } @@ -2996,7 +3038,7 @@ $this->total_localtax1 = $tabprice[9]; $this->total_localtax2 = $tabprice[10]; - if (empty($this->pa_ht)) $this->pa_ht = 0; + if (empty($this->pa_ht)) $this->pa_ht = 0; // if buy price not defined, define buyprice as configured in margin admin if ($this->pa_ht == 0) @@ -3004,7 +3046,9 @@ if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0) { return $result; - } else { + } + else + { $this->pa_ht = $result; } } @@ -3014,7 +3058,7 @@ $this->oldcopy = new ContratLigne($this->db); $this->oldcopy->fetch($this->id); - $this->oldcopy->fetch_optionals(); + $this->oldcopy->fetch_optionals(); // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET"; @@ -3102,18 +3146,18 @@ } if (!$error && !$notrigger) { - // Call trigger - $result = $this->call_trigger('LINECONTRACT_UPDATE', $user); - if ($result < 0) { - $error++; - $this->db->rollback(); - } - // End call triggers + // Call trigger + $result = $this->call_trigger('LINECONTRACT_UPDATE', $user); + if ($result < 0) { + $error++; + $this->db->rollback(); + } + // End call triggers } if (!$error) { - $this->db->commit(); + $this->db->commit(); return 1; } else { $this->db->rollback(); @@ -3123,7 +3167,7 @@ } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Mise a jour en base des champs total_xxx de ligne * Used by migration process @@ -3132,7 +3176,7 @@ */ public function update_total() { - // phpcs:enable + // phpcs:enable $this->db->begin(); // Mise a jour ligne en base @@ -3151,7 +3195,9 @@ { $this->db->commit(); return 1; - } else { + } + else + { $this->error = $this->db->error(); $this->db->rollback(); return -2; @@ -3232,14 +3278,16 @@ $this->db->commit(); return 1; - } else { + } + else + { $this->db->rollback(); $this->error = $this->db->error()." sql=".$sql; return -1; } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Activate a contract line * @@ -3251,7 +3299,7 @@ */ public function active_line($user, $date, $date_end = '', $comment = '') { - // phpcs:enable + // phpcs:enable global $langs, $conf; $error = 0; @@ -3285,7 +3333,9 @@ $this->db->commit(); return 1; - } else { + } + else + { $this->db->rollback(); return -1; } @@ -3296,19 +3346,19 @@ } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Close a contract line * * @param User $user Objet User who close contract * @param int $date_end Date end * @param string $comment A comment typed by user - * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers + * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers * @return int <0 if KO, >0 if OK */ public function close_line($user, $date_end, $comment = '', $notrigger = 0) { - // phpcs:enable + // phpcs:enable global $langs, $conf; // Update object