From 60493d0a4774735616feefe769cfe40a74db7921 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur <eldy@destailleur.fr> Date: Fri, 28 Jul 2017 10:16:17 +0200 Subject: [PATCH] Several fixes (permission, missing method or class) in REST APIs --- htdocs/api/index.php | 1 + .../comm/propal/class/api_proposals.class.php | 128 +++--- htdocs/commande/class/api_orders.class.php | 20 +- .../facture/class/api_invoices.class.php | 127 ++++-- htdocs/core/lib/functions2.lib.php | 2 +- .../class/api_supplier_invoices.class.php | 126 ++++-- .../fourn/class/api_supplier_orders.class.php | 365 ++++++++++++++++++ 7 files changed, 623 insertions(+), 146 deletions(-) create mode 100644 htdocs/fourn/class/api_supplier_orders.class.php diff --git a/htdocs/api/index.php b/htdocs/api/index.php index 905d560f9c2..9f734c9e24d 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -238,6 +238,7 @@ if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/resources.json' { $classfile = str_replace('_', '', $module); if ($module == 'supplierinvoices') $classfile = 'supplier_invoices'; + if ($module == 'supplierorders') $classfile = 'supplier_orders'; $dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_'.$classfile.'.class.php'); $classname=ucwords($module); diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 2f067f46b18..42dbdbf9d2c 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -24,14 +24,14 @@ require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; /** * API class for orders * - * @access protected + * @access protected * @class DolibarrApiAccess {@requires user,external} */ class Proposals extends DolibarrApi { /** - * @var array $FIELDS Mandatory fields, checked when create and update object + * @var array $FIELDS Mandatory fields, checked when create and update object */ static $FIELDS = array( 'socid' @@ -56,36 +56,36 @@ class Proposals extends DolibarrApi * Get properties of a commercial proposal object * * Return an array with commercial proposal informations - * + * * @param int $id ID of commercial proposal * @return array|mixed data without useless information * * @throws RestException */ function get($id) - { + { if(! DolibarrApiAccess::$user->rights->propal->lire) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Commercial Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - + $this->propal->fetchObjectLinked(); return $this->_cleanObjectDatas($this->propal); } /** * List commercial proposals - * + * * Get a list of commercial proposals - * + * * @param string $sortfield Sort field * @param string $sortorder Sort order * @param int $limit Limit for list @@ -96,12 +96,12 @@ class Proposals extends DolibarrApi */ function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $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; @@ -109,7 +109,7 @@ class Proposals extends DolibarrApi $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."propal 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').')'; @@ -122,7 +122,7 @@ class Proposals extends DolibarrApi $sql .= " AND sc.fk_user = ".$search_sale; } // Add sql filters - if ($sqlfilters) + if ($sqlfilters) { if (! DolibarrApi::_checkFilters($sqlfilters)) { @@ -131,7 +131,7 @@ class Proposals extends DolibarrApi $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; } - + $sql.= $db->order($sortfield, $sortorder); if ($limit) { if ($page < 0) @@ -144,7 +144,7 @@ class Proposals extends DolibarrApi } $result = $db->query($sql); - + if ($result) { $num = $db->num_rows($result); @@ -195,7 +195,7 @@ class Proposals extends DolibarrApi if ($this->propal->create(DolibarrApiAccess::$user) < 0) { throw new RestException(500, "Error creating order", array_merge(array($this->propal->error), $this->propal->errors)); } - + return $this->propal->id; } @@ -203,21 +203,21 @@ class Proposals extends DolibarrApi * Get lines of a commercial proposal * * @param int $id Id of commercial proposal - * + * * @url GET {id}/lines - * - * @return int + * + * @return int */ function getLines($id) { if(! DolibarrApiAccess::$user->rights->propal->lire) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Commercial Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -233,22 +233,22 @@ class Proposals extends DolibarrApi * Add a line to given commercial proposal * * @param int $id Id of commercial proposal to update - * @param array $request_data Commercial proposal line data - * + * @param array $request_data Commercial proposal line data + * * @url POST {id}/lines - * - * @return int + * + * @return int */ function postLine($id, $request_data = NULL) { if(! DolibarrApiAccess::$user->rights->propal->creer) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Commercial Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -294,22 +294,22 @@ class Proposals extends DolibarrApi * * @param int $id Id of commercial proposal to update * @param int $lineid Id of line to update - * @param array $request_data Commercial proposal line data - * + * @param array $request_data Commercial proposal line data + * * @url PUT {id}/lines/{lineid} - * - * @return object + * + * @return object */ function putLine($id, $lineid, $request_data = NULL) { if(! DolibarrApiAccess::$user->rights->propal->creer) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -352,21 +352,21 @@ class Proposals extends DolibarrApi * * @param int $id Id of commercial proposal to update * @param int $lineid Id of line to delete - * + * * @url DELETE {id}/lines/{lineid} - * - * @return int + * + * @return int */ function delLine($id, $lineid) { if(! DolibarrApiAccess::$user->rights->propal->creer) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -382,20 +382,20 @@ class Proposals extends DolibarrApi * Update commercial proposal general fields (won't touch lines of commercial proposal) * * @param int $id Id of commercial proposal to update - * @param array $request_data Datas - * - * @return int + * @param array $request_data Datas + * + * @return int */ function put($id, $request_data = NULL) { if(! DolibarrApiAccess::$user->rights->propal->creer) { throw new RestException(401); } - + $result = $this->propal->fetch($id); if( ! $result ) { throw new RestException(404, 'Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -403,18 +403,18 @@ class Proposals extends DolibarrApi if ($field == 'id') continue; $this->propal->$field = $value; } - + if($this->propal->update($id, DolibarrApiAccess::$user,1,'','','update')) return $this->get($id); - + return false; } - + /** * Delete commercial proposal * * @param int $id Commercial proposal ID - * + * * @return array */ function delete($id) @@ -426,32 +426,32 @@ class Proposals extends DolibarrApi if( ! $result ) { throw new RestException(404, 'Commercial Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - + if( ! $this->propal->delete(DolibarrApiAccess::$user)) { throw new RestException(500, 'Error when delete Commercial Proposal : '.$this->propal->error); } - + return array( 'success' => array( 'code' => 200, 'message' => 'Commercial Proposal deleted' ) ); - + } - + /** * Validate a commercial proposal - * + * * @param int $id Commercial proposal ID * @param int $notrigger Use {} - * + * * @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." @@ -469,11 +469,11 @@ class Proposals extends DolibarrApi if( ! $result ) { throw new RestException(404, 'Commercial Proposal not found'); } - + if( ! DolibarrApi::_checkAccessToResource('propal',$this->propal->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - + $result = $this->propal->valid(DolibarrApiAccess::$user, $notrigger); if ($result == 0) { throw new RestException(500, 'Error nothing done. May be object is already validated'); @@ -481,30 +481,30 @@ class Proposals extends DolibarrApi if ($result < 0) { throw new RestException(500, 'Error when validating Commercial Proposal: '.$this->propal->error); } - + return array( 'success' => array( 'code' => 200, - 'message' => 'Commercial Proposal validated' + 'message' => 'Commercial Proposal validated (Ref='.$this->propal->ref.')' ) ); } - + /** * Validate fields before create or update object - * + * * @param array $data Array with data to verify - * @return array + * @return array * @throws RestException */ function _validate($data) { $propal = array(); - foreach (Orders::$FIELDS as $field) { + foreach (Proposals::$FIELDS as $field) { if (!isset($data[$field])) throw new RestException(400, "$field field missing"); $propal[$field] = $data[$field]; - + } return $propal; } diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index a1330a7be04..d4b4502d4ed 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -80,8 +80,8 @@ class Orders extends DolibarrApi return $this->_cleanObjectDatas($this->commande); } - - + + /** * List orders * @@ -101,7 +101,7 @@ class Orders extends DolibarrApi 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; @@ -125,7 +125,7 @@ class Orders extends DolibarrApi $sql .= " AND sc.fk_user = ".$search_sale; } // Add sql filters - if ($sqlfilters) + if ($sqlfilters) { if (! DolibarrApi::_checkFilters($sqlfilters)) { @@ -134,7 +134,7 @@ class Orders extends DolibarrApi $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; } - + $sql.= $db->order($sortfield, $sortorder); if ($limit) { if ($page < 0) @@ -490,7 +490,7 @@ class Orders extends DolibarrApi return array( 'success' => array( 'code' => 200, - 'message' => 'Order validated' + 'message' => 'Order validated (Ref='.$this->commande->ref.')' ) ); } @@ -502,14 +502,14 @@ class Orders extends DolibarrApi * @return array Array of cleaned object properties */ function _cleanObjectDatas($object) { - + $object = parent::_cleanObjectDatas($object); - + unset($object->address); - + return $object; } - + /** * Validate fields before create or update object * diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 55304136ed6..f841fc80050 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -22,14 +22,14 @@ /** * API class for invoices * - * @access protected + * @access protected * @class DolibarrApiAccess {@requires user,external} */ class Invoices extends DolibarrApi { /** * - * @var array $FIELDS Mandatory fields, checked when create and update object + * @var array $FIELDS Mandatory fields, checked when create and update object */ static $FIELDS = array( 'socid' @@ -54,23 +54,23 @@ class Invoices extends DolibarrApi * Get properties of a invoice object * * Return an array with invoice informations - * + * * @param int $id ID of invoice * @return array|mixed data without useless information * * @throws RestException */ function get($id) - { + { if(! DolibarrApiAccess::$user->rights->facture->lire) { throw new RestException(401); } - + $result = $this->invoice->fetch($id); if( ! $result ) { throw new RestException(404, 'Invoice not found'); } - + if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -80,9 +80,9 @@ class Invoices extends DolibarrApi /** * List invoices - * + * * Get a list of invoices - * + * * @param string $sortfield Sort field * @param string $sortorder Sort order * @param int $limit Limit for list @@ -96,12 +96,12 @@ class Invoices extends DolibarrApi */ function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $thirdparty_ids='', $status='', $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; @@ -109,7 +109,7 @@ class Invoices extends DolibarrApi $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."facture 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('facture').')'; @@ -117,7 +117,7 @@ class Invoices extends DolibarrApi 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 - + // Filter by status if ($status == 'draft') $sql.= " AND t.fk_statut IN (0)"; if ($status == 'unpaid') $sql.= " AND t.fk_statut IN (1)"; @@ -129,7 +129,7 @@ class Invoices extends DolibarrApi $sql .= " AND sc.fk_user = ".$search_sale; } // Add sql filters - if ($sqlfilters) + if ($sqlfilters) { if (! DolibarrApi::_checkFilters($sqlfilters)) { @@ -138,7 +138,7 @@ class Invoices extends DolibarrApi $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; } - + $sql.= $db->order($sortfield, $sortorder); if ($limit) { if ($page < 0) @@ -174,10 +174,10 @@ class Invoices extends DolibarrApi } return $obj_ret; } - + /** * Create invoice object - * + * * @param array $request_data Request datas * @return int ID of invoice */ @@ -188,7 +188,7 @@ class Invoices extends DolibarrApi } // Check mandatory fields $result = $this->_validate($request_data); - + foreach($request_data as $field => $value) { $this->invoice->$field = $value; } @@ -203,7 +203,7 @@ class Invoices extends DolibarrApi } $this->invoice->lines = $lines; }*/ - + if ($this->invoice->create(DolibarrApiAccess::$user) < 0) { throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors)); } @@ -214,20 +214,20 @@ class Invoices extends DolibarrApi * Update invoice * * @param int $id Id of invoice to update - * @param array $request_data Datas - * @return int + * @param array $request_data Datas + * @return int */ function put($id, $request_data = NULL) { if(! DolibarrApiAccess::$user->rights->facture->creer) { throw new RestException(401); } - + $result = $this->invoice->fetch($id); if( ! $result ) { throw new RestException(404, 'Invoice not found'); } - + if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -236,13 +236,13 @@ class Invoices extends DolibarrApi if ($field == 'id') continue; $this->invoice->$field = $value; } - + if($this->invoice->update($id, DolibarrApiAccess::$user)) return $this->get ($id); - + return false; } - + /** * Delete invoice * @@ -258,16 +258,16 @@ class Invoices extends DolibarrApi if( ! $result ) { throw new RestException(404, 'Invoice not found'); } - + if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - + if( $this->invoice->delete($id) < 0) { throw new RestException(500); } - + return array( 'success' => array( 'code' => 200, @@ -275,13 +275,76 @@ class Invoices extends DolibarrApi ) ); } - + + /** + * Validate an order + * + * @param int $id Order ID + * @param int $idwarehouse Warehouse 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 + * { + * "idwarehouse": 0, + * "notrigger": 0 + * } + */ + function validate($id, $idwarehouse=0, $notrigger=0) + { + if(! DolibarrApiAccess::$user->rights->facture->creer) { + throw new RestException(401); + } + $result = $this->invoice->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Invoice not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->invoice->validate(DolibarrApiAccess::$user, '', $idwarehouse, $notrigger); + if ($result == 0) { + throw new RestException(500, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when validating Invoice: '.$this->invoice->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Invoice validated (Ref='.$this->invoice->ref.')' + ) + ); + } + + /** + * 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->address); + + return $object; + } + /** * Validate fields before create or update object - * + * * @param array|null $data Datas to validate * @return array - * + * * @throws RestException */ function _validate($data) @@ -294,5 +357,5 @@ class Invoices extends DolibarrApi } return $invoice; } - + } diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 72f27a16602..181e8a7fe11 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -2200,7 +2200,7 @@ function getModuleDirForApiClass($module) elseif ($module == 'stock' || $module == 'stockmovements' || $module == 'warehouses') { $moduledirforclass = 'product/stock'; } - elseif ($module == 'fournisseur' || $module == 'supplierinvoices') { + elseif ($module == 'fournisseur' || $module == 'supplierinvoices' || $module == 'supplierorders') { $moduledirforclass = 'fourn'; } elseif ($module == 'expensereports') { diff --git a/htdocs/fourn/class/api_supplier_invoices.class.php b/htdocs/fourn/class/api_supplier_invoices.class.php index 6f3291518ca..26ae936d5a0 100644 --- a/htdocs/fourn/class/api_supplier_invoices.class.php +++ b/htdocs/fourn/class/api_supplier_invoices.class.php @@ -23,14 +23,14 @@ require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; /** * API class for supplier invoices * - * @access protected + * @access protected * @class DolibarrApiAccess {@requires user,external} */ class SupplierInvoices extends DolibarrApi { /** * - * @var array $FIELDS Mandatory fields, checked when create and update object + * @var array $FIELDS Mandatory fields, checked when create and update object */ static $FIELDS = array( 'socid' @@ -55,24 +55,24 @@ class SupplierInvoices extends DolibarrApi * Get properties of a supplier invoice object * * Return an array with supplier invoice information - * + * * @param int $id ID of supplier invoice * @return array|mixed data without useless information * * @throws RestException */ function get($id) - { + { if(! DolibarrApiAccess::$user->rights->fournisseur->facture->lire) { throw new RestException(401); } - + $result = $this->invoice->fetch($id); if( ! $result ) { throw new RestException(404, 'Supplier invoice not found'); } - - if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->invoice->id,'facture_fourn','facture')) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -81,9 +81,9 @@ class SupplierInvoices extends DolibarrApi /** * List invoices - * + * * Get a list of supplier invoices - * + * * @param string $sortfield Sort field * @param string $sortorder Sort order * @param int $limit Limit for list @@ -97,12 +97,12 @@ class SupplierInvoices extends DolibarrApi */ function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $thirdparty_ids='', $status='', $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 && !$socid) $search_sale = DolibarrApiAccess::$user->id; @@ -110,14 +110,14 @@ class SupplierInvoices extends DolibarrApi $sql = "SELECT t.rowid"; if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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."facture_fourn as t"; - + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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('supplier_invoice').')'; if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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 - + // Filter by status if ($status == 'draft') $sql.= " AND t.fk_statut IN (0)"; if ($status == 'unpaid') $sql.= " AND t.fk_statut IN (1)"; @@ -129,7 +129,7 @@ class SupplierInvoices extends DolibarrApi $sql .= " AND sc.fk_user = ".$search_sale; } // Add sql filters - if ($sqlfilters) + if ($sqlfilters) { if (! DolibarrApi::_checkFilters($sqlfilters)) { @@ -138,7 +138,7 @@ class SupplierInvoices extends DolibarrApi $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; } - + $sql.= $db->order($sortfield, $sortorder); if ($limit) { if ($page < 0) @@ -174,10 +174,10 @@ class SupplierInvoices extends DolibarrApi } return $obj_ret; } - + /** * Create supplier invoice object - * + * * @param array $request_data Request datas * @return int ID of supplier invoice */ @@ -188,7 +188,7 @@ class SupplierInvoices extends DolibarrApi } // Check mandatory fields $result = $this->_validate($request_data); - + foreach($request_data as $field => $value) { $this->invoice->$field = $value; } @@ -203,7 +203,7 @@ class SupplierInvoices extends DolibarrApi } $this->invoice->lines = $lines; }*/ - + if ($this->invoice->create(DolibarrApiAccess::$user) < 0) { throw new RestException(500, "Error creating order", array_merge(array($this->invoice->error), $this->invoice->errors)); } @@ -214,21 +214,21 @@ class SupplierInvoices extends DolibarrApi * Update supplier invoice * * @param int $id Id of supplier invoice to update - * @param array $request_data Datas - * @return int + * @param array $request_data Datas + * @return int */ function put($id, $request_data = NULL) { if(! DolibarrApiAccess::$user->rights->fournisseur->facture->creer) { throw new RestException(401); } - + $result = $this->invoice->fetch($id); if( ! $result ) { throw new RestException(404, 'Supplier invoice not found'); } - - if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->invoice->id,'facture_fourn','facture')) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -236,13 +236,13 @@ class SupplierInvoices extends DolibarrApi if ($field == 'id') continue; $this->invoice->$field = $value; } - + if($this->invoice->update($id, DolibarrApiAccess::$user)) return $this->get ($id); - + return false; } - + /** * Delete supplier invoice * @@ -258,16 +258,16 @@ class SupplierInvoices extends DolibarrApi if( ! $result ) { throw new RestException(404, 'Supplier invoice not found'); } - - if( ! DolibarrApi::_checkAccessToResource('facture',$this->invoice->id)) { + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->invoice->id,'facture_fourn','facture')) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - + if( $this->invoice->delete(DolibarrApiAccess::$user) < 0) { throw new RestException(500); } - + return array( 'success' => array( 'code' => 200, @@ -275,8 +275,56 @@ class SupplierInvoices extends DolibarrApi ) ); } - - + + + /** + * Validate an order + * + * @param int $id Order ID + * @param int $idwarehouse Warehouse 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 + * { + * "idwarehouse": 0, + * "notrigger": 0 + * } + */ + function validate($id, $idwarehouse=0, $notrigger=0) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->facture->creer) { + throw new RestException(401); + } + $result = $this->invoice->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Invoice not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->invoice->id,'facture_fourn','facture')) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->invoice->validate(DolibarrApiAccess::$user, '', $idwarehouse, $notrigger); + if ($result == 0) { + throw new RestException(500, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when validating Invoice: '.$this->invoice->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Invoice validated (Ref='.$this->invoice->ref.')' + ) + ); + } + /** * Clean sensible object datas * @@ -284,20 +332,20 @@ class SupplierInvoices extends DolibarrApi * @return array Array of cleaned object properties */ function _cleanObjectDatas($object) { - + $object = parent::_cleanObjectDatas($object); - + unset($object->rowid); - + return $object; } - + /** * Validate fields before create or update object - * + * * @param array $data Datas to validate * @return array - * + * * @throws RestException */ function _validate($data) diff --git a/htdocs/fourn/class/api_supplier_orders.class.php b/htdocs/fourn/class/api_supplier_orders.class.php new file mode 100644 index 00000000000..2695727c3ee --- /dev/null +++ b/htdocs/fourn/class/api_supplier_orders.class.php @@ -0,0 +1,365 @@ +<?php +/* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr> + * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +use Luracast\Restler\RestException; + +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; + +/** + * API class for supplier orders + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class SupplierOrders extends DolibarrApi +{ + /** + * + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'socid' + ); + + /** + * @var CommandeFournisseur $order {@type CommandeFournisseur} + */ + public $order; + + /** + * Constructor + */ + function __construct() + { + global $db, $conf; + $this->db = $db; + $this->order = new CommandeFournisseur($this->db); + } + + /** + * Get properties of a supplier order object + * + * Return an array with supplier order information + * + * @param int $id ID of supplier order + * @return array|mixed data without useless information + * + * @throws RestException + */ + function get($id) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->commande->lire) { + throw new RestException(401); + } + + $result = $this->order->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Supplier order not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->order->id,'','commande')) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + return $this->_cleanObjectDatas($this->order); + } + + /** + * List orders + * + * Get a list of supplier orders + * + * @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 orders of. {@example '1' or '1,2,3'} {@pattern /^[0-9,]*$/i} + * @param string $status Filter by order status : draft | validated | approved | running | received_start | received_end | cancelled | refused + * @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 + * + * @throws RestException + */ + function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $thirdparty_ids='', $status='', $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 && !$socid) $search_sale = DolibarrApiAccess::$user->id; + + $sql = "SELECT t.rowid"; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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."commande_fournisseur as t"; + + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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('supplier_order').')'; + if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $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 + + // Filter by status + if ($status == 'draft') $sql.= " AND t.fk_statut IN (0)"; + if ($status == 'validated') $sql.= " AND t.fk_statut IN (1)"; + if ($status == 'approved') $sql.= " AND t.fk_statut IN (2)"; + if ($status == 'running') $sql.= " AND t.fk_statut IN (3)"; + if ($status == 'received_start') $sql.= " AND t.fk_statut IN (4)"; + if ($status == 'received_end') $sql.= " AND t.fk_statut IN (5)"; + if ($status == 'cancelled') $sql.= " AND t.fk_statut IN (6,7)"; + if ($status == 'refused') $sql.= " AND t.fk_statut IN (9)"; + // 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) + { + $i = 0; + $num = $db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + while ($i < $min) + { + $obj = $db->fetch_object($result); + $order_static = new CommandeFournisseur($db); + if($order_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($order_static); + } + $i++; + } + } + else { + throw new RestException(503, 'Error when retrieve supplier order list : '.$db->lasterror()); + } + if( ! count($obj_ret)) { + throw new RestException(404, 'No supplier order found'); + } + return $obj_ret; + } + + /** + * Create supplier order object + * + * @param array $request_data Request datas + * @return int ID of supplier order + */ + function post($request_data = NULL) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->commande->creer) { + throw new RestException(401, "Insuffisant rights"); + } + // Check mandatory fields + $result = $this->_validate($request_data); + + foreach($request_data as $field => $value) { + $this->order->$field = $value; + } + if(! array_keys($request_data,'date')) { + $this->order->date = dol_now(); + } + /* We keep lines as an array + if (isset($request_data["lines"])) { + $lines = array(); + foreach ($request_data["lines"] as $line) { + array_push($lines, (object) $line); + } + $this->order->lines = $lines; + }*/ + + if ($this->order->create(DolibarrApiAccess::$user) < 0) { + throw new RestException(500, "Error creating order", array_merge(array($this->order->error), $this->order->errors)); + } + return $this->order->id; + } + + /** + * Update supplier order + * + * @param int $id Id of supplier order to update + * @param array $request_data Datas + * @return int + */ + function put($id, $request_data = NULL) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->commande->creer) { + throw new RestException(401); + } + + $result = $this->order->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Supplier order not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->order->id,'','commande')) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + foreach($request_data as $field => $value) { + if ($field == 'id') continue; + $this->order->$field = $value; + } + + if($this->order->update($id, DolibarrApiAccess::$user)) + return $this->get ($id); + + return false; + } + + /** + * Delete supplier order + * + * @param int $id Supplier order ID + * @return type + */ + function delete($id) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->commande->supprimer) { + throw new RestException(401); + } + $result = $this->order->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Supplier order not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->order->id,'','commande')) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if( $this->order->delete(DolibarrApiAccess::$user) < 0) + { + throw new RestException(500); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Supplier order deleted' + ) + ); + } + + + /** + * Validate an order + * + * @param int $id Order ID + * @param int $idwarehouse Warehouse 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 + * { + * "idwarehouse": 0, + * "notrigger": 0 + * } + */ + function validate($id, $idwarehouse=0, $notrigger=0) + { + if(! DolibarrApiAccess::$user->rights->fournisseur->commande->creer) { + throw new RestException(401); + } + $result = $this->order->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Order not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('fournisseur',$this->order->id,'','commande')) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + $result = $this->order->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger); + if ($result == 0) { + throw new RestException(500, 'Error nothing done. May be object is already validated'); + } + if ($result < 0) { + throw new RestException(500, 'Error when validating Order: '.$this->order->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Order validated (Ref='.$this->order->ref.')' + ) + ); + } + + /** + * 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->rowid); + + return $object; + } + + /** + * Validate fields before create or update object + * + * @param array $data Datas to validate + * @return array + * + * @throws RestException + */ + function _validate($data) + { + $order = array(); + foreach (SupplierOrders::$FIELDS as $field) { + if (!isset($data[$field])) + throw new RestException(400, "$field field missing"); + $order[$field] = $data[$field]; + } + return $order; + } +} -- GitLab