Merge pull request #31 from Dolibarr/develop

Update fork
This commit is contained in:
Damien BENOIT 2021-07-19 17:12:20 +02:00 committed by GitHub
commit dc5dac8c04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1342 additions and 250 deletions

View File

@ -2,6 +2,27 @@
English Dolibarr ChangeLog
--------------------------------------------------------------
***** ChangeLog for 13.0.4 compared to 13.0.2 *****
FIX: Allow disabling of a module (not a dangerous action) even if there is problem with token (due to bugged modules).
FIX: 13.0 - fatal - missing inclusion of ajax.lib.php for calling `ajax_autocompleter()`
FIX: #17919 pictures in docs.
FIX: #18006
FIX: Accountancy - if we define a date start, automatic binding try to continue to solve old binding
FIX: Accoutancy Limit date payment not registered on purchases operations
FIX: Can't edit replacement invoice
FIX: deposit can create credit note in payment conf
FIX: division by zero on create
FIX: holiday: balances not updated correctly with pgsql because of case sensitivity field
FIX: holiday: status filter parameter has been renamed but not in links it was used
FIX: List and Create Companies Left Menus
FIX: method exists
FIX: need to add payment sum to getlibstatus function in object linked block
FIX: permission to close a proposal when using advanced permissions
FIX: Problem of z-index with popup and top menu
FIX: same thing on supplier orders
FIX: Status of invoice when making a replacement invoice
FIX: update contact birthday alert
***** ChangeLog for 14.0.0 compared to 13.0.0 *****

View File

@ -103,6 +103,7 @@ $debuginfo = '';
$parameters = array();
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
@ -239,7 +240,6 @@ if ($action == 'confirm_collect') {
/*
* View
*/
@ -434,6 +434,14 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
$connectstringtarget = $connectstringserver.$object->getEncodedUtf7($targetdir);
}
$timeoutconnect = empty($conf->global->MAIN_USE_CONNECT_TIMEOUT) ? 10 : $conf->global->MAIN_USE_CONNECT_TIMEOUT;
$timeoutread = empty($conf->global->MAIN_USE_RESPONSE_TIMEOUT) ? 30 : $conf->global->MAIN_USE_RESPONSE_TIMEOUT;
dol_syslog("imap_open connectstring=".$connectstringsource." login=".$object->login." password=".$object->password." timeoutconnect=".$timeoutconnect." timeoutread=".$timeoutread);
imap_timeout(IMAP_OPENTIMEOUT, $timeoutconnect);
imap_timeout(IMAP_READTIMEOUT, $timeoutread);
$connection = imap_open($connectstringsource, $object->login, $object->password);
} catch (Exception $e) {
print $e->getMessage();
@ -449,12 +457,15 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
if (function_exists('imap_last_error')) {
$morehtml .= '<br>'.imap_last_error();
}
dol_syslog("Error ".$morehtml, LOG_WARNING);
//var_dump(imap_errors())
} else {
dol_syslog("Imap connected. Now we call imap_num_msg()");
$morehtml .= imap_num_msg($connection);
}
if ($connection) {
dol_syslog("Imap close");
imap_close($connection);
}

View File

@ -549,110 +549,111 @@ class BlockedLog
$totalamount = 0;
if (!is_array($object->amounts) && $object->amount) {
$object->amounts = array($object->id => $object->amount);
}
// Loop on each invoice payment amount
if (is_array($object->amounts) && !empty($object->amounts)) {
$paymentpartnumber = 0;
foreach ($object->amounts as $objid => $amount) {
if (empty($amount)) {
continue;
}
$paymentpartnumber = 0;
foreach ($object->amounts as $objid => $amount) {
if (empty($amount)) {
continue;
}
$totalamount += $amount;
$totalamount += $amount;
$tmpobject = null;
if ($this->element == 'payment_supplier') {
include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
$tmpobject = new FactureFournisseur($this->db);
} elseif ($this->element == 'payment') {
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
$tmpobject = new Facture($this->db);
} elseif ($this->element == 'payment_donation') {
include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
$tmpobject = new Don($this->db);
} elseif ($this->element == 'payment_various') {
include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
$tmpobject = new PaymentVarious($this->db);
}
$tmpobject = null;
if ($this->element == 'payment_supplier') {
include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
$tmpobject = new FactureFournisseur($this->db);
} elseif ($this->element == 'payment') {
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
$tmpobject = new Facture($this->db);
} elseif ($this->element == 'payment_donation') {
include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
$tmpobject = new Don($this->db);
} elseif ($this->element == 'payment_various') {
include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
$tmpobject = new PaymentVarious($this->db);
}
if (!is_object($tmpobject)) {
continue;
}
if (!is_object($tmpobject)) {
continue;
}
$result = $tmpobject->fetch($objid);
$result = $tmpobject->fetch($objid);
if ($result <= 0) {
$this->error = $tmpobject->error;
$this->errors = $tmpobject->errors;
dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
return -1;
}
$paymentpart = new stdClass();
$paymentpart->amount = $amount;
if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
$result = $tmpobject->fetch_thirdparty();
if ($result == 0) {
$this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
$this->errors[] = $this->error;
dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
return -1;
} elseif ($result < 0) {
if ($result <= 0) {
$this->error = $tmpobject->error;
$this->errors = $tmpobject->errors;
dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
return -1;
}
$paymentpart->thirdparty = new stdClass();
foreach ($tmpobject->thirdparty as $key => $value) {
if (in_array($key, $arrayoffieldstoexclude)) {
continue; // Discard some properties
}
if (!in_array($key, array(
'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
))) {
continue; // Discard if not into a dedicated list
}
if (!is_object($value) && !is_null($value) && $value !== '') {
$paymentpart->thirdparty->{$key} = $value;
}
}
}
$paymentpart = new stdClass();
$paymentpart->amount = $amount;
// Init object to avoid warnings
if ($this->element == 'payment_donation') {
$paymentpart->donation = new stdClass();
} else {
$paymentpart->invoice = new stdClass();
}
if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
$result = $tmpobject->fetch_thirdparty();
if ($result == 0) {
$this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
$this->errors[] = $this->error;
dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
return -1;
} elseif ($result < 0) {
$this->error = $tmpobject->error;
$this->errors = $tmpobject->errors;
return -1;
}
if ($this->element != 'payment_various') {
foreach ($tmpobject as $key => $value) {
if (in_array($key, $arrayoffieldstoexclude)) {
continue; // Discard some properties
}
if (!in_array($key, array(
'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
))) {
continue; // Discard if not into a dedicated list
}
if (!is_object($value) && !is_null($value) && $value !== '') {
if ($this->element == 'payment_donation') {
$paymentpart->donation->{$key} = $value;
} elseif ($this->element == 'payment_various') {
$paymentpart->various->{$key} = $value;
} else {
$paymentpart->invoice->{$key} = $value;
$paymentpart->thirdparty = new stdClass();
foreach ($tmpobject->thirdparty as $key => $value) {
if (in_array($key, $arrayoffieldstoexclude)) {
continue; // Discard some properties
}
if (!in_array($key, array(
'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
))) {
continue; // Discard if not into a dedicated list
}
if (!is_object($value) && !is_null($value) && $value !== '') {
$paymentpart->thirdparty->{$key} = $value;
}
}
}
$paymentpartnumber++; // first payment will be 1
$this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
// Init object to avoid warnings
if ($this->element == 'payment_donation') {
$paymentpart->donation = new stdClass();
} else {
$paymentpart->invoice = new stdClass();
}
if ($this->element != 'payment_various') {
foreach ($tmpobject as $key => $value) {
if (in_array($key, $arrayoffieldstoexclude)) {
continue; // Discard some properties
}
if (!in_array($key, array(
'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
))) {
continue; // Discard if not into a dedicated list
}
if (!is_object($value) && !is_null($value) && $value !== '') {
if ($this->element == 'payment_donation') {
$paymentpart->donation->{$key} = $value;
} elseif ($this->element == 'payment_various') {
$paymentpart->various->{$key} = $value;
} else {
$paymentpart->invoice->{$key} = $value;
}
}
}
$paymentpartnumber++; // first payment will be 1
$this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
}
}
} elseif (!empty($object->amount)) {
$totalamount = $object->amount;
}
$this->object_data->amount = $totalamount;

View File

@ -34,6 +34,7 @@
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
@ -56,6 +57,7 @@ class Categorie extends CommonObject
const TYPE_WAREHOUSE = 'warehouse';
const TYPE_ACTIONCOMM = 'actioncomm';
const TYPE_WEBSITE_PAGE = 'website_page';
const TYPE_TICKET = 'ticket';
/**
* @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
@ -78,7 +80,8 @@ class Categorie extends CommonObject
'bank_line' => 8,
'warehouse' => 9,
'actioncomm' => 10,
'website_page' => 11
'website_page' => 11,
'ticket' => 12
);
/**
@ -98,7 +101,8 @@ class Categorie extends CommonObject
8 => 'bank_line',
9 => 'warehouse',
10 => 'actioncomm',
11 => 'website_page'
11 => 'website_page',
12 => 'ticket'
);
/**
@ -141,7 +145,8 @@ class Categorie extends CommonObject
'project' => 'Project',
'warehouse'=> 'Entrepot',
'actioncomm' => 'ActionComm',
'website_page' => 'WebsitePage'
'website_page' => 'WebsitePage',
'ticket' => 'Ticket'
);
/**
@ -234,6 +239,8 @@ class Categorie extends CommonObject
* @see Categorie::TYPE_WAREHOUSE
* @see Categorie::TYPE_ACTIONCOMM
* @see Categorie::TYPE_WEBSITE_PAGE
* @see Categorie::TYPE_TICKET
*/
public $type;

View File

@ -142,6 +142,11 @@ if ($id > 0 && $removeelem > 0) {
$tmpobject = new User($db);
$result = $tmpobject->fetch($removeelem);
$elementtype = 'user';
} elseif ($type == Categorie::TYPE_TICKET && $user->rights->ticket->write) {
require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
$tmpobject = new Ticket($db);
$result = $tmpobject->fetch($removeelem);
$elementtype = 'ticket';
}
$result = $object->del_type($tmpobject, $elementtype);
@ -167,7 +172,8 @@ if ($user->rights->categorie->supprimer && $action == 'confirm_delete' && $confi
if ($elemid && $action == 'addintocategory' &&
(($type == Categorie::TYPE_PRODUCT && ($user->rights->produit->creer || $user->rights->service->creer)) ||
($type == Categorie::TYPE_CUSTOMER && $user->rights->societe->creer) ||
($type == Categorie::TYPE_SUPPLIER && $user->rights->societe->creer)
($type == Categorie::TYPE_SUPPLIER && $user->rights->societe->creer) ||
($type == Categorie::TYPE_TICKET && $user->rights->ticket->write)
)) {
if ($type == Categorie::TYPE_PRODUCT) {
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
@ -181,6 +187,10 @@ if ($elemid && $action == 'addintocategory' &&
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
$newobject = new Societe($db);
$elementtype = 'supplier';
} elseif ($type == Categorie::TYPE_TICKET) {
require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
$newobject = new Ticket($db);
$elementtype = 'ticket';
}
$result = $newobject->fetch($elemid);
@ -1024,6 +1034,78 @@ if ($type == Categorie::TYPE_WAREHOUSE) {
}
}
if ($type == Categorie::TYPE_TICKET) {
$permission = ($user->rights->categorie->creer || $user->rights->categorie->creer);
$tickets = $object->getObjectsInCateg($type, 0, $limit, $offset);
if ($tickets < 0) {
dol_print_error($db, $object->error, $object->errors);
} else {
// Form to add record into a category
$showclassifyform = 1;
if ($showclassifyform) {
print '<br>';
print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="typeid" value="'.$typeid.'">';
print '<input type="hidden" name="type" value="'.$typeid.'">';
print '<input type="hidden" name="id" value="'.$object->id.'">';
print '<input type="hidden" name="action" value="addintocategory">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre"><td>';
print $langs->trans("AddTicketIntoCategory").' &nbsp;';
$form->selectTickets('', 'elemid');
print '<input type="submit" class="button buttongen" value="'.$langs->trans("ClassifyInCategory").'"></td>';
print '</tr>';
print '</table>';
print '</form>';
}
print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="typeid" value="'.$typeid.'">';
print '<input type="hidden" name="type" value="'.$typeid.'">';
print '<input type="hidden" name="id" value="'.$object->id.'">';
print '<input type="hidden" name="action" value="list">';
print '<br>';
$param = '&limit='.$limit.'&id='.$id.'&type='.$type; $num = count($tickets); $nbtotalofrecords = ''; $newcardbutton = '';
print_barre_liste($langs->trans("Ticket"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'ticket', 0, $newcardbutton, '', $limit);
print '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre"><td colspan="3">'.$langs->trans("Ref").'</td></tr>'."\n";
if (count($tickets) > 0) {
$i = 0;
foreach ($tickets as $ticket) {
$i++;
if ($i > $limit) break;
print "\t".'<tr class="oddeven">'."\n";
print '<td class="nowrap" valign="top">';
print $ticket->getNomUrl(1);
print "</td>\n";
print '<td class="tdtop">'.$ticket->label."</td>\n";
// Link to delete from category
print '<td class="right">';
if ($permission) {
print "<a href= '".$_SERVER['PHP_SELF']."?".(empty($socid) ? 'id' : 'socid')."=".$object->id."&amp;type=".$typeid."&amp;removeelem=".$ticket->id."'>";
print $langs->trans("DeleteFromCat");
print img_picto($langs->trans("DeleteFromCat"), 'unlink', '', false, 0, 0, '', 'paddingleft');
print "</a>";
}
print '</td>';
print "</tr>\n";
}
} else {
print '<tr class="oddeven"><td colspan="2" class="opacitymedium">'.$langs->trans("ThisCategoryHasNoItems").'</td></tr>';
}
print "</table>\n";
print '</form>'."\n";
}
}
// End of page
llxFooter();

View File

@ -497,6 +497,50 @@ if ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SU
}
}
/*
* Draft interventionals
*/
if (!empty($conf->ficheinter->enabled)) {
$sql = "SELECT f.rowid, f.ref, s.nom as name, s.rowid as socid";
$sql .= " FROM ".MAIN_DB_PREFIX."fichinter as f";
$sql .= ", ".MAIN_DB_PREFIX."societe as s";
if (!$user->rights->societe->client->voir && !$socid) {
$sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
}
$sql .= " WHERE f.entity IN (".getEntity('intervention').")";
$sql .= " AND f.fk_soc = s.rowid";
$sql .= " AND f.fk_statut = 0";
if ($socid) {
$sql .= " AND f.fk_soc = ".((int) $socid);
}
if (!$user->rights->societe->client->voir && !$socid) {
$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
}
$resql = $db->query($sql);
if ($resql) {
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans("DraftFichinter").'</th></tr>';
$langs->load("fichinter");
$num = $db->num_rows($resql);
if ($num) {
$i = 0;
while ($i < $num) {
$obj = $db->fetch_object($resql);
print '<tr class="oddeven">';
print '<td class="nowrap">';
print "<a href=\"card.php?id=".$obj->rowid."\">".img_object($langs->trans("ShowFichinter"), "intervention").' '.$obj->ref."</a></td>";
print '<td><a href="'.DOL_URL_ROOT.'/comm/card.php?socid='.$obj->socid.'">'.img_object($langs->trans("ShowCompany"), "company").' '.dol_trunc($obj->name, 24).'</a></td></tr>';
$i++;
}
}
print "</table></div>";
}
}
print '</div><div class="fichetwothirdright">';
print '<div class="ficheaddleft">';

View File

@ -1043,7 +1043,7 @@ if ($resql) {
$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250');
$moreforfilter .= '</div>';
}
// If the user can view prospects other than his'
// Filter on product tags
if (!empty($conf->categorie->enabled) && $user->rights->categorie->lire && ($user->rights->produit->lire || $user->rights->service->lire)) {
include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
$moreforfilter .= '<div class="divsearchfield">';

View File

@ -226,7 +226,7 @@ if (!empty($conf->facture->enabled) && !empty($user->rights->facture->lire)) {
print $thirdpartystatic->getNomUrl(1, 'customer', 44);
print '</td>';
if (!empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) {
print '<td class="nowrap right">'.price($obj->total_ht).'</td>';
print '<td class="nowrap right"><span class="amount">'.price($obj->total_ht).'</span></td>';
}
print '<td class="nowrap right"><span class="amount">'.price($obj->total_ttc).'</span></td>';
print '<td class="right">'.dol_print_date($db->jdate($obj->tms), 'day').'</td>';

View File

@ -1470,6 +1470,80 @@ if (!$error && ($action == 'affecttag' && $confirm == 'yes') && $permissiontoadd
}
}
if (!$error && ($massaction == 'enable' || ($action == 'enable' && $confirm == 'yes')) && $permissiontoadd) {
$db->begin();
$objecttmp = new $objectclass($db);
$nbok = 0;
foreach ($toselect as $toselectid) {
$result = $objecttmp->fetch($toselectid);
if ($result>0) {
if (in_array($objecttmp->element, array('societe'))) {
$result =$objecttmp->setStatut(1);
}
if ($result <= 0) {
setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
$error++;
break;
} else {
$nbok++;
}
} else {
setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
$error++;
break;
}
}
if (!$error) {
if ($nbok > 1) {
setEventMessages($langs->trans("RecordsEnabled", $nbok), null, 'mesgs');
} else {
setEventMessages($langs->trans("RecordEnabled"), null, 'mesgs');
}
$db->commit();
} else {
$db->rollback();
}
}
if (!$error && ($massaction == 'disable' || ($action == 'disable' && $confirm == 'yes')) && $permissiontoadd) {
$db->begin();
$objecttmp = new $objectclass($db);
$nbok = 0;
foreach ($toselect as $toselectid) {
$result = $objecttmp->fetch($toselectid);
if ($result>0) {
if (in_array($objecttmp->element, array('societe'))) {
$result =$objecttmp->setStatut(0);
}
if ($result <= 0) {
setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
$error++;
break;
} else {
$nbok++;
}
} else {
setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
$error++;
break;
}
}
if (!$error) {
if ($nbok > 1) {
setEventMessages($langs->trans("RecordsDisabled", $nbok), null, 'mesgs');
} else {
setEventMessages($langs->trans("RecordDisabled"), null, 'mesgs');
}
$db->commit();
} else {
$db->rollback();
}
}
$parameters['toselect'] = $toselect;
$parameters['uploaddir'] = $uploaddir;
$parameters['massaction'] = $massaction;

View File

@ -180,7 +180,7 @@ class box_factures extends ModeleBoxes
);
$this->info_box_contents[$line][] = array(
'td' => 'class="right nowraponall"',
'td' => 'class="right nowraponall amount"',
'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
);

View File

@ -182,7 +182,7 @@ class box_factures_imp extends ModeleBoxes
);
$this->info_box_contents[$line][] = array(
'td' => 'class="nowraponall right"',
'td' => 'class="nowraponall right amount"',
'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
);

View File

@ -6521,11 +6521,11 @@ abstract class CommonObject
} elseif (in_array($type, array('int', 'integer'))) {
$tmp = explode(',', $size);
$newsize = $tmp[0];
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$newsize.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"'.($newsize > 0 ? ' maxlength="'.$newsize.'"' : '').' value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
} elseif (in_array($type, array('real'))) {
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
} elseif (preg_match('/varchar/', $type)) {
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" maxlength="'.$size.'" value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'"'.($size > 0 ? ' maxlength="'.$size.'"' : '').' value="'.dol_escape_htmltag($value).'"'.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
} elseif (in_array($type, array('mail', 'phone', 'url'))) {
$out = '<input type="text" class="flat '.$morecss.'" name="'.$keyprefix.$key.$keysuffix.'" id="'.$keyprefix.$key.$keysuffix.'" value="'.dol_escape_htmltag($value).'" '.($moreparam ? $moreparam : '').($autofocusoncreate ? ' autofocus' : '').'>';
} elseif (preg_match('/^text/', $type)) {
@ -7492,7 +7492,7 @@ abstract class CommonObject
if ($display_type == 'card') {
$out .= '<tr '.($html_id ? 'id="'.$html_id.'" ' : '').$csstyle.' class="valuefieldcreate '.$class.$this->element.'_extras_'.$key.' trextrafields_collapse'.$extrafields_collapse_num.(!empty($this->id)?'_'.$this->id:'').'" '.$domData.' >';
if ( ! empty($conf->global->MAIN_VIEW_LINE_NUMBER) ) {
if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER) && $action == 'view') {
$out .= '<td></td>';
}
$out .= '<td class="wordbreak';
@ -8532,7 +8532,6 @@ abstract class CommonObject
// Retrieve all extrafield
// fetch optionals attributes and labels
$this->fetch_optionals();
dol_syslog("aaa=".$this->id);
return $this->id;
} else {

View File

@ -272,8 +272,10 @@ class HookManager
$parameters['currentcontext'] = $context;
// Hooks that must return int (hooks with type 'addreplace')
if ($hooktype == 'addreplace') {
$resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example)
if ($resaction < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) {
$resactiontmp = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example)
$resaction += $resactiontmp;
if ($resactiontmp < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) {
$error++;
$this->error = $actionclassinstance->error;
$this->errors = array_merge($this->errors, (array) $actionclassinstance->errors);
@ -281,13 +283,22 @@ class HookManager
}
if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) {
$this->resArray = array_merge($this->resArray, $actionclassinstance->results);
if ($resactiontmp > 0) {
$this->resArray = $actionclassinstance->results;
} else {
$this->resArray = array_merge($this->resArray, $actionclassinstance->results);
}
}
if (!empty($actionclassinstance->resprints)) {
$this->resPrint .= $actionclassinstance->resprints;
if ($resactiontmp > 0) {
$this->resPrint = $actionclassinstance->resprints;
} else {
$this->resPrint .= $actionclassinstance->resprints;
}
}
} else {
// Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...)
// TODO. this test should be done into the method of hook by returning nothing
if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) {
continue;

View File

@ -4454,7 +4454,6 @@ class Form
*/
public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
{
// phpcs:enable
global $langs, $conf;
$langs->load("admin");
@ -6582,6 +6581,213 @@ class Form
return;
}
/**
* Return list of tickets in Ajax if Ajax activated or go to selectTicketsList
*
* @param int $selected Preselected tickets
* @param string $htmlname Name of HTML select field (must be unique in page).
* @param string $filtertype To add a filter
* @param int $limit Limit on number of returned lines
* @param int $status Ticket status
* @param string $selected_input_value Value of preselected input text (for use with ajax)
* @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
* @param array $ajaxoptions Options for ajax_autocompleter
* @param int $socid Thirdparty Id (to get also price dedicated to this customer)
* @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
* @param int $forcecombo Force to use combo box
* @param string $morecss Add more css on select
* @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...])
* @param string $nooutput No print, return the output into a string
* @return void|string
*/
public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
{
global $langs, $conf;
$out = '';
// check parameters
if (is_null($ajaxoptions)) $ajaxoptions = array();
if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
$placeholder = '';
if ($selected && empty($selected_input_value)) {
require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
$tickettmpselect = new Ticket($this->db);
$tickettmpselect->fetch($selected);
$selected_input_value = $tickettmpselect->ref;
unset($tickettmpselect);
}
$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
elseif ($hidelabel > 1) {
$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
if ($hidelabel == 2) {
$out .= img_picto($langs->trans("Search"), 'search');
}
}
$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
if ($hidelabel == 3) {
$out .= img_picto($langs->trans("Search"), 'search');
}
} else {
$out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
}
if (empty($nooutput)) print $out;
else return $out;
}
/**
* Return list of tickets.
* Called by selectTickets.
*
* @param int $selected Preselected ticket
* @param string $htmlname Name of select html
* @param string $filtertype Filter on ticket type
* @param int $limit Limit on number of returned lines
* @param string $filterkey Filter on product
* @param int $status Ticket status
* @param int $outputmode 0=HTML select string, 1=Array
* @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
* @param int $forcecombo Force to use combo box
* @param string $morecss Add more css on select
* @return array Array of keys for json
*/
public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
{
global $langs, $conf, $user, $db;
$out = '';
$outarray = array();
$selectFields = " p.rowid, p.ref, p.message";
$sql = "SELECT ";
$sql .= $selectFields;
$sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
$sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
// Add criteria on ref/label
if ($filterkey != '') {
$sql .= ' AND (';
$prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
// For natural search
$scrit = explode(' ', $filterkey);
$i = 0;
if (count($scrit) > 1) $sql .= "(";
foreach ($scrit as $crit) {
if ($i > 0) $sql .= " AND ";
$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
$sql .= ")";
$i++;
}
if (count($scrit) > 1) $sql .= ")";
$sql .= ')';
}
$sql .= $this->db->plimit($limit, 0);
// Build output string
dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
$result = $this->db->query($sql);
if ($result) {
require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
$num = $this->db->num_rows($result);
$events = null;
if (!$forcecombo) {
include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
$out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
}
$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
$textifempty = '';
// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
else $textifempty .= $langs->trans("All");
} else {
if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
}
if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
$i = 0;
while ($num && $i < $num) {
$opt = '';
$optJson = array();
$objp = $this->db->fetch_object($result);
$this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
// Add new entry
// "key" value of json key array is used by jQuery automatically as selected value
// "label" value of json key array is used by jQuery automatically as text for combo box
$out .= $opt;
array_push($outarray, $optJson);
$i++;
}
$out .= '</select>';
$this->db->free($result);
if (empty($outputmode)) return $out;
return $outarray;
} else {
dol_print_error($db);
}
}
/**
* constructTicketListOption.
* This define value for &$opt and &$optJson.
*
* @param resource $objp Result set of fetch
* @param string $opt Option (var used for returned value in string option format)
* @param string $optJson Option (var used for returned value in json format)
* @param string $selected Preselected value
* @param string $filterkey Filter key to highlight
* @return void
*/
protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
{
global $langs, $conf, $user, $db;
$outkey = '';
$outval = '';
$outref = '';
$outlabel = '';
$outtype = '';
$label = $objp->label;
$outkey = $objp->rowid;
$outref = $objp->ref;
$outlabel = $objp->label;
$outtype = $objp->fk_product_type;
$opt = '<option value="'.$objp->rowid.'"';
$opt .= ($objp->rowid == $selected) ? ' selected' : '';
$opt .= '>';
$opt .= $objp->ref;
$objRef = $objp->ref;
if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
$outval .= $objRef;
$opt .= "</option>\n";
$optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtypem);
}
/**
* Generic method to select a component from a combo list.

View File

@ -272,6 +272,15 @@ class FormTicket
print '</td></tr>';
}
//Categories
if ($conf->categorie->enabled) {
// Categories
print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
$cate_arbo = $form->select_all_categories(Categorie::TYPE_TICKET, '', 'parent', 64, 0, 1);
print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
print "</td></tr>";
}
// Attached files
if (!empty($this->withfile)) {
// Define list of attached files
@ -656,11 +665,11 @@ class FormTicket
print ajax_combobox('select'.$htmlname);
} elseif ($htmlname!='') {
$groupticket=GETPOST($htmlname, 'aZ09');
$groupticketchild=GETPOST($htmlname.'_child', 'aZ09');
$child_id=GETPOST($htmlname.'_child_id', 'aZ09')?GETPOST($htmlname.'_child_id', 'aZ09'):0;
$arraycodenotparent[] = "";
$arrayidused = array();
$stringtoprint = '<span class="supportemailfield bold">'.$langs->trans("GroupOfTicket").'</span> ';
$stringtoprint .= '<select name="'.$htmlname.'" id ="'.$htmlname.'" class="maxwidth500 minwidth400" child_id="0">';
$stringtoprint .= '<select id ="'.$htmlname.'" class="maxwidth500 minwidth400" child_id="0">';
$stringtoprint .= '<option value="">&nbsp;</option>';
$sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ";
@ -697,13 +706,16 @@ class FormTicket
}
if ($num_rows_level0 == 1) {
return '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.dol_escape_htmltag($groupvalue).'">';
} else {
$stringtoprint .= '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'_select" class="maxwidth500 minwidth400">';
$stringtoprint .= '<input type="hidden" name="'.$htmlname.'_child_id" id="'.$htmlname.'_select_child_id" class="maxwidth500 minwidth400">';
}
$stringtoprint .= '</select>&nbsp;';
$levelid = 1;
while ($levelid <= $use_multilevel) {
$tabscript = array();
$stringtoprint .= '<select name="'.$htmlname.'_child_'.$levelid.'" id ="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
$stringtoprint .= '<select id ="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
$stringtoprint .= '<option value="">&nbsp;</option>';
$sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctcjoin.code as codefather, ";
@ -742,7 +754,7 @@ class FormTicket
if ($isparent == 'NOTPARENT') {
$arraycodenotparent[] = $groupvalue;
}
$iselected = $groupticketchild == $obj->code ?'selected':'';
$iselected = $groupticket == $obj->code ?'selected':'';
$stringtoprint .= '<option '.$iselected.' class="'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'" value="'.dol_escape_htmltag($groupvalue).'" data-html="'.dol_escape_htmltag($grouplabel).'">'.dol_escape_htmltag($grouplabel).'</option>';
if (empty($tabscript[$groupcodefather])) {
$tabscript[$groupcodefather] = 'if ($("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid-1:'').'")[0].value == "'.dol_escape_js($groupcodefather).'"){
@ -760,15 +772,43 @@ class FormTicket
dol_print_error($this->db);
}
$stringtoprint .='</select>';
//$stringtoprint .= ajax_combobox($htmlname.'_child_'.$levelid);
$stringtoprint .='<script>';
$stringtoprint .='arraynotparents = '.json_encode($arraycodenotparent).';';
$stringtoprint .='if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid-1:'').'")[0].value)){$("#'.$htmlname.'_child_'.$levelid.'").hide()}
$stringtoprint .='if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid-1:'').'")[0].value)){
console.log("'.$htmlname.'_child_'.$levelid.'")
if($("#'.$htmlname.'_child_'.$levelid.'")[0].value == "" && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")>'.$child_id.')){
$("#'.$htmlname.'_child_'.$levelid.'").hide();
console.log("We hide '.$htmlname.'_child_'.$levelid.' input")
}else if(($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")!=0) && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")<'.$child_id.')){
$("#'.$htmlname.'_child_'.$levelid.'").attr("disabled",true);
console.log("We disable '.$htmlname.'_child_'.$levelid.' input");
}else{
$("#'.$htmlname.'_child_'.$levelid.'").attr("disabled",true);
$("#ticketcategory_select_child_id")[0].value = $("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")
$("#ticketcategory_select")[0].value = $("#'.$htmlname.'_child_'.$levelid.'")[0].value;
console.log("We disable '.$htmlname.'_child_'.$levelid.' input and reload hidden input");
}
if(arraynotparents.includes("'.$groupticket.'") && '.$child_id.' == 0){
$("#ticketcategory_select_child_id")[0].value = $("#'.$htmlname.'").attr("child_id")
$("#ticketcategory_select")[0].value = $("#'.$htmlname.'")[0].value;
console.log("We choose '.$htmlname.' input and reload hidden input");
}
}
$("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid-1:'').'").change(function() {
child_id = $("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid-1:'').'").attr("child_id");
console.log("We select a new value into combo child_id="+child_id);
child_id = $("#'.$htmlname.($levelid > 1 ?'_child_'.$levelid:'').'").attr("child_id");
/* Change of value to select this value*/
if (arraynotparents.includes(this.value) || $(this).attr("child_id") == '.$use_multilevel.') {
$("#ticketcategory_select")[0].value = this.value;
$("#ticketcategory_select_child_id")[0].value = $(this).attr("child_id");
console.log("We choose to select "+ $("#ticketcategory_select")[0].value );
}else{
$("#ticketcategory_select")[0].value = "";
$("#ticketcategory_select_child_id")[0].value = "";
}
console.log("We select a new value into combo child_id="+child_id);
/* Hide all selected box that are child of the one modified */
$(".groupticketchild").each(function(){
@ -794,7 +834,13 @@ class FormTicket
$stringtoprint .='})';
$stringtoprint .='</script>';
}
$stringtoprint .='<script>';
$stringtoprint .='$("#'.$htmlname.'_child_'.$use_multilevel.'").change(function() {
$("#ticketcategory_select")[0].value = this.value;
$("#ticketcategory_select_child_id")[0].value = $(this).attr("child_id");
console.log($("#ticketcategory_select")[0].value);
})';
$stringtoprint .='</script>';
$stringtoprint .= ajax_combobox($htmlname);
return $stringtoprint;

View File

@ -263,6 +263,8 @@ print '$( document ).ready(function() {
var confirmContent = $(this).attr(\'data-confirm-content\');
var confirmActionBtnLabel = $(this).attr(\'data-confirm-action-btn-label\');
var confirmCancelBtnLabel = $(this).attr(\'data-confirm-cancel-btn-label\');
var confirmModal = $(this).attr(\'data-confirm-modal\');
if(confirmModal == undefined){ confirmModal = false; }
var confirmId = \'confirm-dialog-box\';
if($(this).attr(\'id\') != undefined){ var confirmId = confirmId + "-" + $(this).attr(\'id\'); }
@ -277,8 +279,9 @@ print '$( document ).ready(function() {
$confirmBox.dialog({
autoOpen: true,
modal: false,
modal: confirmModal,
//width: Math.min($( window ).width() - 50, 1700),
width: \'auto\',
dialogClass: \'confirm-dialog-box\',
buttons: [
{
@ -297,11 +300,11 @@ print '$( document ).ready(function() {
}
],
close: function( event, ui ) {
$(\'#\'+confirmBox).remove();
},
$(\'#\'+confirmBox).remove();
},
open: function( event, ui ) {
$confirmBox.html(confirmContent);
}
$confirmBox.html(confirmContent);
}
});
});
});

View File

@ -1899,7 +1899,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin
}
// Status
$out .= '<td class="nowrap center">'.$actionstatic->LibStatut($histo[$key]['percent'], 3, 0, $histo[$key]['datestart']).'</td>';
$out .= '<td class="nowrap center">'.$actionstatic->LibStatut($histo[$key]['percent'], 2, 0, $histo[$key]['datestart']).'</td>';
// Actions
$out .= '<td></td>';

View File

@ -6828,6 +6828,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
$substitutionarray = array_merge($substitutionarray, array(
'__MYCOMPANY_NAME__' => $mysoc->name,
'__MYCOMPANY_EMAIL__' => $mysoc->email,
'__MYCOMPANY_PHONE__' => $mysoc->phone,
'__MYCOMPANY_FAX__' => $mysoc->fax,
'__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
'__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
'__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
@ -8487,8 +8489,10 @@ function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type,
if (!empty($hookmanager)) {
$parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head);
$reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
if ($reshook > 0) {
if ($reshook > 0) { // Hook ask to replace completely the array
$head = $hookmanager->resArray;
} else { // Hook
$head = array_merge($head, $hookmanager->resArray);
}
$h = count($head);
}
@ -9768,7 +9772,23 @@ function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $st
* @param string $url the url for link
* @param string $id attribute id of button
* @param int $userRight user action right
* @param array $params various params for future : recommended rather than adding more function arguments
* // phpcs:disable
* @param array $params = [ // Various params for future : recommended rather than adding more function arguments
* 'attr' => [ // to add or override button attributes
* 'xxxxx' => '', // your xxxxx attribute you want
* 'class' => '', // to add more css class to the button class attribute
* 'classOverride' => '' // to replace class attribute of the button
* ],
* 'confirm' => [
* 'url' => 'http://', // Overide Url to go when user click on action btn, if empty default url is $url.?confirm=yes, for no js compatibility use $url for fallback confirm.
* 'title' => '', // Overide title of modal, if empty default title use "ConfirmBtnCommonTitle" lang key
* 'action-btn-label' => '', // Overide label of action button, if empty default label use "Confirm" lang key
* 'cancel-btn-label' => '', // Overide label of cancel button, if empty default label use "CloseDialog" lang key
* 'content' => '', // Overide text of content, if empty default content use "ConfirmBtnCommonContent" lang key
* 'modal' => true, // true|false to display dialog as a modal (with dark background)
* ],
* ]
* // phpcs:enable
* @return string html button
*/
function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
@ -9816,7 +9836,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url =
}
// Js Confirm button
if (!empty($params['confirm'])) {
if ($userRight && !empty($params['confirm'])) {
if (!is_array($params['confirm'])) {
$params['confirm'] = array(
'url' => $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes'
@ -9827,8 +9847,11 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url =
$attr['data-confirm-url'] = $params['confirm']['url'];
$attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
$attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
$attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
$attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
$attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
$attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
$attr['class'].= ' butActionConfirm';
}

View File

@ -93,6 +93,7 @@ class modBarcode extends DolibarrModules
// Main menu entries
$r = 0;
$this->menu[$r] = array(
'fk_menu'=>'fk_mainmenu=tools', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
'mainmenu'=>'tools',
@ -106,7 +107,7 @@ class modBarcode extends DolibarrModules
'enabled'=>'$conf->barcode->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
'perms'=>'($conf->global->MAIN_USE_ADVANCED_PERMS && $user->rights->barcode->lire_advance) || (! $conf->global->MAIN_USE_ADVANCED_PERMS)', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
'target'=>'',
'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
'user'=>0, // 0=Menu for internal users, 1=external users, 2=both
);
$r++;

View File

@ -135,6 +135,28 @@ class modHoliday extends DolibarrModules
//$r++;
// Cronjobs
$arraydate = dol_getdate(dol_now());
$datestart = dol_mktime(4, 0, 0, $arraydate['mon'], $arraydate['mday'], $arraydate['year']);
$this->cronjobs = array(
0 => array(
'label' => 'HolidayBalanceMonthlyUpdate',
'jobtype' => 'method',
'class' => 'holiday/class/holiday.class.php',
'objectname' => 'Holiday',
'method' => 'updateBalance',
'parameters' => '',
'comment' => 'Update holiday balance every month',
'frequency' => 1,
'unitfrequency' => 3600 * 24,
'priority' => 50,
'status' => 1,
'test' => '$conf->holiday->enabled',
'datestart' => $datestart
)
);
// Permissions
$this->rights = array(); // Permission array used by this module
$r = 0;

View File

@ -283,6 +283,19 @@ class modTicket extends DolibarrModules
'target' => '',
'user' => 0);
$r++;
$this->menu[$r] = array('fk_menu' => 'fk_mainmenu=ticket,fk_leftmenu=ticket',
'type' => 'left',
'titre' => 'Categories',
'mainmenu' => 'ticket',
'url' => '/categories/index.php?type=12',
'langs' => 'ticket',
'position' => 107,
'enabled' => '$conf->categorie->enabled',
'perms' => '$user->rights->ticket->read',
'target' => '',
'user' => 0);
$r++;
}
/**

View File

@ -194,6 +194,14 @@ if ($massaction == 'presend') {
print dol_get_fiche_end();
}
if ($massaction == 'preenable') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassEnabling"), $langs->trans("ConfirmMassEnablingQuestion", count($toselect)), "enable", null, '', 0, 200, 500, 1);
}
if ($massaction == 'predisable') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDisabling"), $langs->trans("ConfirmMassDisablingQuestion", count($toselect)), "disable", null, '', 0, 200, 500, 1);
}
// Allow Pre-Mass-Action hook (eg for confirmation dialog)
$parameters = array(
'toselect' => $toselect,

View File

@ -118,6 +118,8 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
foreach ($object->amounts as $amount) {
$amounts += price2num($amount);
}
} elseif (!empty($object->amount)) {
$amounts = $object->amount;
}
} elseif (strpos($action, 'PAYMENT') !== false && !in_array($action, array('PAYMENT_ADD_TO_BANK'))) {
$qualified++;

View File

@ -324,6 +324,9 @@ class EmailCollector extends CommonObject
// Clear fields
$object->ref = "copy_of_".$object->ref;
$object->title = $langs->trans("CopyOf")." ".$object->title;
if (empty($object->host)) {
$object->host = 'imap.example.com';
}
// ...
// Clear extrafields that are unique
if (is_array($object->array_options) && count($object->array_options) > 0) {
@ -849,11 +852,11 @@ class EmailCollector extends CommonObject
$regexstring = '';
//$transformationstring='';
$regforregex = array();
if (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*):([^:])$/', $valueforproperty, $regforregex)) {
if (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*):([^:])$/', $valueforproperty, $regforregex)) {
$sourcefield = $regforregex[1];
$regexstring = $regforregex[2];
//$transofrmationstring=$regforregex[3];
} elseif (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*)$/', $valueforproperty, $regforregex)) {
} elseif (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*)$/', $valueforproperty, $regforregex)) {
$sourcefield = $regforregex[1];
$regexstring = $regforregex[2];
}
@ -1199,15 +1202,20 @@ class EmailCollector extends CommonObject
$iforemailloop = 0;
foreach ($arrayofemail as $imapemail) {
if ($nbemailprocessed > 1000) {
break; // Do not process more than 1000 email per launch (this is a different protection than maxnbcollectedpercollect
break; // Do not process more than 1000 email per launch (this is a different protection than maxnbcollectedpercollect)
}
$iforemailloop++;
// GET header and overview datas
$header = imap_fetchheader($connection, $imapemail, 0);
$overview = imap_fetch_overview($connection, $imapemail, 0);
/* print $header; var_dump($overview); */
// Process $header of email
$header = preg_replace('/\r\n\s+/m', ' ', $header); // When a header line is on several lines, merge lines
/*print $header;
print $header;*/
$matches = array();
preg_match_all('/([^: ]+): (.+?(?:\r\n\s(?:.+?))*)\r\n/m', $header, $matches);
@ -1297,9 +1305,6 @@ class EmailCollector extends CommonObject
$this->db->begin();
// GET Email meta datas
$overview = imap_fetch_overview($connection, $imapemail, 0);
dol_syslog("msgid=".$overview[0]->message_id." date=".dol_print_date($overview[0]->udate, 'dayrfc', 'gmt')." from=".$overview[0]->from." to=".$overview[0]->to." subject=".$overview[0]->subject);
$overview[0]->subject = $this->decodeSMTPSubject($overview[0]->subject);
@ -1309,10 +1314,14 @@ class EmailCollector extends CommonObject
// Removed emojis
$overview[0]->subject = preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $overview[0]->subject);
// Parse IMAP email structure
// GET IMAP email structure/content
global $htmlmsg, $plainmsg, $charset, $attachments;
$this->getmsg($connection, $imapemail);
//print $plainmsg; var_dump($plainmsg); exit;
//$htmlmsg,$plainmsg,$charset,$attachments
$messagetext = $plainmsg ? $plainmsg : dol_string_nohtmltag($htmlmsg, 0);
// Removed emojis
@ -1640,13 +1649,15 @@ class EmailCollector extends CommonObject
if ($operation['type'] == 'loadthirdparty' || $operation['type'] == 'loadandcreatethirdparty') {
if (empty($operation['actionparam'])) {
$errorforactions++;
$this->error = "Action loadthirdparty or loadandcreatethirdparty has empty parameter. Must be a rule like 'SET:xxx' or 'EXTRACT:(body|subject):regex' to define how to set or extract data";
$this->error = "Action loadthirdparty or loadandcreatethirdparty has empty parameter. Must be a rule like 'name=HEADER:^From:(.*);' or 'name=SET:xxx' or 'name=EXTRACT:(body|subject):regex where 'name' can be replaced with 'id' or 'email' to define how to set or extract data. More properties can also be set, for example client=SET:2;";
$this->errors[] = $this->error;
} else {
$actionparam = $operation['actionparam'];
$idtouseforthirdparty = '';
$nametouseforthirdparty = '';
$emailtouseforthirdparty = '';
// $this->actionparam = 'SET:aaa' or 'EXTRACT:BODY:....'
// $actionparam = 'param=SET:aaa' or 'param=EXTRACT:BODY:....'
$arrayvaluetouse = dolExplodeIntoArray($actionparam, ';', '=');
foreach ($arrayvaluetouse as $propertytooverwrite => $valueforproperty) {
$sourcestring = '';
@ -1654,7 +1665,7 @@ class EmailCollector extends CommonObject
$regexstring = '';
$regforregex = array();
if (preg_match('/^EXTRACT:([a-zA-Z0-9]+):(.*)$/', $valueforproperty, $regforregex)) {
if (preg_match('/^EXTRACT:([a-zA-Z0-9_]+):(.*)$/', $valueforproperty, $regforregex)) {
$sourcefield = $regforregex[1];
$regexstring = $regforregex[2];
}
@ -1674,10 +1685,18 @@ class EmailCollector extends CommonObject
if (preg_match('/'.$regexstring.'/ms', $sourcestring, $regforval)) {
//var_dump($regforval[count($regforval)-1]);exit;
// Overwrite param $tmpproperty
$nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
if ($propertytooverwrite == 'id') {
$idtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
} elseif ($propertytooverwrite == 'email') {
$emailtouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
} else {
$nametouseforthirdparty = isset($regforval[count($regforval) - 1]) ? trim($regforval[count($regforval) - 1]) : null;
}
} else {
// Regex not found
$idtouseforthirdparty = null;
$nametouseforthirdparty = null;
$emailtouseforthirdparty = null;
}
//var_dump($object->$tmpproperty);exit;
} else {
@ -1689,7 +1708,13 @@ class EmailCollector extends CommonObject
} elseif (preg_match('/^(SET|SETIFEMPTY):(.*)$/', $valueforproperty, $reg)) {
//if (preg_match('/^options_/', $tmpproperty)) $object->array_options[preg_replace('/^options_/', '', $tmpproperty)] = $reg[1];
//else $object->$tmpproperty = $reg[1];
$nametouseforthirdparty = $reg[2];
if ($propertytooverwrite == 'id') {
$idtouseforthirdparty = $reg[2];
} elseif ($propertytooverwrite == 'email') {
$emailtouseforthirdparty = $reg[2];
} else {
$nametouseforthirdparty = $reg[2];
}
} else {
$errorforactions++;
$this->error = 'Bad syntax for description of action parameters: '.$actionparam;
@ -1698,8 +1723,8 @@ class EmailCollector extends CommonObject
}
}
if (!$errorforactions && $nametouseforthirdparty) {
$result = $thirdpartystatic->fetch(0, $nametouseforthirdparty);
if (!$errorforactions && ($idtouseforthirdparty || $emailtouseforthirdparty || $nametouseforthirdparty)) {
$result = $thirdpartystatic->fetch($idtouseforthirdparty, $nametouseforthirdparty, '', '', '', '', '', '', '', '', $emailtouseforthirdparty);
if ($result < 0) {
$errorforactions++;
$this->error = 'Error when getting thirdparty with name '.$nametouseforthirdparty.' (may be 2 record exists with same name ?)';
@ -1707,20 +1732,20 @@ class EmailCollector extends CommonObject
break;
} elseif ($result == 0) {
if ($operation['type'] == 'loadthirdparty') {
dol_syslog("Third party with name ".$nametouseforthirdparty." was not found");
dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." was not found");
$errorforactions++;
$this->error = 'ErrorFailedToLoadThirdParty';
$this->errors[] = 'ErrorFailedToLoadThirdParty';
} elseif ($operation['type'] == 'loadandcreatethirdparty') {
dol_syslog("Third party with name ".$nametouseforthirdparty." was not found. We try to create it.");
dol_syslog("Third party with id=".$idtouseforthirdparty." email=".$emailtouseforthirdparty." name=".$nametouseforthirdparty." was not found. We try to create it.");
// Create thirdparty
$thirdpartystatic->name = $nametouseforthirdparty;
if ($fromtext != $nametouseforthirdparty) {
$thirdpartystatic->name_alias = $fromtext;
}
$thirdpartystatic->email = $from;
$thirdpartystatic->email = ($emailtouseforthirdparty ? $emailtouseforthirdparty : $from);
// Overwrite values with values extracted from source email
$errorforthisaction = $this->overwritePropertiesOfObject($thirdpartystatic, $operation['actionparam'], $messagetext, $subject, $header);

View File

@ -220,13 +220,12 @@ class CommandeFournisseurDispatch extends CommonObject
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.$this->table_element);
if (!$notrigger) {
// Uncomment this and change MYOBJECT to your own tag if you
// want this action calls a trigger.
//// Call triggers
//$result=$this->call_trigger('MYOBJECT_CREATE',$user);
//if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
//// End call triggers
// Call triggers
$result=$this->call_trigger('LINERECEPTION_CREATE', $user);
if ($result < 0) {
$error++;
}
// End call triggers
}
}

View File

@ -227,7 +227,7 @@ class Holiday extends CommonObject
if ($result >= 0) {
$this->db->commit();
return 1;
return 0; // for cronjob use (0 is OK, any other value is an error code)
} else {
$this->db->rollback();
return -1;
@ -1251,6 +1251,8 @@ class Holiday extends CommonObject
public function LibStatut($status, $mode = 0, $startdate = '')
{
// phpcs:enable
global $langs;
if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
global $langs;
//$langs->load("mymodule");
@ -1266,9 +1268,11 @@ class Holiday extends CommonObject
$this->labelStatusShort[self::STATUS_REFUSED] = $langs->trans('RefuseCP');
}
$params = array();
$statusType = 'status6';
if (!empty($startdate) && $startdate > dol_now()) {
if (!empty($startdate) && $startdate >= dol_now()) { // If not yet passed, we use a green "in live" color
$statusType = 'status4';
$params = array('tooltip'=>$this->labelStatus[$status].' - '.$langs->trans("Forthcoming"));
}
if ($status == self::STATUS_DRAFT) {
$statusType = 'status0';
@ -1283,7 +1287,7 @@ class Holiday extends CommonObject
$statusType = 'status5';
}
return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode, '', $params);
}

View File

@ -730,6 +730,7 @@ if ($resql) {
$holidaystatic->id = $obj->rowid;
$holidaystatic->ref = ($obj->ref ? $obj->ref : $obj->rowid);
$holidaystatic->statut = $obj->status;
$holidaystatic->date_debut = $db->jdate($obj->date_debut);
// User
$userstatic->id = $obj->fk_user;
@ -790,7 +791,7 @@ if ($resql) {
}
if (!empty($arrayfields['duration']['checked'])) {
print '<td class="right">';
$nbopenedday = num_open_day($db->jdate($obj->date_debut, 1), $db->jdate($obj->date_fin, 1), 0, 1, $obj->halfday);
$nbopenedday = num_open_day($db->jdate($obj->date_debut, 1), $db->jdate($obj->date_fin, 1), 0, 1, $obj->halfday); // user jdate(..., 1) because num_open_day need UTC dates
print $nbopenedday.' '.$langs->trans('DurationDays');
print '</td>';
if (!$i) {

View File

@ -367,7 +367,7 @@ ALTER TABLE llx_actioncomm_reminder ADD UNIQUE uk_actioncomm_reminder_unique (fk
ALTER TABLE llx_actioncomm_reminder ADD INDEX idx_actioncomm_reminder_status (status);
ALTER TABLE llx_inventorydet ADD COLUMN fk_warehouse integer DEFAULT 0;
ALTER TABLE llx_inventorydet ADD UNIQUE uk_inventorydet(fk_inventory, fk_warehouse, fk_product, batch);
ALTER TABLE llx_commandedet ADD COLUMN ref_ext varchar(255) AFTER label;

View File

@ -86,7 +86,7 @@ create table llx_facture
fk_incoterms integer, -- for incoterms
location_incoterms varchar(255), -- for incoterms
fk_mode_transport integer, -- for intracomm report
fk_transport_mode integer, -- for intracomm report
situation_cycle_ref smallint, -- situation cycle reference
situation_counter smallint, -- situation counter

View File

@ -74,7 +74,7 @@ create table llx_facture_fourn
fk_incoterms integer, -- for incoterms
location_incoterms varchar(255), -- for incoterms
fk_mode_transport integer, -- for intracomm report
fk_transport_mode integer, -- for intracomm report
model_pdf varchar(255),
last_main_doc varchar(255), -- relative filepath+filename of last main generated document

View File

@ -25,7 +25,7 @@ create table llx_object_lang
fk_object integer DEFAULT 0 NOT NULL,
type_object varchar(32) NOT NULL, -- value found into $object->element: 'thirdparty', 'contact', '...'
property varchar(32) NOT NULL, -- name of property
lang varchar(5) DEFAULT 0 NOT NULL,
lang varchar(5) DEFAULT '' NOT NULL,
value text,
import_key varchar(14) DEFAULT NULL
)ENGINE=innodb;

View File

@ -2092,7 +2092,7 @@ LargerThan=Larger than
IfTrackingIDFoundEventWillBeLinked=Note that If a tracking ID of an object is found into email, or if the email is an answer of an email aready collected and linked to an object, the created event will be automatically linked to the known related object.
WithGMailYouCanCreateADedicatedPassword=With a GMail account, if you enabled the 2 steps validation, it is recommanded to create a dedicated second password for the application instead of using your own account passsword from https://myaccount.google.com/.
EmailCollectorTargetDir=It may be a desired behaviour to move the email into another tag/directory when it was processed successfully. Just set name of directory here to use this feature (Do NOT use special characters in name). Note that you must also use a read/write login account.
EmailCollectorLoadThirdPartyHelp=You can use this action to use the email content to find and load an existing thirdparty in your database. The found (or created) thirdparty will be used for following actions that need it. In the parameter field you can use for example 'EXTRACT:BODY:Name:\s([^\s]*)' if you want to extract the name of the thirdparty from a string 'Name: name to find' found into the body.
EmailCollectorLoadThirdPartyHelp=You can use this action to use the email content to find and load an existing thirdparty in your database. The found (or created) thirdparty will be used for following actions that need it.<br>For example, if you want to create a thirdparty with a name extracted a string 'Name: name to find' found into the body, use sender email as email, you can set the parameter field like this:<br>'email=HEADER:^From:(.*);name=EXTRACT:BODY:Name:\s([^\s]*);client=SET:2;'<br>
EndPointFor=End point for %s : %s
DeleteEmailCollector=Delete email collector
ConfirmDeleteEmailCollector=Are you sure you want to delete this email collector?

View File

@ -264,6 +264,7 @@ ErrorAnAmountWithoutTaxIsRequired=Error, amount is mandatory
ErrorAPercentIsRequired=Error, please fill in the percentage correctly
ErrorYouMustFirstSetupYourChartOfAccount=You must first setup your chart of account
ErrorFailedToFindEmailTemplate=Failed to find template with code name %s
ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice=Duration not defined on service. No way to calculate the hourly price.
# Warnings
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.

View File

@ -132,3 +132,4 @@ FreeLegalTextOnHolidays=Free text on PDF
WatermarkOnDraftHolidayCards=Watermarks on draft leave requests
HolidaysToApprove=Holidays to approve
NobodyHasPermissionToValidateHolidays=Nobody has permission to validate holidays
HolidayBalanceMonthlyUpdate=Monthly update of holiday balance

View File

@ -1137,3 +1137,14 @@ CopiedToClipboard=Copied to clipboard
InformationOnLinkToContract=This amount is only the total of all the lines of the contract. No notion of time is taken into consideration.
ConfirmCancel=Are you sure you want to cancel
EmailMsgID=Email MsgID
SetToEnabled=Set to enabled
SetToDisabled=Set to disabled
ConfirmMassEnabling=mass enabling confirmation
ConfirmMassEnablingQuestion=Are you sure you want to enable the %s selected record(s)?
ConfirmMassDisabling=mass disabling confirmation
ConfirmMassDisablingQuestion=Are you sure you want to disable the %s selected record(s)?
RecordsEnabled=%s record(s) enabled
RecordsDisabled=%s record(s) disabled
RecordEnabled=Record enabled
RecordDisabled=Record disabled
Forthcoming=Forthcoming

View File

@ -17,6 +17,7 @@ ContactsCategoriesArea=Espace tags/catégories de contacts
AccountsCategoriesArea=Espace des tags/categories de comptes bancaires
ProjectsCategoriesArea=Espace des tags/catégories des projets
UsersCategoriesArea=Espace des tags/catégories des utilisateurs
TicketsCategoriesArea=Espace tags/catégories des tickets
SubCats=Sous-catégories
CatList=Liste des tags/catégories
CatListAll=Liste de toutes les catégories (de tous types)
@ -90,6 +91,7 @@ CategorieRecursivHelp=Si l'option est activé, quand un produit est ajouté dans
AddProductServiceIntoCategory=Ajouter le produit/service suivant
AddCustomerIntoCategory=Assigner cette catégorie au client
AddSupplierIntoCategory=Assigner cette catégorie au fournisseur
AddTicketIntoCategory=Assigner cette catégorie au ticket
ShowCategory=Afficher tag/catégorie
ByDefaultInList=Par défaut dans la liste
ChooseCategory=Choisissez une catégorie

View File

@ -1137,3 +1137,13 @@ CopiedToClipboard=Copié dans le presse-papier
InformationOnLinkToContract=Ce montant nest que le total de toutes les lignes du contrat. Aucune notion de temps nest prise en considération.
ConfirmCancel=Êtes-vous sûr de vous annuler
EmailMsgID=E-mail MsgID
SetToEnabled=Activer
SetToDisabled=Désactiver
ConfirmMassEnabling=Confirmation d'activation en masse
ConfirmMassEnablingQuestion=Êtes-vous sur de vouloir activer les %s enregistrement(s) sélectionné(s) ?
ConfirmMassDisabling=Confirmation de desactivation en masse
ConfirmMassDisablingQuestion=Êtes-vous sur de vouloir desactiver les %s enregistrement(s) sélectionné(s) ?
RecordsEnabled=%s enregistrement(s) activé(s)
RecordsDisabled=%s enregistrement(s) désactivé(s)
RecordEnabled=Enregistrement activé
RecordDisabled=Enregistrement désactivé

View File

@ -1234,7 +1234,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
if ($type == 1) {
print '<tr><td>'.$langs->trans("Duration").'</td><td>';
print '<input name="duration_value" size="4" value="'.GETPOST('duration_value', 'int').'">';
print $formproduct->selectMeasuringUnits("duration_unit", "time", GETPOST('duration_value', 'alpha'), 0, 1);
print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_value') ? GETPOSTISSET('duration_value', 'alpha') : 'h'), 0, 1);
print '</td></tr>';
}

View File

@ -414,7 +414,7 @@ class FormProduct
dol_print_error($db);
return -1;
} else {
$return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'">';
$return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'" id="'.$name.'">';
if ($adddefault || $adddefault === '') {
$return .= '<option value="0">'.($adddefault ? $langs->trans("Default") : '').'</option>';
}
@ -447,6 +447,8 @@ class FormProduct
$return .= '</select>';
}
$return .= ajax_combobox($name);
return $return;
}

View File

@ -116,6 +116,7 @@ class Task extends CommonObject
public $timespent_datehour; // More accurate start date (same than timespent_date but includes hours, minutes and seconds)
public $timespent_withhour; // 1 = we entered also start hours for timesheet line
public $timespent_fk_user;
public $timespent_thm;
public $timespent_note;
public $comments = array();
@ -1224,6 +1225,7 @@ class Task extends CommonObject
$ret = -2;
}
// Update hourly rate of this time spent entry
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time";
$sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user
$sql .= " WHERE rowid = ".((int) $tasktime_id);
@ -1437,6 +1439,7 @@ class Task extends CommonObject
$sql .= " ptt.task_duration,";
$sql .= " ptt.fk_user,";
$sql .= " ptt.note,";
$sql .= " ptt.thm,";
$sql .= " pt.rowid as task_id,";
$sql .= " pt.ref as task_ref,";
$sql .= " pt.label as task_label,";
@ -1447,7 +1450,7 @@ class Task extends CommonObject
$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
$sql .= " WHERE ptt.fk_task = pt.rowid AND pt.fk_projet = p.rowid";
$sql .= " AND ptt.fk_user = ".$userobj->id;
$sql .= " AND ptt.fk_user = ".((int) $userobj->id);
$sql .= " AND pt.entity IN (".getEntity('project').")";
if ($morewherefilter) {
$sql .= $morewherefilter;
@ -1483,6 +1486,7 @@ class Task extends CommonObject
$newobj->timespent_withhour = $obj->task_date_withhour;
$newobj->timespent_duration = $obj->task_duration;
$newobj->timespent_fk_user = $obj->fk_user;
$newobj->timespent_thm = $obj->thm; // hourly rate
$newobj->timespent_note = $obj->note;
$arrayres[] = $newobj;
@ -1575,10 +1579,12 @@ class Task extends CommonObject
}
if ($ret == 1 && ($this->timespent_old_duration != $this->timespent_duration)) {
$newDuration = $this->timespent_duration - $this->timespent_old_duration;
// Recalculate amount of time spent for task and update denormalized field
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
$sql .= " SET duration_effective = (SELECT SUM(task_duration) FROM ".MAIN_DB_PREFIX."projet_task_time as ptt where ptt.fk_task = ".((int) $this->id).")";
if (isset($this->progress)) {
$sql .= ", progress = ".((float) $this->progress); // Do not overwrite value if not provided
}
$sql .= " WHERE rowid = ".((int) $this->id);
dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
@ -1587,6 +1593,17 @@ class Task extends CommonObject
$this->db->rollback();
$ret = -2;
}
// Update hourly rate of this time spent entry, but only if it was not set initialy
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time";
$sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user
$sql .= " WHERE (thm IS NULL OR thm = 0) AND rowid = ".((int) $this->timespent_id);
dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
if (!$this->db->query($sql)) {
$this->error = $this->db->lasterror();
$ret = -2;
}
}
if ($ret >= 0) {

View File

@ -262,10 +262,10 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us
$object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
$object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered
$object->timespent_date = dol_mktime(GETPOST("timelinehour"), GETPOST("timelinemin"), 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
$object->timespent_date = dol_mktime(GETPOST("timelinehour", 'int'), GETPOST("timelinemin", 'int'), 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
$object->timespent_withhour = 1;
} else {
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
}
$object->timespent_fk_user = GETPOST("userid_line", 'int');
@ -354,6 +354,13 @@ if ($action == 'confirm_generateinvoice') {
$prodDurationHours = 1.0;
if ($idprod > 0) {
$tmpproduct->fetch($idprod);
if (empty($tmpproduct->duration_value)) {
$error++;
$langs->load("errors");
setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors');
}
if ($tmpproduct->duration_unit == 'i') {
$prodDurationHours = 1. / 60;
}
@ -381,6 +388,8 @@ if ($action == 'confirm_generateinvoice') {
$localtax1 = $dataforprice['localtax1'];
$localtax2 = $dataforprice['localtax2'];
} else {
$prodDurationHours = 1;
$pu_ht = 0;
$txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
$localtax1 = get_default_localtax($mysoc, $projectstatic->thirdparty, 1);
@ -483,14 +492,14 @@ if ($action == 'confirm_generateinvoice') {
break;
}
}
} elseif ($generateinvoicemode == 'onelinepertask') {
} elseif ($generateinvoicemode == 'onelinepertask') { // One line for each different task
$arrayoftasks = array();
foreach ($toselect as $key => $value) {
// Get userid, timepent
$object->fetchTimeSpent($value);
// $object->id is the task id
$object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object)
// $object->id is now the task id
$arrayoftasks[$object->id]['timespent'] += $object->timespent_duration;
$arrayoftasks[$object->id]['totalvaluetodivideby3600'] += $object->timespent_duration * $object->timespent_thm;
$arrayoftasks[$object->id]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
}
foreach ($arrayoftasks as $task_id => $value) {
@ -500,24 +509,46 @@ if ($action == 'confirm_generateinvoice') {
$qtyhour = $value['timespent'] / 3600;
$qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
// If no unit price known
if (empty($pu_ht)) {
$pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU');
if ($idprod > 0) {
// If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously).
$pu_ht_for_task = $pu_ht;
// If we want to reuse the value of timespent (so use same price than cost price)
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
}
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
} else {
// If not product used, we use the hour unit for duration and unit price.
$pu_ht_for_task = 0;
// If we want to reuse the value of timespent (so use same price than cost price)
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
}
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
}
// Add lines
$date_start = '';
$date_end = '';
$lineName = $ftask->ref.' - '.$ftask->label;
$lineid = $tmpinvoice->addline($lineName, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0));
// Update lineid into line of timespent
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
$result = $db->query($sql);
if (!$result) {
$lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht);
if ($lineid < 0) {
$error++;
setEventMessages($db->lasterror(), null, 'errors');
setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
break;
}
if (!$error) {
// Update lineid into line of timespent
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
$result = $db->query($sql);
if (!$result) {
$error++;
setEventMessages($db->lasterror(), null, 'errors');
break;
}
}
}
}
}
@ -1042,7 +1073,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
print '<input type="hidden" name="massaction" value="confirm_createbills">';
if ($projectstatic->thirdparty->id > 0) {
print '<table class="noborder" width="100%" >';
print '<table class="noborder centerpercent">';
print '<tr>';
print '<td class="titlefield">';
print $langs->trans('DateInvoice');
@ -1464,11 +1495,11 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
break;
}
print '<tr class="oddeven">';
$date1 = $db->jdate($task_time->task_date);
$date2 = $db->jdate($task_time->task_datehour);
print '<tr class="oddeven">';
// Date
if (!empty($arrayfields['t.task_date']['checked'])) {
print '<td class="nowrap">';
@ -1592,9 +1623,13 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
// Value spent
if (!empty($arrayfields['value']['checked'])) {
$langs->load("salaries");
print '<td class="nowraponall right">';
$value = price2num($task_time->thm * $task_time->task_duration / 3600, 'MT', 1);
print '<span class="amount" title="'.$langs->trans("THM").': '.price($task_time->thm).'">';
print price($value, 1, $langs, 1, -1, -1, $conf->currency);
print '</span>';
print '</td>';
if (!$i) {
$totalarray['nbfield']++;

View File

@ -813,6 +813,111 @@ if ($ispaymentok) {
$postactionmessages[] = 'Invoice paid '.$tmptag['INV'].' was not found';
$ispostactionok = -1;
}
} elseif (array_key_exists('ORD', $tmptag) && $tmptag['ORD'] > 0) {
include_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
$object = new Commande($db);
$result = $object->fetch($tmptag['ORD']);
if ($result) {
$FinalPaymentAmt = $_SESSION["FinalPaymentAmt"];
$paymentTypeId = 0;
if ($paymentmethod == 'paybox') $paymentTypeId = $conf->global->PAYBOX_PAYMENT_MODE_FOR_PAYMENTS;
if ($paymentmethod == 'paypal') $paymentTypeId = $conf->global->PAYPAL_PAYMENT_MODE_FOR_PAYMENTS;
if ($paymentmethod == 'stripe') $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS;
if (empty($paymentTypeId)) {
$paymentType = $_SESSION["paymentType"];
if (empty($paymentType)) $paymentType = 'CB';
$paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1);
}
$currencyCodeType = $_SESSION['currencyCodeType'];
// Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time)
if (!empty($conf->facture->enabled)) {
if (!empty($FinalPaymentAmt) && $paymentTypeId > 0 ) {
include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
$invoice = new Facture($db);
$result = $invoice->createFromOrder($object, $user);
if ($result > 0) {
$object->classifyBilled($user);
$invoice->validate($user);
// Creation of payment line
include_once DOL_DOCUMENT_ROOT . '/compta/paiement/class/paiement.class.php';
$paiement = new Paiement($db);
$paiement->datepaye = $now;
if ($currencyCodeType == $conf->currency) {
$paiement->amounts = array($invoice->id => $FinalPaymentAmt); // Array with all payments dispatching with invoice id
} else {
$paiement->multicurrency_amounts = array($invoice->id => $FinalPaymentAmt); // Array with all payments dispatching
$postactionmessages[] = 'Payment was done in a different currency that currency expected of company';
$ispostactionok = -1;
$error++;
}
$paiement->paiementid = $paymentTypeId;
$paiement->num_payment = '';
$paiement->note_public = 'Online payment ' . dol_print_date($now, 'standard') . ' from ' . $ipaddress;
$paiement->ext_payment_id = $TRANSACTIONID;
$paiement->ext_payment_site = '';
if (!$error) {
$paiement_id = $paiement->create($user, 1); // This include closing invoices and regenerating documents
if ($paiement_id < 0) {
$postactionmessages[] = $paiement->error . ' ' . join("<br>\n", $paiement->errors);
$ispostactionok = -1;
$error++;
} else {
$postactionmessages[] = 'Payment created';
$ispostactionok = 1;
}
}
if (!$error && !empty($conf->banque->enabled)) {
$bankaccountid = 0;
if ($paymentmethod == 'paybox') $bankaccountid = $conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS;
elseif ($paymentmethod == 'paypal') $bankaccountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS;
elseif ($paymentmethod == 'stripe') $bankaccountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS;
if ($bankaccountid > 0) {
$label = '(CustomerInvoicePayment)';
if ($object->type == Facture::TYPE_CREDIT_NOTE) $label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
$result = $paiement->addPaymentToBank($user, 'payment', $label, $bankaccountid, '', '');
if ($result < 0) {
$postactionmessages[] = $paiement->error . ' ' . join("<br>\n", $paiement->errors);
$ispostactionok = -1;
$error++;
} else {
$postactionmessages[] = 'Bank transaction of payment created';
$ispostactionok = 1;
}
} else {
$postactionmessages[] = 'Setup of bank account to use in module ' . $paymentmethod . ' was not set. No way to record the payment.';
$ispostactionok = -1;
$error++;
}
}
if (!$error) {
$db->commit();
} else {
$db->rollback();
}
} else {
$postactionmessages[] = 'Failed to create invoice form order ' . $tmptag['ORD'] . '.';
$ispostactionok = -1;
}
} else {
$postactionmessages[] = 'Failed to get a valid value for "amount paid" (' . $FinalPaymentAmt . ') or "payment type" (' . $paymentType . ') to record the payment of order ' . $tmptag['ORD'] . '. May be payment was already recorded.';
$ispostactionok = -1;
}
} else {
$postactionmessages[] = 'Invoice module is not enable';
$ispostactionok = -1;
}
} else {
$postactionmessages[] = 'Order paid ' . $tmptag['ORD'] . ' was not found';
$ispostactionok = -1;
}
} elseif (array_key_exists('DON', $tmptag) && $tmptag['DON'] > 0) {
include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
$don = new Don($db);

View File

@ -20,7 +20,9 @@ if (!defined('NOREQUIREAJAX')) {
if (!defined('NOSESSION')) {
define('NOSESSION', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
session_cache_limiter('public');
require_once '../../main.inc.php';
@ -30,19 +32,9 @@ if ($dolibarr_main_prod) {
accessforbidden();
}
llxHeader('', 'Documentation and examples for theme');
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Documentation and examples for theme.">
<link href="<?php echo DOL_URL_ROOT ?>/theme/eldy/style.css.php" rel="stylesheet">
</head>
<body class="docpage" style="padding: 20px;">
<main role="main" >
<h1 class="bd-title" id="content">Badges</h1>
<p class="bd-lead">Documentation and examples for badges, our small count and labeling component.</p>
@ -342,5 +334,4 @@ if ($dolibarr_main_prod) {
</main>
</body>
</html>
<?php llxFooter();

View File

@ -0,0 +1,196 @@
<?php
if (!defined('NOREQUIRESOC')) {
define('NOREQUIRESOC', '1');
}
if (!defined('NOCSRFCHECK')) {
define('NOCSRFCHECK', 1);
}
if (!defined('NOTOKENRENEWAL')) {
define('NOTOKENRENEWAL', 1);
}
if (!defined('NOLOGIN')) {
define('NOLOGIN', 1); // File must be accessed by logon page so without login
}
if (!defined('NOREQUIREHTML')) {
define('NOREQUIREHTML', 1);
}
if (!defined('NOREQUIREAJAX')) {
define('NOREQUIREAJAX', '1');
}
if (!defined('NOSESSION')) {
define('NOSESSION', '1');
}
if (!defined('NOREQUIREMENU')) {
define('NOREQUIREMENU', '1');
}
session_cache_limiter('public');
require_once '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
if ($dolibarr_main_prod) {
accessforbidden();
}
llxHeader('', 'Documentation and examples for theme');
?>
<main role="main" >
<h1 class="bd-title" id="content">Button for action</h1>
<p class="bd-lead">Documentation and examples for buttons.</p>
<h2 id="example01">Example of simple usage</h2>
<p>Buttons for user allowed to click.</p>
<div class="bd-example">
<?php
$n = 1;
$label = 'My action label used for accessibility visually for impaired people';
$html = '<span class="fa fa-clone" ></span> My default action';
$actionType = 'default';
$n++;
$id = 'mybuttonid'.$n;
$url = '#'.$id;
$userRight = 1;
$params = array();
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
$html = '<span class="fa fa-clone" ></span> My delete action';
$actionType = 'delete';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
$html = '<span class="fa fa-clone" ></span> My danger action';
$actionType = 'danger';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
?>
</div>
<p>Buttons for user <strong>NOT</strong> allowed to click.</p>
<div class="bd-example">
<?php
$label = 'My action label used for accessibility visually for impaired people';
$html = '<span class="fa fa-clone" ></span> My default action';
$actionType = 'default';
$n++;
$id = 'mybuttonid'.$n;
$url = '#'.$id;
$userRight = 0;
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
$html = '<span class="fa fa-clone" ></span> My delete action';
$actionType = 'delete';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
$html = '<span class="fa fa-clone" ></span> My danger action';
$actionType = 'danger';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight);
?>
</div>
<h2 id="example01">Example of confirm dialog</h2>
<p>Buttons for user allowed to click.</p>
<div class="bd-example">
<?php
$label = 'My action label used for accessibility visually for impaired people';
$html = '<span class="fa fa-clone" ></span> My default action';
$actionType = 'default';
$n++;
$id = 'mybuttonid'.$n;
$url = '#'.$id;
$userRight = 1;
$params = array(
'confirm' => true
);
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight, $params);
$html = '<span class="fa fa-clone" ></span> My delete action';
$actionType = 'delete';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
$params = array(
'confirm' => array(
'url' => 'your confirm action url',
'title' => 'Your title to display',
'action-btn-label' => 'Your confirm label',
'cancel-btn-label' => 'Your cancel label',
'content' => 'Content to display with <strong>HTML</strong> compatible <ul><li>test 01</li><li>test 02</li><li>test 03</li></ul>'
)
);
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight, $params);
?>
</div>
<p>Buttons for user <strong>NOT</strong> allowed to click.</p>
<div class="bd-example">
<?php
$label = 'My action label used for accessibility visually for impaired people';
$html = '<span class="fa fa-clone" ></span> My default action';
$actionType = 'default';
$n++;
$id = 'mybuttonid'.$n;
$url = '#'.$id;
$userRight = 0;
$params = array(
'confirm' => true
);
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight, $params);
$html = '<span class="fa fa-clone" ></span> My delete action';
$actionType = 'delete';
$n++;
$id = 'mybuttonid'.$n;
$url = $_SERVER['PHP_SELF'] . '?token='.newToken().'#'.$id;
$params = array(
'confirm' => array(
'url' => 'your confirm action url',
'title' => 'Your title to display',
'action-btn-label' => 'Your confirm label',
'cancel-btn-label' => 'Your cancel label',
'content' => 'Content to display with <strong>HTML</strong> compatible <ul><li>test 01</li><li>test 02</li><li>test 03</li></ul>'
)
);
print dolGetButtonAction($label, $html, $actionType, $url, $id, $userRight, $params);
?>
</div>
</main>
<?php llxFooter();

View File

@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2002-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2019 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004-2021 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2003 Brian Fraval <brian@fraval.org>
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
@ -1280,7 +1280,8 @@ class Societe extends CommonObject
$this->get_codefournisseur($this, 1);
}
$this->code_compta = trim($this->code_compta);
$this->code_compta_client = trim(empty($this->code_compta) ? $this->code_compta_client : $this->code_compta);
$this->code_compta = $this->code_compta_client; // for backward compatbility
$this->code_compta_fournisseur = trim($this->code_compta_fournisseur);
// Check parameters. More tests are done later in the ->verify()
@ -1292,8 +1293,8 @@ class Societe extends CommonObject
$customer = false;
if (!empty($allowmodcodeclient) && !empty($this->client)) {
// Attention get_codecompta peut modifier le code suivant le module utilise
if (empty($this->code_compta)) {
// If $allowmodcodeclient is set and value is not set, we generate it
if (empty($this->code_compta_client)) {
$ret = $this->get_codecompta('customer');
if ($ret < 0) {
return -1;
@ -1305,8 +1306,8 @@ class Societe extends CommonObject
$supplier = false;
if (!empty($allowmodcodefournisseur) && !empty($this->fournisseur)) {
// Attention get_codecompta peut modifier le code suivant le module utilise
if ($this->code_compta_fournisseur == "") {
// If $allowmodcodefournisseur is set and value is not set, we generate it
if (empty($this->code_compta_fournisseur)) {
$ret = $this->get_codecompta('supplier');
if ($ret < 0) {
return -1;
@ -1460,7 +1461,7 @@ class Societe extends CommonObject
if ($customer) {
$sql .= ", code_client = ".(!empty($this->code_client) ? "'".$this->db->escape($this->code_client)."'" : "null");
$sql .= ", code_compta = ".(!empty($this->code_compta) ? "'".$this->db->escape($this->code_compta)."'" : "null");
$sql .= ", code_compta = ".(!empty($this->code_compta_client) ? "'".$this->db->escape($this->code_compta_client)."'" : "null");
}
if ($supplier) {
@ -3311,7 +3312,8 @@ class Societe extends CommonObject
$result = $mod->get_code($this->db, $this, $type);
if ($type == 'customer') {
$this->code_compta = $mod->code;
$this->code_compta_client = $mod->code;
$this->code_compta = $this->code_compta_client; // For backward compatibility
} elseif ($type == 'supplier') {
$this->code_compta_fournisseur = $mod->code;
}
@ -3323,6 +3325,7 @@ class Societe extends CommonObject
}
} else {
if ($type == 'customer') {
$this->code_compta_client = '';
$this->code_compta = '';
} elseif ($type == 'supplier') {
$this->code_compta_fournisseur = '';
@ -4262,21 +4265,6 @@ class Societe extends CommonObject
return $lib;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Set prospect level
*
* @param User $user User who sets the discount
* @return int <0 if KO, >0 if OK
* @deprecated Use update function instead
*/
public function set_prospect_level(User $user)
{
// phpcs:enable
return $this->update($this->id, $user);
}
/**
* Return status of prospect
*
@ -4356,20 +4344,6 @@ class Societe extends CommonObject
return "Error, mode/status not found";
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Set outstanding value
*
* @param User $user User making change
* @return int <0 if KO, >0 if OK
* @deprecated Use update function instead
*/
public function set_OutstandingBill(User $user)
{
// phpcs:enable
return $this->update($this->id, $user);
}
/**
* Return amount of order not paid and total
*

View File

@ -865,7 +865,13 @@ if ($user->rights->societe->supprimer) {
if ($user->rights->societe->creer) {
$arrayofmassactions['preaffecttag'] = img_picto('', 'category', 'class="pictofixedwidth"').$langs->trans("AffectTag");
}
if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete', 'preaffecttag'))) {
if ($user->rights->societe->creer) {
$arrayofmassactions['preenable'] = img_picto('', '', 'class="pictofixedwidth"').$langs->trans("SetToEnabled");
}
if ($user->rights->societe->creer) {
$arrayofmassactions['predisable'] = img_picto('', '', 'class="pictofixedwidth"').$langs->trans("SetToDisabled");
}
if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete', 'preaffecttag', 'preenable', 'preclose'))) {
$arrayofmassactions = array();
}
$massactionbutton = $form->selectMassAction('', $arrayofmassactions);

View File

@ -136,7 +136,7 @@ if ($socid) {
$params = '';
$backtopage = $_SERVER['PHP_SELF'].'?socid='.$object->id;
$newcardbutton = dolGetButtonTitle($langs->trans("NewProject"), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/projet/card.php?action=create&socid='.$object->id.'&amp;backtopage='.urlencode($backtopage), '', 1, $params);
$newcardbutton = dolGetButtonTitle($langs->trans("NewProject"), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/projet/card.php?action=create&socid='.$object->id.'&backtopageforcancel='.urlencode($backtopage), '', 1, $params);
print '<br>';

View File

@ -1095,7 +1095,7 @@ $( document ).ready(function() {
$max_sale = 0;
while ($obj = $db->fetch_object($resql)) {
echo '$("#customerandsales").append(\'';
echo '<a class="valignmiddle" title="'.dol_escape_js($langs->trans("SaleStartedAt", dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser'))).'" onclick="place=\\\'';
echo '<a class="valignmiddle" title="'.dol_escape_js($langs->trans("SaleStartedAt", dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser')).' - '.$obj->ref).'" onclick="place=\\\'';
$num_sale = str_replace(")", "", str_replace("(PROV-POS".$_SESSION["takeposterminal"]."-", "", $obj->ref));
echo $num_sale;
if (str_replace("-", "", $num_sale) > $max_sale) {

View File

@ -258,9 +258,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
print $cssPrefix.".badge-status".$statusName." {\n";
print " color: ".$thisBadgeTextColor." !important;\n";
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
print " border-color: ".$thisBadgeBorderColor.";\n";
print " border-color: ".$thisBadgeBorderColor." !important;\n";
}
print " background-color: ".$thisBadgeBackgroundColor.";\n";
print " background-color: ".$thisBadgeBackgroundColor." !important;\n";
print "}\n";
print $cssPrefix.".font-status".$statusName." {\n";
@ -269,14 +269,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n";
print " outline: 0;\n";
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n";
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n";
print "}\n";
print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n";
print " color: ".$thisBadgeTextColor." !important;\n";
//print " background-color: " . colorDarker($thisBadgeBackgroundColor, 10) . ";\n";
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n";
print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n";
}
print "}\n";
}

View File

@ -261,9 +261,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
print $cssPrefix.".badge-status".$statusName." {\n";
print " color: ".$thisBadgeTextColor." !important;\n";
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
print " border-color: ".$thisBadgeBorderColor.";\n";
print " border-color: ".$thisBadgeBorderColor." !important;\n";
}
print " background-color: ".$thisBadgeBackgroundColor.";\n";
print " background-color: ".$thisBadgeBackgroundColor." !important;\n";
print "}\n";
print $cssPrefix.".font-status".$statusName." {\n";
@ -272,14 +272,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n";
print " outline: 0;\n";
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n";
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n";
print "}\n";
print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n";
print " color: ".$thisBadgeTextColor." !important;\n";
//print " background-color: ".colorDarker($thisBadgeBackgroundColor, 10).";\n";
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n";
print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n";
}
print "}\n";
}

View File

@ -31,6 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
if (!empty($conf->projet->enabled)) {
include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
@ -202,6 +203,10 @@ if (empty($reshook)) {
$contactid = GETPOST('contactid', 'int');
$type_contact = GETPOST("type", 'alpha');
// Category association
$categories = GETPOST('categories', 'array');
$object->setCategories($categories);
if ($contactid > 0 && $type_contact) {
$typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
$result = $object->add_contact($contactid, $typeid, 'external');
@ -312,7 +317,11 @@ if (empty($reshook)) {
$object->severity_code = GETPOST('severity_code', 'alpha');
$ret = $object->update($user);
if ($ret <= 0) {
if ($ret > 0) {
// Category association
$categories = GETPOST('categories', 'array');
$object->setCategories($categories);
} else {
$error++;
}
@ -1054,6 +1063,13 @@ if ($action == 'create' || $action == 'presend') {
print '</td></tr>';
}
// Categories
if ($conf->categorie->enabled) {
print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td colspan="3">';
print $form->showCategories($object->id, Categorie::TYPE_TICKET, 1);
print "</td></tr>";
}
// Other attributes
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';

View File

@ -2499,6 +2499,51 @@ class Ticket extends CommonObject
return array('listofpaths'=>$listofpaths, 'listofnames'=>$listofnames, 'listofmimes'=>$mimetype);
}
/**
* Sets object to supplied categories.
*
* Deletes object from existing categories not supplied.
* Adds it to non existing supplied categories.
* Existing categories are left untouch.
*
* @param int[]|int $categories Category or categories IDs
* @return void
*/
public function setCategories($categories)
{
// Handle single category
if (!is_array($categories)) {
$categories = array($categories);
}
// Get current categories
include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
$c = new Categorie($this->db);
$existing = $c->containing($this->id, Categorie::TYPE_TICKET, 'id');
// Diff
if (is_array($existing)) {
$to_del = array_diff($existing, $categories);
$to_add = array_diff($categories, $existing);
} else {
$to_del = array(); // Nothing to delete
$to_add = $categories;
}
// Process
foreach ($to_del as $del) {
if ($c->fetch($del) > 0) {
$c->del_type($this, Categorie::TYPE_TICKET);
}
}
foreach ($to_add as $add) {
if ($c->fetch($add) > 0) {
$c->add_type($this, Categorie::TYPE_TICKET);
}
}
return;
}
/**
* Add new message on a ticket (private/public area). Can also send it be email if GETPOST('send_email', 'int') is set.

View File

@ -366,6 +366,6 @@ class HolidayTest extends PHPUnit\Framework\TestCase
$localobjecta->updateConfCP('lastUpdate', '20100101120000');
$result = $localobjecta->updateBalance();
$this->assertEquals($result, 1);
$this->assertEquals($result, 0);
}
}

View File

@ -0,0 +1,75 @@
Delivered-To: testldrdev@gmail.com
Received: by 2002:ab3:5782:0:0:0:0:0 with SMTP id e2csp698208ltc; Thu, 15 Jul
2021 13:49:41 -0700 (PDT)
X-Received: by 2002:a63:eb51:: with SMTP id b17mr490127pgk.288.1626382180943;
Thu, 15 Jul 2021 13:49:40 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1626382180; cv=none; d=google.com;
s=arc-20160816;
b=rEpZkUN9MvFJ+8ckMD+urx6epAp5zUAICUiJjTY9yAAwmp54gZ9XYu/qoVgqVe5rAU
oayiqojPUzHArxaIlmftWyK4kF6ErAQxMZocn944kHeCGOigIB2y+u+ij3Ip4Vg6PW62
4cATlnRoDTpnckwrXHnOonzSEHunE2smZgtujdNJ/1p/vbmhByQl3Kg71NzCLzdE3nr6
PYQNl/XbTL4BUpKBsbPCbJDNeNOqu/FHBI3R7Nfoy+HDY9LR+aYBR4N6jBQMKyKM32JJ
2yrN9ky6N1n2xfvD4lnbqDyqvgWjmTGP+Dk+UAUeAj3YsS/hM2z41UA9xicPoC/B+Wft XWPQ==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
s=arc-20160816; h=to:from:subject:message-id:feedback-id:date:mime-version
:dkim-signature; bh=jzUFV8bCmEmAeTpb8amH8O1QwkNos0xYlYqLtpP6SBc=;
b=cLnW/O5/vTbct4uiVIanDpvITsoy5pp8c0Cy3ZKppY1t2U0bCaedhyI9LkbwXU0ytU
i+qgnSrwydhnvY8Yy13KDUkVtjU9dxmQ/YDYBsLjS7WeFEy9OQkIqCR1czmUoUSEPbgr
d/tsVEPg/LwHW74WuG6vUVRidF9XBBQqQHR7ADCvo4DQKRURzpeDF4ggDceiWfhpYjbZ
Un//GKujM5WGfV7kkqfprw5UsVG8+pjbKdnTwsCKJ3htju9eYXANf4Odn/kjA5OjP3l3
fuqCeus0fSyUw9T4DLe4knRxReOL+MfjQc65ATjFlOfl/9/CPauSFkmPrGKeUHi7m2bA rVCQ==
ARC-Authentication-Results: i=1; mx.google.com; dkim=pass
header.i=@accounts.google.com header.s=20161025 header.b=XOpeYXK3; spf=pass
(google.com: domain of
3zj_wyagtcnmef-ivgcprttflekj.xffxcv.tfdkvjkcuiuvmxdrzc.tfd@gaia.bounces.google.com
designates 209.85.220.73 as permitted sender)
smtp.mailfrom=3ZJ_wYAgTCnMef-iVgcpRTTflekj.XffXcV.TfdkVjkcUiUVmXdRZc.Tfd@gaia.bounces.google.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=accounts.google.com
Return-Path: <3ZJ_wYAgTCnMef-iVgcpRTTflekj.XffXcV.TfdkVjkcUiUVmXdRZc.Tfd@gaia.bounces.google.com>
Received: from mail-sor-f73.google.com (mail-sor-f73.google.com.
[209.85.220.73]) by mx.google.com with SMTPS id
m24sor3147147pls.67.2021.07.15.13.49.40 for <testldrdev@gmail.com> (Google
Transport Security); Thu, 15 Jul 2021 13:49:40 -0700 (PDT)
Received-SPF: pass (google.com: domain of
3zj_wyagtcnmef-ivgcprttflekj.xffxcv.tfdkvjkcuiuvmxdrzc.tfd@gaia.bounces.google.com
designates 209.85.220.73 as permitted sender) client-ip=209.85.220.73;
Authentication-Results: mx.google.com; dkim=pass header.i=@accounts.google.com
header.s=20161025 header.b=XOpeYXK3; spf=pass (google.com: domain of
3zj_wyagtcnmef-ivgcprttflekj.xffxcv.tfdkvjkcuiuvmxdrzc.tfd@gaia.bounces.google.com
designates 209.85.220.73 as permitted sender)
smtp.mailfrom=3ZJ_wYAgTCnMef-iVgcpRTTflekj.XffXcV.TfdkVjkcUiUVmXdRZc.Tfd@gaia.bounces.google.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=accounts.google.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=accounts.google.com;
s=20161025; h=mime-version:date:feedback-id:message-id:subject:from:to;
bh=jzUFV8bCmEmAeTpb8amH8O1QwkNos0xYlYqLtpP6SBc=;
b=XOpeYXK3QbrfDh9/pqAG7UruMxyCVah4Lj5tfBPHRh8C6AvzStTVsgRTFzPGuxB9cq
XRneLOf3kYKud2kkKMNShaG+/t65suM2MTo3q81Qvt9N6n8motuXmnLnNM7kVCaXM//s
BxZjiL4nXdjrQBF0N7wcns7xFS+J9pKZbfbm0BaUV32Kb7ef63PQHwhE+au4ytUynBqj
hxfA977RfwEXbFmUInVRJ6IJhMoygnx/Y10AccV0TuuLtnNKJIsPFv04SJcOclwaNJ3H
69GSdpRSNJyqn7Rzm4va6l4Lxhjfjzm7+IVzMx717A5e8dLiLjxftCRS1F6EXTeYUvQ+ QcUQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net;
s=20161025;
h=x-gm-message-state:mime-version:date:feedback-id:message-id:subject
:from:to; bh=jzUFV8bCmEmAeTpb8amH8O1QwkNos0xYlYqLtpP6SBc=;
b=uWWatGm2u/TYFa5pXhZCPJ59bmYVNEj9qv3Z5wiotMZ7pWc9mR0LYGgD99IjNs7E0G
hhv+GwtrMGft69VPG4GyUbmd7pm27G+ykFu2kLfB5lTRhZNjaqeLLkIS4KgbTlAsJJ7q
UNrIvPgpAksxnY79qtneThZOTI4o0s+V94A5T5p3/PN99YXq22RxE/aHCIpMIj/NyJeJ
RUGdEaiAjQXuG70ekiFAy2cePOI+WCFZEfYmq6vAJO4y285ID/ovjv4cpFIqTu3QFb/u
gdZFQriVXnKyZryLbjN1PlpK0772vsatNh5jC8GgOsJjSqJmZLNR5urtUlnRmTaJ8hoV F3lA==
X-Gm-Message-State: AOAM5338zSEHryX6TtcvwcYlbrnaMvleKLH9RhoGJaqMLvXSPlD7sWEt
pW5IuEivfKUIAHzbl8HeQWtM86OUvsPb26Z/ddNWtw==
X-Google-Smtp-Source: ABdhPJxfD6pBcAwUGMIoqNyPu3KT+9RON4ujFwzRhm3eCKUYxpRR+2hPoCLgdMzCE1TnOL7ShV3hLBEBAQzFtzZ6ue8glg==
MIME-Version: 1.0
X-Received: by 2002:a17:902:ed82:b029:ef:48c8:128e with SMTP id
e2-20020a170902ed82b02900ef48c8128emr4950093plj.72.1626382180494; Thu, 15 Jul
2021 13:49:40 -0700 (PDT)
Date: Thu, 15 Jul 2021 20:49:40 GMT
X-Account-Notification-Type: 46-anexp#nret-fa
Feedback-ID: 46-anexp#nret-fa:account-notifier
X-Notifications: 56c00ab9d6600000
X-Notifications-Bounce-Info: ARgXy4C6Xm7P0JA65M5w_0EB-KbSHnYA8DuTVsZzaMJT7AktG4DWNKZC7qYb4FkrhakLBYzS11Hsoc4qaJocq__FbWMZwTVOmo9d1gWCxx2JMJOgcGQxMKdQ_UVnkuDZugVRr6nih0prpV8OI7Y0ijFI5KVo1M_9f-HXojR-v_jydOpt3lpHGJ-AIQ
Message-ID: <btsOkB97XRj0uTo4jpgzYg@notifications.google.com>
Subject: =?UTF-8?B?QWxlcnRlIGRlIHPDqWN1cml0w6k=?=
From: Google <no-reply@accounts.google.com>
To: testldrdev@gmail.com
Content-Type: multipart/alternative; boundary="000000000000232f0005c72f9c4b"

View File

@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta name="format-detection" content="email=no"/><meta name="format-detection" content="date=no"/><style nonce="TOqK6jIi0eJsTXLtZ88YTg">.awl a {color: #FFFFFF; text-decoration: none;} .abml a {color: #000000; font-family: Roboto-Medium,Helvetica,Arial,sans-serif; font-weight: bold; text-decoration: none;} .adgl a {color: rgba(0, 0, 0, 0.87); text-decoration: none;} .afal a {color: #b0b0b0; text-decoration: none;} @media screen and (min-width: 600px) {.v2sp {padding: 6px 30px 0px;} .v2rsp {padding: 0px 10px;}} @media screen and (min-width: 600px) {.mdv2rw {padding: 40px 40px;}} </style><link href="//fonts.googleapis.com/css?family=Google+Sans" rel="stylesheet" type="text/css" nonce="TOqK6jIi0eJsTXLtZ88YTg"/></head><body style="margin: 0; padding: 0;" bgcolor="#FFFFFF"><table width="100%" height="100%" style="min-width: 348px;" border="0" cellspacing="0" cellpadding="0" lang="en"><tr height="32" style="height: 32px;"><td></td></tr><tr align="center"><td><div itemscope itemtype="//schema.org/EmailMessage"><div itemprop="action" itemscope itemtype="//schema.org/ViewAction"><link itemprop="url" href="https://accounts.google.com/AccountChooser?Email=testldrdev@gmail.com&amp;continue=https://myaccount.google.com/alert/nt/1626382180096?rfn%3D46%26rfnc%3D1%26eid%3D4797880215322882540%26et%3D0%26anexp%3Dnret-fa"/><meta itemprop="name" content="Consulter l&#39;activité du compte"/></div></div><table border="0" cellspacing="0" cellpadding="0" style="padding-bottom: 20px; max-width: 516px; min-width: 220px;"><tr><td width="8" style="width: 8px;"></td><td><div style="border-style: solid; border-width: thin; border-color:#dadce0; border-radius: 8px; padding: 40px 20px;" align="center" class="mdv2rw"><img src="https://www.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_74x24dp.png" width="74" height="24" aria-hidden="true" style="margin-bottom: 16px;" alt="Google"><div style="font-family: &#39;Google Sans&#39;,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;border-bottom: thin solid #dadce0; color: rgba(0,0,0,0.87); line-height: 32px; padding-bottom: 24px;text-align: center; word-break: break-word;"><div style="font-size: 24px;">Clé de sécurité ajoutée pour la validation en deux étapes </div><table align="center" style="margin-top:8px;"><tr style="line-height: normal;"><td align="right" style="padding-right:8px;"><img width="20" height="20" style="width: 20px; height: 20px; vertical-align: sub; border-radius: 50%;;" src="https://lh3.googleusercontent.com/a/AATXAJwvtB7TqgrMnOW7GMwuA9xGYOPud8oelpVYYNle=s96" alt=""></td><td><a style="font-family: &#39;Google Sans&#39;,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;color: rgba(0,0,0,0.87); font-size: 14px; line-height: 20px;">testldrdev@gmail.com</a></td></tr></table> </div><div style="font-family: Roboto-Regular,Helvetica,Arial,sans-serif; font-size: 14px; color: rgba(0,0,0,0.87); line-height: 20px;padding-top: 20px; text-align: left;">Si vous n'avez pas ajouté de clé de sécurité, quelqu'un utilise peut-être votre compte. Vérifiez et sécurisez votre compte dès maintenant.<div style="padding-top: 32px; text-align: center;"><a href="https://accounts.google.com/AccountChooser?Email=testldrdev@gmail.com&amp;continue=https://myaccount.google.com/alert/nt/1626382180096?rfn%3D46%26rfnc%3D1%26eid%3D4797880215322882540%26et%3D0%26anexp%3Dnret-fa" target="_blank" link-id="main-button-link" style="font-family: &#39;Google Sans&#39;,Roboto,RobotoDraft,Helvetica,Arial,sans-serif; line-height: 16px; color: #ffffff; font-weight: 400; text-decoration: none;font-size: 14px;display:inline-block;padding: 10px 24px;background-color: #4184F3; border-radius: 5px; min-width: 90px;">Consulter l&#39;activité</a></div></div><div style="padding-top: 20px; font-size: 12px; line-height: 16px; color: #5f6368; letter-spacing: 0.3px; text-align: center">Vous pouvez aussi voir l'activité liée à la sécurité de votre compte ici :<br><a style="color: rgba(0, 0, 0, 0.87);text-decoration: inherit;">https://myaccount.google.com/notifications</a></div></div><div style="text-align: left;"><div style="font-family: Roboto-Regular,Helvetica,Arial,sans-serif;color: rgba(0,0,0,0.54); font-size: 11px; line-height: 18px; padding-top: 12px; text-align: center;"><div>Cet e-mail vous a été envoyé pour vous informer de modifications importantes apportées à votre compte et aux services Google que vous utilisez.</div><div style="direction: ltr;">&copy; 2021 Google Ireland Ltd., <a class="afal" style="font-family: Roboto-Regular,Helvetica,Arial,sans-serif;color: rgba(0,0,0,0.54); font-size: 11px; line-height: 18px; padding-top: 12px; text-align: center;">Gordon House, Barrow Street, Dublin 4, Ireland</a></div></div></div></td><td width="8" style="width: 8px;"></td></tr></table></td></tr><tr height="32" style="height: 32px;"><td></td></tr></table></body></html><br><br>

View File

@ -0,0 +1 @@
[image: Google] Clé de sécurité ajoutée pour la validation en deux étapes testldrdev@gmail.com Si vous n'avez pas ajouté de clé de sécurité, quelqu'un utilise peut-être votre compte. Vérifiez et sécurisez votre compte dès maintenant. Consulter l'activité Vous pouvez aussi voir l'activité liée à la sécurité de votre compte ici : https://myaccount.google.com/notifications Cet e-mail vous a été envoyé pour vous informer de modifications importantes apportées à votre compte et aux services Google que vous utilisez. © 2021 Google Ireland Ltd., Gordon House, Barrow Street, Dublin 4, Ireland