diff --git a/dev/tools/phan/baseline.txt b/dev/tools/phan/baseline.txt index 074c97342dc..08c4603f85e 100644 --- a/dev/tools/phan/baseline.txt +++ b/dev/tools/phan/baseline.txt @@ -12,7 +12,7 @@ return [ // PhanUndeclaredProperty : 420+ occurrences // PhanTypeMismatchProperty : 100+ occurrences // PhanTypeMismatchArgument : 70+ occurrences - // PhanUndeclaredGlobalVariable : 70+ occurrences + // PhanUndeclaredGlobalVariable : 65+ occurrences // PhanTypeMismatchArgumentNullable : 40+ occurrences // PhanTypeInvalidDimOffset : 15+ occurrences // PhanTypeMismatchDimFetch : 15+ occurrences @@ -230,7 +230,6 @@ return [ 'htdocs/projet/tasks.php' => ['PhanTypeMismatchArgument'], 'htdocs/projet/tasks/time.php' => ['PhanTypeInvalidDimOffset', 'PhanUndeclaredProperty'], 'htdocs/projet/tasks/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], - 'htdocs/public/eventorganization/subscriptionok.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/members/new.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/payment/newpayment.php' => ['PhanUndeclaredProperty'], 'htdocs/public/payment/paymentok.php' => ['PhanTypeMismatchArgumentProbablyReal'], diff --git a/htdocs/api/class/api_documents.class.php b/htdocs/api/class/api_documents.class.php index ab0d6da9155..e2e6f7f9f1e 100644 --- a/htdocs/api/class/api_documents.class.php +++ b/htdocs/api/class/api_documents.class.php @@ -505,7 +505,7 @@ class Documents extends DolibarrApi throw new RestException(404, 'Invoice not found'); } - $upload_dir = getMultidirOutput($object) . "/facture/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref); + $upload_dir = getMultidirOutput($object) . "/".get_exdir($object->id, 2, 0, 0, $object, 'invoice_supplier').dol_sanitizeFileName($object->ref); } elseif ($modulepart == 'produit' || $modulepart == 'product' || $modulepart == 'service') { require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; diff --git a/htdocs/comm/mailing/class/api_mailings.class.php b/htdocs/comm/mailing/class/api_mailings.class.php index 46830e90e32..26aa006f5fc 100644 --- a/htdocs/comm/mailing/class/api_mailings.class.php +++ b/htdocs/comm/mailing/class/api_mailings.class.php @@ -19,6 +19,7 @@ use Luracast\Restler\RestException; require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing_targets.class.php'; /** * API class for mass mailings @@ -39,11 +40,24 @@ class Mailings extends DolibarrApi 'body' ); + /** + * @var string[] Mandatory fields, checked when create and update object + */ + public static $TARGETFIELDS = array( + 'fk_mailing', + 'email' + ); + /** * @var Mailing {@type Mailing} */ public $mailing; + /** + * @var MailingTarget {@type MailingTarget} + */ + public $mailing_target; + /** * Constructor */ @@ -52,6 +66,7 @@ class Mailings extends DolibarrApi global $db; $this->db = $db; $this->mailing = new Mailing($this->db); + $this->mailing_target = new MailingTarget($this->db); } /** @@ -125,7 +140,8 @@ class Mailings extends DolibarrApi * @phan-return Mailing[]|array{data:Mailing[],pagination:array{total:int,page:int,page_count:int,limit:int}} * @phpstan-return Mailing[]|array{data:Mailing[],pagination:array{total:int,page:int,page_count:int,limit:int}} * - * @throws RestException + * @throws RestException 400 + * @throws RestException 403 */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $fk_projects = '', $sqlfilters = '', $properties = '', $pagination_data = false, $loadlinkedobjects = 0) { @@ -213,6 +229,114 @@ class Mailings extends DolibarrApi return $obj_ret; } + /** + * List mass mailing targets + * + * Get a list of mass mailing targets + * + * @since 23.0.0 Initial implementation + * + * @param int $id Mass mailing ID + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.lastname:like:'John Doe') and (t.statut:=:3)" + * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names + * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* + * @return array Array of order objects + * @phan-return Mailing[]|array{data:Mailing[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Mailing[]|array{data:Mailing[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * + * @url GET {id}/targets + * + * @throws RestException 400 + * @throws RestException 403 + * @throws RestException 404 + */ + public function indexTargets($id, $sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '', $pagination_data = false) + { + if (!DolibarrApiAccess::$user->hasRight('mailing', 'read')) { + throw new RestException(403); + } + + $fetchMailingResult = $this->mailing->fetch($id); + if ($fetchMailingResult < 0) { + throw new RestException(404, 'Mass mailing not found, id='.$id); + } + + $fk_project = $this->mailing->fk_project; + if (!DolibarrApi::_checkAccessToResource('project', ((int) $fk_project))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + + $obj_ret = array(); + + $sql = "SELECT t.rowid"; + $sql .= " FROM ".MAIN_DB_PREFIX."mailing_cibles AS t"; + $sql .= " WHERE t.fk_mailing = ".((int) $id); + + // Add sql filters + if ($sqlfilters) { + $errormessage = ''; + $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage); + if ($errormessage) { + throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage); + } + } + + //this query will return total mass mailing targets with the filters given + $sqlTotals = str_replace('SELECT t.rowid', 'SELECT count(t.rowid) as total', $sql); + + $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 mass mailing target"); + $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); + $mailing_target = new MailingTarget($this->db); + if ($mailing_target->fetch($obj->rowid) > 0) { + $obj_ret[] = $this->_filterObjectProperties($this->_cleanTargetDatas($mailing_target), $properties); + } + $i++; + } + } else { + throw new RestException(503, 'Error when retrieve list of mass mailing targetss : '.$this->db->lasterror()); + } + + //if $pagination_data is true the response will contain element data with all values and element pagination with pagination data(total,page,limit) + if ($pagination_data) { + $totalsResult = $this->db->query($sqlTotals); + $total = $this->db->fetch_object($totalsResult)->total; + + $tmp = $obj_ret; + $obj_ret = []; + + $obj_ret['data'] = $tmp; + $obj_ret['pagination'] = [ + 'total' => (int) $total, + 'page' => $page, //count starts from 0 + 'page_count' => ceil((int) $total / $limit), + 'limit' => $limit + ]; + } + + return $obj_ret; + } + /** * Clone a mass mailing * @@ -264,7 +388,8 @@ class Mailings extends DolibarrApi * @phpstan-param ?array $request_data * @return int ID of mass mailing * - * @throws RestException + * @throws RestException 403 + * @throws RestException 500 System error */ public function post($request_data = null) { @@ -307,7 +432,9 @@ class Mailings extends DolibarrApi * @phpstan-param ?array $request_data * @return Object Object with cleaned properties * - * @throws RestException + * @throws RestException 403 + * @throws RestException 404 + * @throws RestException 500 System error */ public function put($id, $request_data = null) { @@ -397,6 +524,254 @@ class Mailings extends DolibarrApi ); } + /** + * Update a mass mailing general fields (won't change lines of mass mailing) + * + * @since 23.0.0 Initial implementation + * + * @param int $id Id of mass mailing with the targetid to update + * @param int $targetid Id mass mailing target to update + * @param array $request_data Datas + * @phan-param ?array $request_data + * @phpstan-param ?array $request_data + * @return Object Object with cleaned properties + * + * @url PUT {id}/updateTarget/{targetid} + * + * @throws RestException 403 + * @throws RestException 404 + * @throws RestException 500 System error + */ + public function updateTarget($id, $targetid, $request_data = null) + { + if (!DolibarrApiAccess::$user->hasRight('mailing', 'write')) { + throw new RestException(403); + } + + $fetchMailingResult = $this->mailing->fetch($id); + if ($fetchMailingResult < 0) { + throw new RestException(404, 'Mass mailing not found, id='.$id); + } + $result = $this->mailing_target->fetch($targetid); + if ($result < 0) { + throw new RestException(404, 'Mass mailing target not found, id='.$targetid); + } + if ($id != $this->mailing_target->fk_mailing) { + throw new RestException(404, 'Target id='.$targetid.' is does not belong to mailing id='.$id); + } + + if (!DolibarrApi::_checkAccessToResource('project', ((int) $this->mailing->fk_project))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (!DolibarrApi::_checkAccessToResource('mailing', $this->mailing->id)) { + throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + foreach ($request_data as $field => $value) { + if ($field == 'id') { + throw new RestException(400, 'Changing id field is forbidden'); + } + if ($field == 'fk_mailing') { + throw new RestException(400, 'Changing fk_mailing field is forbidden to protect inserting a wrong fk_mailing number. Use a POST to create a new mailing target with the correct mailing id, then an PUT to update the new target in the right mailing id, and finally a delete to remove the old target'); + } + if ($field === 'caller') { + // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller + $this->mailing_target->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09'); + continue; + } + + $this->mailing_target->$field = $this->_checkValForAPI($field, $value, $this->mailing_target); + } + + if ($this->mailing_target->update(DolibarrApiAccess::$user) > 0) { + return $this->getTarget($id, $targetid); + } else { + throw new RestException(500, $this->mailing_target->error); + } + } + + /** + * Create a mass mailing + * + * @since 23.0.0 Initial implementation + * + * @param int $id Id of mass mailing to create a target for + * @param array $request_data Request data + * @phan-param ?array $request_data + * @phpstan-param ?array $request_data + * @return int ID of mass mailing + * + * @url POST {id}/createTarget + * + * @throws RestException 400 + * @throws RestException 403 + * @throws RestException 404 + * @throws RestException 500 System error + */ + public function postTarget($id, $request_data = null) + { + if (!DolibarrApiAccess::$user->hasRight('mailing', 'write')) { + throw new RestException(403, "Insufficiant rights"); + } + // Check mandatory fields + $result = $this->_validateTarget($request_data); + + $fk_mailing_id = 0; + + foreach ($request_data as $field => $value) { + if ($field === 'caller') { + // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again with the caller + $this->mailing_target->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09'); + continue; + } + if ($field === 'fk_project') { + if (!DolibarrApi::_checkAccessToResource('project', ((int) $value))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + } + + if ($field == 'id') { + throw new RestException(400, 'Creating with id field is forbidden'); + } + if ($field == 'fk_mailing') { + $fetchMailingResult = $this->mailing->fetch((int) $value); + if ($fetchMailingResult < 0) { + throw new RestException(404, 'Mass mailing not found, id='.((int) $value)); + } + if (!DolibarrApi::_checkAccessToResource('project', ((int) $this->mailing->fk_project))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + $fk_mailing_id = ((int) $value); + } + + $this->mailing_target->$field = $this->_checkValForAPI($field, $value, $this->mailing_target); + } + + if (0 == $fk_mailing_id) { + throw new RestException(404, 'Mass mailing not found, id='.((int) $fk_mailing_id)); + } + + if ($this->mailing_target->create(DolibarrApiAccess::$user) < 0) { + throw new RestException(500, "Error creating mass mailing target", array_merge(array($this->mailing->error), $this->mailing->errors)); + } + + return ((int) $this->mailing_target->id); + } + + /** + * Get a target in a mass mailing + * + * Return an array with info about a mass mailing target + * + * @since 23.0.0 Initial implementation + * + * @param int $id Id of mass mailing with the targetid to get + * @param int $targetid Id mass mailing target to get + * @return Object Object with cleaned properties + * + * @url GET {id}/getTarget/{targetid} + * + * @throws RestException + */ + public function getTarget($id, $targetid) + { + return $this->_fetchTarget($id, $targetid); + } + + /** + * Get properties of an mailing object + * + * Return an array with mailing information + * + * @param int $id ID of mailing object + * @param int $targetid Id mass mailing target + * @return Object Object with cleaned properties + * + * @throws RestException 403 + * @throws RestException 404 + */ + private function _fetchTarget($id, $targetid) + { + if (!DolibarrApiAccess::$user->hasRight('mailing', 'read')) { + throw new RestException(403); + } + + $fetchMailingResult = $this->mailing->fetch($id); + if ($fetchMailingResult < 0) { + throw new RestException(404, 'Mass mailing not found, id='.$id); + } + $result = $this->mailing_target->fetch($targetid); + if ($result < 0) { + throw new RestException(404, 'Mass mailing target not found, id='.$targetid); + } + if ($id != $this->mailing_target->fk_mailing) { + throw new RestException(404, 'Target id='.$targetid.' is does not belong to mailing id='.$id); + } + + if (!DolibarrApi::_checkAccessToResource('project', ((int) $this->mailing->fk_project))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (!DolibarrApi::_checkAccessToResource('mailing', $this->mailing->id)) { + throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + return $this->_cleanTargetDatas($this->mailing_target); + } + + /** + * Delete a mass mailing general fields (won't change lines of mass mailing) + * + * @since 23.0.0 Initial implementation + * + * @param int $id Id of mass mailing with the targetid to delete + * @param int $targetid Id mass mailing target to delete + * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} + * + * @url DELETE {id}/deleteTarget/{targetid} + * + * @throws RestException 403 + * @throws RestException 404 + * @throws RestException 500 System error + */ + public function deleteTarget($id, $targetid) + { + if (!DolibarrApiAccess::$user->hasRight('mailing', 'delete')) { + throw new RestException(403); + } + + $fetchMailingResult = $this->mailing->fetch($id); + if ($fetchMailingResult < 0) { + throw new RestException(404, 'Mass mailing not found, id='.$id); + } + $result = $this->mailing_target->fetch($targetid); + if ($result < 0) { + throw new RestException(404, 'Mass mailing target not found, id='.$targetid); + } + if ($id != $this->mailing_target->fk_mailing) { + throw new RestException(404, 'Target id='.$targetid.' is does not belong to mailing id='.$id); + } + if (!DolibarrApi::_checkAccessToResource('project', ((int) $this->mailing->fk_project))) { + throw new RestException(403, 'Access (project) not allowed for login '.DolibarrApiAccess::$user->login); + } + if (!DolibarrApi::_checkAccessToResource('mailing', $this->mailing->id)) { + throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (!$this->mailing_target->delete(DolibarrApiAccess::$user)) { + throw new RestException(500, 'Error when delete Mass mailing target: '.$this->mailing->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Deleting target id='.$targetid.' belonging to mailing id='.$id + ) + ); + } + /** * Delete targets of a mass mailing * @@ -612,6 +987,162 @@ class Mailings extends DolibarrApi return $mailing; } + /** + * Validate fields before create or update object + * + * @param ?array $data Array with data to verify + * @return array + * + * @throws RestException + */ + private function _validateTarget($data) + { + if ($data === null) { + $data = array(); + } + $mailing_target = array(); + foreach (Mailings::$TARGETFIELDS as $field) { + if (!isset($data[$field])) { + throw new RestException(400, "$field field missing"); + } + $mailing_target[$field] = $data[$field]; + } + return $mailing_target; + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Clean sensible object (mailing target) datas + * + * @param Object $object Object to clean + * @return Object Object with cleaned properties + */ + protected function _cleanTargetDatas($object) + { + // phpcs:enable + $object = parent::_cleanObjectDatas($object); + + unset($object->TRIGGER_PREFIX); + unset($object->actionmsg); + unset($object->actionmsg2); + unset($object->actiontypecode); + unset($object->alreadypaid); + unset($object->array_options); + unset($object->array_languages); + unset($object->barcode_type_code); + unset($object->barcode_type_coder); + unset($object->barcode_type_label); + unset($object->barcode_type); + unset($object->canvas); + unset($object->civility_code); + unset($object->civility_id); + unset($object->comments); + unset($object->cond_reglement_id); + unset($object->cond_reglement_supplier_id); + unset($object->contact_id); + unset($object->contact); + unset($object->contacts_ids_internal); + unset($object->contacts_ids); + unset($object->context); + unset($object->country_code); + unset($object->country_id); + unset($object->country); + unset($object->date_cloture); + unset($object->date_creation); + unset($object->date_validation); + unset($object->db); + unset($object->demand_reason_id); + unset($object->deposit_percent); + unset($object->element_for_permission); + unset($object->element); + unset($object->entity); + unset($object->error); + unset($object->errorhidden); + unset($object->errors); + unset($object->extraparams); + unset($object->fields); + unset($object->fk_account); + unset($object->fk_bank); + unset($object->fk_delivery_address); + unset($object->fk_element); + unset($object->fk_multicurrency); + unset($object->fk_projet); + unset($object->fk_project); + unset($object->fk_user_creat); + unset($object->fk_user_modif); + unset($object->import_key); + unset($object->isextrafieldmanaged); + unset($object->ismultientitymanaged); + unset($object->last_main_doc); + unset($object->lines); + unset($object->linked_objects); + unset($object->linkedObjects); + unset($object->linkedObjectsIds); + unset($object->mode_reglement_id); + unset($object->model_pdf); + unset($object->module); + unset($object->multicurrency_code); + unset($object->multicurrency_total_ht); + unset($object->multicurrency_total_localtax1); + unset($object->multicurrency_total_localtax2); + unset($object->multicurrency_total_ttc); + unset($object->multicurrency_total_tva); + unset($object->multicurrency_tx); + unset($object->name); + unset($object->nb); + unset($object->nbphoto); + unset($object->newref); + unset($object->next_prev_filter); + unset($object->note); + unset($object->note_public); + unset($object->note_private); + unset($object->oldcopy); + unset($object->oldref); + unset($object->origin_id); + unset($object->origin_object); + unset($object->origin_type); + unset($object->origin); + unset($object->output); + unset($object->product); + unset($object->project); + unset($object->ref_ext); + unset($object->ref_next); + unset($object->ref_previous); + unset($object->ref); + unset($object->region_code); + unset($object->region_id); + unset($object->region); + unset($object->restrictiononfksoc); + unset($object->retained_warranty_fk_cond_reglement); + unset($object->sendtoid); + unset($object->shipping_method_id); + unset($object->shipping_method); + unset($object->showphoto_on_popup); + unset($object->specimen); + unset($object->state_code); + unset($object->state_id); + unset($object->state); + unset($object->table_element_line); + unset($object->table_element); + unset($object->thirdparty); + unset($object->total_ht); + unset($object->total_localtax1); + unset($object->total_localtax2); + unset($object->total_ttc); + unset($object->total_tva); + unset($object->totalpaid_multicurrency); + unset($object->totalpaid); + unset($object->tpl); + unset($object->transport_mode_id); + unset($object->user); + unset($object->user_creation_id); + unset($object->user_validation_id); + unset($object->user_closing_id); + unset($object->user_modification_id); + unset($object->warehouse_id); + + return $object; + } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** @@ -666,8 +1197,6 @@ class Mailings extends DolibarrApi unset($object->import_key); unset($object->isextrafieldmanaged); unset($object->ismultientitymanaged); - unset($object->labelStatus); - unset($object->labelStatusShort); unset($object->last_main_doc); unset($object->lastname); unset($object->lines); diff --git a/htdocs/comm/mailing/class/mailing.class.php b/htdocs/comm/mailing/class/mailing.class.php index e4eb696499d..893e6896b84 100644 --- a/htdocs/comm/mailing/class/mailing.class.php +++ b/htdocs/comm/mailing/class/mailing.class.php @@ -26,7 +26,7 @@ */ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; - +require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing_targets.class.php'; /** * Class to manage emailings module @@ -174,6 +174,11 @@ class Mailing extends CommonObject */ public $substitutionarrayfortest; + /** + * @var MailingTarget[] + */ + public $targets = array(); + /** * @var ?int The related project ID * @see setProject(), project @@ -621,7 +626,7 @@ class Mailing extends CommonObject $now = dol_now(); $sql = "UPDATE ".MAIN_DB_PREFIX."mailing "; - $sql .= " SET statut = 0, fk_user_modif=".$user->id; + $sql .= " SET statut = 0, tms = '".$this->db->idate($now)."', fk_user_modif=".$user->id; $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog("Mailing::valid", LOG_DEBUG); diff --git a/htdocs/comm/mailing/class/mailing_targets.class.php b/htdocs/comm/mailing/class/mailing_targets.class.php new file mode 100644 index 00000000000..b3c08cdc8f7 --- /dev/null +++ b/htdocs/comm/mailing/class/mailing_targets.class.php @@ -0,0 +1,505 @@ + + * + * 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 . + */ + +/** + * \file htdocs/comm/mailing/class/mailing_target.class.php + * \ingroup mailing + * \brief File of class to manage emailing targets module + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; + + +/** + * Class to manage emailings module + */ +class MailingTarget extends CommonObject +{ + /** + * @var string ID to identify managed object + */ + public $element = 'mailing_target'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'mailing_cibles'; + + /** + * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png + */ + public $picto = 'contact'; + + /** + * @var int Mailing id that this mailing_target is related to. + */ + public $fk_mailing; + + /** + * @var int Contact id that this mailing_target is related to. + */ + public $fk_contact; + + /** + * @var string lastname of the mailing_target + */ + public $lastname; + + /** + * @var string firstname of the mailing_target + */ + public $firstname; + + /** + * @var string email of the mailing_target + */ + public $email; + + /** + * @var string other + */ + public $other; + + /** + * @var string tag + */ + public $tag; + + /** + * @var int status + * @deprecated Use $status + */ + public $statut; // Status 0=Not sent, 1=Sent, 2=Read, 3=Read and unsubscribed, -1=Error + + /** + * @var int status + */ + public $status; // Status 0=Not sent, 1=Sent, 2=Read, 3=Read and unsubscribed, -1=Error + + /** + * @var array statut dest + */ + public $statut_dest = array(); + + /** + * @var string source_url of the mailing_target + */ + public $source_url; + + /** + * @var int source_id of the mailing_target + */ + public $source_id; + + /** + * @var string source_type + */ + public $source_type; + + /** + * @var integer|''|null date sending + */ + public $date_envoi; + + /** + * Update timestamp record (tms) + * @var integer + * @deprecated Use $date_modification + */ + public $tms; + + /** + * @var string error_text from trying to send email + */ + public $error_text; + + const STATUS_NOTSENT = 0; + const STATUS_SENT = 1; + const STATUS_READ = 2; + const STATUS_READANDUNSUBSCRIBED = 3; + const STATUS_ERROR = -1; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + + // List of language codes for status + $this->labelStatus[0] = 'TargetStatusNotSent'; + $this->labelStatus[1] = 'TargetStatusSent'; + $this->labelStatus[2] = 'TargetStatusRead'; + $this->labelStatus[3] = 'TargetStatusReadAndUnsubscribed'; + $this->labelStatus[-1] = 'TargetStatusError'; + + $this->statut_dest[0] = 'TargetStatusNotSent'; + $this->statut_dest[1] = 'TargetStatusSent'; + $this->statut_dest[2] = 'TargetStatusRead'; + $this->statut_dest[3] = 'TargetStatusReadAndUnsubscribed'; // Read but ask to not be contacted anymore + $this->statut_dest[-1] = 'TargetStatusError'; + } + + /** + * Create an Mailing Target + * + * @param User $user Object of user making creation + * @return int Return integer <0 if KO, Id of created object if OK + */ + public function create($user) + { + global $conf, $langs; + + if (empty($this->fk_mailing)) { + $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Mailing")); + return -2; + // we probably should also check that this number actually exists in ".MAIN_DB_PREFIX."mailing"; + } + if (0 == $this->fk_mailing) { + $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Mailing")); + return -4; + } + if (empty($this->email)) { + $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Email")); + return -3; + } + if (empty($this->statut)) { + $statut = 0; + } + if (empty($this->status)) { + $status = 0; + } + if ($this->status !== $this->statut) { + $this->error = 'Status='.$this->status.' and Statut='.$this->statut.' field must be identical'; + return -4; + } + if (empty($this->fk_contact)) { + $fk_contact = 0; + } + + $error = 0; + + $this->db->begin(); + + + // 2025-10-09 06:33:26 DEBUG 192.168.127.1 52 33 sql=INSERT INTO llx_mailing_cibles (fk_mailing, fk_contact, email, statut) VALUES ('4', .((int) 0)., 'jon@jonb.dk', .((int) )). + //2025-10-09 06:35:13 DEBUG 192.168.127.1 54 33 sql=INSERT INTO llx_mailing_cibles (fk_mailing, fk_contact, email, statut) VALUES (4, .((int) 0)., 'jon@jonb.dk', .((int) )). + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."mailing_cibles"; + $sql .= " (fk_mailing, fk_contact, email, statut)"; + $sql .= " VALUES (".((int) $this->fk_mailing).", "; + $sql .= ((int) $this->fk_contact).", "; + $sql .= "'".$this->db->escape($this->email)."', "; + $sql .= ((int) $conf->statut)." )"; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $resql = $this->db->query($sql); + if ($resql) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."mailing_cibles"); + + $result = $this->update($user); + if ($result < 0) { + $error++; + } + + if (!$error) { + $this->db->commit(); + return $this->id; + } else { + $this->db->rollback(); + dol_syslog(__METHOD__ . ' ' . $this->error, LOG_ERR); + return -2; + } + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + /** + * Delete Mailing target + * + * @param User $user User that delete + * @return int >0 if OK, <0 if KO + */ + public function delete($user) + { + $error = 0; + + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."mailing_cibles"; + $sql .= " WHERE rowid = " . ((int) $this->id); + + dol_syslog(__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + dol_syslog(__METHOD__ . ' success'); + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Set notsent mailing target + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setNotSent() + { + $now = dol_now(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles "; + $sql .= " SET statut = ".((int) self::STATUS_NOTSENT).", tms = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog("Mailing::valid", LOG_DEBUG); + if ($this->db->query($sql)) { + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Set sent mailing target + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setSent() + { + $now = dol_now(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles "; + $sql .= " SET statut = ".((int) self::STATUS_SENT).", tms = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog("Mailing::valid", LOG_DEBUG); + if ($this->db->query($sql)) { + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Set read mailing target + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setRead() + { + $now = dol_now(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles "; + $sql .= " SET statut = ".((int) self::STATUS_READ).", tms = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog("Mailing::valid", LOG_DEBUG); + if ($this->db->query($sql)) { + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Set read and unsubscribed mailing target + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setReadAndUnsubscribed() + { + $now = dol_now(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles "; + $sql .= " SET statut = ".((int) self::STATUS_READANDUNSUBSCRIBED).", tms = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog("Mailing::valid", LOG_DEBUG); + if ($this->db->query($sql)) { + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Set error mailing target + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setError() + { + $now = dol_now(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles "; + $sql .= " SET statut = ".((int) self::STATUS_ERROR).", tms = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog("Mailing::valid", LOG_DEBUG); + if ($this->db->query($sql)) { + return 1; + } else { + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Update an Mailing Target + * + * @param User $user Object of user making change + * @return int Return integer < 0 if KO, > 0 if OK + */ + public function update($user) + { + global $langs; + + if (empty($this->fk_mailing)) { + return -2; + // we probably should also check that this number actually exists in ".MAIN_DB_PREFIX."mailing"; + } + if (empty($this->email)) { + return -3; + } + if (empty($this->statut)) { + $statut = 0; + } + if (empty($this->status)) { + $status = 0; + } + if ($this->status !== $this->statut) { + return -4; + } + if (empty($this->fk_contact)) { + $fk_contact = 0; + } + + $now = dol_now(); + $error = 0; + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."mailing_cibles"; + $sql .= " SET fk_mailing = '".((int) $this->fk_mailing)."'"; + $sql .= ", fk_contact = '".((int) $this->fk_contact)."'"; + $sql .= ", lastname = '".$this->db->escape($this->lastname)."'"; + $sql .= ", firstname = '".$this->db->escape($this->firstname)."'"; + $sql .= ", email = '".$this->db->escape($this->email)."'"; + $sql .= ", other = '".$this->db->escape($this->other)."'"; + $sql .= ", tag = '".$this->db->escape($this->tag)."'"; + $sql .= ", statut = '".((int) $this->statut)."'"; + $sql .= ", source_url = '".$this->db->escape($this->source_url)."'"; + $sql .= ", source_id = '".((int) $this->source_id)."'"; + $sql .= ", source_type = '".$this->db->escape($this->source_type)."'"; + if ($this->date_envoi) { + $sql .= ", date_envoi = '".$this->db->idate($this->date_envoi)."'"; + } + $sql .= ", error_text = '".($this->error_text ? $this->db->escape($this->error_text) : null)."'"; + $sql .= " WHERE rowid = ".(int) $this->id; + + dol_syslog(__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + dol_syslog(__METHOD__ . ' success'); + $this->db->commit(); + return 1; + } else { + if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $this->error = $langs->trans("ErrorRecordAlreadyExists", $this->email); + } else { + $this->error = $this->db->lasterror(); + } + $this->db->rollback(); + return -6; + } + } + + /** + * Get object from database + * + * @param int $rowid Id of Mailing Target + * @return int Return integer <0 if KO, >0 if OK + */ + public function fetch($rowid) + { + $sql = "SELECT t.rowid"; + $sql .= ", t.fk_mailing"; + $sql .= ", t.fk_contact"; + $sql .= ", t.lastname"; + $sql .= ", t.firstname"; + $sql .= ", t.email"; + $sql .= ", t.other"; + $sql .= ", t.tag"; + $sql .= ", t.statut as status"; + $sql .= ", t.source_url"; + $sql .= ", t.source_id"; + $sql .= ", t.source_type"; + $sql .= ", t.date_envoi"; + $sql .= ", t.tms as date_modification"; + $sql .= ", t.error_text"; + $sql .= " FROM ".MAIN_DB_PREFIX."mailing_cibles as t"; + $sql .= " WHERE t.rowid = ".(int) $rowid; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + $this->fk_mailing = $obj->fk_mailing; + $this->fk_contact = $obj->fk_contact; + $this->lastname = $obj->lastname; + $this->firstname = $obj->firstname; + $this->email = $obj->email; + $this->other = $obj->other; + $this->tag = $obj->tag; + $this->statut = $obj->status; // deprecated + $this->status = $obj->status; + $this->source_url = $obj->source_url; + $this->source_id = $obj->source_id; + $this->source_type = $obj->source_type; + $this->date_envoi = $this->db->jdate($obj->date_envoi); + $this->date_modification = $this->db->jdate($obj->date_modification); // tms + $this->tms = $this->db->jdate($obj->date_modification); // tms + $this->error_text = $obj->error_text; + + return 1; + } else { + dol_syslog(get_class($this)."::fetch Error -1"); + return -1; + } + } else { + dol_syslog(get_class($this)."::fetch Error -2"); + return -2; + } + } +} diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 992073021c2..7a692b81fa7 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -1062,7 +1062,7 @@ abstract class CommonInvoice extends CommonObject $statusdispute = $moreparams['dispute_status'] ? img_picto($langs->trans("DisputeOpen"), 'warning') : ''; } */ - if ($moreparams['dispute_status']) { + if (isset($moreparams['dispute_status']) && $moreparams['dispute_status']) { $labelStatus .= ' - '.$langs->trans("DisputeOpen"); $statusType = 'status8'; } diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 830f8470498..c621fbca403 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -2345,8 +2345,8 @@ function get_left_menu_mrp($mainmenu, &$newmenu, $usemenuhider = 1, $leftmenu = $langs->load("mrp"); $newmenu->add("", $langs->trans("MenuMRP"), 0, $user->hasRight('mrp', 'read'), '', $mainmenu, 'mrp', 0, '', '', '', img_picto('', 'mrp', 'class="paddingright pictofixedwidth"')); - $newmenu->add("/mrp/mo_card.php?leftmenu=mo&action=create", $langs->trans("NewMO"), 1, $user->hasRight('mrp', 'write'), '', $mainmenu, ''); - $newmenu->add("/mrp/mo_list.php?leftmenu=mo", $langs->trans("List"), 1, $user->hasRight('mrp', 'read'), '', $mainmenu, ''); + $newmenu->add("/mrp/mo_card.php?leftmenu=mrp&action=create", $langs->trans("NewMO"), 1, $user->hasRight('mrp', 'write'), '', $mainmenu, ''); + $newmenu->add("/mrp/mo_list.php?leftmenu=mrp", $langs->trans("List"), 1, $user->hasRight('mrp', 'read'), '', $mainmenu, ''); } } } diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 46b08605ad3..0ffacc97e04 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -934,7 +934,7 @@ if (empty($reshook)) { $object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); - $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx'); + $object->multicurrency_tx = GETPOSTFLOAT('originmulticurrency_tx'); $object->transport_mode_id = GETPOSTINT('transport_mode_id'); // Proprietes particulieres a facture avoir @@ -1037,7 +1037,7 @@ if (empty($reshook)) { $object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); - $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx'); + $object->multicurrency_tx = GETPOSTFLOAT('originmulticurrency_tx'); // Source facture $object->fac_rec = $fac_recid; @@ -1104,7 +1104,7 @@ if (empty($reshook)) { $object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); - $object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx'); + $object->multicurrency_tx = GETPOSTFLOAT('originmulticurrency_tx'); $object->transport_mode_id = GETPOSTINT('transport_mode_id'); // Auto calculation of date due if not filled by user diff --git a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql index 7f0fc7ff536..635099b6b3f 100644 --- a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql +++ b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql @@ -234,4 +234,8 @@ ALTER TABLE llx_accounting_bookkeeping_piece ADD INDEX idx_accounting_bookkeepin ALTER TABLE llx_mailing ADD COLUMN fk_project integer DEFAULT NULL; UPDATE llx_c_units SET label = 'unitP' WHERE code = 'P'; + +ALTER TABLE llx_receptiondet_batch ADD COLUMN description text AFTER fk_product; +ALTER TABLE llx_receptiondet_batch ADD COLUMN fk_unit integer AFTER qty; +ALTER TABLE llx_receptiondet_batch ADD COLUMN rang integer DEFAULT 0 AFTER cost_price; -- end of migration diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql index 13e3935a39a..8217fe16caa 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql @@ -30,11 +30,13 @@ create table llx_receptiondet_batch fk_elementdet integer, -- ID of line of main source object. element_type varchar(50) DEFAULT 'supplier_order' NOT NULL, -- Type of source object ('supplier_order', ...) fk_product integer, - qty float, -- qty to move - fk_entrepot integer, -- ID of warehouse to use for the stock change + description text, -- Product description/label of non origin + qty float, -- qty to move + fk_unit integer, -- ID of unit code + fk_entrepot integer, -- ID of warehouse to use for the stock change fk_projet integer DEFAULT NULL, - comment varchar(255), -- comment on movement - batch varchar(128) DEFAULT NULL, -- serial/lot number + comment varchar(255), -- comment on movement + batch varchar(128) DEFAULT NULL, -- serial/lot number eatby date DEFAULT NULL, sellby date DEFAULT NULL, status integer, @@ -42,5 +44,6 @@ create table llx_receptiondet_batch datec datetime, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, cost_price double(24,8) DEFAULT 0, - extraparams varchar(255) -- to stock other parameters in json format + rang integer DEFAULT 0, -- Position of line + extraparams varchar(255) -- to stock other parameters in json format )ENGINE=innodb; diff --git a/test/hurl/api/mailings/10_mailings.hurl b/test/hurl/api/mailings/10_mailings.hurl new file mode 100644 index 00000000000..6208539e43b --- /dev/null +++ b/test/hurl/api/mailings/10_mailings.hurl @@ -0,0 +1,187 @@ +# GET mass mailings +GET http://{{hostnport}}/api/index.php/mailings +HTTP 200 + +# GET mass sorted mailings +GET http://{{hostnport}}/api/index.php/mailings?sortfield=t.rowid&sortorder=ASC +HTTP 200 + +# GET mass sorted mailings +GET http://{{hostnport}}/api/index.php/mailings?sortfield=t.rowid&sortorder=ASC +HTTP 200 + +# GET with limit and page +GET http://{{hostnport}}/api/index.php/mailings?limit=100&page=1 +HTTP 200 + +# GET with fk_project +GET http://{{hostnport}}/api/index.php/mailings?fk_projects=1 +HTTP 200 + +# GET with properties=id%2Cstatus +GET http://{{hostnport}}/api/index.php/mailings?properties=id%2Cstatus +HTTP 200 + +# GET with pagination_data=false +GET http://{{hostnport}}/api/index.php/mailings?pagination_data=false +HTTP 200 + +# GET with pagination_data=true +GET http://{{hostnport}}/api/index.php/mailings?pagination_data=true +HTTP 200 +[Asserts] +jsonpath "$.data" exists +jsonpath "$.pagination.total" >= 0 +jsonpath "$.pagination.page" >= 0 +jsonpath "$.pagination.page_count" >= 0 +jsonpath "$.pagination.limit" == 100 + +# GET mailing with ID 0 - which should not exist +GET http://{{hostnport}}/api/index.php/mailings/0 +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + +# POST {} +POST http://{{hostnport}}/api/index.php/mailings +{} +HTTP 400 +{"error":{"code":400,"message":"Bad Request: title field missing"}} + +# DELETE +DELETE http://{{hostnport}}/api/index.php/mailings/ +HTTP 405 + +# DELETE mailing with ID 0 - which should not exist +DELETE http://{{hostnport}}/api/index.php/mailings/0 +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + +# PUT +PUT http://{{hostnport}}/api/index.php/mailings/ +{} +HTTP 405 + +# PUT +PUT http://{{hostnport}}/api/index.php/mailings/0 +{} +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + +DELETE http://{{hostnport}}/api/index.php/mailings//deleteTargets +HTTP 400 + +# DELETE targets of mailing with ID 0 - which should not exist +DELETE http://{{hostnport}}/api/index.php/mailings/0/deleteTargets +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + + +PUT http://{{hostnport}}/api/index.php/mailings//resetTargetsStatus +HTTP 400 + +# reset target status of mailing with ID 0 - which should not exist +PUT http://{{hostnport}}/api/index.php/mailings/0/resetTargetsStatus +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + + +PUT http://{{hostnport}}/api/index.php/mailings//settodraft +HTTP 400 + +# set mailing to draft with ID 0 - which should not exist +PUT http://{{hostnport}}/api/index.php/mailings/0/settodraft +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + + +PUT http://{{hostnport}}/api/index.php/mailings//validate +HTTP 400 + +# validate mailing with ID 0 - which should not exist +PUT http://{{hostnport}}/api/index.php/mailings/0/validate +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + +GET http://{{hostnport}}/api/index.php/mailings/clone/ +HTTP 400 + +GET http://{{hostnport}}/api/index.php/mailings/clone/0 +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing to clone not found, id=0"}} + + +GET http://{{hostnport}}/api/index.php/mailings//targets +HTTP 400 + +# get targets of mailing with ID 0 - which should not exist +GET http://{{hostnport}}/api/index.php/mailings/0/targets +HTTP 404 +{"error":{"code":404,"message":"Not Found: Mass mailing not found, id=0"}} + +# get a target in a mailing +GET http://{{hostnport}}/api/index.php/mailings/0/getTarget/0 +HTTP 404 + +# get a target in a mailing +PUT http://{{hostnport}}/api/index.php/mailings/0/updateTarget/0 +{} +HTTP 404 + +# Delete a target in a mailing +DELETE http://{{hostnport}}/api/index.php/mailings/0/deleteTarget/0 +{} +HTTP 404 + +# Create a target in a mailing +POST http://{{hostnport}}/api/index.php/mailings/0/createTarget +{} +HTTP 400 + +# Create a target in a mailing +POST http://{{hostnport}}/api/index.php/mailings/0/createTarget +{ + "statut": "0", + "status": "0", + "lastname": "Example", + "firstname": "Bad", + "date_modification": 1759051258, + "tms": 1759051258, + "fk_mailing": "0", + "fk_contact": "0", + "email": "bad@example.com", + "other": "", + "tag": "acaa266a6b12a85a7db47a377a10333b", + "source_url": "", + "source_id": null, + "source_type": "file", + "date_envoi": "", + "error_text": null +} +HTTP 404 + +# Create a target in a mailing +POST http://{{hostnport}}/api/index.php/mailings/0/createTarget +{ + "id": "0" +} +HTTP 400 +{"error":{"code":400,"message":"Bad Request: fk_mailing field missing"}} + +# Create a target in a mailing +POST http://{{hostnport}}/api/index.php/mailings/0/createTarget +{ + "id": "0", + "fk_mailing" : "0" +} +HTTP 400 +{"error":{"code":400,"message":"Bad Request: email field missing"}} + +# Create a target in a mailing +POST http://{{hostnport}}/api/index.php/mailings/0/createTarget +{ + "id": "0", + "email": "bad@example.com", + "fk_mailing" : "0" +} +HTTP 400 +{"error":{"code":400,"message":"Bad Request: Creating with id field is forbidden"}} diff --git a/test/hurl/run.sh b/test/hurl/run.sh index dfe3870eb0d..db96888494a 100755 --- a/test/hurl/run.sh +++ b/test/hurl/run.sh @@ -17,14 +17,14 @@ if [[ "" != "${DOLISUBURL}" ]]; then fi echo "First we run tests that do not require authentication" -find api/ gui/ public/ -type f -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --test "{}" \; +find api/ gui/ public/ -type f -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --test "{}" + || exit 1 # Now we get ready to run tests that do require authentication if [[ -z ${DOLAPIKEY+x} ]]; then echo "DOLAPIKEY bash variable is unset, no API tests that require authentication" else echo "Now we are ready to run API tests that do require authentication" - find api/ -type f -iname '10*.hurl' -not -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --header "${DOLAPIKEY}" --test "{}" \; + find api/ -type f -iname '10*.hurl' -not -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --header "${DOLAPIKEY}" --test "{}" + || exit 2 fi ./save_login_cookie.sh @@ -32,5 +32,5 @@ if [[ -z ${COOKIEJAR+x} ]]; then COOKIEJAR=/tmp/cookie.jar fi echo "Now we are ready to run GUI tests that do require authentication" -find gui/ -type f -iname '10*.hurl' -not -iname 'save_login_cookie.hurl' -not -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --cookie "${COOKIEJAR}" --test "{}" \; +find gui/ -type f -iname '10*.hurl' -not -iname 'save_login_cookie.hurl' -not -iname '00*.hurl' -exec hurl --variable "hostnport=${hostnport}" --cookie "${COOKIEJAR}" --test "{}" + || exit 3 rm -rf "${COOKIEJAR}" diff --git a/test/hurl/save_login_cookie.sh b/test/hurl/save_login_cookie.sh index c18d2426b0f..c1204211158 100755 --- a/test/hurl/save_login_cookie.sh +++ b/test/hurl/save_login_cookie.sh @@ -17,10 +17,12 @@ if [[ "" != "${DOLISUBURL}" ]]; then fi if [[ -z ${DOLIUSERNAME+x} ]]; then - read -rp "Your Dolibarr Username: " DOLIUSERNAME + echo "To do GUI tests we need:" + read -rp " Your Dolibarr Username: " DOLIUSERNAME fi if [[ -z ${DOLIPASSWORD+x} ]]; then - read -rsp "Your Dolibarr Password: " DOLIPASSWORD + echo "To do GUI tests we need:" + read -rsp " Your Dolibarr Password: " DOLIPASSWORD echo "" fi