From 235817c58132e81e4254d90ba8b88ab4151bef71 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 17 Oct 2017 12:02:58 +0200 Subject: [PATCH 01/10] Fix missing default limit --- .../societe/class/api_thirdparties.class.php | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 24cf991da52..292288d9015 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -21,15 +21,15 @@ /** * API class for thirdparties * - * @access protected + * @access protected * @class DolibarrApiAccess {@requires user,external} - * + * */ class Thirdparties 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( 'name' @@ -48,7 +48,7 @@ class Thirdparties extends DolibarrApi global $db, $conf; $this->db = $db; $this->company = new Societe($this->db); - + if (! empty($conf->global->SOCIETE_MAIL_REQUIRED)) { static::$FIELDS[] = 'email'; } @@ -61,20 +61,20 @@ class Thirdparties extends DolibarrApi * * @param int $id ID of thirdparty * @return array|mixed data without useless information - * + * * @throws RestException */ function get($id) - { + { if(! DolibarrApiAccess::$user->rights->societe->lire) { throw new RestException(401); } - + $result = $this->company->fetch($id); if( ! $result ) { throw new RestException(404, 'Thirdparty not found'); } - + if( ! DolibarrApi::_checkAccessToResource('societe',$this->company->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -84,27 +84,27 @@ class Thirdparties extends DolibarrApi /** * List thirdparties - * + * * Get a list of thirdparties - * + * * @param string $sortfield Sort field * @param string $sortorder Sort order * @param int $limit Limit for list * @param int $page Page number - * @param int $mode Set to 1 to show only customers + * @param int $mode Set to 1 to show only customers * Set to 2 to show only prospects * Set to 3 to show only those are not customer neither prospect - * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.nom:like:'TheCompany%') and (t.date_creation:<:'20160101')" * @return array Array of thirdparty objects */ - function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $mode=0, $sqlfilters = '') { + function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $mode=0, $sqlfilters = '') { global $db, $conf; - + $obj_ret = array(); - + // case of external user, we force socids $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : ''; - + // 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; @@ -112,7 +112,7 @@ class Thirdparties 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."societe 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.= ", ".MAIN_DB_PREFIX."c_stcomm as st"; $sql.= " WHERE t.fk_stcomm = st.id"; @@ -130,7 +130,7 @@ class Thirdparties extends DolibarrApi $sql .= " AND sc.fk_user = ".$search_sale; } // Add sql filters - if ($sqlfilters) + if ($sqlfilters) { if (! DolibarrApi::_checkFilters($sqlfilters)) { @@ -139,7 +139,7 @@ class Thirdparties extends DolibarrApi $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; } - + $sql.= $db->order($sortfield, $sortorder); if ($limit) { @@ -175,7 +175,7 @@ class Thirdparties extends DolibarrApi } return $obj_ret; } - + /** * Create thirdparty object * @@ -189,13 +189,13 @@ class Thirdparties extends DolibarrApi } // Check mandatory fields $result = $this->_validate($request_data); - + foreach($request_data as $field => $value) { $this->company->$field = $value; } if ($this->company->create(DolibarrApiAccess::$user) < 0) throw new RestException(500, 'Error creating thirdparty', array_merge(array($this->company->error), $this->company->errors)); - + return $this->company->id; } @@ -203,20 +203,20 @@ class Thirdparties extends DolibarrApi * Update thirdparty * * @param int $id Id of thirdparty 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->societe->creer) { throw new RestException(401); } - + $result = $this->company->fetch($id); if( ! $result ) { throw new RestException(404, 'Thirdparty not found'); } - + if( ! DolibarrApi::_checkAccessToResource('societe',$this->company->id)) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } @@ -225,13 +225,13 @@ class Thirdparties extends DolibarrApi if ($field == 'id') continue; $this->company->$field = $value; } - + if($this->company->update($id, DolibarrApiAccess::$user,1,'','','update')) return $this->get ($id); - + return false; } - + /** * Delete thirdparty * @@ -252,7 +252,7 @@ class Thirdparties extends DolibarrApi } return $this->company->delete($id); } - + /** * Get categories for a thirdparty * @@ -318,24 +318,24 @@ class Thirdparties extends DolibarrApi * @return array Array of cleaned object properties */ function _cleanObjectDatas($object) { - + $object = parent::_cleanObjectDatas($object); - + unset($object->total_ht); unset($object->total_tva); unset($object->total_localtax1); unset($object->total_localtax2); unset($object->total_ttc); - + return $object; - } - + } + /** * Validate fields before create or update object - * + * * @param array $data Datas to validate * @return array - * + * * @throws RestException */ function _validate($data) From aa1ff189e16efea6b774bb4abc0f2a047b4bdf7f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 17 Oct 2017 12:58:26 +0200 Subject: [PATCH 02/10] Fix var not correctly initialized when using api + multicompany --- htdocs/core/lib/security.lib.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/security.lib.php b/htdocs/core/lib/security.lib.php index 581c324674a..e799579b181 100644 --- a/htdocs/core/lib/security.lib.php +++ b/htdocs/core/lib/security.lib.php @@ -382,8 +382,12 @@ function checkUserAccessToObject($user, $featuresarray, $objectid=0, $tableandsh $nocheck = array('barcode','stock','fournisseur'); // No test $checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...). - // If dbtable not defined, we use same name for table than module name - if (empty($dbtablename)) $dbtablename = $feature; + // If dbtablename not defined, we use same name for table than module name + if (empty($dbtablename)) + { + $dbtablename = $feature; + $sharedelement = (! empty($params[1]) ? $params[1] : $dbtablename); // We change dbtablename, so we set sharedelement too. + } // Check permission for object with entity if (in_array($feature,$check)) From 347883b7be588a65617452b2f60a9444747f5973 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 10:39:36 +0200 Subject: [PATCH 03/10] Code comment --- htdocs/product/list.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 07a9da3bdb0..c18935ec845 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -893,7 +893,7 @@ else print ''; if (! $i) $totalarray['nbfield']++; } - // Stock + // Stock real if (! empty($arrayfields['p.stock']['checked'])) { print ''; @@ -905,7 +905,7 @@ else print ''; if (! $i) $totalarray['nbfield']++; } - // Stock + // Stock virtual if (! empty($arrayfields['stock_virtual']['checked'])) { print ''; From d40dda83cf867638ead8cc2cc2b949fb7a49fd6f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:10:08 +0200 Subject: [PATCH 04/10] Add API "close" for proposals Standardize code --- htdocs/comm/propal/card.php | 5 +- .../comm/propal/class/api_proposals.class.php | 44 ++++++++++++++++- htdocs/comm/propal/class/propal.class.php | 46 +----------------- htdocs/commande/class/commande.class.php | 47 ++----------------- htdocs/compta/facture/class/facture.class.php | 7 +-- ...e_20_modWorkflow_WorkflowManager.class.php | 14 +++--- .../class/supplier_proposal.class.php | 38 --------------- htdocs/webservices/server_invoice.php | 46 +++++++++--------- 8 files changed, 85 insertions(+), 162 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 48756a8828c..af32f12c8e0 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -612,14 +612,15 @@ if (empty($reshook)) // Close proposal else if ($action == 'setstatut' && $user->rights->propal->cloturer && ! GETPOST('cancel','alpha')) { - if (! GETPOST('statut')) { + if (! GETPOST('statut','int')) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors'); $action = 'statut'; } else { // prevent browser refresh from closing proposal several times if ($object->statut == Propal::STATUS_VALIDATED) { - $result=$object->cloture($user, GETPOST('statut','int'), GETPOST('note_private','alpha')); + $newprivatenote = dol_concatdesc($object->note_private, GETPOST('note_private','alpha')); + $result=$object->cloture($user, GETPOST('statut','int'), $newprivatenote); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index b49baf164ca..e13b9b71b90 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 /^[0-9,]*$/i} + * @param string $thirdparty_ids Thirdparty ids to filter commercial proposal of. Example: '1' or '1,2,3' {@pattern /^2|3$/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 */ @@ -507,6 +507,48 @@ class Proposals extends DolibarrApi ); } + /** + * Close (Accept or refuse) a quote / commercial proposal + * + * @param int $id Commercial proposal ID + * @param int $status Must be 2 (accepted) or 3 (refused) {@min 2}{@max 3} + * @param string $note_private Add this mention to the private note + * @param int $notrigger Disabled triggers + * + * @url POST {id}/close + * + * @return array + */ + function close($id, $status, $note_private='', $notrigger=0) + { + 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); + } + + $result = $this->propal->cloture(DolibarrApiAccess::$user, $status, $note_private, $notrigger); + if ($result == 0) { + throw new RestException(500, 'Error nothing done. May be object is already closed'); + } + if ($result < 0) { + throw new RestException(500, 'Error when closing Commercial Proposal: '.$this->propal->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Commercial Proposal closed (Ref='.$this->propal->ref.')' + ) + ); + } + /** * Validate fields before create or update object * diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index cd5f81783b7..61aa2a3ddb6 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1505,48 +1505,6 @@ class Propal extends CommonObject } } - /** - * Update value of extrafields on the proposal - * - * @param User $user Object user that modify - * @return int <0 if ko, >0 if ok - */ - function update_extrafields($user) - { - global $conf, $hookmanager; - - $action='update'; - $error = 0; - - // Actions on extra fields (by external module or standard code) - // TODO le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('propaldao')); - $parameters=array('id'=>$this->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; - - if (!$error) - { - return 1; - } - else - { - return -1; - } - - } - /** * Set status to validated * @@ -2258,7 +2216,7 @@ class Propal extends CommonObject * @param User $user Object user that close * @param int $statut Statut * @param string $note Comment - * @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 */ function cloture($user, $statut, $note, $notrigger=0) @@ -2297,7 +2255,7 @@ class Propal extends CommonObject return -2; } } - if ($statut == self::STATUS_BILLED) + if ($statut == self::STATUS_BILLED) // Why this ? { $trigger_name='PROPAL_CLASSIFY_BILLED'; } diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 79109ff511a..4cda7e931d4 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1077,11 +1077,12 @@ class Commande extends CommonOrder * Load an object from a proposal and create a new order into database * * @param Object $object Object source + * @param User $user User making creation * @return int <0 if KO, 0 if nothing done, 1 if OK */ - function createFromProposal($object) + function createFromProposal($object, User $user) { - global $conf,$user,$hookmanager; + global $conf, $hookmanager; dol_include_once('/core/class/extrafields.class.php'); @@ -3048,48 +3049,6 @@ class Commande extends CommonOrder } } - /** - * Update value of extrafields on order - * - * @param User $user Object user that modify - * @return int <0 if ko, >0 if ok - */ - function update_extrafields($user) - { - global $hookmanager, $conf; - - $action='create'; - $error = 0; - - // Actions on extra fields (by external module or standard code) - // TODO le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('orderdao')); - $parameters=array('id'=>$this->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; - - if (!$error) - { - return 1; - } - else - { - return -1; - } - - } - /** * Delete the customer order * diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 6452c689215..826d13fecd6 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -747,7 +747,7 @@ class Facture extends CommonInvoice * @param int $invertdetail Reverse sign of amounts for lines * @return int <0 if KO, >0 if OK */ - function createFromCurrent($user,$invertdetail=0) + function createFromCurrent(User $user, $invertdetail=0) { global $conf; @@ -948,11 +948,12 @@ class Facture extends CommonInvoice * Load an object from an order and create a new invoice into database * * @param Object $object Object source + * @param User $user Object user * @return int <0 if KO, 0 if nothing done, 1 if OK */ - function createFromOrder($object) + function createFromOrder($object, User $user) { - global $user,$hookmanager; + global $hookmanager; $error=0; diff --git a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php index bfa0efad8e6..c25e1ae9ad7 100644 --- a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php +++ b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php @@ -65,7 +65,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers $newobject->context['origin'] = $object->element; $newobject->context['origin_id'] = $object->id; - $ret=$newobject->createFromProposal($object); + $ret=$newobject->createFromProposal($object, $user); if ($ret < 0) { $this->error=$newobject->error; $this->errors[]=$newobject->error; } return $ret; } @@ -84,7 +84,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers $newobject->context['origin'] = $object->element; $newobject->context['origin_id'] = $object->id; - $ret=$newobject->createFromOrder($object); + $ret=$newobject->createFromOrder($object, $user); if ($ret < 0) { $this->error=$newobject->error; $this->errors[]=$newobject->error; } return $ret; } @@ -117,11 +117,11 @@ class InterfaceWorkflowManager extends DolibarrTriggers } } - // classify billed order & billed propososal + // classify billed order & billed propososal if ($action == 'BILL_VALIDATE') { dol_syslog( "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id ); - + // First classify billed the order to allow the proposal classify process if (! empty($conf->commande->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER)) { @@ -144,7 +144,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers } return $ret; } - + // Second classify billed the proposal. if (! empty($conf->propal->enabled) && ! empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL)) { @@ -167,7 +167,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers } return $ret; } - + } // Invoice classify billed order @@ -234,7 +234,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers } } } - + //Build array of quantity ordered by product if (is_array($order->lines) && count($order->lines)>0) { foreach($order->lines as $orderline) { diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index 6ddd5d2fc18..29f48f03d35 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -1304,44 +1304,6 @@ class SupplierProposal extends CommonObject } } - /** - * Update value of extrafields on the proposal - * - * @param User $user Object user that modify - * @return int <0 if ko, >0 if ok - */ - function update_extrafields($user) - { - $action='update'; - - // Actions on extra fields (by external module or standard code) - $hookmanager->initHooks(array('supplier_proposaldao')); - $parameters=array('id'=>$this->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; - - if (!$error) - { - return 1; - } - else - { - return -1; - } - - } - /** * Set status to validated * diff --git a/htdocs/webservices/server_invoice.php b/htdocs/webservices/server_invoice.php index 2150017577b..c93605ab2ea 100644 --- a/htdocs/webservices/server_invoice.php +++ b/htdocs/webservices/server_invoice.php @@ -555,7 +555,7 @@ function createInvoice($authentication,$invoice) if (empty($invoice['id']) && empty($invoice['ref']) && empty($invoice['ref_ext'])) { $error++; $errorcode='KO'; $errorlabel="Invoice id or ref or ref_ext is mandatory."; } - + if (! $error) { $new_invoice=new Facture($db); @@ -568,13 +568,13 @@ function createInvoice($authentication,$invoice) $new_invoice->statut= Facture::STATUS_DRAFT; // We start with status draft $new_invoice->fk_project=$invoice['project_id']; $new_invoice->date_creation=$now; - + //take mode_reglement and cond_reglement from thirdparty $soc = new Societe($db); $res=$soc->fetch($new_invoice->socid); if ($res > 0) { $new_invoice->mode_reglement_id = ! empty($invoice['payment_mode_id'])?$invoice['payment_mode_id']:$soc->mode_reglement_id; - $new_invoice->cond_reglement_id = $soc->cond_reglement_id; + $new_invoice->cond_reglement_id = $soc->cond_reglement_id; } else $new_invoice->mode_reglement_id = $invoice['payment_mode_id']; @@ -677,12 +677,12 @@ function createInvoiceFromOrder($authentication,$id_order='', $ref_order='', $re if (empty($id_order) && empty($ref_order) && empty($ref_ext_order)) { $error++; $errorcode='KO'; $errorlabel="order id or ref or ref_ext is mandatory."; } - + ////////////////////// if (! $error) { $fuser->getrights(); - + if ($fuser->rights->commande->lire) { $order=new Commande($db); @@ -695,19 +695,19 @@ function createInvoiceFromOrder($authentication,$id_order='', $ref_order='', $re $error++; $errorcode='PERMISSION_DENIED'; $errorlabel=$order->socid.'User does not have permission for this request'; } - + if(!$error) { - + $newobject=new Facture($db); - $result = $newobject->createFromOrder($order); - + $result = $newobject->createFromOrder($order, $fuser); + if ($result < 0) { $error++; dol_syslog("Webservice server_invoice:: invoice creation from order failed", LOG_ERR); } - + } } else @@ -722,7 +722,7 @@ function createInvoiceFromOrder($authentication,$id_order='', $ref_order='', $re $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request'; } } - + if ($error) { $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); @@ -731,7 +731,7 @@ function createInvoiceFromOrder($authentication,$id_order='', $ref_order='', $re { $objectresp= array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref,'ref_ext'=>$newobject->ref_ext); } - + return $objectresp; } @@ -761,20 +761,20 @@ function updateInvoice($authentication,$invoice) if (empty($invoice['id']) && empty($invoice['ref']) && empty($invoice['ref_ext'])) { $error++; $errorcode='KO'; $errorlabel="Invoice id or ref or ref_ext is mandatory."; } - + if (! $error) { $objectfound=false; - + $object=new Facture($db); $result=$object->fetch($invoice['id'],$invoice['ref'],$invoice['ref_ext'], ''); - + if (!empty($object->id)) { - + $objectfound=true; - + $db->begin(); - + if (isset($invoice['status'])) { if ($invoice['status'] == Facture::STATUS_DRAFT) @@ -784,7 +784,7 @@ function updateInvoice($authentication,$invoice) if ($invoice['status'] == Facture::STATUS_VALIDATED) { $result = $object->validate($fuser); - + if ($result >= 0) { // Define output language @@ -794,13 +794,13 @@ function updateInvoice($authentication,$invoice) } if ($invoice['status'] == Facture::STATUS_CLOSED) { - $result = $object->set_paid($fuser,$invoice->close_code,$invoice->close_note); + $result = $object->set_paid($fuser,$invoice->close_code,$invoice->close_note); } if ($invoice['status'] == Facture::STATUS_ABANDONED) $result = $object->set_canceled($fuser,$invoice->close_code,$invoice->close_note); } } - + if ((! $error) && ($objectfound)) { $db->commit(); @@ -823,12 +823,12 @@ function updateInvoice($authentication,$invoice) $errorlabel='Invoice id='.$invoice['id'].' ref='.$invoice['ref'].' ref_ext='.$invoice['ref_ext'].' cannot be found'; } } - + if ($error) { $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel)); } - + return $objectresp; } From 000c1bddb22cb2e7ff8901e4597a93665b986d07 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:12:59 +0200 Subject: [PATCH 05/10] Fix we lose the private not when closing proposal --- htdocs/comm/propal/card.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index b603d1e6a17..057a0d1edfd 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -611,7 +611,8 @@ if (empty($reshook)) // prevent browser refresh from closing proposal several times if ($object->statut == Propal::STATUS_VALIDATED) { - $result=$object->cloture($user, GETPOST('statut'), GETPOST('note')); + $newprivatenote = dol_concatdesc($object->note_private, GETPOST('note_private','alpha')); + $result=$object->cloture($user, GETPOST('statut','int'), $newprivatenote); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); From b124c7f16d4a0a9b8080a53b0e5f060bff77148e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:15:54 +0200 Subject: [PATCH 06/10] Clean params --- htdocs/comm/propal/card.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 057a0d1edfd..7fb13234a94 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -611,8 +611,7 @@ if (empty($reshook)) // prevent browser refresh from closing proposal several times if ($object->statut == Propal::STATUS_VALIDATED) { - $newprivatenote = dol_concatdesc($object->note_private, GETPOST('note_private','alpha')); - $result=$object->cloture($user, GETPOST('statut','int'), $newprivatenote); + $result=$object->cloture($user, GETPOST('statut','int'), GETPOST('note','none')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); From 037b90f2f37abe8e577eaf5dcd79964e34d0b524 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:23:16 +0200 Subject: [PATCH 07/10] NEW The comment when closing a proposal is added to commercial proposal --- htdocs/comm/propal/card.php | 7 +++---- htdocs/comm/propal/class/api_proposals.class.php | 2 +- htdocs/comm/propal/class/propal.class.php | 6 ++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index af32f12c8e0..7de5c0e25ce 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -619,8 +619,7 @@ if (empty($reshook)) // prevent browser refresh from closing proposal several times if ($object->statut == Propal::STATUS_VALIDATED) { - $newprivatenote = dol_concatdesc($object->note_private, GETPOST('note_private','alpha')); - $result=$object->cloture($user, GETPOST('statut','int'), $newprivatenote); + $result=$object->cloture($user, GETPOST('statut','int'), GETPOST('note_private','none')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); @@ -1688,8 +1687,8 @@ if ($action == 'create') //Form to close proposal (signed or not) $formquestion = array( array('type' => 'select','name' => 'statut','label' => $langs->trans("CloseAs"),'values' => array(2=>$object->labelstatut [2],3=>$object->labelstatut [3])), - //array('type' => 'other','name' => 'note_private', 'label' => $langs->trans("Note"),'value' => '')); - array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"),'value' => $object->note_private)); + array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"),'value' => '') // Field to complete private note (not replace) + ); if (! empty($conf->notification->enabled)) { require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php'; diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index e13b9b71b90..97632a8b4a3 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -512,7 +512,7 @@ class Proposals extends DolibarrApi * * @param int $id Commercial proposal ID * @param int $status Must be 2 (accepted) or 3 (refused) {@min 2}{@max 3} - * @param string $note_private Add this mention to the private note + * @param string $note_private Add this mention at end of private note * @param int $notrigger Disabled triggers * * @url POST {id}/close diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 61aa2a3ddb6..322deadfee3 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -2215,7 +2215,7 @@ class Propal extends CommonObject * * @param User $user Object user that close * @param int $statut Statut - * @param string $note Comment + * @param string $note Complete private note with this note * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers * @return int <0 if KO, >0 if OK */ @@ -2228,8 +2228,10 @@ class Propal extends CommonObject $this->db->begin(); + $newprivatenote = dol_concatdesc($this->note_private, $note); + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; + $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($newprivatenote)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; $sql.= " WHERE rowid = ".$this->id; $resql=$this->db->query($sql); From 07a6f75b95de3ae40c2cbbdfb44b296e71815711 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:25:41 +0200 Subject: [PATCH 08/10] Update changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 9b5eef7aca5..da61a6e9584 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ Following changes may create regressions for some external modules, but were nec 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) ***** ChangeLog for 6.0.2 compared to 6.0.1 ***** From 66538c7c0ffd6cadbacaf8758f2d21071216b74e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 11:34:49 +0200 Subject: [PATCH 09/10] Position of method --- htdocs/comm/propal/class/api_proposals.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 97632a8b4a3..ea03bc0eb71 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -549,6 +549,7 @@ class Proposals extends DolibarrApi ); } + /** * Validate fields before create or update object * @@ -568,6 +569,7 @@ class Proposals extends DolibarrApi return $propal; } + /** * Clean sensible object datas * From 8e4cb2ea793974d4f0912d0a0a63b3c753d35c3e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 18 Oct 2017 12:09:11 +0200 Subject: [PATCH 10/10] Update doc/test --- ChangeLog | 1 + test/phpunit/BuildDocTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index da61a6e9584..32d73692354 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,7 @@ Following changes may create regressions for some external modules, but were nec * 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. ***** ChangeLog for 6.0.2 compared to 6.0.1 ***** diff --git a/test/phpunit/BuildDocTest.php b/test/phpunit/BuildDocTest.php index 25b7bd15c03..c30bf1b9a96 100644 --- a/test/phpunit/BuildDocTest.php +++ b/test/phpunit/BuildDocTest.php @@ -172,7 +172,7 @@ class BuildDocTest extends PHPUnit_Framework_TestCase $localobjectcom->initAsSpecimen(); $localobject=new Facture($this->savdb); - $localobject->createFromOrder($localobjectcom); + $localobject->createFromOrder($localobjectcom, $user); $localobject->date_lim_reglement = dol_now() + 3600 * 24 *30; // Crabe (english)