2
0
forked from Wavyzz/dolibarr

Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
ldestailleur
2025-10-09 18:41:49 +02:00
13 changed files with 1260 additions and 26 deletions

View File

@@ -12,7 +12,7 @@ return [
// PhanUndeclaredProperty : 420+ occurrences // PhanUndeclaredProperty : 420+ occurrences
// PhanTypeMismatchProperty : 100+ occurrences // PhanTypeMismatchProperty : 100+ occurrences
// PhanTypeMismatchArgument : 70+ occurrences // PhanTypeMismatchArgument : 70+ occurrences
// PhanUndeclaredGlobalVariable : 70+ occurrences // PhanUndeclaredGlobalVariable : 65+ occurrences
// PhanTypeMismatchArgumentNullable : 40+ occurrences // PhanTypeMismatchArgumentNullable : 40+ occurrences
// PhanTypeInvalidDimOffset : 15+ occurrences // PhanTypeInvalidDimOffset : 15+ occurrences
// PhanTypeMismatchDimFetch : 15+ occurrences // PhanTypeMismatchDimFetch : 15+ occurrences
@@ -230,7 +230,6 @@ return [
'htdocs/projet/tasks.php' => ['PhanTypeMismatchArgument'], 'htdocs/projet/tasks.php' => ['PhanTypeMismatchArgument'],
'htdocs/projet/tasks/time.php' => ['PhanTypeInvalidDimOffset', 'PhanUndeclaredProperty'], 'htdocs/projet/tasks/time.php' => ['PhanTypeInvalidDimOffset', 'PhanUndeclaredProperty'],
'htdocs/projet/tasks/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/projet/tasks/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'],
'htdocs/public/eventorganization/subscriptionok.php' => ['PhanUndeclaredGlobalVariable'],
'htdocs/public/members/new.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/members/new.php' => ['PhanUndeclaredGlobalVariable'],
'htdocs/public/payment/newpayment.php' => ['PhanUndeclaredProperty'], 'htdocs/public/payment/newpayment.php' => ['PhanUndeclaredProperty'],
'htdocs/public/payment/paymentok.php' => ['PhanTypeMismatchArgumentProbablyReal'], 'htdocs/public/payment/paymentok.php' => ['PhanTypeMismatchArgumentProbablyReal'],

View File

@@ -505,7 +505,7 @@ class Documents extends DolibarrApi
throw new RestException(404, 'Invoice not found'); 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') { } elseif ($modulepart == 'produit' || $modulepart == 'product' || $modulepart == 'service') {
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';

View File

@@ -19,6 +19,7 @@
use Luracast\Restler\RestException; use Luracast\Restler\RestException;
require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php'; 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 * API class for mass mailings
@@ -39,11 +40,24 @@ class Mailings extends DolibarrApi
'body' 'body'
); );
/**
* @var string[] Mandatory fields, checked when create and update object
*/
public static $TARGETFIELDS = array(
'fk_mailing',
'email'
);
/** /**
* @var Mailing {@type Mailing} * @var Mailing {@type Mailing}
*/ */
public $mailing; public $mailing;
/**
* @var MailingTarget {@type MailingTarget}
*/
public $mailing_target;
/** /**
* Constructor * Constructor
*/ */
@@ -52,6 +66,7 @@ class Mailings extends DolibarrApi
global $db; global $db;
$this->db = $db; $this->db = $db;
$this->mailing = new Mailing($this->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}} * @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}} * @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) 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; 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 * Clone a mass mailing
* *
@@ -264,7 +388,8 @@ class Mailings extends DolibarrApi
* @phpstan-param ?array<string,string> $request_data * @phpstan-param ?array<string,string> $request_data
* @return int ID of mass mailing * @return int ID of mass mailing
* *
* @throws RestException * @throws RestException 403
* @throws RestException 500 System error
*/ */
public function post($request_data = null) public function post($request_data = null)
{ {
@@ -307,7 +432,9 @@ class Mailings extends DolibarrApi
* @phpstan-param ?array<string,string> $request_data * @phpstan-param ?array<string,string> $request_data
* @return Object Object with cleaned properties * @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) 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<string,string> $request_data
* @phpstan-param ?array<string,string> $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<string,string> $request_data
* @phpstan-param ?array<string,string> $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 * Delete targets of a mass mailing
* *
@@ -612,6 +987,162 @@ class Mailings extends DolibarrApi
return $mailing; return $mailing;
} }
/**
* Validate fields before create or update object
*
* @param ?array<string,string> $data Array with data to verify
* @return array<string,string>
*
* @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 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
/** /**
@@ -666,8 +1197,6 @@ class Mailings extends DolibarrApi
unset($object->import_key); unset($object->import_key);
unset($object->isextrafieldmanaged); unset($object->isextrafieldmanaged);
unset($object->ismultientitymanaged); unset($object->ismultientitymanaged);
unset($object->labelStatus);
unset($object->labelStatusShort);
unset($object->last_main_doc); unset($object->last_main_doc);
unset($object->lastname); unset($object->lastname);
unset($object->lines); unset($object->lines);

View File

@@ -26,7 +26,7 @@
*/ */
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; 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 * Class to manage emailings module
@@ -174,6 +174,11 @@ class Mailing extends CommonObject
*/ */
public $substitutionarrayfortest; public $substitutionarrayfortest;
/**
* @var MailingTarget[]
*/
public $targets = array();
/** /**
* @var ?int The related project ID * @var ?int The related project ID
* @see setProject(), project * @see setProject(), project
@@ -621,7 +626,7 @@ class Mailing extends CommonObject
$now = dol_now(); $now = dol_now();
$sql = "UPDATE ".MAIN_DB_PREFIX."mailing "; $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); $sql .= " WHERE rowid = ".((int) $this->id);
dol_syslog("Mailing::valid", LOG_DEBUG); dol_syslog("Mailing::valid", LOG_DEBUG);

View File

@@ -0,0 +1,505 @@
<?php
/* Copyright (C) 2025 Cloned from htdocs/comm/mailing/class/mailing.class.php then modified
* Copyright (C) 2025 Jon Bendtsen <jon.bendtsen.github@jonb.dk>
*
* 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 <https://www.gnu.org/licenses/>.
*/
/**
* \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<int,string> 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;
}
}
}

View File

@@ -1062,7 +1062,7 @@ abstract class CommonInvoice extends CommonObject
$statusdispute = $moreparams['dispute_status'] ? img_picto($langs->trans("DisputeOpen"), 'warning') : ''; $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"); $labelStatus .= ' - '.$langs->trans("DisputeOpen");
$statusType = 'status8'; $statusType = 'status8';
} }

View File

@@ -2345,8 +2345,8 @@ function get_left_menu_mrp($mainmenu, &$newmenu, $usemenuhider = 1, $leftmenu =
$langs->load("mrp"); $langs->load("mrp");
$newmenu->add("", $langs->trans("MenuMRP"), 0, $user->hasRight('mrp', 'read'), '', $mainmenu, 'mrp', 0, '', '', '', img_picto('', 'mrp', 'class="paddingright pictofixedwidth"')); $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_card.php?leftmenu=mrp&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_list.php?leftmenu=mrp", $langs->trans("List"), 1, $user->hasRight('mrp', 'read'), '', $mainmenu, '');
} }
} }
} }

View File

@@ -934,7 +934,7 @@ if (empty($reshook)) {
$object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->fk_incoterms = GETPOSTINT('incoterm_id');
$object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
$object->multicurrency_code = GETPOST('multicurrency_code', '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'); $object->transport_mode_id = GETPOSTINT('transport_mode_id');
// Proprietes particulieres a facture avoir // Proprietes particulieres a facture avoir
@@ -1037,7 +1037,7 @@ if (empty($reshook)) {
$object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->fk_incoterms = GETPOSTINT('incoterm_id');
$object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
$object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
$object->multicurrency_tx = GETPOSTINT('originmulticurrency_tx'); $object->multicurrency_tx = GETPOSTFLOAT('originmulticurrency_tx');
// Source facture // Source facture
$object->fac_rec = $fac_recid; $object->fac_rec = $fac_recid;
@@ -1104,7 +1104,7 @@ if (empty($reshook)) {
$object->fk_incoterms = GETPOSTINT('incoterm_id'); $object->fk_incoterms = GETPOSTINT('incoterm_id');
$object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
$object->multicurrency_code = GETPOST('multicurrency_code', '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'); $object->transport_mode_id = GETPOSTINT('transport_mode_id');
// Auto calculation of date due if not filled by user // Auto calculation of date due if not filled by user

View File

@@ -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; ALTER TABLE llx_mailing ADD COLUMN fk_project integer DEFAULT NULL;
UPDATE llx_c_units SET label = 'unitP' WHERE code = 'P'; 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 -- end of migration

View File

@@ -30,7 +30,9 @@ create table llx_receptiondet_batch
fk_elementdet integer, -- ID of line of main source object. 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', ...) element_type varchar(50) DEFAULT 'supplier_order' NOT NULL, -- Type of source object ('supplier_order', ...)
fk_product integer, fk_product integer,
description text, -- Product description/label of non origin
qty float, -- qty to move 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_entrepot integer, -- ID of warehouse to use for the stock change
fk_projet integer DEFAULT NULL, fk_projet integer DEFAULT NULL,
comment varchar(255), -- comment on movement comment varchar(255), -- comment on movement
@@ -42,5 +44,6 @@ create table llx_receptiondet_batch
datec datetime, datec datetime,
tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
cost_price double(24,8) DEFAULT 0, cost_price double(24,8) DEFAULT 0,
rang integer DEFAULT 0, -- Position of line
extraparams varchar(255) -- to stock other parameters in json format extraparams varchar(255) -- to stock other parameters in json format
)ENGINE=innodb; )ENGINE=innodb;

View File

@@ -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"}}

View File

@@ -17,14 +17,14 @@ if [[ "" != "${DOLISUBURL}" ]]; then
fi fi
echo "First we run tests that do not require authentication" 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 # Now we get ready to run tests that do require authentication
if [[ -z ${DOLAPIKEY+x} ]]; then if [[ -z ${DOLAPIKEY+x} ]]; then
echo "DOLAPIKEY bash variable is unset, no API tests that require authentication" echo "DOLAPIKEY bash variable is unset, no API tests that require authentication"
else else
echo "Now we are ready to run API tests that do require authentication" 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 fi
./save_login_cookie.sh ./save_login_cookie.sh
@@ -32,5 +32,5 @@ if [[ -z ${COOKIEJAR+x} ]]; then
COOKIEJAR=/tmp/cookie.jar COOKIEJAR=/tmp/cookie.jar
fi fi
echo "Now we are ready to run GUI tests that do require authentication" 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}" rm -rf "${COOKIEJAR}"

View File

@@ -17,9 +17,11 @@ if [[ "" != "${DOLISUBURL}" ]]; then
fi fi
if [[ -z ${DOLIUSERNAME+x} ]]; then if [[ -z ${DOLIUSERNAME+x} ]]; then
echo "To do GUI tests we need:"
read -rp " Your Dolibarr Username: " DOLIUSERNAME read -rp " Your Dolibarr Username: " DOLIUSERNAME
fi fi
if [[ -z ${DOLIPASSWORD+x} ]]; then if [[ -z ${DOLIPASSWORD+x} ]]; then
echo "To do GUI tests we need:"
read -rsp " Your Dolibarr Password: " DOLIPASSWORD read -rsp " Your Dolibarr Password: " DOLIPASSWORD
echo "" echo ""
fi fi