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
// 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'],

View File

@@ -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';

View File

@@ -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<string,string> $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<string,string> $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<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
*
@@ -612,6 +987,162 @@ class Mailings extends DolibarrApi
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
/**
@@ -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);

View File

@@ -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);

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') : '';
}
*/
if ($moreparams['dispute_status']) {
if (isset($moreparams['dispute_status']) && $moreparams['dispute_status']) {
$labelStatus .= ' - '.$langs->trans("DisputeOpen");
$statusType = 'status8';
}

View File

@@ -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, '');
}
}
}

View File

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

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;
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

View File

@@ -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;

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

View File

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