diff --git a/ChangeLog b/ChangeLog index d80f8781ba1..c5ddefd980e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,17 +17,18 @@ Following changes may create regressions for some external modules, but were nec * The methode "cloture" on contract were renamed into "closeAll". * The substitution key for reference of object is now __REF__ whatever is the object (it replaces __ORDERREF__, __PROPALREF__, ...) -* The substition key __SIGNATURE__ was renamed into __USER_SIGNATURE__ to standardize naming conventions. +* The substition key __SIGNATURE__ was renamed into __USER_SIGNATURE__ to follow naming conventions. * Substitution keys with syntax %XXX% were renamed into __XXX__ to match others. * Some REST API to access setup features, like dictionaries (country, town, extrafields, ...) were moved into a - common API "/setup". + common API "/setup". +* The REST API /documents were renamed into /documents/download and /documents/upload. * Page bank/index.php and bank/bankentries.php were renamed into bank/list.php and bank/bankentries_list.php to follow page naming conventions (so default filter/sort order features can also work). -* The trigger ORDER_SUPPLIER_STATUS_ONPROCESS was renamed into ORDER_SUPPLIER_STATUS_ORDERED -* The trigger ORDER_SUPPLIER_STATUS_RECEIVED_ALL was renamed into ORDER_SUPPLIER_STATUS_RECEIVED_COMPLETELY -* The parameter note into method cloture() is added at end of private note (previously in v6, it replaced) +* The trigger ORDER_SUPPLIER_STATUS_ONPROCESS was renamed into ORDER_SUPPLIER_STATUS_ORDERED. +* The trigger ORDER_SUPPLIER_STATUS_RECEIVED_ALL was renamed into ORDER_SUPPLIER_STATUS_RECEIVED_COMPLETELY. +* The parameter note into method cloture() is added at end of private note (previously in v6, it replaced). * The parameter $user is now mandatory for method createFromOrder and createFromPropal. -* Remove js library fileupload that was not used by core code. +* Removed js library 'fileupload' that was not used by core code. ***** ChangeLog for 6.0.3 compared to 6.0.2 ***** diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index dede8690c06..5c85cddfaee 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -96,6 +96,7 @@ class DolibarrApi // Remove $db object property for object unset($object->db); + unset($object->ismultientitymanaged); // Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses unset($object->linkedObjects); @@ -129,6 +130,8 @@ class DolibarrApi unset($object->statuts_short); unset($object->statuts_logo); unset($object->statuts_long); + unset($object->labelstatut); + unset($object->labelstatut_short); unset($object->element); unset($object->fk_element); diff --git a/htdocs/api/class/api_documents.class.php b/htdocs/api/class/api_documents.class.php index 92b48dfd0c6..da97215dc0c 100644 --- a/htdocs/api/class/api_documents.class.php +++ b/htdocs/api/class/api_documents.class.php @@ -53,8 +53,10 @@ class Documents extends DolibarrApi /** - * Returns a document. Note that, this API is similar to using the wrapper link "documents.php" to download - * a file (used for internal HTML links of documents into application), but with no need to be into a logged session (no need to post the session cookie). + * Download a document. + * + * Note that, this API is similar to using the wrapper link "documents.php" to download a file (used for + * internal HTML links of documents into application), but with no need to have a session cookie (the token is used instead). * * @param string $module_part Name of module or area concerned by file download ('facture', ...) * @param string $original_file Relative path with filename, relative to modulepart (for example: IN201701-999/IN201701-999.pdf) @@ -67,6 +69,8 @@ class Documents extends DolibarrApi * @throws 400 * @throws 401 * @throws 200 + * + * @url GET /download */ public function index($module_part, $original_file='', $regeneratedoc=0) { @@ -132,7 +136,7 @@ class Documents extends DolibarrApi /** * Return the list of documents of a dedicated element (from its ID or Ref) * - * @param string $modulepart Name of module or area concerned ('facture', 'project', 'member', ...) + * @param string $modulepart Name of module or area concerned ('thirdparty', 'member', 'facture', 'project', ...) * @param int $id ID of element * @param string $ref Ref of element * @param string $sortfield Sort criteria ('','fullname','relativename','name','date','size') @@ -141,7 +145,7 @@ class Documents extends DolibarrApi * * @throws RestException * - * @url GET list + * @url GET / */ function getDocumentsListByElement($modulepart, $id=0, $ref='', $sortfield='', $sortorder='') { @@ -216,7 +220,8 @@ class Documents extends DolibarrApi /** - * Push a file. + * Upload a file. + * * Test sample 1: { "filename": "mynewfile.txt", "modulepart": "facture", "ref": "FA1701-001", "subdir": "", "filecontent": "content text", "fileencoding": "", "overwriteifexists": "0" }. * Test sample 2: { "filename": "mynewfile.txt", "modulepart": "medias", "ref": "", "subdir": "mysubdir1/mysubdir2", "filecontent": "content text", "fileencoding": "", "overwriteifexists": "0" }. * @@ -229,6 +234,8 @@ class Documents extends DolibarrApi * @param int $overwriteifexists Overwrite file if exists (1 by default) * @return bool State of copy * @throws RestException + * + * @url GET /upload */ public function post($filename, $modulepart, $ref='', $subdir='', $filecontent='', $fileencoding='', $overwriteifexists=0) { diff --git a/htdocs/api/index.php b/htdocs/api/index.php index 09f5cdb7cfe..246d3d26296 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -141,8 +141,9 @@ if (! empty($reg[1]) && $reg[1] == 'explorer' && ($reg[2] == '/resources.json' | $moduledirforclass = getModuleDirForApiClass($module); $modulenameforenabled = $module; if ($module == 'propale') { $modulenameforenabled='propal'; } + if ($module == 'supplierproposal') { $modulenameforenabled='supplier_proposal'; } - dol_syslog("Found module file ".$file." - module=".$module." - moduledirforclass=".$moduledirforclass); + dol_syslog("Found module file ".$file." - module=".$module." - modulenameforenabled=".$modulenameforenabled." - moduledirforclass=".$moduledirforclass); // Defined if module is enabled $enabled=true; @@ -255,8 +256,9 @@ if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/resources.json' $tmpmodule = $module; if ($tmpmodule != 'api') $tmpmodule = preg_replace('/api$/i','', $tmpmodule); $classfile = str_replace('_', '', $tmpmodule); - if ($module == 'supplierinvoices') $classfile = 'supplier_invoices'; - if ($module == 'supplierorders') $classfile = 'supplier_orders'; + if ($module == 'supplierproposals') $classfile = 'supplier_proposals'; + if ($module == 'supplierorders') $classfile = 'supplier_orders'; + if ($module == 'supplierinvoices') $classfile = 'supplier_invoices'; $dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_'.$classfile.'.class.php', 0, 2); $classname=ucwords($module); diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 364f63bd4e4..97ea07bf7e6 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -90,7 +90,7 @@ class Proposals extends DolibarrApi * @param string $sortorder Sort order * @param int $limit Limit for list * @param int $page Page number - * @param string $thirdparty_ids Thirdparty ids to filter commercial proposal of. Example: '1' or '1,2,3' {@pattern /^2|3$/i} + * @param string $thirdparty_ids Thirdparty ids to filter commercial proposals. {@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.datec:<:'20160101')" * @return array Array of order objects */ @@ -152,9 +152,9 @@ class Proposals extends DolibarrApi while ($i < $min) { $obj = $db->fetch_object($result); - $propal_static = new Propal($db); - if($propal_static->fetch($obj->rowid)) { - $obj_ret[] = $this->_cleanObjectDatas($propal_static); + $proposal_static = new Propal($db); + if($proposal_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($proposal_static); } $i++; } @@ -163,7 +163,7 @@ class Proposals extends DolibarrApi throw new RestException(503, 'Error when retrieve propal list : '.$db->lasterror()); } if( ! count($obj_ret)) { - throw new RestException(404, 'No order found'); + throw new RestException(404, 'No proposal found'); } return $obj_ret; } @@ -580,6 +580,7 @@ class Proposals extends DolibarrApi $object = parent::_cleanObjectDatas($object); + unset($object->note); unset($object->name); unset($object->lastname); unset($object->firstname); diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index e31aaa4e060..a6788f95698 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -552,6 +552,7 @@ class Orders extends DolibarrApi $object = parent::_cleanObjectDatas($object); + unset($object->note); unset($object->address); unset($object->barcode_type); unset($object->barcode_type_code); diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 222404411d7..fec3edd11ea 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -903,6 +903,7 @@ class Invoices extends DolibarrApi $object = parent::_cleanObjectDatas($object); + unset($object->note); unset($object->address); unset($object->barcode_type); unset($object->barcode_type_code); diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 0806cabed4d..e699758de99 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -2237,6 +2237,9 @@ function getModuleDirForApiClass($module) elseif ($module == 'stock' || $module == 'stockmovements' || $module == 'warehouses') { $moduledirforclass = 'product/stock'; } + elseif ($module == 'supplierproposals' || $module == 'supplierproposal' || $module == 'supplier_proposal') { + $moduledirforclass = 'supplier_proposal'; + } elseif ($module == 'fournisseur' || $module == 'supplierinvoices' || $module == 'supplierorders') { $moduledirforclass = 'fourn'; } diff --git a/htdocs/supplier_proposal/class/api_supplier_proposals.class.php b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php new file mode 100644 index 00000000000..8cb883a2d9b --- /dev/null +++ b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php @@ -0,0 +1,212 @@ + + * 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.'/supplier_proposal/class/supplier_proposal.class.php'; + + +/** + * API class for orders + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class Supplierproposals extends DolibarrApi +{ + + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'socid' + ); + + /** + * @var supplier_proposal $supplier_proposal {@type supplier_proposal} + */ + public $supplier_proposal; + + /** + * Constructor + */ + function __construct() + { + global $db, $conf; + $this->db = $db; + $this->supplier_proposal = new SupplierProposal($this->db); + } + + /** + * Get properties of a supplier proposal (price request) object + * + * Return an array with supplier proposal informations + * + * @param int $id ID of supplier proposal + * @return array|mixed data without useless information + * + * @throws RestException + */ + function get($id) + { + if(! DolibarrApiAccess::$user->rights->supplier_proposal->lire) { + throw new RestException(401); + } + + $result = $this->supplier_proposal->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Supplier Proposal not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('supplier_proposal',$this->propal->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $this->supplier_proposal->fetchObjectLinked(); + return $this->_cleanObjectDatas($this->supplier_proposal); + } + + /** + * List supplier proposals + * + * Get a list of supplier proposals + * + * @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 supplier proposals. {@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.datec:<:'20160101')" + * @return array Array of order objects + */ + 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->societe_id ? DolibarrApiAccess::$user->societe_id : $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."supplier_proposal 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('propal').')'; + 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); + } + + $result = $db->query($sql); + + if ($result) + { + $num = $db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + while ($i < $min) + { + $obj = $db->fetch_object($result); + $propal_static = new SupplierProposal($db); + if($propal_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($propal_static); + } + $i++; + } + } + else { + throw new RestException(503, 'Error when retrieving supplier proposal list : '.$db->lasterror()); + } + if( ! count($obj_ret)) { + throw new RestException(404, 'No supplier proposal found'); + } + return $obj_ret; + } + + + /** + * Validate fields before create or update object + * + * @param array $data Array with data to verify + * @return array + * @throws RestException + */ + function _validate($data) + { + $propal = array(); + foreach (SupplierProposals::$FIELDS as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $propal[$field] = $data[$field]; + + } + return $propal; + } + + + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + */ + function _cleanObjectDatas($object) { + + $object = parent::_cleanObjectDatas($object); + + unset($object->name); + unset($object->lastname); + unset($object->firstname); + unset($object->civility_id); + unset($object->address); + unset($object->datec); + unset($object->datev); + + return $object; + } +}