Merge remote-tracking branch 'upstream/develop' into develop_hotfix19760
# Conflicts: # htdocs/install/mysql/migration/15.0.0-16.0.0.sql
This commit is contained in:
commit
56cb81287e
10
ChangeLog
10
ChangeLog
@ -15,7 +15,7 @@ NEW: Add option to disable globaly some notifications emails.
|
||||
NEW: #18326 Workflow: Close order on shipment closing.
|
||||
NEW: #18401 Add __NEWREF__ subtitute to get new object reference.
|
||||
NEW: #18403 Add __URL_SHIPMENT__ substitute to get the URL of a shipment
|
||||
NEW: #18689 REST API module: add api key generate / modify right.
|
||||
NEW: #18689 REST API module: add api key generate / modify pemrission.
|
||||
NEW: #18663 Make "L'Annuaire des Entreprises" the default provider for SIREN verification for French thirdparties.
|
||||
NEW: #18046 Add tags on ticket/categories
|
||||
NEW: #18326 Workflow: Close order on shipment closing.
|
||||
@ -109,6 +109,13 @@ NEW: External backups can be downloaded from the "About info page".
|
||||
NEW: Add massaction to switch status on sale / on purchase of a product.
|
||||
|
||||
|
||||
Modules
|
||||
NEW: Stable module Knowledge Management
|
||||
NEW: Experimental module Event Organization Management
|
||||
NEW: Experimental module Workstations Management
|
||||
NEW: Development of module Partnership Management
|
||||
|
||||
|
||||
For developers:
|
||||
---------------
|
||||
|
||||
@ -116,6 +123,7 @@ NEW: Introduce method hasRight
|
||||
NEW: Can use textarea field into a confirm popup.
|
||||
NEW: Can use the result_mode of mysqli driver. Save memory for list count
|
||||
NEW: #18319 REST API - Shipment: Add 'close' action / endpoint / POST method.
|
||||
NEW: Add API /approve and /makeOrder for purchase orders.
|
||||
NEW: add action trigger for member excluded
|
||||
NEW: add option MAIN_IBAN_IS_NEVER_MANDATORY, MAIN_IBAN_NOT_MANDATORY, PROPAL_NOT_BILLABLE, PROPAL_REOPEN_UNSIGNED_ONLY, PROPOSAL_ARE_NOT_BILLABLE, TICKETS_MESSAGE_FORCE_MAIL
|
||||
NEW: Add code codebar column on serial/lot structure
|
||||
|
||||
@ -39,15 +39,13 @@ RUN chmod +x /usr/local/bin/docker-run.sh
|
||||
|
||||
RUN pecl install xdebug && docker-php-ext-enable xdebug
|
||||
RUN echo 'zend_extension="/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so"' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.remote_autostart=1' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.remote_enable=1' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.default_enable=1' >> ${PHP_INI_DIR}/php.ini
|
||||
#RUN echo 'xdebug.remote_host=docker.host' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.remote_port=9000' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.remote_connect_back=1' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.profiler_enable=0' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.remote_log="/tmp/xdebug.log"' >> ${PHP_INI_DIR}/php.ini
|
||||
#RUN echo 'localhost docker.host' >> /etc/hosts
|
||||
RUN echo 'xdebug.mode=debug' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.start_with_request=yes' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.client_host=host.docker.internal' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.client_port=9003' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.discover_client_host=true' >> ${PHP_INI_DIR}/php.ini
|
||||
#RUN echo 'xdebug.log="/tmp/xdebug.log"' >> ${PHP_INI_DIR}/php.ini
|
||||
RUN echo 'xdebug.idekey="netbeans-xdebug"' >> ${PHP_INI_DIR}/php.ini
|
||||
|
||||
# set up sendmail config, to use maildev
|
||||
RUN echo "account default" > /etc/msmtprc
|
||||
|
||||
@ -48,6 +48,7 @@ services:
|
||||
- external-pod
|
||||
extra_hosts:
|
||||
- "localhost.localdomain:127.0.0.1"
|
||||
- "host.docker.internal:host-gateway"
|
||||
|
||||
mail:
|
||||
image: maildev/maildev
|
||||
|
||||
@ -94,9 +94,15 @@ class AdherentType extends CommonObject
|
||||
*/
|
||||
public $amount;
|
||||
|
||||
/** @var string Public note */
|
||||
/**
|
||||
* @var string Public note
|
||||
* @deprecated
|
||||
*/
|
||||
public $note;
|
||||
|
||||
/** @var string Public note */
|
||||
public $note_public;
|
||||
|
||||
/** @var integer Can vote */
|
||||
public $vote;
|
||||
|
||||
@ -358,6 +364,10 @@ class AdherentType extends CommonObject
|
||||
|
||||
$this->label = trim($this->label);
|
||||
|
||||
if (empty($this->note_public) && !empty($this->note)) { // For backward compatibility
|
||||
$this->note_public = $this->note;
|
||||
}
|
||||
|
||||
$this->db->begin();
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."adherent_type ";
|
||||
@ -368,14 +378,14 @@ class AdherentType extends CommonObject
|
||||
$sql .= "subscription = '".$this->db->escape($this->subscription)."',";
|
||||
$sql .= "amount = ".((empty($this->amount) && $this->amount == '') ? 'null' : ((float) $this->amount)).",";
|
||||
$sql .= "duration = '".$this->db->escape($this->duration_value.$this->duration_unit)."',";
|
||||
$sql .= "note = '".$this->db->escape($this->note)."',";
|
||||
$sql .= "note = '".$this->db->escape($this->note_public)."',";
|
||||
$sql .= "vote = ".(integer) $this->db->escape($this->vote).",";
|
||||
$sql .= "mail_valid = '".$this->db->escape($this->mail_valid)."'";
|
||||
$sql .= " WHERE rowid =".((int) $this->id);
|
||||
|
||||
$result = $this->db->query($sql);
|
||||
if ($result) {
|
||||
$this->description = $this->db->escape($this->note);
|
||||
$this->description = $this->db->escape($this->note_public);
|
||||
|
||||
// Multilangs
|
||||
if (!empty($conf->global->MAIN_MULTILANGS)) {
|
||||
@ -461,7 +471,7 @@ class AdherentType extends CommonObject
|
||||
{
|
||||
global $langs, $conf;
|
||||
|
||||
$sql = "SELECT d.rowid, d.libelle as label, d.morphy, d.statut as status, d.duration, d.subscription, d.amount, d.mail_valid, d.note, d.vote";
|
||||
$sql = "SELECT d.rowid, d.libelle as label, d.morphy, d.statut as status, d.duration, d.subscription, d.amount, d.mail_valid, d.note as note_public, d.vote";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."adherent_type as d";
|
||||
$sql .= " WHERE d.rowid = ".(int) $rowid;
|
||||
|
||||
@ -483,7 +493,8 @@ class AdherentType extends CommonObject
|
||||
$this->subscription = $obj->subscription;
|
||||
$this->amount = $obj->amount;
|
||||
$this->mail_valid = $obj->mail_valid;
|
||||
$this->note = $obj->note;
|
||||
$this->note = $obj->note_public; // deprecated
|
||||
$this->note_public = $obj->note_public;
|
||||
$this->vote = $obj->vote;
|
||||
|
||||
// multilangs
|
||||
@ -792,12 +803,16 @@ class AdherentType extends CommonObject
|
||||
// Object classes
|
||||
$info["objectclass"] = explode(',', $conf->global->LDAP_MEMBER_TYPE_OBJECT_CLASS);
|
||||
|
||||
if (empty($this->note_public) && !empty($this->note)) { // For backward compatibility
|
||||
$this->note_public = $this->note;
|
||||
}
|
||||
|
||||
// Champs
|
||||
if ($this->label && !empty($conf->global->LDAP_MEMBER_TYPE_FIELD_FULLNAME)) {
|
||||
$info[$conf->global->LDAP_MEMBER_TYPE_FIELD_FULLNAME] = $this->label;
|
||||
}
|
||||
if ($this->note && !empty($conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION)) {
|
||||
$info[$conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION] = dol_string_nohtmltag($this->note, 0, 'UTF-8', 1);
|
||||
if ($this->note_public && !empty($conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION)) {
|
||||
$info[$conf->global->LDAP_MEMBER_TYPE_FIELD_DESCRIPTION] = dol_string_nohtmltag($this->note_public, 0, 'UTF-8', 1);
|
||||
}
|
||||
if (!empty($conf->global->LDAP_MEMBER_TYPE_FIELD_GROUPMEMBERS)) {
|
||||
$valueofldapfield = array();
|
||||
@ -829,7 +844,7 @@ class AdherentType extends CommonObject
|
||||
$this->specimen = 1;
|
||||
|
||||
$this->label = 'MEMBERS TYPE SPECIMEN';
|
||||
$this->note = 'This is a note';
|
||||
$this->note_public = 'This is a public note';
|
||||
$this->mail_valid = 'This is welcome email';
|
||||
$this->subscription = 1;
|
||||
$this->vote = 0;
|
||||
|
||||
@ -215,7 +215,7 @@ class Subscription extends CommonObject
|
||||
$sql .= " tms,";
|
||||
$sql .= " dateadh as dateh,";
|
||||
$sql .= " datef,";
|
||||
$sql .= " subscription, note, fk_bank";
|
||||
$sql .= " subscription, note as note_public, fk_bank";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."subscription";
|
||||
$sql .= " WHERE rowid=".((int) $rowid);
|
||||
|
||||
@ -235,7 +235,8 @@ class Subscription extends CommonObject
|
||||
$this->dateh = $this->db->jdate($obj->dateh);
|
||||
$this->datef = $this->db->jdate($obj->datef);
|
||||
$this->amount = $obj->subscription;
|
||||
$this->note = $obj->note;
|
||||
$this->note = $obj->note_public; // deprecated
|
||||
$this->note_public = $obj->note_public;
|
||||
$this->fk_bank = $obj->fk_bank;
|
||||
return 1;
|
||||
} else {
|
||||
@ -266,10 +267,14 @@ class Subscription extends CommonObject
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (empty($this->note_public) && !empty($this->note)) { // For backward compatibility
|
||||
$this->note_public = $this->note;
|
||||
}
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."subscription SET ";
|
||||
$sql .= " fk_type = ".((int) $this->fk_type).",";
|
||||
$sql .= " fk_adherent = ".((int) $this->fk_adherent).",";
|
||||
$sql .= " note=".($this->note ? "'".$this->db->escape($this->note)."'" : 'null').",";
|
||||
$sql .= " note=".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null').",";
|
||||
$sql .= " subscription = ".price2num($this->amount).",";
|
||||
$sql .= " dateadh='".$this->db->idate($this->dateh)."',";
|
||||
$sql .= " datef='".$this->db->idate($this->datef)."',";
|
||||
|
||||
@ -1163,9 +1163,13 @@ if ($rowid > 0) {
|
||||
print dol_get_fiche_end();
|
||||
|
||||
print '<div class="center">';
|
||||
print '<input type="submit" class="button" name="add" value="'.$langs->trans("AddSubscription").'">';
|
||||
print ' ';
|
||||
print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
|
||||
$parameters = array();
|
||||
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action);
|
||||
if (empty($reshook)) {
|
||||
print '<input type="submit" class="button" name="add" value="'.$langs->trans("AddSubscription").'">';
|
||||
print ' ';
|
||||
print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
|
||||
}
|
||||
print '</div>';
|
||||
|
||||
print '</form>';
|
||||
|
||||
@ -158,18 +158,6 @@ if ($action == 'updateMask') {
|
||||
$error++;
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
||||
} else {
|
||||
setEventMessages($langs->trans("Error"), null, 'errors');
|
||||
}
|
||||
} elseif ($action == "setshippableiconinlist") {
|
||||
// Activate Set Shippable Icon In List
|
||||
$setshippableiconinlist = GETPOST('value', 'int');
|
||||
$res = dolibarr_set_const($db, "SHIPPABLE_ORDER_ICON_IN_LIST", $setshippableiconinlist, 'yesno', 0, '', $conf->entity);
|
||||
if (!($res > 0)) {
|
||||
$error++;
|
||||
}
|
||||
if (!$error) {
|
||||
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
|
||||
} else {
|
||||
@ -646,25 +634,6 @@ print '<input type="submit" class="button button-edit" value="'.$langs->trans("M
|
||||
print "</td></tr>\n";
|
||||
print '</form>';
|
||||
|
||||
// Shippable Icon in List
|
||||
/* Kept as hidden feature for the moment, result seems bugged.
|
||||
Where is definition of "shippable" according to all different STOCK_CALCULATE_... options ?
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
print '<td>'.$langs->trans("ShippableOrderIconInList").'</td>';
|
||||
print '<td> </td>';
|
||||
print '<td class="center">';
|
||||
if (!empty($conf->global->SHIPPABLE_ORDER_ICON_IN_LIST)) {
|
||||
print '<a href="'.$_SERVER['PHP_SELF'].'?action=setshippableiconinlist&token='.newToken().'&value=0">';
|
||||
print img_picto($langs->trans("Activated"),'switch_on');
|
||||
} else {
|
||||
print '<a href="'.$_SERVER['PHP_SELF'].'?action=setshippableiconinlist&token='.newToken().'&value=1">';
|
||||
print img_picto($langs->trans("Disabled"),'switch_off');
|
||||
}
|
||||
print '</a></td>';
|
||||
print '</tr>';
|
||||
*/
|
||||
|
||||
/*
|
||||
// Seems to be not so used. So kept hidden for the moment to avoid dangerous options inflation.
|
||||
// Ask for payment bank during order
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
|
||||
div.divsearchfield {
|
||||
float: left;
|
||||
margin: 4px 12px 4px 2px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/eventorganization.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
|
||||
|
||||
// Translations
|
||||
$langs->loadLangs(array("admin", "eventorganization"));
|
||||
$langs->loadLangs(array("admin", "eventorganization", "categories"));
|
||||
|
||||
// Parameters
|
||||
$action = GETPOST('action', 'aZ09');
|
||||
@ -54,11 +54,11 @@ $arrayofparameters = array(
|
||||
'EVENTORGANIZATION_TEMPLATE_EMAIL_ASK_BOOTH'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_TEMPLATE_EMAIL_AFT_SUBS_BOOTH'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_TEMPLATE_EMAIL_AFT_SUBS_EVENT'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_SPEAKER'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_ATTENDES'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_SECUREKEY'=>array('type'=>'securekey', 'enabled'=>1),
|
||||
//'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_SPEAKER'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
//'EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_ATTENDES'=>array('type'=>'emailtemplate:conferenceorbooth', 'enabled'=>1),
|
||||
'SERVICE_BOOTH_LOCATION'=>array('type'=>'product', 'enabled'=>1),
|
||||
'SERVICE_CONFERENCE_ATTENDEE_SUBSCRIPTION'=>array('type'=>'product', 'enabled'=>1),
|
||||
'EVENTORGANIZATION_SECUREKEY'=>array('type'=>'securekey', 'enabled'=>1),
|
||||
);
|
||||
|
||||
$error = 0;
|
||||
|
||||
@ -28,24 +28,91 @@
|
||||
*/
|
||||
|
||||
require '../main.inc.php';
|
||||
|
||||
// Libraries
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
|
||||
|
||||
// Load translation files required by the page
|
||||
$langs->loadLangs(array('admin', 'errors', 'other', 'bills'));
|
||||
|
||||
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
|
||||
$hookmanager->initHooks(array('situationinvoicesetup', 'globalsetup'));
|
||||
|
||||
// Access control
|
||||
if (!$user->admin) {
|
||||
accessforbidden();
|
||||
}
|
||||
|
||||
$action = GETPOST('action', 'aZ09');
|
||||
$backtopage = GETPOST('backtopage', 'alpha');
|
||||
|
||||
$value = GETPOST('value', 'alpha');
|
||||
$label = GETPOST('label', 'alpha');
|
||||
$scandir = GETPOST('scan_dir', 'alpha');
|
||||
$type = 'invoice';
|
||||
|
||||
$form = new Form($db);
|
||||
$formSetup = new FormSetup($db);
|
||||
|
||||
|
||||
// Setup conf MYMODULE_MYPARAM4 : exemple of quick define write style
|
||||
$formSetup->newItem('INVOICE_USE_SITUATION')
|
||||
->setAsYesNo()
|
||||
->nameText = $langs->trans('UseSituationInvoices');
|
||||
|
||||
$item = $formSetup->newItem('INVOICE_USE_SITUATION_CREDIT_NOTE')
|
||||
->setAsYesNo()
|
||||
->nameText = $langs->trans('UseSituationInvoicesCreditNote');
|
||||
|
||||
//$item = $formSetup->newItem('INVOICE_USE_RETAINED_WARRANTY')
|
||||
// ->setAsYesNo()
|
||||
// ->nameText = $langs->trans('Retainedwarranty');
|
||||
|
||||
|
||||
$item = $formSetup->newItem('INVOICE_USE_RETAINED_WARRANTY');
|
||||
$item->nameText = $langs->trans('AllowedInvoiceForRetainedWarranty');
|
||||
|
||||
$arrayAvailableType = array(
|
||||
Facture::TYPE_SITUATION => $langs->trans("InvoiceSituation"),
|
||||
Facture::TYPE_STANDARD.'+'.Facture::TYPE_SITUATION => $langs->trans("InvoiceSituation").' + '.$langs->trans("InvoiceStandard"),
|
||||
);
|
||||
|
||||
if ($action == 'edit') {
|
||||
$item->fieldInputOverride = $form->selectarray('INVOICE_USE_RETAINED_WARRANTY', $arrayAvailableType, $conf->global->INVOICE_USE_RETAINED_WARRANTY, 1);
|
||||
} else {
|
||||
$item->fieldOutputOverride= isset($arrayAvailableType[$conf->global->INVOICE_USE_RETAINED_WARRANTY])?$arrayAvailableType[$conf->global->INVOICE_USE_RETAINED_WARRANTY]:'';
|
||||
}
|
||||
|
||||
//$item = $formSetup->newItem('INVOICE_RETAINED_WARRANTY_LIMITED_TO_SITUATION')->setAsYesNo();
|
||||
//$item->nameText = $langs->trans('RetainedwarrantyOnlyForSituation');
|
||||
|
||||
$formSetup->newItem('INVOICE_RETAINED_WARRANTY_LIMITED_TO_FINAL_SITUATION')
|
||||
->setAsYesNo()
|
||||
->nameText = $langs->trans('RetainedwarrantyOnlyForSituationFinal');
|
||||
|
||||
|
||||
$item = $formSetup->newItem('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_PERCENT');
|
||||
$item->nameText = $langs->trans('RetainedwarrantyDefaultPercent');
|
||||
$item->fieldAttr = array(
|
||||
'type' => 'number',
|
||||
'step' => '0.01',
|
||||
'min' => 0,
|
||||
'max' => 100
|
||||
);
|
||||
|
||||
|
||||
// Conditions paiements
|
||||
$item = $formSetup->newItem('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID');
|
||||
$item->nameText = $langs->trans('PaymentConditionsShortRetainedWarranty');
|
||||
$form->load_cache_conditions_paiements();
|
||||
if (!empty($conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID) && isset($form->cache_conditions_paiements[$conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID]['label'])) {
|
||||
$item->fieldOutputOverride = $form->cache_conditions_paiements[$conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID]['label'];
|
||||
}
|
||||
$item->fieldInputOverride = $form->getSelectConditionsPaiements($conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID, 'INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID', -1, 1);
|
||||
|
||||
|
||||
/*
|
||||
* Actions
|
||||
@ -67,7 +134,6 @@ llxHeader(
|
||||
'EN:Invoice_Configuration|FR:Configuration_module_facture|ES:ConfiguracionFactura'
|
||||
);
|
||||
|
||||
$form = new Form($db);
|
||||
|
||||
|
||||
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
|
||||
@ -84,170 +150,25 @@ print '<span class="opacitymedium">'.$langs->trans("InvoiceFirstSituationDesc").
|
||||
* Numbering module
|
||||
*/
|
||||
|
||||
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
|
||||
print '<input type="hidden" name="token" value="'.newToken().'">';
|
||||
if ($action == 'edit') {
|
||||
print $formSetup->generateOutput(true);
|
||||
} else {
|
||||
print $formSetup->generateOutput();
|
||||
}
|
||||
|
||||
if (count($formSetup->items) > 0) {
|
||||
if ($action != 'edit') {
|
||||
print '<div class="tabsAction">';
|
||||
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>';
|
||||
print '</div>';
|
||||
}
|
||||
} else {
|
||||
print '<br>'.$langs->trans("NothingToSetup");
|
||||
}
|
||||
|
||||
print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
|
||||
print '<table class="noborder centpercent">';
|
||||
|
||||
print '<tr class="liste_titre">';
|
||||
print '<td>'.$langs->trans("Parameter").'</td>';
|
||||
print '<td align="center" width="60">'.$langs->trans("Value").'</td>';
|
||||
print '<td width="80"> </td>';
|
||||
print "</tr>\n";
|
||||
|
||||
_printOnOff('INVOICE_USE_SITUATION', $langs->trans('UseSituationInvoices'));
|
||||
_printOnOff('INVOICE_USE_SITUATION_CREDIT_NOTE', $langs->trans('UseSituationInvoicesCreditNote'));
|
||||
//_printOnOff('INVOICE_USE_RETAINED_WARRANTY', $langs->trans('Retainedwarranty'));
|
||||
|
||||
$confkey = 'INVOICE_USE_RETAINED_WARRANTY';
|
||||
|
||||
$arrayAvailableType = array(
|
||||
Facture::TYPE_SITUATION => $langs->trans("InvoiceSituation"),
|
||||
Facture::TYPE_STANDARD.'+'.Facture::TYPE_SITUATION => $langs->trans("InvoiceSituation").' + '.$langs->trans("InvoiceStandard"),
|
||||
);
|
||||
$selected = $conf->global->$confkey;
|
||||
$curentInput = (empty($inputCount) ? 1 : ($inputCount + 1));
|
||||
$formSelectInvoiceType = $form->selectarray('value'.$curentInput, $arrayAvailableType, $selected, 1);
|
||||
_printInputFormPart($confkey, $langs->trans('AllowedInvoiceForRetainedWarranty'), '', array(), $formSelectInvoiceType);
|
||||
|
||||
//_printOnOff('INVOICE_RETAINED_WARRANTY_LIMITED_TO_SITUATION', $langs->trans('RetainedwarrantyOnlyForSituation'));
|
||||
_printOnOff('INVOICE_RETAINED_WARRANTY_LIMITED_TO_FINAL_SITUATION', $langs->trans('RetainedwarrantyOnlyForSituationFinal'));
|
||||
|
||||
$metas = array(
|
||||
'type' => 'number',
|
||||
'step' => '0.01',
|
||||
'min' => 0,
|
||||
'max' => 100
|
||||
);
|
||||
_printInputFormPart('INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_PERCENT', $langs->trans('RetainedwarrantyDefaultPercent'), '', $metas);
|
||||
|
||||
// Conditions paiements
|
||||
$inputCount = empty($inputCount) ? 1 : ($inputCount + 1);
|
||||
print '<tr class="oddeven">';
|
||||
print '<td>'.$langs->trans('PaymentConditionsShortRetainedWarranty').'</td>';
|
||||
print '<td class="center" width="20"> </td>';
|
||||
print '<td class="right" width="300">';
|
||||
print '<input type="hidden" name="param'.$inputCount.'" value="INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID">';
|
||||
$form->select_conditions_paiements($conf->global->INVOICE_SITUATION_DEFAULT_RETAINED_WARRANTY_COND_ID, 'value'.$inputCount, -1, 1);
|
||||
print '</td></tr>';
|
||||
|
||||
|
||||
print '</table>';
|
||||
print '</div>';
|
||||
|
||||
print '<br>';
|
||||
|
||||
_updateBtn();
|
||||
|
||||
print '</form>';
|
||||
|
||||
print dol_get_fiche_end();
|
||||
|
||||
// End of page
|
||||
llxFooter();
|
||||
$db->close();
|
||||
|
||||
/**
|
||||
* Print an update button
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function _updateBtn()
|
||||
{
|
||||
global $langs;
|
||||
print '<div class="center">';
|
||||
print '<input type="submit" class="button button-save" value="'.$langs->trans("Save").'">';
|
||||
print '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a On/Off button
|
||||
*
|
||||
* @param string $confkey the conf key
|
||||
* @param bool $title Title of conf
|
||||
* @param string $desc Description
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function _printOnOff($confkey, $title = false, $desc = '')
|
||||
{
|
||||
global $langs;
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
print '<td>'.($title ? $title : $langs->trans($confkey));
|
||||
if (!empty($desc)) {
|
||||
print '<br><small>'.$langs->trans($desc).'</small>';
|
||||
}
|
||||
print '</td>';
|
||||
print '<td class="center" width="20"> </td>';
|
||||
print '<td class="right" width="300">';
|
||||
print ajax_constantonoff($confkey);
|
||||
print '</td></tr>';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print a form part
|
||||
*
|
||||
* @param string $confkey the conf key
|
||||
* @param bool $title Title of conf
|
||||
* @param string $desc Description of
|
||||
* @param array $metas html meta
|
||||
* @param string $type type of input textarea or input
|
||||
* @param bool $help help description
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function _printInputFormPart($confkey, $title = false, $desc = '', $metas = array(), $type = 'input', $help = false)
|
||||
{
|
||||
global $langs, $conf, $db, $inputCount;
|
||||
|
||||
$inputCount = empty($inputCount) ? 1 : ($inputCount + 1);
|
||||
$form = new Form($db);
|
||||
|
||||
$defaultMetas = array(
|
||||
'name' => 'value'.$inputCount
|
||||
);
|
||||
|
||||
if ($type != 'textarea') {
|
||||
$defaultMetas['type'] = 'text';
|
||||
$defaultMetas['value'] = $conf->global->{$confkey};
|
||||
}
|
||||
|
||||
|
||||
$metas = array_merge($defaultMetas, $metas);
|
||||
$metascompil = '';
|
||||
foreach ($metas as $key => $values) {
|
||||
$metascompil .= ' '.$key.'="'.$values.'" ';
|
||||
}
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
print '<td>';
|
||||
|
||||
if (!empty($help)) {
|
||||
print $form->textwithtooltip(($title ? $title : $langs->trans($confkey)), $langs->trans($help), 2, 1, img_help(1, ''));
|
||||
} else {
|
||||
print $title ? $title : $langs->trans($confkey);
|
||||
}
|
||||
|
||||
if (!empty($desc)) {
|
||||
print '<br><small>'.$langs->trans($desc).'</small>';
|
||||
}
|
||||
|
||||
print '</td>';
|
||||
print '<td class="center" width="20"> </td>';
|
||||
print '<td class="right" width="300">';
|
||||
print '<input type="hidden" name="param'.$inputCount.'" value="'.$confkey.'">';
|
||||
print '<input type="hidden" name="action" value="setModuleOptions">';
|
||||
if ($type == 'textarea') {
|
||||
print '<textarea '.$metascompil.' >'.dol_htmlentities($conf->global->{$confkey}).'</textarea>';
|
||||
} elseif ($type == 'input') {
|
||||
print '<input '.$metascompil.' />';
|
||||
} else {
|
||||
// custom
|
||||
print $type;
|
||||
}
|
||||
print '</td></tr>';
|
||||
}
|
||||
|
||||
@ -535,11 +535,11 @@ if ($mode == 'common' || $mode == 'commonkanban') {
|
||||
|
||||
//$moreforfilter .= '<div class="floatright center marginrightonly hideonsmartphone" style="padding-top: 3px"><span class="paddingright">'.$moreinfo.'</span> '.$moreinfo2.'</div>';
|
||||
|
||||
$moreforfilter .= '<div class="colorbacktimesheet float valignmiddle">';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop">';
|
||||
$moreforfilter .= '<div class="divfilteralone colorbacktimesheet float valignmiddle">';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">';
|
||||
$moreforfilter .= img_picto($langs->trans("Filter"), 'filter', 'class="paddingright opacityhigh hideonsmartphone"').'<input type="text" id="search_keyword" name="search_keyword" class="maxwidth125" value="'.dol_escape_htmltag($search_keyword).'" placeholder="'.dol_escape_htmltag($langs->trans('Keyword')).'">';
|
||||
$moreforfilter .= '</div>';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop">';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">';
|
||||
$moreforfilter .= $form->selectarray('search_nature', $arrayofnatures, dol_escape_htmltag($search_nature), $langs->trans('Origin'), 0, 0, '', 0, 0, 0, '', 'maxwidth250', 1);
|
||||
$moreforfilter .= '</div>';
|
||||
if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
|
||||
@ -553,16 +553,16 @@ if ($mode == 'common' || $mode == 'commonkanban') {
|
||||
if ($conf->global->MAIN_FEATURES_LEVEL > 1) {
|
||||
$array_version['development'] = $langs->trans("Development");
|
||||
}
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop">';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">';
|
||||
$moreforfilter .= $form->selectarray('search_version', $array_version, $search_version, $langs->trans('Version'), 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1);
|
||||
$moreforfilter .= '</div>';
|
||||
}
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop">';
|
||||
$moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">';
|
||||
$moreforfilter .= $form->selectarray('search_status', array('active'=>$langs->transnoentitiesnoconv("Enabled"), 'disabled'=>$langs->transnoentitiesnoconv("Disabled")), $search_status, $langs->trans('Status'), 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1);
|
||||
$moreforfilter .= '</div>';
|
||||
$moreforfilter .= ' ';
|
||||
$moreforfilter .= '<div class="divsearchfield">';
|
||||
$moreforfilter .= '<input type="submit" name="buttonsubmit" class="button" value="'.dol_escape_htmltag($langs->trans("Refresh")).'">';
|
||||
$moreforfilter .= '<div class="divsearchfield valignmiddle inline-block">';
|
||||
$moreforfilter .= '<input type="submit" name="buttonsubmit" class="button small" value="'.dol_escape_htmltag($langs->trans("Refresh")).'">';
|
||||
if ($search_keyword || ($search_nature && $search_nature != '-1') || ($search_version && $search_version != '-1') || ($search_status && $search_status != '-1')) {
|
||||
$moreforfilter .= ' ';
|
||||
$moreforfilter .= '<input type="submit" name="buttonreset" class="buttonreset noborderbottom" value="'.dol_escape_htmltag($langs->trans("Reset")).'">';
|
||||
@ -1139,7 +1139,7 @@ if ($mode == 'deploy') {
|
||||
}
|
||||
|
||||
if ($allowfromweb == 1) {
|
||||
print $langs->trans("UnpackPackageInModulesRoot", $dirins).'<br>';
|
||||
print '<span class="opacitymedium">'.$langs->trans("UnpackPackageInModulesRoot", $dirins).'</span><br>';
|
||||
|
||||
print '<br>';
|
||||
|
||||
|
||||
@ -400,8 +400,6 @@ print '</td>';
|
||||
print '</tr>';
|
||||
print '</table>';
|
||||
|
||||
print '</td></tr>';
|
||||
print '</table>';
|
||||
|
||||
|
||||
|
||||
@ -538,6 +536,8 @@ if (!empty($_SESSION["commandbackuptorun"])) {
|
||||
|
||||
print "</div> <!-- end div center button -->\n";
|
||||
|
||||
print '</td></tr>';
|
||||
print '</table>';
|
||||
|
||||
print "</div> <!-- end div fichehalfleft -->\n";
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ $dirtocompress = basename($fulldirtocompress);
|
||||
|
||||
if ($compression == 'zip') {
|
||||
$file .= '.zip';
|
||||
$excludefiles = '/(\.back|\.old|\.log|[\/\\\]temp[\/\\\]|documents[\/\\\]admin[\/\\\]documents[\/\\\])/i';
|
||||
$excludefiles = '/(\.back|\.old|\.log|\.pdf_preview-.*\.png|[\/\\\]temp[\/\\\]|documents[\/\\\]admin[\/\\\]documents[\/\\\])/i';
|
||||
|
||||
//var_dump($fulldirtocompress);
|
||||
//var_dump($outputdir."/".$file);exit;
|
||||
@ -173,7 +173,7 @@ if ($compression == 'zip') {
|
||||
|
||||
// We also exclude '/temp/' dir and 'documents/admin/documents'
|
||||
// We make escapement here and call executeCLI without escapement because we don't want to have the '*.log' escaped.
|
||||
$cmd = "tar -cf ".escapeshellcmd($outputdir."/".$file)." --exclude-vcs --exclude-caches-all --exclude='temp' --exclude='*.log' --exclude='documents/admin/documents' -C '".escapeshellcmd(dol_sanitizePathName($dirtoswitch))."' '".escapeshellcmd(dol_sanitizeFileName($dirtocompress))."'";
|
||||
$cmd = "tar -cf ".escapeshellcmd($outputdir."/".$file)." --exclude-vcs --exclude-caches-all --exclude='temp' --exclude='*.log' --exclude='*.pdf_preview-*.png' --exclude='documents/admin/documents' -C '".escapeshellcmd(dol_sanitizePathName($dirtoswitch))."' '".escapeshellcmd(dol_sanitizeFileName($dirtocompress))."'";
|
||||
|
||||
$result = $utils->executeCLI($cmd, $outputfile, 0, null, 1);
|
||||
|
||||
|
||||
@ -624,6 +624,9 @@ class Documents extends DolibarrApi
|
||||
} elseif ($modulepart == 'expensereport') {
|
||||
require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
|
||||
$object = new ExpenseReport($this->db);
|
||||
} elseif ($modulepart == 'fichinter') {
|
||||
require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
|
||||
$object = new Fichinter($this->db);
|
||||
} elseif ($modulepart == 'adherent' || $modulepart == 'member') {
|
||||
$modulepart = 'adherent';
|
||||
require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
|
||||
|
||||
@ -261,6 +261,11 @@ class Commande extends CommonOrder
|
||||
//! key of pos source ('0', '1', ...)
|
||||
public $pos_source;
|
||||
|
||||
/**
|
||||
* @var array Array with line of all shipments
|
||||
*/
|
||||
public $expeditions;
|
||||
|
||||
|
||||
/**
|
||||
* 'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
|
||||
@ -490,7 +495,8 @@ class Commande extends CommonOrder
|
||||
$sql .= " SET ref = '".$this->db->escape($num)."',";
|
||||
$sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
|
||||
$sql .= " date_valid='".$this->db->idate($now)."',";
|
||||
$sql .= " fk_user_valid = ".((int) $user->id);
|
||||
$sql .= " fk_user_valid = ".((int) $user->id).",";
|
||||
$sql .= " fk_user_modif = ".((int) $user->id);
|
||||
$sql .= " WHERE rowid = ".((int) $this->id);
|
||||
|
||||
dol_syslog(get_class($this)."::valid", LOG_DEBUG);
|
||||
@ -620,7 +626,8 @@ class Commande extends CommonOrder
|
||||
$this->db->begin();
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."commande";
|
||||
$sql .= " SET fk_statut = ".self::STATUS_DRAFT;
|
||||
$sql .= " SET fk_statut = ".self::STATUS_DRAFT."',";
|
||||
$sql .= " fk_user_modif = ".((int) $user->id);
|
||||
$sql .= " WHERE rowid = ".((int) $this->id);
|
||||
|
||||
if ($this->db->query($sql)) {
|
||||
@ -694,7 +701,8 @@ class Commande extends CommonOrder
|
||||
$this->db->begin();
|
||||
|
||||
$sql = 'UPDATE '.MAIN_DB_PREFIX.'commande';
|
||||
$sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0';
|
||||
$sql .= ' SET fk_statut='.self::STATUS_VALIDATED.', facture=0,';
|
||||
$sql .= " fk_user_modif = ".((int) $user->id);
|
||||
$sql .= " WHERE rowid = ".((int) $this->id);
|
||||
|
||||
dol_syslog(get_class($this)."::set_reopen", LOG_DEBUG);
|
||||
@ -755,7 +763,8 @@ class Commande extends CommonOrder
|
||||
$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
|
||||
$sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
|
||||
$sql .= ' fk_user_cloture = '.((int) $user->id).',';
|
||||
$sql .= " date_cloture = '".$this->db->idate($now)."'";
|
||||
$sql .= " date_cloture = '".$this->db->idate($now)."',";
|
||||
$sql .= " fk_user_modif = ".((int) $user->id);
|
||||
$sql .= " WHERE rowid = ".((int) $this->id).' AND fk_statut > '.self::STATUS_DRAFT;
|
||||
|
||||
if ($this->db->query($sql)) {
|
||||
@ -803,7 +812,8 @@ class Commande extends CommonOrder
|
||||
$this->db->begin();
|
||||
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."commande";
|
||||
$sql .= " SET fk_statut = ".self::STATUS_CANCELED;
|
||||
$sql .= " SET fk_statut = ".self::STATUS_CANCELED.",";
|
||||
$sql .= " fk_user_modif = ".((int) $user->id);
|
||||
$sql .= " WHERE rowid = ".((int) $this->id);
|
||||
$sql .= " AND fk_statut = ".self::STATUS_VALIDATED;
|
||||
|
||||
@ -1779,7 +1789,7 @@ class Commande extends CommonOrder
|
||||
return -1;
|
||||
}
|
||||
|
||||
$sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut';
|
||||
$sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_user_modif, c.fk_statut';
|
||||
$sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
|
||||
$sql .= ', c.fk_account';
|
||||
$sql .= ', c.date_commande, c.date_valid, c.tms';
|
||||
@ -1844,6 +1854,7 @@ class Commande extends CommonOrder
|
||||
|
||||
$this->user_author_id = $obj->fk_user_author;
|
||||
$this->user_valid = $obj->fk_user_valid;
|
||||
$this->user_modification = $obj->fk_user_modif;
|
||||
$this->total_ht = $obj->total_ht;
|
||||
$this->total_tva = $obj->total_tva;
|
||||
$this->total_localtax1 = $obj->total_localtax1;
|
||||
@ -2004,9 +2015,9 @@ class Commande extends CommonOrder
|
||||
/**
|
||||
* Load array lines
|
||||
*
|
||||
* @param int $only_product Return only physical products, not services
|
||||
* @param int $only_product Return only physical products, not services
|
||||
* @param int $loadalsotranslation Return translation for products
|
||||
* @return int <0 if KO, >0 if OK
|
||||
* @return int <0 if KO, >0 if OK
|
||||
*/
|
||||
public function fetch_lines($only_product = 0, $loadalsotranslation = 0)
|
||||
{
|
||||
@ -2201,9 +2212,10 @@ class Commande extends CommonOrder
|
||||
* Note: For a dedicated shipment, the fetch_lines can be used to load the qty_asked and qty_shipped. This function is use to return qty_shipped cumulated for the order
|
||||
*
|
||||
* @param int $filtre_statut Filter on shipment status
|
||||
* @param int $fk_product Add a filter on a product
|
||||
* @return int <0 if KO, Nb of lines found if OK
|
||||
*/
|
||||
public function loadExpeditions($filtre_statut = -1)
|
||||
public function loadExpeditions($filtre_statut = -1, $fk_product = 0)
|
||||
{
|
||||
$this->expeditions = array();
|
||||
|
||||
|
||||
@ -1854,10 +1854,13 @@ if ($resql) {
|
||||
print '<td class="center">';
|
||||
if (!empty($show_shippable_command) && !empty($conf->stock->enabled)) {
|
||||
if (($obj->fk_statut > $generic_commande::STATUS_DRAFT) && ($obj->fk_statut < $generic_commande::STATUS_CLOSED)) {
|
||||
$generic_commande->getLinesArray(); // This set ->lines
|
||||
$generic_commande->getLinesArray(); // Load array ->lines
|
||||
$generic_commande->loadExpeditions(); // Load array ->expeditions
|
||||
|
||||
$numlines = count($generic_commande->lines); // Loop on each line of order
|
||||
for ($lig = 0; $lig < $numlines; $lig++) {
|
||||
$reliquat = $generic_commande->lines[$lig]->qty - $generic_commande->expeditions[$generic_commande->lines[$lig]->id];
|
||||
|
||||
if ($generic_commande->lines[$lig]->product_type == 0 && $generic_commande->lines[$lig]->fk_product > 0) { // If line is a product and not a service
|
||||
$nbprod++; // order contains real products
|
||||
$generic_product->id = $generic_commande->lines[$lig]->fk_product;
|
||||
@ -1872,15 +1875,15 @@ if ($resql) {
|
||||
$generic_product->stock_theorique = $productstat_cachevirtual[$generic_commande->lines[$lig]->fk_product]['stock_reel'] = $generic_product->stock_theorique;
|
||||
}
|
||||
|
||||
if ($reliquat > $generic_product->stock_reel) {
|
||||
$notshippable++;
|
||||
}
|
||||
if (empty($conf->global->SHIPPABLE_ORDER_ICON_IN_LIST)) { // Default code. Default should be this case.
|
||||
$text_info .= $generic_commande->lines[$lig]->qty.' X '.$generic_commande->lines[$lig]->product_ref.' '.dol_trunc($generic_commande->lines[$lig]->product_label, 25);
|
||||
$text_info .= $reliquat.' x '.$generic_commande->lines[$lig]->product_ref.' '.dol_trunc($generic_commande->lines[$lig]->product_label, 20);
|
||||
$text_info .= ' - '.$langs->trans("Stock").': <span class="'.($generic_product->stock_reel > 0 ? 'ok' : 'error').'">'.$generic_product->stock_reel.'</span>';
|
||||
$text_info .= ' - '.$langs->trans("VirtualStock").': <span class="'.($generic_product->stock_theorique > 0 ? 'ok' : 'error').'">'.$generic_product->stock_theorique.'</span>';
|
||||
$text_info .= ($reliquat != $generic_commande->lines[$lig]->qty ? ' <span class="opacitymedium">('.$langs->trans("QtyInOtherShipments").' '.($generic_commande->lines[$lig]->qty - $reliquat).')</span>' : '');
|
||||
$text_info .= '<br>';
|
||||
|
||||
if ($generic_commande->lines[$lig]->qty > $generic_product->stock_reel) {
|
||||
$notshippable++;
|
||||
}
|
||||
} else { // BUGGED CODE.
|
||||
// DOES NOT TAKE INTO ACCOUNT MANUFACTURING. THIS CODE SHOULD BE USELESS. PREVIOUS CODE SEEMS COMPLETE.
|
||||
// COUNT STOCK WHEN WE SHOULD ALREADY HAVE VALUE
|
||||
@ -1908,32 +1911,31 @@ if ($resql) {
|
||||
$stock_order_supplier = $generic_product->stats_commande_fournisseur['qty'];
|
||||
}
|
||||
}
|
||||
$text_info .= $generic_commande->lines[$lig]->qty.' X '.$generic_commande->lines[$lig]->ref.' '.dol_trunc($generic_commande->lines[$lig]->product_label, 25);
|
||||
$text_info .= $reliquat.' x '.$generic_commande->lines[$lig]->ref.' '.dol_trunc($generic_commande->lines[$lig]->product_label, 20);
|
||||
$text_stock_reel = $generic_product->stock_reel.'/'.$stock_order;
|
||||
if ($stock_order > $generic_product->stock_reel && !($generic_product->stock_reel < $generic_commande->lines[$lig]->qty)) {
|
||||
$warning++;
|
||||
$text_warning .= '<span class="warning">'.$langs->trans('Available').' : '.$text_stock_reel.'</span>';
|
||||
}
|
||||
if ($generic_product->stock_reel < $generic_commande->lines[$lig]->qty) {
|
||||
$notshippable++;
|
||||
if ($reliquat > $generic_product->stock_reel) {
|
||||
$text_info .= '<span class="warning">'.$langs->trans('Available').' : '.$text_stock_reel.'</span>';
|
||||
} else {
|
||||
$text_info .= '<span class="ok">'.$langs->trans('Available').' : '.$text_stock_reel.'</span>';
|
||||
}
|
||||
if ((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled)) {
|
||||
$text_info .= ' '.$langs->trans('SupplierOrder').' : '.$stock_order_supplier.'<br>';
|
||||
} else {
|
||||
$text_info .= '<br>';
|
||||
$text_info .= ' '.$langs->trans('SupplierOrder').' : '.$stock_order_supplier;
|
||||
}
|
||||
$text_info .= ($reliquat != $generic_commande->lines[$lig]->qty ? ' <span class="opacitymedium">('.$langs->trans("QtyInOtherShipments").' '.($generic_commande->lines[$lig]->qty - $reliquat).')</span>' : '');
|
||||
$text_info .= '<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($notshippable == 0) {
|
||||
$text_icon = img_picto('', 'dolly', '', false, 0, 0, '', 'green paddingleft');
|
||||
$text_info = $langs->trans('Shippable').'<br>'.$text_info;
|
||||
$text_info = $text_icon.' '.$langs->trans('Shippable').'<br>'.$text_info;
|
||||
} else {
|
||||
$text_icon = img_picto('', 'dolly', '', false, 0, 0, '', 'error paddingleft');
|
||||
$text_info = $langs->trans('NonShippable').'<br>'.$text_info;
|
||||
$text_info = $text_icon.' '.$langs->trans('NonShippable').'<br>'.$text_info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1339,14 +1339,15 @@ if ($resql) {
|
||||
$labeltoshow = $langs->trans($reg[1]);
|
||||
} else {
|
||||
if ($objp->label == '(payment_salary)') {
|
||||
$labeltoshow = dol_trunc($langs->trans("SalaryPayment", 40));
|
||||
$labeltoshow = $langs->trans("SalaryPayment");
|
||||
} else {
|
||||
$labeltoshow = dol_escape_htmltag($objp->label);
|
||||
$titletoshow = $objp->label;
|
||||
}
|
||||
}
|
||||
print '<td class="tdoverflowmax300"'.($titletoshow ? ' title="'.dol_escape_htmltag($titletoshow).'"' : '').'>';
|
||||
print $labeltoshow; // Already escaped
|
||||
|
||||
|
||||
print '<td class="tdoverflowmax250"'.($titletoshow ? ' title="'.dol_escape_htmltag($titletoshow).'"' : '').'>';
|
||||
|
||||
// Add info about links after description
|
||||
$cachebankaccount = array();
|
||||
@ -1355,70 +1356,70 @@ if ($resql) {
|
||||
if ($links[$key]['type'] == 'withdraw') {
|
||||
$banktransferstatic->id = $links[$key]['url_id'];
|
||||
$banktransferstatic->ref = $links[$key]['label'];
|
||||
print ' '.$banktransferstatic->getNomUrl(0);
|
||||
print $banktransferstatic->getNomUrl(0).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment') {
|
||||
$paymentstatic->id = $links[$key]['url_id'];
|
||||
$paymentstatic->ref = $links[$key]['url_id']; // FIXME This is id, not ref of payment
|
||||
$paymentstatic->date = $db->jdate($objp->do);
|
||||
print ' '.$paymentstatic->getNomUrl(2);
|
||||
print $paymentstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_supplier') {
|
||||
$paymentsupplierstatic->id = $links[$key]['url_id'];
|
||||
$paymentsupplierstatic->ref = $links[$key]['url_id']; // FIXME This is id, not ref of payment
|
||||
print ' '.$paymentsupplierstatic->getNomUrl(2);
|
||||
print $paymentsupplierstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_sc') {
|
||||
$paymentscstatic->id = $links[$key]['url_id'];
|
||||
$paymentscstatic->ref = $links[$key]['url_id'];
|
||||
$paymentscstatic->label = $links[$key]['label'];
|
||||
print ' '.$paymentscstatic->getNomUrl(2);
|
||||
print $paymentscstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_vat') {
|
||||
$paymentvatstatic->id = $links[$key]['url_id'];
|
||||
$paymentvatstatic->ref = $links[$key]['url_id'];
|
||||
print ' '.$paymentvatstatic->getNomUrl(2);
|
||||
print $paymentvatstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_salary') {
|
||||
$paymentsalstatic->id = $links[$key]['url_id'];
|
||||
$paymentsalstatic->ref = $links[$key]['url_id'];
|
||||
$paymentsalstatic->label = $links[$key]['label'];
|
||||
print ' '.$paymentsalstatic->getNomUrl(2);
|
||||
print $paymentsalstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_loan') {
|
||||
print '<a href="'.DOL_URL_ROOT.'/loan/payment/card.php?id='.$links[$key]['url_id'].'">';
|
||||
print ' '.img_object($langs->trans('ShowPayment'), 'payment').' ';
|
||||
print '</a>';
|
||||
print '</a> ';
|
||||
} elseif ($links[$key]['type'] == 'payment_donation') {
|
||||
$paymentdonationstatic->id = $links[$key]['url_id'];
|
||||
$paymentdonationstatic->ref = $links[$key]['url_id'];
|
||||
print ' '.$paymentdonationstatic->getNomUrl(2);
|
||||
print $paymentdonationstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_expensereport') {
|
||||
$paymentexpensereportstatic->id = $links[$key]['url_id'];
|
||||
$paymentexpensereportstatic->ref = $links[$key]['url_id'];
|
||||
print ' '.$paymentexpensereportstatic->getNomUrl(2);
|
||||
print $paymentexpensereportstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'payment_various') {
|
||||
$paymentvariousstatic->id = $links[$key]['url_id'];
|
||||
$paymentvariousstatic->ref = $links[$key]['url_id'];
|
||||
print ' '.$paymentvariousstatic->getNomUrl(2);
|
||||
print $paymentvariousstatic->getNomUrl(2).' ';
|
||||
} elseif ($links[$key]['type'] == 'banktransfert') {
|
||||
// Do not show link to transfer since there is no transfer card (avoid confusion). Can already be accessed from transaction detail.
|
||||
if ($objp->amount > 0) {
|
||||
$banklinestatic->fetch($links[$key]['url_id']);
|
||||
$bankstatic->id = $banklinestatic->fk_account;
|
||||
$bankstatic->label = $banklinestatic->bank_account_ref;
|
||||
print ' ('.$langs->trans("TransferFrom").' ';
|
||||
print $langs->trans("TransferFrom").' ';
|
||||
print $bankstatic->getNomUrl(1, 'transactions');
|
||||
print ' '.$langs->trans("toward").' ';
|
||||
$bankstatic->id = $objp->bankid;
|
||||
$bankstatic->label = $objp->bankref;
|
||||
print $bankstatic->getNomUrl(1, '');
|
||||
print ')';
|
||||
print ' - ';
|
||||
} else {
|
||||
$bankstatic->id = $objp->bankid;
|
||||
$bankstatic->label = $objp->bankref;
|
||||
print ' ('.$langs->trans("TransferFrom").' ';
|
||||
print $langs->trans("TransferFrom").' ';
|
||||
print $bankstatic->getNomUrl(1, '');
|
||||
print ' '.$langs->trans("toward").' ';
|
||||
$banklinestatic->fetch($links[$key]['url_id']);
|
||||
$bankstatic->id = $banklinestatic->fk_account;
|
||||
$bankstatic->label = $banklinestatic->bank_account_ref;
|
||||
print $bankstatic->getNomUrl(1, 'transactions');
|
||||
print ')';
|
||||
print ' - ';
|
||||
}
|
||||
//var_dump($links);
|
||||
} elseif ($links[$key]['type'] == 'company') {
|
||||
@ -1430,22 +1431,22 @@ if ($resql) {
|
||||
// Information is already shown using the payment_salary link. No need of this link.
|
||||
} else {
|
||||
// Show link with label $links[$key]['label']
|
||||
if (!empty($objp->label) && !empty($links[$key]['label'])) {
|
||||
print ' - ';
|
||||
}
|
||||
print '<a href="'.$links[$key]['url'].$links[$key]['url_id'].'">';
|
||||
if (preg_match('/^\((.*)\)$/i', $links[$key]['label'], $reg)) {
|
||||
// Label generique car entre parentheses. On l'affiche en le traduisant
|
||||
if ($reg[1] == 'paiement') {
|
||||
$reg[1] = 'Payment';
|
||||
}
|
||||
print ' '.$langs->trans($reg[1]);
|
||||
print $langs->trans($reg[1]);
|
||||
} else {
|
||||
print ' '.$links[$key]['label'];
|
||||
print $links[$key]['label'];
|
||||
}
|
||||
print '</a>';
|
||||
print '</a>'.($labeltoshow ? ' - ' : '');
|
||||
}
|
||||
}
|
||||
|
||||
print $labeltoshow; // Already escaped
|
||||
|
||||
print '</td>';
|
||||
if (!$i) {
|
||||
$totalarray['nbfield']++;
|
||||
@ -1488,7 +1489,7 @@ if ($resql) {
|
||||
|
||||
// Payment type
|
||||
if (!empty($arrayfields['type']['checked'])) {
|
||||
print '<td align="center" class="nowrap">';
|
||||
print '<td class="tdoverflowmax100 center">';
|
||||
$labeltype = ($langs->trans("PaymentTypeShort".$objp->fk_type) != "PaymentTypeShort".$objp->fk_type) ? $langs->trans("PaymentTypeShort".$objp->fk_type) : $langs->getLabelFromKey($db, $objp->fk_type, 'c_paiement', 'code', 'libelle', '', 1);
|
||||
if ($labeltype == 'SOLD') {
|
||||
print ' '; //$langs->trans("InitialBankBalance");
|
||||
@ -1514,9 +1515,9 @@ if ($resql) {
|
||||
print '<td class="tdoverflowmax150">';
|
||||
|
||||
$companylinked_id = 0;
|
||||
$userlinked_id = 0;
|
||||
$userlinked_id = 0;
|
||||
|
||||
//payment line type to define user display and user or company linked
|
||||
//payment line type to define user display and user or company linked
|
||||
foreach ($links as $key => $value) {
|
||||
if ($links[$key]['type'] == 'payment_sc') {
|
||||
$type_link = 'payment_sc';
|
||||
|
||||
@ -130,6 +130,7 @@ $usercanread = $user->rights->facture->lire;
|
||||
$usercancreate = $user->rights->facture->creer;
|
||||
$usercanissuepayment = $user->rights->facture->paiement;
|
||||
$usercandelete = $user->rights->facture->supprimer;
|
||||
$usercancreatecontract = $user->rights->contrat->creer;
|
||||
$usercanvalidate = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $usercancreate) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->validate)));
|
||||
$usercansend = (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->send)));
|
||||
$usercanreopen = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $usercancreate) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->facture->invoice_advance->reopen)));
|
||||
@ -609,7 +610,7 @@ if (empty($reshook)) {
|
||||
// Check parameters
|
||||
|
||||
// Check for mandatory fields in thirdparty (defined into setup)
|
||||
$array_to_check = array('IDPROF1', 'IDPROF2', 'IDPROF3', 'IDPROF4', 'IDPROF5', 'IDPROF6', 'EMAIL');
|
||||
$array_to_check = array('IDPROF1', 'IDPROF2', 'IDPROF3', 'IDPROF4', 'IDPROF5', 'IDPROF6', 'EMAIL', 'ACCOUNTANCY_CODE_CUSTOMER');
|
||||
foreach ($array_to_check as $key) {
|
||||
$keymin = strtolower($key);
|
||||
$i = (int) preg_replace('/[^0-9]/', '', $key);
|
||||
@ -637,6 +638,14 @@ if (empty($reshook)) {
|
||||
setEventMessages($langs->trans("ErrorBadEMail", $object->thirdparty->email).' ('.$langs->trans("ForbiddenBySetupRules").')', null, 'errors');
|
||||
}
|
||||
}
|
||||
if ($key == 'ACCOUNTANCY_CODE_CUSTOMER') {
|
||||
// Check for mandatory
|
||||
if (!empty($conf->global->SOCIETE_ACCOUNTANCY_CODE_CUSTOMER_INVOICE_MANDATORY) && empty($object->thirdparty->code_compta)) {
|
||||
$langs->load("errors");
|
||||
$error++;
|
||||
setEventMessages($langs->trans("ErrorAccountancyCodeCustomerIsMandatory", $object->thirdparty->name).' ('.$langs->trans("ForbiddenBySetupRules").')', null, 'errors');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3417,6 +3426,10 @@ if ($action == 'create') {
|
||||
$optionsav .= '<option value="'.$key.'"';
|
||||
if ($key == GETPOST('fac_avoir')) {
|
||||
$optionsav .= ' selected';
|
||||
|
||||
// pre-filled extra fields with selected credit note
|
||||
$newinvoice_static->fetch_optionals($key);
|
||||
$object->array_options = $newinvoice_static->array_options;
|
||||
}
|
||||
$optionsav .= '>';
|
||||
$optionsav .= $newinvoice_static->ref;
|
||||
@ -5378,6 +5391,17 @@ if ($action == 'create') {
|
||||
}
|
||||
}
|
||||
|
||||
// Create contract
|
||||
if (!empty($conf->global->CONTRACT_CREATE_FROM_INVOICE)) {
|
||||
if ($conf->contrat->enabled && $object->statut == Facture::STATUS_VALIDATED) {
|
||||
$langs->load("contracts");
|
||||
|
||||
if ($usercancreatecontract) {
|
||||
print '<a class="butAction" href="' . DOL_URL_ROOT . '/contrat/card.php?action=create&origin=' . $object->element . '&originid=' . $object->id . '&socid=' . $object->socid . '">' . $langs->trans('AddContract') . '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate
|
||||
if ($object->statut == Facture::STATUS_DRAFT && count($object->lines) > 0 && ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA || $object->type == Facture::TYPE_SITUATION) && (!empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) || ($object->type == Facture::TYPE_CREDIT_NOTE && $object->total_ttc <= 0))) {
|
||||
if ($usercanvalidate) {
|
||||
|
||||
@ -1622,7 +1622,7 @@ class Facture extends CommonInvoice
|
||||
if ($rowid) {
|
||||
$sql .= " WHERE f.rowid=".((int) $rowid);
|
||||
} else {
|
||||
$sql .= ' WHERE f.entity IN ('.getEntity('invoice').')'; // Dont't use entity if you use rowid
|
||||
$sql .= ' WHERE f.entity IN ('.getEntity('invoice').')'; // Don't use entity if you use rowid
|
||||
if ($ref) {
|
||||
$sql .= " AND f.ref='".$this->db->escape($ref)."'";
|
||||
}
|
||||
|
||||
117
htdocs/contact/project.php
Normal file
117
htdocs/contact/project.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2021 VIAL--GOUTEYRON Quentin <quentin.vial-gouteyron@atm-consulting.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file htdocs/contact/project.php
|
||||
* \ingroup contact
|
||||
* \brief Page of third party projects
|
||||
*/
|
||||
|
||||
require '../main.inc.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
|
||||
|
||||
$langs->loadLangs(array("contacts", "companies", "projects"));
|
||||
|
||||
// Security check
|
||||
$id = GETPOST('id', 'int');
|
||||
$result = restrictedArea($user, 'contact', $id, 'socpeople&societe');
|
||||
|
||||
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
|
||||
$hookmanager->initHooks(array('projectcontact'));
|
||||
|
||||
/*
|
||||
* Actions
|
||||
*/
|
||||
|
||||
$parameters = array('id' => $id);
|
||||
$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');
|
||||
}
|
||||
|
||||
/*
|
||||
* View
|
||||
*/
|
||||
|
||||
$form = new Form($db);
|
||||
|
||||
if ($id) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/contact.lib.php';
|
||||
|
||||
$object = new Contact($db);
|
||||
|
||||
$result = $object->fetch($id);
|
||||
if (empty($object->thirdparty)) {
|
||||
$object->fetch_thirdparty();
|
||||
}
|
||||
$socid = $object->thirdparty->id;
|
||||
$title = $langs->trans("Projects");
|
||||
if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/', $conf->global->MAIN_HTML_TITLE) && $object->name) {
|
||||
$title = $object->name." - ".$title;
|
||||
}
|
||||
llxHeader('', $title);
|
||||
|
||||
if (! empty($conf->notification->enabled)) {
|
||||
$langs->load("mails");
|
||||
}
|
||||
$head = contact_prepare_head($object);
|
||||
|
||||
print dol_get_fiche_head($head, 'project', $langs->trans("Contact"), -1, 'contact');
|
||||
|
||||
$linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
|
||||
|
||||
$morehtmlref = '<div class="refidno">';
|
||||
if (empty($conf->global->SOCIETE_DISABLE_CONTACTS) && !empty($socid)) {
|
||||
$object->thirdparty->fetch($socid);
|
||||
// Thirdparty
|
||||
$morehtmlref .= $langs->trans('ThirdParty').' : ';
|
||||
if ($object->thirdparty->id > 0) {
|
||||
$morehtmlref .= $object->thirdparty->getNomUrl(1, 'contact');
|
||||
} else {
|
||||
$morehtmlref .= $langs->trans("ContactNotLinkedToCompany");
|
||||
}
|
||||
}
|
||||
$morehtmlref .= '</div>';
|
||||
|
||||
dol_banner_tab($object, 'id', $linkback, ($user->socid ? 0 : 1), 'rowid', 'nom', $morehtmlref);
|
||||
|
||||
print '<div class="fichecenter">';
|
||||
|
||||
print '<div class="underbanner clearboth"></div>';
|
||||
print '<table class="border centpercent tableforfield">';
|
||||
|
||||
// Civility
|
||||
print '<tr><td class="titlefield">'.$langs->trans("UserTitle").'</td><td>';
|
||||
print $object->getCivilityLabel();
|
||||
print '</td></tr>';
|
||||
|
||||
print '</table>';
|
||||
|
||||
print '</div>';
|
||||
|
||||
print dol_get_fiche_end();
|
||||
print '<br>';
|
||||
|
||||
// Projects list
|
||||
$result = show_contacts_projects($conf, $langs, $db, $object, $_SERVER["PHP_SELF"].'?id='.$object->id, 1);
|
||||
}
|
||||
|
||||
// End of page
|
||||
llxFooter();
|
||||
$db->close();
|
||||
@ -245,6 +245,8 @@ if ($id > 0) {
|
||||
$newcardbutton = '';
|
||||
if (!empty($conf->agenda->enabled)) {
|
||||
if (!empty($user->rights->agenda->myactions->create) || !empty($user->rights->agenda->allactions->create)) {
|
||||
$backtopage = $_SERVER['PHP_SELF'].'?id='.$object->id;
|
||||
$out = '&origin='.$object->element.'&originid='.$object->id.'&backtopage='.urlencode($backtopage);
|
||||
$newcardbutton .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/comm/action/card.php?action=create'.$out);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/modules/contract/modules_contract.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
||||
if (!empty($conf->propal->enabled)) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
|
||||
}
|
||||
@ -248,6 +249,10 @@ if (empty($reshook)) {
|
||||
if ($element == 'propal') {
|
||||
$element = 'comm/propal'; $subelement = 'propal';
|
||||
}
|
||||
if ($element == 'invoice' || $element == 'facture') {
|
||||
$element = 'compta/facture';
|
||||
$subelement = 'facture';
|
||||
}
|
||||
|
||||
$object->origin = $origin;
|
||||
$object->origin_id = $originid;
|
||||
@ -1040,6 +1045,10 @@ if ($action == 'create') {
|
||||
if ($element == 'propal') {
|
||||
$element = 'comm/propal'; $subelement = 'propal';
|
||||
}
|
||||
if ($element == 'invoice' || $element == 'facture') {
|
||||
$element = 'compta/facture';
|
||||
$subelement = 'facture';
|
||||
}
|
||||
|
||||
dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ if (!$error && $massaction == 'confirm_presend') {
|
||||
$listofobjectref = array();
|
||||
$contactidtosend = array();
|
||||
$attachedfilesThirdpartyObj = array();
|
||||
$oneemailperrecipient = (GETPOST('oneemailperrecipient') == 'on' ? 1 : 0);
|
||||
$oneemailperrecipient = (GETPOST('oneemailperrecipient', 'int') ? 1 : 0);
|
||||
|
||||
if (!$error) {
|
||||
$thirdparty = new Societe($db);
|
||||
|
||||
@ -29,13 +29,13 @@
|
||||
// $formSetup may be defined
|
||||
|
||||
|
||||
if ($action == 'update' && !empty($formSetup) && is_object($formSetup)) {
|
||||
if ($action == 'update' && !empty($formSetup) && is_object($formSetup) && !empty($user->admin)) {
|
||||
$formSetup->saveConfFromPost();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ($action == 'update' && is_array($arrayofparameters)) {
|
||||
if ($action == 'update' && is_array($arrayofparameters) && !empty($user->admin)) {
|
||||
$db->begin();
|
||||
|
||||
foreach ($arrayofparameters as $key => $val) {
|
||||
@ -72,8 +72,37 @@ if ($action == 'update' && is_array($arrayofparameters)) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($action == 'deletefile' && $modulepart == 'doctemplates' && !empty($user->admin)) {
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
$keyforuploaddir = GETPOST('keyforuploaddir', 'aZ09');
|
||||
|
||||
$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString($keyforuploaddir))));
|
||||
foreach ($listofdir as $key => $tmpdir) {
|
||||
$tmpdir = preg_replace('/DOL_DATA_ROOT\/*/', '', $tmpdir); // Clean string if we found a hardcoded DOL_DATA_ROOT
|
||||
if (!$tmpdir) {
|
||||
unset($listofdir[$key]);
|
||||
continue;
|
||||
}
|
||||
$tmpdir = DOL_DATA_ROOT.'/'.$tmpdir; // Complete with DOL_DATA_ROOT. Only files into DOL_DATA_ROOT can be reach/set
|
||||
if (!is_dir($tmpdir)) {
|
||||
if (empty($nomessageinsetmoduleoptions)) {
|
||||
setEventMessages($langs->trans("ErrorDirNotFound", $tmpdir), null, 'warnings');
|
||||
}
|
||||
} else {
|
||||
$upload_dir = $tmpdir;
|
||||
break; // So we take the first directory found into setup $conf->global->$keyforuploaddir
|
||||
}
|
||||
}
|
||||
|
||||
$filetodelete = $tmpdir.'/'.GETPOST('file');
|
||||
$result = dol_delete_file($filetodelete);
|
||||
if ($result > 0) {
|
||||
setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs');
|
||||
}
|
||||
}
|
||||
|
||||
// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...)
|
||||
if ($action == 'setModuleOptions') {
|
||||
if ($action == 'setModuleOptions' && !empty($user->admin)) {
|
||||
$db->begin();
|
||||
|
||||
// Process common param fields
|
||||
@ -97,20 +126,22 @@ if ($action == 'setModuleOptions') {
|
||||
if (GETPOST('upload', 'alpha') && GETPOST('keyforuploaddir', 'aZ09')) {
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
$keyforuploaddir = GETPOST('keyforuploaddir', 'aZ09');
|
||||
$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->$keyforuploaddir)));
|
||||
$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString($keyforuploaddir))));
|
||||
foreach ($listofdir as $key => $tmpdir) {
|
||||
$tmpdir = trim($tmpdir);
|
||||
$tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
|
||||
$tmpdir = preg_replace('/DOL_DATA_ROOT\/*/', '', $tmpdir); // Clean string if we found a hardcoded DOL_DATA_ROOT
|
||||
if (!$tmpdir) {
|
||||
unset($listofdir[$key]);
|
||||
continue;
|
||||
}
|
||||
$tmpdir = DOL_DATA_ROOT.'/'.$tmpdir; // Complete with DOL_DATA_ROOT. Only files into DOL_DATA_ROOT can be reach/set
|
||||
if (!is_dir($tmpdir)) {
|
||||
if (empty($nomessageinsetmoduleoptions)) {
|
||||
setEventMessages($langs->trans("ErrorDirNotFound", $tmpdir), null, 'warnings');
|
||||
}
|
||||
} else {
|
||||
$upload_dir = $tmpdir;
|
||||
break; // So we take the first directory found into setup $conf->global->$keyforuploaddir
|
||||
}
|
||||
}
|
||||
if ($upload_dir) {
|
||||
|
||||
@ -163,7 +163,7 @@ class box_produits_alerte_stock extends ModeleBoxes
|
||||
);
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
|
||||
'td' => 'class="tdoverflowmax100 maxwidth150onsmartphone"',
|
||||
'text' => $objp->label,
|
||||
);
|
||||
|
||||
@ -186,18 +186,13 @@ class box_produits_alerte_stock extends ModeleBoxes
|
||||
}
|
||||
}
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
/*$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="nowraponall right amount"',
|
||||
'text' => $price,
|
||||
);
|
||||
'text' => $price.' '.$price_base_type,
|
||||
);*/
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="right"',
|
||||
'text' => $price_base_type,
|
||||
);
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="center"',
|
||||
'td' => 'class="center nowraponall"',
|
||||
'text' => price2num($objp->total_stock, 'MS').' / '.$objp->seuil_stock_alerte,
|
||||
'text2'=>img_warning($langs->transnoentitiesnoconv("StockLowerThanLimit", $objp->seuil_stock_alerte)),
|
||||
);
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
*/
|
||||
include_once DOL_DOCUMENT_ROOT."/core/boxes/modules_boxes.php";
|
||||
|
||||
|
||||
/**
|
||||
* Class to manage the box to show last projet
|
||||
*/
|
||||
@ -63,7 +64,7 @@ class box_validated_projects extends ModeleBoxes
|
||||
$langs->loadLangs(array('boxes', 'projects'));
|
||||
|
||||
$this->db = $db;
|
||||
$this->boxlabel = "ProjectsWithTask";
|
||||
$this->boxlabel = "ProjectTasksWithoutTimeSpent";
|
||||
|
||||
$this->hidden = !($user->rights->projet->lire);
|
||||
|
||||
@ -116,7 +117,7 @@ class box_validated_projects extends ModeleBoxes
|
||||
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_contact as ec ON ec.element_id = t.rowid AND fk_c_type_contact IN (-1, -2, -3)";
|
||||
$sql .= " WHERE p.fk_statut = 1"; // Only open projects
|
||||
if ($projectsListId) {
|
||||
$sql .= ' AND p.rowid IN ('.$this->db->sanitize($projectsListId).')'; // Only project are allowed
|
||||
$sql .= ' AND p.rowid IN ('.$this->db->sanitize($projectsListId).')'; // Only projects that are allowed
|
||||
}
|
||||
$sql .= " AND t.rowid NOT IN (SELECT fk_task FROM ".MAIN_DB_PREFIX."projet_task_time WHERE fk_user = ".((int) $user->id).")";
|
||||
$sql .= " GROUP BY p.rowid, p.ref, p.fk_soc, p.dateo";
|
||||
|
||||
@ -1215,17 +1215,20 @@ abstract class CommonObject
|
||||
public function delete_linked_contact($source = '', $code = '')
|
||||
{
|
||||
// phpcs:enable
|
||||
$listId = '';
|
||||
$temp = array();
|
||||
$typeContact = $this->liste_type_contact($source, '', 0, 0, $code);
|
||||
|
||||
foreach ($typeContact as $key => $value) {
|
||||
array_push($temp, $key);
|
||||
if (!empty($typeContact)) {
|
||||
foreach ($typeContact as $key => $value) {
|
||||
array_push($temp, $key);
|
||||
}
|
||||
$listId = implode(",", $temp);
|
||||
}
|
||||
$listId = implode(",", $temp);
|
||||
|
||||
$sql = "DELETE FROM ".MAIN_DB_PREFIX."element_contact";
|
||||
$sql .= " WHERE element_id = ".((int) $this->id);
|
||||
if ($listId) {
|
||||
if (!empty($listId)) {
|
||||
$sql .= " AND fk_c_type_contact IN (".$this->db->sanitize($listId).")";
|
||||
}
|
||||
|
||||
@ -7595,7 +7598,7 @@ abstract class CommonObject
|
||||
} else { return true; }
|
||||
} elseif (in_array($type, array('double', 'real', 'price'))) {
|
||||
// is numeric
|
||||
if (!$validate->isDuration($fieldValue)) {
|
||||
if (!$validate->isNumeric($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
|
||||
@ -258,7 +258,7 @@ class Conf
|
||||
// Define all global constants into $this->global->key=value
|
||||
$sql = "SELECT ".$db->decrypt('name')." as name,";
|
||||
$sql .= " ".$db->decrypt('value')." as value, entity";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."const";
|
||||
$sql .= " FROM ".$db->prefix()."const";
|
||||
$sql .= " WHERE entity IN (0,".$this->entity.")";
|
||||
$sql .= " ORDER BY entity"; // This is to have entity 0 first, then entity 1 that overwrite.
|
||||
|
||||
|
||||
@ -1690,11 +1690,17 @@ class Form
|
||||
$out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
|
||||
}
|
||||
|
||||
if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
|
||||
$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'> </option>';
|
||||
if ($showempty && ! is_numeric($showempty)) {
|
||||
$textforempty = $showempty;
|
||||
$out .= '<option class="optiongrey" value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>'.$textforempty.'</option>';
|
||||
}
|
||||
if ($showempty == 2) {
|
||||
$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
|
||||
else {
|
||||
if (($showempty == 1 || ($showempty == 3 && $num > 1)) && ! $multiple) {
|
||||
$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'> </option>';
|
||||
}
|
||||
if ($showempty == 2) {
|
||||
$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
@ -3896,7 +3902,7 @@ class Form
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
||||
/**
|
||||
* Return list of payment modes.
|
||||
* print list of payment modes.
|
||||
* Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
|
||||
* See instead to force the default value by the caller.
|
||||
*
|
||||
@ -3911,8 +3917,28 @@ class Form
|
||||
public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
|
||||
{
|
||||
// phpcs:enable
|
||||
global $langs, $user, $conf;
|
||||
print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return list of payment modes.
|
||||
* Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
|
||||
* See instead to force the default value by the caller.
|
||||
*
|
||||
* @param int $selected Id of payment term to preselect by default
|
||||
* @param string $htmlname Nom de la zone select
|
||||
* @param int $filtertype Not used
|
||||
* @param int $addempty Add an empty entry
|
||||
* @param int $noinfoadmin 0=Add admin info, 1=Disable admin info
|
||||
* @param string $morecss Add more CSS on select tag
|
||||
* @return void
|
||||
*/
|
||||
public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
|
||||
{
|
||||
|
||||
global $langs, $user, $conf;
|
||||
$out = '';
|
||||
dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
|
||||
|
||||
$this->load_cache_conditions_paiements();
|
||||
@ -3922,24 +3948,25 @@ class Form
|
||||
$selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
|
||||
}
|
||||
|
||||
print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
|
||||
$out.= '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
|
||||
if ($addempty) {
|
||||
print '<option value="0"> </option>';
|
||||
$out.= '<option value="0"> </option>';
|
||||
}
|
||||
foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
|
||||
if ($selected == $id) {
|
||||
print '<option value="'.$id.'" selected>';
|
||||
$out.= '<option value="'.$id.'" selected>';
|
||||
} else {
|
||||
print '<option value="'.$id.'">';
|
||||
$out.= '<option value="'.$id.'">';
|
||||
}
|
||||
print $arrayconditions['label'];
|
||||
print '</option>';
|
||||
$out.= $arrayconditions['label'];
|
||||
$out.= '</option>';
|
||||
}
|
||||
print '</select>';
|
||||
$out.= '</select>';
|
||||
if ($user->admin && empty($noinfoadmin)) {
|
||||
print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
|
||||
$out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
|
||||
}
|
||||
print ajax_combobox($htmlname);
|
||||
$out.= ajax_combobox($htmlname);
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -379,9 +379,10 @@ class FormFile
|
||||
* @param Object $object Object when method is called from an object card.
|
||||
* @param int $hideifempty Hide section of generated files if there is no file
|
||||
* @param string $removeaction (optional) The action to remove a file
|
||||
* @param string $tooltipontemplatecombo Text to show on a tooltip after the combo list of templates
|
||||
* @return string Output string with HTML array of documents (might be empty string)
|
||||
*/
|
||||
public function showdocuments($modulepart, $modulesubdir, $filedir, $urlsource, $genallowed, $delallowed = 0, $modelselected = '', $allowgenifempty = 1, $forcenomultilang = 0, $iconPDF = 0, $notused = 0, $noform = 0, $param = '', $title = '', $buttonlabel = '', $codelang = '', $morepicto = '', $object = null, $hideifempty = 0, $removeaction = 'remove_file')
|
||||
public function showdocuments($modulepart, $modulesubdir, $filedir, $urlsource, $genallowed, $delallowed = 0, $modelselected = '', $allowgenifempty = 1, $forcenomultilang = 0, $iconPDF = 0, $notused = 0, $noform = 0, $param = '', $title = '', $buttonlabel = '', $codelang = '', $morepicto = '', $object = null, $hideifempty = 0, $removeaction = 'remove_file', $tooltipontemplatecombo = '')
|
||||
{
|
||||
global $dolibarr_main_url_root;
|
||||
|
||||
@ -769,6 +770,7 @@ class FormFile
|
||||
if ($conf->use_javascript_ajax) {
|
||||
$out .= ajax_combobox('model');
|
||||
}
|
||||
$out .= $form->textwithpicto('', $tooltipontemplatecombo, 1, 'help', 'marginrightonly', 0, 3, '', 0);
|
||||
} else {
|
||||
$out .= '<div class="float">'.$langs->trans("Files").'</div>';
|
||||
}
|
||||
|
||||
@ -157,6 +157,7 @@ class FormMail extends Form
|
||||
|
||||
public $lines_model;
|
||||
|
||||
// -1 suggest the checkbox 'one email per recipient' not checked, 0 = no suggestion, 1 = suggest and checked
|
||||
public $withoptiononeemailperrecipient;
|
||||
|
||||
|
||||
@ -357,7 +358,7 @@ class FormMail extends Form
|
||||
// phpcs:enable
|
||||
global $conf, $langs, $user, $hookmanager, $form;
|
||||
|
||||
// Required to show preview of mail attachments
|
||||
// Required to show preview wof mail attachments
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
|
||||
$formfile = new Formfile($this->db);
|
||||
|
||||
@ -366,7 +367,7 @@ class FormMail extends Form
|
||||
}
|
||||
|
||||
// Load translation files required by the page
|
||||
$langs->loadLangs(array('other', 'mails'));
|
||||
$langs->loadLangs(array('other', 'mails', 'members'));
|
||||
|
||||
// Clear temp files. Must be done before call of triggers, at beginning (mode = init), or when we select a new template
|
||||
if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
|
||||
@ -464,11 +465,10 @@ class FormMail extends Form
|
||||
$modelmail_array = array();
|
||||
if ($this->param['models'] != 'none') {
|
||||
$result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs);
|
||||
|
||||
if ($result < 0) {
|
||||
setEventMessages($this->error, $this->errors, 'errors');
|
||||
}
|
||||
$langs->trans("members");
|
||||
|
||||
foreach ($this->lines_model as $line) {
|
||||
$reg = array();
|
||||
if (preg_match('/\((.*)\)/', $line->label, $reg)) {
|
||||
@ -503,7 +503,7 @@ class FormMail extends Form
|
||||
}
|
||||
|
||||
$out .= ' ';
|
||||
$out .= '<input type="submit" class="button" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
|
||||
$out .= '<input type="submit" class="button reposition" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
|
||||
$out .= ' ';
|
||||
$out .= '</div>';
|
||||
} elseif (!empty($this->param['models']) && in_array($this->param['models'], array(
|
||||
@ -526,7 +526,7 @@ class FormMail extends Form
|
||||
}
|
||||
|
||||
|
||||
$out .= '<table class="tableforemailform boxtablenotop" width="100%">'."\n";
|
||||
$out .= '<table class="tableforemailform boxtablenotop centpercent">'."\n";
|
||||
|
||||
// Substitution array/string
|
||||
$helpforsubstitution = '';
|
||||
@ -688,16 +688,20 @@ class FormMail extends Form
|
||||
|
||||
// With option one email per recipient
|
||||
if (!empty($this->withoptiononeemailperrecipient)) {
|
||||
$out .= '<tr><td class="minwidth200">';
|
||||
$out .= $langs->trans("GroupEmails");
|
||||
$out .= '</td><td>';
|
||||
$out .= ' <input type="checkbox" id="oneemailperrecipient" name="oneemailperrecipient"'.($this->withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> ';
|
||||
$out .= '<label for="oneemailperrecipient">'.$langs->trans("OneEmailPerRecipient").'</label>';
|
||||
$out .= '<span class="hideonsmartphone opacitymedium">';
|
||||
$out .= ' - ';
|
||||
$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail");
|
||||
$out .= '</span>';
|
||||
$out .= '</td></tr>';
|
||||
if (abs($this->withoptiononeemailperrecipient) == 1) {
|
||||
$out .= '<tr><td class="minwidth200">';
|
||||
$out .= $langs->trans("GroupEmails");
|
||||
$out .= '</td><td>';
|
||||
$out .= ' <input type="checkbox" id="oneemailperrecipient" value="1" name="oneemailperrecipient"'.($this->withoptiononeemailperrecipient > 0 ? ' checked="checked"' : '').'> ';
|
||||
$out .= '<label for="oneemailperrecipient">'.$langs->trans("OneEmailPerRecipient").'</label>';
|
||||
$out .= '<span class="hideonsmartphone opacitymedium">';
|
||||
$out .= ' - ';
|
||||
$out .= $langs->trans("WarningIfYouCheckOneRecipientPerEmail");
|
||||
$out .= '</span>';
|
||||
$out .= '</td></tr>';
|
||||
} else {
|
||||
$out .= '<tr><td><input type="hidden" name="oneemailperrecipient" value="1"></td><td></td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
// CC
|
||||
@ -813,8 +817,7 @@ class FormMail extends Form
|
||||
$out .= '<br></div>';
|
||||
}
|
||||
} elseif (empty($this->withmaindocfile)) {
|
||||
// Do not show message if we asked to show the checkbox
|
||||
$out .= $langs->trans("NoAttachedFiles").'<br>';
|
||||
$out .= '<span class="opacitymedium">'.$langs->trans("NoAttachedFiles").'</span><br>';
|
||||
}
|
||||
if ($this->withfile == 2) {
|
||||
// Can add other files
|
||||
@ -1217,6 +1220,7 @@ class FormMail extends Form
|
||||
global $conf, $langs, $form;
|
||||
|
||||
$defaulttopic = GETPOST('subject', 'restricthtml');
|
||||
|
||||
if (!GETPOST('modelselected', 'alpha') || GETPOST('modelmailselected') != '-1') {
|
||||
if ($arraydefaultmessage && $arraydefaultmessage->topic) {
|
||||
$defaulttopic = $arraydefaultmessage->topic;
|
||||
|
||||
@ -1261,7 +1261,7 @@ class FormTicket
|
||||
// Zone to select its email template
|
||||
if (count($modelmail_array) > 0) {
|
||||
print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">'."\n";
|
||||
print $langs->trans('SelectMailModel').': '.$formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], 1);
|
||||
print $langs->trans('SelectMailModel').': '.$formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], 1, 0, "", "", 0, 0, 0, '', 'minwidth200');
|
||||
if ($user->admin) {
|
||||
print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
|
||||
}
|
||||
|
||||
@ -55,18 +55,17 @@ class Validate
|
||||
{
|
||||
global $langs;
|
||||
|
||||
if ($outputLang) {
|
||||
if (empty($outputLang)) {
|
||||
$this->outputLang = $langs;
|
||||
} else {
|
||||
$this->outputLang = $outputLang;
|
||||
}
|
||||
|
||||
if (!is_object($this->outputLang) || !method_exists($outputLang, 'load')) {
|
||||
if (!is_object($this->outputLang) || !method_exists($this->outputLang, 'load')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Translate $outputLang */
|
||||
$outputLang->load('validate');
|
||||
$this->outputLang->loadLangs(array('validate', 'errors'));
|
||||
|
||||
$this->db = $db;
|
||||
}
|
||||
@ -229,6 +228,21 @@ class Validate
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check numeric validity
|
||||
*
|
||||
* @param mixed $string to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isNumeric($string)
|
||||
{
|
||||
if (!is_numeric($string)) {
|
||||
$this->error = $this->outputLang->trans('RequireValidNumeric');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for boolean validity
|
||||
*
|
||||
|
||||
@ -57,6 +57,40 @@ function contact_prepare_head(Contact $object)
|
||||
$head[$tab][2] = 'perso';
|
||||
$tab++;
|
||||
|
||||
if (!empty($conf->projet->enabled) && (!empty($user->rights->projet->lire))) {
|
||||
$nbProject = 0;
|
||||
// Enable caching of thirdrparty count projects
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
|
||||
$cachekey = 'count_projects_contact_'.$object->id;
|
||||
$dataretrieved = dol_getcache($cachekey);
|
||||
|
||||
if (!is_null($dataretrieved)) {
|
||||
$nbProject = $dataretrieved;
|
||||
} else {
|
||||
$sql = 'SELECT COUNT(n.rowid) as nb';
|
||||
$sql .= ' FROM '.MAIN_DB_PREFIX.'projet as n';
|
||||
$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'element_contact as cc ON (n.rowid = cc.element_id)';
|
||||
$sql .= ' WHERE cc.fk_socpeople = '.((int) $object->id);
|
||||
$sql .= ' AND cc.fk_c_type_contact IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'c_type_contact WHERE element="project" AND source="external")';
|
||||
$sql .= ' AND n.entity IN ('.getEntity('project').')';
|
||||
$resql = $db->query($sql);
|
||||
if ($resql) {
|
||||
$obj = $db->fetch_object($resql);
|
||||
$nbProject = $obj->nb;
|
||||
} else {
|
||||
dol_print_error($db);
|
||||
}
|
||||
dol_setcache($cachekey, $nbProject, 120); // If setting cache fails, this is not a problem, so we do not test result.
|
||||
}
|
||||
$head[$tab][0] = DOL_URL_ROOT.'/contact/project.php?id='.$object->id;
|
||||
$head[$tab][1] = $langs->trans("Projects");
|
||||
if ($nbProject > 0) {
|
||||
$head[$tab][1] .= '<span class="badge marginleftonlyshort">'.$nbProject.'</span>';
|
||||
}
|
||||
$head[$tab][2] = 'project';
|
||||
$tab++;
|
||||
}
|
||||
|
||||
// Related items
|
||||
if (!empty($conf->commande->enabled) || !empty($conf->propal->enabled) || !empty($conf->facture->enabled) || !empty($conf->ficheinter->enabled) || (!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) {
|
||||
$head[$tab][0] = DOL_URL_ROOT.'/contact/consumption.php?id='.$object->id;
|
||||
@ -117,3 +151,131 @@ function contact_prepare_head(Contact $object)
|
||||
|
||||
return $head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show html area for list of projects
|
||||
*
|
||||
* @param Conf $conf Object conf
|
||||
* @param Translate $langs Object langs
|
||||
* @param DoliDB $db Database handler
|
||||
* @param Object $object Third party object
|
||||
* @param string $backtopage Url to go once contact is created
|
||||
* @param int $nocreatelink 1=Hide create project link
|
||||
* @param string $morehtmlright More html on right of title
|
||||
* @return int
|
||||
*/
|
||||
function show_contacts_projects($conf, $langs, $db, $object, $backtopage = '', $nocreatelink = 0, $morehtmlright = '')
|
||||
{
|
||||
global $user;
|
||||
|
||||
$i = -1;
|
||||
|
||||
if (!empty($conf->projet->enabled) && $user->rights->projet->lire) {
|
||||
$langs->load("projects");
|
||||
|
||||
$newcardbutton = '';
|
||||
if (!empty($conf->projet->enabled) && $user->rights->projet->creer && empty($nocreatelink)) {
|
||||
$newcardbutton .= dolGetButtonTitle($langs->trans('AddProject'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/projet/card.php?socid='.$object->id.'&action=create&backtopage='.urlencode($backtopage));
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print load_fiche_titre($langs->trans("ProjectsHavingThisContact"), $newcardbutton.$morehtmlright, '');
|
||||
print '<div class="div-table-responsive">';
|
||||
print "\n".'<table class="noborder" width=100%>';
|
||||
|
||||
$sql = 'SELECT p.rowid as id, p.entity, p.title, p.ref, p.public, p.dateo as do, p.datee as de, p.fk_statut as status, p.fk_opp_status, p.opp_amount, p.opp_percent, p.tms as date_update, p.budget_amount';
|
||||
$sql .= ', cls.code as opp_status_code, ctc.libelle';
|
||||
$sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p';
|
||||
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_lead_status as cls on p.fk_opp_status = cls.rowid';
|
||||
$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'element_contact as cc ON (p.rowid = cc.element_id)';
|
||||
$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.'c_type_contact as ctc ON (ctc.rowid = cc.fk_c_type_contact)';
|
||||
$sql .= ' WHERE cc.fk_socpeople = '.((int) $object->id);
|
||||
$sql .= ' AND ctc.element="project" AND ctc.source="external"';
|
||||
$sql .= ' AND p.entity IN ('.getEntity('project').')';
|
||||
$sql .= ' ORDER BY p.dateo DESC';
|
||||
|
||||
$result = $db->query($sql);
|
||||
if ($result) {
|
||||
$num = $db->num_rows($result);
|
||||
|
||||
print '<tr class="liste_titre">';
|
||||
print '<td>'.$langs->trans("Ref").'</td>';
|
||||
print '<td>'.$langs->trans("Name").'</td>';
|
||||
print '<td>'.$langs->trans("ContactType").'</td>';
|
||||
print '<td class="center">'.$langs->trans("DateStart").'</td>';
|
||||
print '<td class="center">'.$langs->trans("DateEnd").'</td>';
|
||||
print '<td class="right">'.$langs->trans("OpportunityAmountShort").'</td>';
|
||||
print '<td class="center">'.$langs->trans("OpportunityStatusShort").'</td>';
|
||||
print '<td class="right">'.$langs->trans("OpportunityProbabilityShort").'</td>';
|
||||
print '<td class="right">'.$langs->trans("Status").'</td>';
|
||||
print '</tr>';
|
||||
|
||||
if ($num > 0) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
|
||||
|
||||
$projecttmp = new Project($db);
|
||||
|
||||
$i = 0;
|
||||
|
||||
while ($i < $num) {
|
||||
$obj = $db->fetch_object($result);
|
||||
$projecttmp->fetch($obj->id);
|
||||
|
||||
// To verify role of users
|
||||
$userAccess = $projecttmp->restrictedProjectArea($user);
|
||||
|
||||
if ($user->rights->projet->lire && $userAccess > 0) {
|
||||
print '<tr class="oddeven">';
|
||||
|
||||
// Ref
|
||||
print '<td>';
|
||||
print $projecttmp->getNomUrl(1);
|
||||
print '</td>';
|
||||
|
||||
// Label
|
||||
print '<td>'.$obj->title.'</td>';
|
||||
print '<td>'.$obj->libelle.'</td>';
|
||||
// Date start
|
||||
print '<td class="center">'.dol_print_date($db->jdate($obj->do), "day").'</td>';
|
||||
// Date end
|
||||
print '<td class="center">'.dol_print_date($db->jdate($obj->de), "day").'</td>';
|
||||
// Opp amount
|
||||
print '<td class="right">';
|
||||
if ($obj->opp_status_code) {
|
||||
print price($obj->opp_amount, 1, '', 1, -1, -1, '');
|
||||
}
|
||||
print '</td>';
|
||||
// Opp status
|
||||
print '<td class="center">';
|
||||
if ($obj->opp_status_code) {
|
||||
print $langs->trans("OppStatus".$obj->opp_status_code);
|
||||
}
|
||||
print '</td>';
|
||||
// Opp percent
|
||||
print '<td class="right">';
|
||||
if ($obj->opp_percent) {
|
||||
print price($obj->opp_percent, 1, '', 1, 0).'%';
|
||||
}
|
||||
print '</td>';
|
||||
// Status
|
||||
print '<td class="right">'.$projecttmp->getLibStatut(5).'</td>';
|
||||
|
||||
print '</tr>';
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
print '<tr class="oddeven"><td colspan="8"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
|
||||
}
|
||||
$db->free($result);
|
||||
} else {
|
||||
dol_print_error($db);
|
||||
}
|
||||
print "</table>";
|
||||
print '</div>';
|
||||
|
||||
print "<br>\n";
|
||||
}
|
||||
|
||||
return $i;
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
* Copyright (C) 2019 Thibault Foucart <support@ptibogxiv.net>
|
||||
* Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
|
||||
* Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
|
||||
* Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -1544,6 +1545,7 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename =
|
||||
// This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
|
||||
$data['ip'] = '???@'.$_SERVER['LOGNAME'];
|
||||
}
|
||||
|
||||
// Loop on each log handler and send output
|
||||
foreach ($conf->loghandlers as $loghandlerinstance) {
|
||||
if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
|
||||
@ -6951,10 +6953,15 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
|
||||
'__USER_ID__' => (string) $user->id,
|
||||
'__USER_LOGIN__' => (string) $user->login,
|
||||
'__USER_EMAIL__' => (string) $user->email,
|
||||
'__USER_PHONE__' => (string) dol_print_phone($user->office_phone),
|
||||
'__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile),
|
||||
'__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile),
|
||||
'__USER_FAX__' => (string) $user->office_fax,
|
||||
'__USER_LASTNAME__' => (string) $user->lastname,
|
||||
'__USER_FIRSTNAME__' => (string) $user->firstname,
|
||||
'__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
|
||||
'__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
|
||||
'__USER_JOB__' => (string) $user->job,
|
||||
'__USER_REMOTE_IP__' => (string) getUserRemoteIP()
|
||||
));
|
||||
}
|
||||
@ -6963,8 +6970,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_PHONE__' => dol_print_phone($mysoc->phone),
|
||||
'__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax),
|
||||
'__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
|
||||
'__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
|
||||
'__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
|
||||
@ -7112,9 +7119,9 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
|
||||
$substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
|
||||
$substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
|
||||
$substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
|
||||
$substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? $object->phone : '');
|
||||
$substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? $object->phone_perso : '');
|
||||
$substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? $object->phone_mobile : '');
|
||||
$substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
|
||||
$substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
|
||||
$substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
|
||||
$substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
|
||||
$substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'dayrfc');
|
||||
$substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->first_subscription_date_start, 'dayrfc');
|
||||
@ -7131,8 +7138,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
|
||||
$substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
|
||||
$substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
|
||||
$substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
|
||||
$substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? $object->phone : '');
|
||||
$substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? $object->fax : '');
|
||||
$substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
|
||||
$substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
|
||||
$substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
|
||||
$substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
|
||||
$substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
|
||||
@ -7154,8 +7161,8 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
|
||||
$substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
|
||||
$substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
|
||||
$substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
|
||||
$substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? $object->thirdparty->phone : '');
|
||||
$substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? $object->thirdparty->fax : '');
|
||||
$substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
|
||||
$substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
|
||||
$substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
|
||||
$substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
|
||||
$substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
|
||||
@ -7236,6 +7243,11 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
|
||||
} elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
|
||||
} elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
|
||||
$substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,9 +35,10 @@
|
||||
* @param string[] $addheaders Array of string to add into header. Example: ('Accept: application/xrds+xml', ....)
|
||||
* @param string[] $allowedschemes List of schemes that are allowed ('http' + 'https' only by default)
|
||||
* @param int $localurl 0=Only external URL are possible, 1=Only local URL, 2=Both external and local URL are allowed.
|
||||
* @param int $ssl_verifypeer -1=Auto (no ssl check on dev, check on prod), 0=No ssl check, 1=Always ssl check
|
||||
* @return array Returns an associative array containing the response from the server array('content'=>response, 'curl_error_no'=>errno, 'curl_error_msg'=>errmsg...)
|
||||
*/
|
||||
function getURLContent($url, $postorget = 'GET', $param = '', $followlocation = 1, $addheaders = array(), $allowedschemes = array('http', 'https'), $localurl = 0)
|
||||
function getURLContent($url, $postorget = 'GET', $param = '', $followlocation = 1, $addheaders = array(), $allowedschemes = array('http', 'https'), $localurl = 0, $ssl_verifypeer = -1)
|
||||
{
|
||||
//declaring of global variables
|
||||
global $conf;
|
||||
@ -75,8 +76,17 @@ function getURLContent($url, $postorget = 'GET', $param = '', $followlocation =
|
||||
}
|
||||
//curl_setopt($ch, CURLOPT_SSLVERSION, 6); for tls 1.2
|
||||
|
||||
// Turning on or off the ssl target certificate
|
||||
if ($ssl_verifypeer < 0) {
|
||||
global $dolibarr_main_prod;
|
||||
$ssl_verifypeer = ($dolibarr_main_prod ? true : false);
|
||||
}
|
||||
if (!empty($conf->global->MAIN_CURL_DISABLE_VERIFYPEER)) {
|
||||
$ssl_verifypeer = 0;
|
||||
}
|
||||
|
||||
// Turning off the server and peer verification(TrustManager Concept).
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, ($ssl_verifypeer ? true : false));
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
|
||||
// Restrict use to some protocols only
|
||||
|
||||
@ -823,7 +823,7 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t
|
||||
}
|
||||
}
|
||||
|
||||
if (count($arrayfields) > 0 && !empty($arrayfields['c.budget_amount']['checked'])) {
|
||||
if (count($arrayfields) > 0 && !empty($arrayfields['t.budget_amount']['checked'])) {
|
||||
print '<td class="center">';
|
||||
print price($lines[$i]->budget_amount, 0, $langs, 1, 0, 0, $conf->currency);
|
||||
$total_budget_amount += $lines[$i]->budget_amount;
|
||||
|
||||
@ -180,7 +180,7 @@ function delivery_prepare_head($object)
|
||||
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
|
||||
$upload_dir = $conf->commande->dir_output."/".dol_sanitizeFileName($tmpobject->ref);
|
||||
$upload_dir = $conf->expedition->dir_output."/sending/".dol_sanitizeFileName($object->ref);
|
||||
$nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
|
||||
$nbLinks = Link::count($db, $tmpobject->element, $tmpobject->id);
|
||||
$head[$h][0] = DOL_URL_ROOT.'/expedition/document.php?id='.$tmpobject->id;
|
||||
|
||||
@ -55,7 +55,7 @@ class modEventOrganization extends DolibarrModules
|
||||
$this->description = "EventOrganizationDescription";
|
||||
$this->descriptionlong = "EventOrganizationDescriptionLong";
|
||||
|
||||
$this->version = 'development';
|
||||
$this->version = 'experimental';
|
||||
|
||||
|
||||
// Key used in llx_const table to save module status enabled/disabled (where EVENTORGANIZATION is value of property name of module in uppercase)
|
||||
|
||||
@ -170,7 +170,10 @@ class doc_generic_product_odt extends ModelePDFProduct
|
||||
$texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
|
||||
// Show list of found files
|
||||
foreach ($listoffiles as $file) {
|
||||
$texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=products/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a><br>';
|
||||
$texte .= '- '.$file['name'];
|
||||
$texte .= ' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=products/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
|
||||
$texte .= ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=PRODUCT_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
|
||||
$texte .= '<br>';
|
||||
}
|
||||
$texte .= '</div>';
|
||||
}
|
||||
|
||||
@ -102,12 +102,13 @@ class doc_generic_odt extends ModeleThirdPartyDoc
|
||||
$form = new Form($this->db);
|
||||
|
||||
$texte = $this->description.".<br>\n";
|
||||
$texte .= '<!-- form for option of ODT templates -->';
|
||||
$texte .= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" enctype="multipart/form-data">';
|
||||
$texte .= '<input type="hidden" name="token" value="'.newToken().'">';
|
||||
$texte .= '<input type="hidden" name="page_y" value="">';
|
||||
$texte .= '<input type="hidden" name="action" value="setModuleOptions">';
|
||||
$texte .= '<input type="hidden" name="param1" value="COMPANY_ADDON_PDF_ODT_PATH">';
|
||||
$texte .= '<table class="nobordernopadding" width="100%">';
|
||||
$texte .= '<table class="nobordernopadding centpercent">';
|
||||
|
||||
// List of directories area
|
||||
$texte .= '<tr><td>';
|
||||
@ -161,7 +162,9 @@ class doc_generic_odt extends ModeleThirdPartyDoc
|
||||
$texte .= '<div id="div_'.get_class($this).'" class="hiddenx">';
|
||||
// Show list of found files
|
||||
foreach ($listoffiles as $file) {
|
||||
$texte .= '- '.$file['name'].' <a href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=thirdparties/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a><br>';
|
||||
$texte .= '- '.$file['name'].' <a class="reposition" href="'.DOL_URL_ROOT.'/document.php?modulepart=doctemplates&file=thirdparties/'.urlencode(basename($file['name'])).'">'.img_picto('', 'listlight').'</a>';
|
||||
$texte .= ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?modulepart=doctemplates&keyforuploaddir=COMPANY_ADDON_PDF_ODT_PATH&action=deletefile&token='.newToken().'&file='.urlencode(basename($file['name'])).'">'.img_picto('', 'delete').'</a>';
|
||||
$texte .= '<br>';
|
||||
}
|
||||
$texte .= '</div>';
|
||||
}
|
||||
|
||||
@ -1252,20 +1252,30 @@ class pdf_cornas extends ModelePDFSuppliersOrders
|
||||
$pdf->SetXY($this->marge_gauche, $posy);
|
||||
|
||||
// Logo
|
||||
$logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
|
||||
if ($this->emetteur->logo) {
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO)) {
|
||||
if ($this->emetteur->logo) {
|
||||
$logodir = $conf->mycompany->dir_output;
|
||||
if (!empty($conf->mycompany->multidir_output[$object->entity])) {
|
||||
$logodir = $conf->mycompany->multidir_output[$object->entity];
|
||||
}
|
||||
if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO)) {
|
||||
$logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
|
||||
} else {
|
||||
$logo = $logodir.'/logos/'.$this->emetteur->logo;
|
||||
}
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
|
||||
}
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToModuleSetup"), 0, 'L');
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
|
||||
}
|
||||
} else {
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
|
||||
}
|
||||
|
||||
$pdf->SetFont('', 'B', $default_font_size + 3);
|
||||
|
||||
@ -1160,20 +1160,30 @@ class pdf_muscadet extends ModelePDFSuppliersOrders
|
||||
$pdf->SetXY($this->marge_gauche, $posy);
|
||||
|
||||
// Logo
|
||||
$logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
|
||||
if ($this->emetteur->logo) {
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO)) {
|
||||
if ($this->emetteur->logo) {
|
||||
$logodir = $conf->mycompany->dir_output;
|
||||
if (!empty($conf->mycompany->multidir_output[$object->entity])) {
|
||||
$logodir = $conf->mycompany->multidir_output[$object->entity];
|
||||
}
|
||||
if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO)) {
|
||||
$logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
|
||||
} else {
|
||||
$logo = $logodir.'/logos/'.$this->emetteur->logo;
|
||||
}
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
|
||||
}
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToModuleSetup"), 0, 'L');
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
|
||||
}
|
||||
} else {
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
|
||||
}
|
||||
|
||||
$pdf->SetFont('', 'B', $default_font_size + 3);
|
||||
|
||||
@ -1295,20 +1295,30 @@ class pdf_aurore extends ModelePDFSupplierProposal
|
||||
$pdf->SetXY($this->marge_gauche, $posy);
|
||||
|
||||
// Logo
|
||||
$logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
|
||||
if ($this->emetteur->logo) {
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO)) {
|
||||
if ($this->emetteur->logo) {
|
||||
$logodir = $conf->mycompany->dir_output;
|
||||
if (!empty($conf->mycompany->multidir_output[$object->entity])) {
|
||||
$logodir = $conf->mycompany->multidir_output[$object->entity];
|
||||
}
|
||||
if (empty($conf->global->MAIN_PDF_USE_LARGE_LOGO)) {
|
||||
$logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small;
|
||||
} else {
|
||||
$logo = $logodir.'/logos/'.$this->emetteur->logo;
|
||||
}
|
||||
if (is_readable($logo)) {
|
||||
$height = pdf_getHeightForLogo($logo);
|
||||
$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
|
||||
}
|
||||
} else {
|
||||
$pdf->SetTextColor(200, 0, 0);
|
||||
$pdf->SetFont('', 'B', $default_font_size - 2);
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L');
|
||||
$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);
|
||||
}
|
||||
} else {
|
||||
$text = $this->emetteur->name;
|
||||
$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
|
||||
}
|
||||
|
||||
$pdf->SetFont('', 'B', $default_font_size + 3);
|
||||
|
||||
@ -124,27 +124,25 @@ if ($action == 'presend') {
|
||||
|
||||
if ($object->element === 'facture' && !empty($conf->global->INVOICE_EMAIL_SENDER)) {
|
||||
$formmail->frommail = $conf->global->INVOICE_EMAIL_SENDER;
|
||||
$formmail->fromname = '';
|
||||
$formmail->fromname = (!empty($conf->global->INVOICE_EMAIL_SENDER_NAME) ? $conf->global->INVOICE_EMAIL_SENDER_NAME : '');
|
||||
$formmail->fromtype = 'special';
|
||||
}
|
||||
if ($object->element === 'shipping' && !empty($conf->global->SHIPPING_EMAIL_SENDER)) {
|
||||
$formmail->frommail = $conf->global->SHIPPING_EMAIL_SENDER;
|
||||
$formmail->fromname = '';
|
||||
$formmail->fromname = (!empty($conf->global->SHIPPING_EMAIL_SENDER_NAME) ? $conf->global->SHIPPING_EMAIL_SENDER_NAME : '');
|
||||
$formmail->fromtype = 'special';
|
||||
}
|
||||
if ($object->element === 'commande' && !empty($conf->global->COMMANDE_EMAIL_SENDER)) {
|
||||
$formmail->frommail = $conf->global->COMMANDE_EMAIL_SENDER;
|
||||
$formmail->fromname = '';
|
||||
$formmail->fromname = (!empty($conf->global->COMMANDE_EMAIL_SENDER_NAME) ? $conf->global->COMMANDE_EMAIL_SENDER_NAME : '');
|
||||
$formmail->fromtype = 'special';
|
||||
}
|
||||
if ($object->element === 'order_supplier' && !empty($conf->global->ORDER_SUPPLIER_EMAIL_SENDER)) {
|
||||
$formmail->frommail = $conf->global->ORDER_SUPPLIER_EMAIL_SENDER;
|
||||
$formmail->fromname = '';
|
||||
$formmail->fromname = (!empty($conf->global->ORDER_SUPPLIER_EMAIL_SENDER_NAME) ? $conf->global->ORDER_SUPPLIER_EMAIL_SENDER_NAME : '');
|
||||
$formmail->fromtype = 'special';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$formmail->trackid = $trackid;
|
||||
$formmail->withfrom = 1;
|
||||
|
||||
|
||||
@ -110,11 +110,9 @@ print '</table>';
|
||||
|
||||
// We close div and reopen for second column
|
||||
print '</div>';
|
||||
print '<div class="fichehalfright">';
|
||||
|
||||
print '<div class="underbanner clearboth"></div>';
|
||||
print '<table class="border centpercent tableforfield">';
|
||||
|
||||
$rightpart = '';
|
||||
$alreadyoutput = 1;
|
||||
foreach ($object->fields as $key => $val) {
|
||||
if ($alreadyoutput) {
|
||||
@ -139,38 +137,46 @@ foreach ($object->fields as $key => $val) {
|
||||
|
||||
$value = $object->$key;
|
||||
|
||||
print '<tr><td';
|
||||
print ' class="'.(empty($val['tdcss']) ? 'titlefield' : $val['tdcss']).' fieldname_'.$key;
|
||||
//if ($val['notnull'] > 0) print ' fieldrequired'; // No fieldrequired inthe view output
|
||||
$rightpart .= '<tr><td';
|
||||
$rightpart .= ' class="'.(empty($val['tdcss']) ? 'titlefield' : $val['tdcss']).' fieldname_'.$key;
|
||||
//if ($val['notnull'] > 0) $rightpart .= ' fieldrequired'; // No fieldrequired inthe view output
|
||||
if ($val['type'] == 'text' || $val['type'] == 'html') {
|
||||
print ' tdtop';
|
||||
$rightpart .= ' tdtop';
|
||||
}
|
||||
print '">';
|
||||
$rightpart.= '">';
|
||||
if (!empty($val['help'])) {
|
||||
print $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help']));
|
||||
$rightpart .= $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help']));
|
||||
} else {
|
||||
print $langs->trans($val['label']);
|
||||
$rightpart .= $langs->trans($val['label']);
|
||||
}
|
||||
print '</td>';
|
||||
print '<td class="valuefield fieldname_'.$key;
|
||||
$rightpart .= '</td>';
|
||||
$rightpart .= '<td class="valuefield fieldname_'.$key;
|
||||
if ($val['type'] == 'text') {
|
||||
print ' wordbreak';
|
||||
$rightpart .= ' wordbreak';
|
||||
}
|
||||
if (!empty($val['cssview'])) {
|
||||
print ' '.$val['cssview'];
|
||||
$rightpart .= ' '.$val['cssview'];
|
||||
}
|
||||
print '">';
|
||||
$rightpart .= '">';
|
||||
if (in_array($val['type'], array('text', 'html'))) {
|
||||
print '<div class="longmessagecut">';
|
||||
$rightpart .= '<div class="longmessagecut">';
|
||||
}
|
||||
print $object->showOutputField($val, $key, $value, '', '', '', 0);
|
||||
//print dol_escape_htmltag($object->$key, 1, 1);
|
||||
$rightpart .= $object->showOutputField($val, $key, $value, '', '', '', 0);
|
||||
//$rightpart .= dol_escape_htmltag($object->$key, 1, 1);
|
||||
if (in_array($val['type'], array('text', 'html'))) {
|
||||
print '</div>';
|
||||
$rightpart .= '</div>';
|
||||
}
|
||||
print '</td>';
|
||||
print '</tr>';
|
||||
$rightpart .= '</td>';
|
||||
$rightpart .= '</tr>';
|
||||
}
|
||||
|
||||
|
||||
print '<div class="fichehalfright">';
|
||||
print '<div class="underbanner clearboth"></div>';
|
||||
|
||||
print '<table class="border centpercent tableforfield">';
|
||||
|
||||
print $rightpart;
|
||||
|
||||
?>
|
||||
<!-- END PHP TEMPLATE commonfields_view.tpl.php -->
|
||||
|
||||
@ -19,12 +19,17 @@
|
||||
*/
|
||||
|
||||
// Following var must be set:
|
||||
// $action
|
||||
// $arrayofselected = array of id selected
|
||||
// $object
|
||||
// $objecttmp=new Propal($db);
|
||||
// $objecttmp = new MyObject($db);
|
||||
// $topicmail="SendSupplierProposalRef";
|
||||
// $modelmail="supplier_proposal_send";
|
||||
// $trackid='ord'.$object->id;
|
||||
// $trackid='ord'.$objecttmp->id;
|
||||
//
|
||||
// Following var can be set
|
||||
// $object = Object fetched;
|
||||
// $sendto
|
||||
// $withmaindocfilemail
|
||||
|
||||
|
||||
if ($massaction == 'predeletedraft') {
|
||||
@ -41,6 +46,7 @@ if ($massaction == 'preaffecttag') {
|
||||
$categ_types = array();
|
||||
$categ_type_array = $categ->getMapList();
|
||||
foreach ($categ_type_array as $categdef) {
|
||||
// Test on $object (should be useless, we already check on $objecttmp just after)
|
||||
if (isset($object) && $categdef['obj_table'] == $object->table_element) {
|
||||
if (!array_key_exists($categdef['code'], $categ_types)) {
|
||||
$categ_types[$categdef['code']] = array('code'=>$categdef['code'], 'label'=>$langs->trans($categdef['obj_class']));
|
||||
@ -76,7 +82,7 @@ if ($massaction == 'presend') {
|
||||
$langs->load("mails");
|
||||
|
||||
$listofselectedid = array();
|
||||
$listofselectedthirdparties = array();
|
||||
$listofselectedrecipientobjid = array();
|
||||
$listofselectedref = array();
|
||||
|
||||
if (!GETPOST('cancel', 'alpha')) {
|
||||
@ -84,14 +90,19 @@ if ($massaction == 'presend') {
|
||||
$result = $objecttmp->fetch($toselectid);
|
||||
if ($result > 0) {
|
||||
$listofselectedid[$toselectid] = $toselectid;
|
||||
$thirdpartyid = ($objecttmp->fk_soc ? $objecttmp->fk_soc : $objecttmp->socid);
|
||||
if ($objecttmp->element == 'societe') {
|
||||
$thirdpartyid = ($objecttmp->fk_soc ? $objecttmp->fk_soc : $objecttmp->socid); // For proposal, order, invoice, conferenceorbooth, ...
|
||||
if (in_array($objecttmp->element, array('societe', 'conferenceorboothattendee'))) {
|
||||
$thirdpartyid = $objecttmp->id;
|
||||
}
|
||||
if ($objecttmp->element == 'expensereport') {
|
||||
$thirdpartyid = $objecttmp->fk_user_author;
|
||||
}
|
||||
$listofselectedthirdparties[$thirdpartyid] = $thirdpartyid;
|
||||
if (empty($thirdpartyid)) {
|
||||
$thirdpartyid = 0;
|
||||
}
|
||||
if ($thirdpartyid) {
|
||||
$listofselectedrecipientobjid[$thirdpartyid] = $thirdpartyid;
|
||||
}
|
||||
$listofselectedref[$thirdpartyid][$toselectid] = $objecttmp->ref;
|
||||
}
|
||||
}
|
||||
@ -113,9 +124,9 @@ if ($massaction == 'presend') {
|
||||
$formmail->trackid = $trackid;
|
||||
$formmail->withfrom = 1;
|
||||
$liste = $langs->trans("AllRecipientSelected", count($arrayofselected));
|
||||
if (count($listofselectedthirdparties) == 1) { // Only 1 different recipient selected, we can suggest contacts
|
||||
if (count($listofselectedrecipientobjid) == 1) { // Only 1 different recipient selected, we can suggest contacts
|
||||
$liste = array();
|
||||
$thirdpartyid = array_shift($listofselectedthirdparties);
|
||||
$thirdpartyid = array_shift($listofselectedrecipientobjid);
|
||||
if ($objecttmp->element == 'expensereport') {
|
||||
$fuser = new User($db);
|
||||
$fuser->fetch($thirdpartyid);
|
||||
@ -136,19 +147,31 @@ if ($massaction == 'presend') {
|
||||
$formmail->withtoreadonly = 1;
|
||||
}
|
||||
|
||||
$formmail->withoptiononeemailperrecipient = ((count($listofselectedref) == 1 && count(reset($listofselectedref)) == 1) || empty($liste)) ? 0 : ((GETPOST('oneemailperrecipient') == 'on') ? 1 : -1);
|
||||
|
||||
$formmail->withoptiononeemailperrecipient = ((count($listofselectedref) == 1 && count(reset($listofselectedref)) == 1) || empty($liste)) ? 0 : (GETPOST('oneemailperrecipient', 'int') ? 1 : -1);
|
||||
if (in_array($objecttmp->element, array('conferenceorboothattendee'))) {
|
||||
$formmail->withoptiononeemailperrecipient = 0;
|
||||
}
|
||||
|
||||
$formmail->withto = empty($liste) ? (GETPOST('sendto', 'alpha') ?GETPOST('sendto', 'alpha') : array()) : $liste;
|
||||
$formmail->withtofree = empty($liste) ? 1 : 0;
|
||||
$formmail->withtocc = 1;
|
||||
$formmail->withtoccc = $conf->global->MAIN_EMAIL_USECCC;
|
||||
$formmail->withtopic = $langs->transnoentities($topicmail, '__REF__', '__REF_CLIENT__');
|
||||
$formmail->withfile = 1;
|
||||
// $formmail->withfile = 2; Not yet supported in mass action
|
||||
$formmail->withmaindocfile = 1; // Add a checkbox "Attach also main document"
|
||||
if ($objecttmp->element != 'societe') {
|
||||
$formmail->withfile = '<span class="hideonsmartphone opacitymedium">'.$langs->trans("OnlyPDFattachmentSupported").'</span>';
|
||||
$formmail->withmaindocfile = - 1; // Add a checkbox "Attach also main document" but not checked by default
|
||||
if (!empty($topicmail)) {
|
||||
$formmail->withtopic = $langs->transnoentities($topicmail, '__REF__', '__REF_CLIENT__');
|
||||
} else {
|
||||
$formmail->withtopic = 1;
|
||||
}
|
||||
$formmail->withfile = 1; // $formmail->withfile = 2 to allow to upload files is not yet supported in mass action
|
||||
// Add a checkbox "Attach also main document"
|
||||
if (isset($withmaindocfilemail)) {
|
||||
$formmail->withmaindocfile = $withmaindocfilemail;
|
||||
} else { // Do an automatic definition of $formmail->withmaindocfile
|
||||
$formmail->withmaindocfile = 1;
|
||||
if ($objecttmp->element != 'societe') {
|
||||
$formmail->withfile = '<span class="hideonsmartphone opacitymedium">'.$langs->trans("OnlyPDFattachmentSupported").'</span>';
|
||||
$formmail->withmaindocfile = -1; // Add a checkbox "Attach also main document" but not checked by default
|
||||
}
|
||||
}
|
||||
$formmail->withbody = 1;
|
||||
$formmail->withdeliveryreceipt = 1;
|
||||
@ -167,16 +190,16 @@ if ($massaction == 'presend') {
|
||||
);
|
||||
complete_substitutions_array($substitutionarray, $langs, $object, $parameters);
|
||||
|
||||
// Tableau des substitutions
|
||||
// Array of substitutions
|
||||
$formmail->substit = $substitutionarray;
|
||||
|
||||
// Tableau des parametres complementaires du post
|
||||
$formmail->param['action'] = $action;
|
||||
$formmail->param['models'] = $modelmail;
|
||||
$formmail->param['models_id'] = GETPOST('modelmailselected', 'int');
|
||||
$formmail->param['models'] = $modelmail; // the filter to know which kind of template emails to show. 'none' means no template suggested.
|
||||
$formmail->param['models_id'] = GETPOST('modelmailselected', 'int') ? GETPOST('modelmailselected', 'int') : '-1';
|
||||
$formmail->param['id'] = join(',', $arrayofselected);
|
||||
// $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id;
|
||||
if (!empty($conf->global->MAILING_LIMIT_SENDBYWEB) && count($listofselectedthirdparties) > $conf->global->MAILING_LIMIT_SENDBYWEB) {
|
||||
if (!empty($conf->global->MAILING_LIMIT_SENDBYWEB) && count($listofselectedrecipientobjid) > $conf->global->MAILING_LIMIT_SENDBYWEB) {
|
||||
$langs->load("errors");
|
||||
print img_warning().' '.$langs->trans('WarningNumberOfRecipientIsRestrictedInMassAction', $conf->global->MAILING_LIMIT_SENDBYWEB);
|
||||
print ' - <a href="javascript: window.history.go(-1)">'.$langs->trans("GoBack").'</a>';
|
||||
|
||||
@ -101,7 +101,7 @@ if ($action == 'add') {
|
||||
$object->fk_incoterms = GETPOST('incoterm_id', 'int');
|
||||
|
||||
if (!$conf->expedition_bon->enabled && !empty($conf->stock->enabled)) {
|
||||
$expedition->entrepot_id = GETPOST('entrepot_id');
|
||||
$expedition->entrepot_id = GETPOST('entrepot_id', 'int');
|
||||
}
|
||||
|
||||
// We loop on each line of order to complete object delivery with qty to delivery
|
||||
@ -282,7 +282,7 @@ if ($action == 'create') { // Create. Seems to no be used
|
||||
print '<input type="hidden" name="id" value="'.$object->id.'">';
|
||||
print '<input type="hidden" name="ref" value="'.$object->ref.'">';
|
||||
|
||||
print dol_get_fiche_head($head, 'delivery', $langs->trans("Shipment"), -1, 'sending');
|
||||
print dol_get_fiche_head($head, 'delivery', $langs->trans("Shipment"), -1, 'dolly');
|
||||
|
||||
/*
|
||||
* Confirmation de la suppression
|
||||
|
||||
@ -2365,8 +2365,9 @@ class EmailCollector extends CommonObject
|
||||
// this code action is hook..... for support this call
|
||||
global $hookmanager;
|
||||
|
||||
if (is_object($hookmanager)) {
|
||||
$hookmanager->initHooks(array('emailcollectorcard'));
|
||||
if (!is_object($hookmanager)) {
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
|
||||
$hookmanager = new HookManager($this->db);
|
||||
}
|
||||
|
||||
$parameters = array(
|
||||
|
||||
@ -621,8 +621,8 @@ $arrayofmassactions = array(
|
||||
//'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"),
|
||||
//'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"),
|
||||
//'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"),
|
||||
'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail").' - '.$langs->trans("ConferenceOrBooth"),
|
||||
'presend_attendees'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail").' - '.$langs->trans("Attendees"),
|
||||
'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail").' ('.$langs->trans("ToSpeakers").')',
|
||||
//'presend_attendees'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail").' - '.$langs->trans("Attendees"),
|
||||
);
|
||||
if ($permissiontodelete) {
|
||||
$arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
|
||||
@ -650,12 +650,13 @@ $newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle'
|
||||
|
||||
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
|
||||
|
||||
|
||||
// Add code for pre mass action (confirmation or email presend form)
|
||||
$topicmail = $object->ref;
|
||||
$topicmail = $projectstatic->title;
|
||||
$modelmail = "conferenceorbooth";
|
||||
$objecttmp = new ConferenceOrBooth($db);
|
||||
$trackid = 'conferenceorbooth_'.$object->id;
|
||||
include DOL_DOCUMENT_ROOT.'/eventorganization/tpl/massactions_mail_pre.tpl.php';
|
||||
$withmaindocfilemail = 0;
|
||||
include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
|
||||
|
||||
|
||||
@ -689,6 +690,7 @@ $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
|
||||
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
|
||||
$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
|
||||
|
||||
|
||||
print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
|
||||
print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
|
||||
|
||||
|
||||
@ -182,8 +182,8 @@ if (GETPOST('cancel', 'alpha')) {
|
||||
$massaction = '';
|
||||
}
|
||||
if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend'
|
||||
&& $massaction != 'presend_attendees'
|
||||
&& $massaction != 'confirm_presend_attendees') {
|
||||
&& $massaction != 'presend'
|
||||
&& $massaction != 'confirm_presend') {
|
||||
$massaction = '';
|
||||
}
|
||||
|
||||
@ -676,8 +676,7 @@ $arrayofmassactions = array(
|
||||
//'validate'=>img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate"),
|
||||
//'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"),
|
||||
//'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"),
|
||||
//'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"),
|
||||
'presend_attendees'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail").' - '.$langs->trans("Attendees"),
|
||||
'presend'=>img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail"),
|
||||
);
|
||||
if ($permissiontodelete) {
|
||||
$arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
|
||||
@ -706,14 +705,16 @@ $newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle'
|
||||
|
||||
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
|
||||
|
||||
|
||||
// Add code for pre mass action (confirmation or email presend form)
|
||||
$topicmail = "SendConferenceOrBoothAttendeeRef";
|
||||
$modelmail = "conferenceorboothattendee";
|
||||
$topicmail = $projectstatic->title;
|
||||
$modelmail = "conferenceorbooth";
|
||||
$objecttmp = new ConferenceOrBoothAttendee($db);
|
||||
$trackid = 'xxxx'.$object->id;
|
||||
include DOL_DOCUMENT_ROOT.'/eventorganization/tpl/massactions_mail_pre.tpl.php';
|
||||
$trackid = 'conferenceorbooth_'.$object->id;
|
||||
$withmaindocfilemail = 0;
|
||||
include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
|
||||
|
||||
|
||||
if ($search_all) {
|
||||
foreach ($fieldstosearchall as $key => $val) {
|
||||
$fieldstosearchall[$key] = $langs->trans($val);
|
||||
|
||||
@ -78,7 +78,7 @@ if (!$error && $massaction == 'confirm_presend_attendees') {
|
||||
$listofobjectid = array();
|
||||
|
||||
$listofobjectref = array();
|
||||
$oneemailperrecipient = (GETPOST('oneemailperrecipient') == 'on' ? 1 : 0);
|
||||
$oneemailperrecipient = (GETPOST('oneemailperrecipient', 'int') ? 1 : 0);
|
||||
|
||||
if (!$error) {
|
||||
require_once DOL_DOCUMENT_ROOT . '/eventorganization/class/conferenceorboothattendee.class.php';
|
||||
|
||||
@ -1,126 +0,0 @@
|
||||
<?php
|
||||
/* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
|
||||
* Copyright (C) 2013-2014 Laurent Destailleur <eldy@users.sourceforge.net>
|
||||
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* or see https://www.gnu.org/
|
||||
*/
|
||||
|
||||
// Following var must be set:
|
||||
// $arrayofselected = array of id selected
|
||||
// $object
|
||||
// $objecttmp=new Propal($db);
|
||||
// $topicmail="SendSupplierProposalRef";
|
||||
// $modelmail="supplier_proposal_send";
|
||||
// $trackid='ord'.$object->id;
|
||||
|
||||
if ($massaction == 'presend_attendees') {
|
||||
$langs->load("mails");
|
||||
require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorboothattendee.class.php';
|
||||
$attendee = new ConferenceOrBoothAttendee($db);
|
||||
$listofselectedid = array();
|
||||
$listofselectedref = array();
|
||||
|
||||
if (!GETPOST('cancel', 'alpha')) {
|
||||
foreach ($arrayofselected as $toselectid) {
|
||||
$result = $objecttmp->fetch($toselectid);
|
||||
if ($result > 0) {
|
||||
$attendees = $attendee->fetchAll();
|
||||
if (is_array($attendees) && count($attendees)>0) {
|
||||
foreach ($attendees as $attmail) {
|
||||
if (!empty($attmail->email)) {
|
||||
$listofselectedid[$attmail->email] = $attmail->id;
|
||||
$listofselectedref[$attmail->id][$toselectid] = $objecttmp->ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print '<input type="hidden" name="massaction" value="confirm_presend_attendees">';
|
||||
print '<input type="hidden" name="projectid" value="'.GETPOST('projectid', 'int').'">';
|
||||
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
|
||||
$formmail = new FormMail($db);
|
||||
|
||||
print dol_get_fiche_head(null, '', '');
|
||||
|
||||
// Create form for email
|
||||
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
|
||||
$formmail = new FormMail($db);
|
||||
$formmail->withform = -1;
|
||||
$formmail->fromtype = (GETPOST('fromtype') ? GETPOST('fromtype') : (!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE) ? $conf->global->MAIN_MAIL_DEFAULT_FROMTYPE : 'user'));
|
||||
|
||||
if ($formmail->fromtype === 'user') {
|
||||
$formmail->fromid = $user->id;
|
||||
}
|
||||
$formmail->trackid = $trackid;
|
||||
$formmail->withfrom = 1;
|
||||
$liste = $langs->trans("AllRecipientSelected", count($listofselectedid));
|
||||
$formmail->withtoreadonly = 1;
|
||||
|
||||
$formmail->withoptiononeemailperrecipient = ((count($listofselectedref) == 1 && count(reset($listofselectedref)) == 1) || empty($liste)) ? 0 : ((GETPOST('oneemailperrecipient') == 'on') ? 1 : -1);
|
||||
|
||||
$formmail->withto = empty($liste) ? (GETPOST('sendto', 'alpha') ?GETPOST('sendto', 'alpha') : array()) : $liste;
|
||||
$formmail->withtofree = empty($liste) ? 1 : 0;
|
||||
$formmail->withtocc = 1;
|
||||
$formmail->withtoccc = $conf->global->MAIN_EMAIL_USECCC;
|
||||
$formmail->withtopic = $langs->transnoentities($topicmail, '__REF__', '__REF_CLIENT__');
|
||||
$formmail->withfile = 0;
|
||||
// $formmail->withfile = 2; Not yet supported in mass action
|
||||
$formmail->withmaindocfile = 0; // Add a checkbox "Attach also main document"
|
||||
$formmail->withbody = 1;
|
||||
$formmail->withdeliveryreceipt = 1;
|
||||
$formmail->withcancel = 1;
|
||||
|
||||
// Make substitution in email content
|
||||
$substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object);
|
||||
|
||||
$substitutionarray['__EMAIL__'] = $sendto;
|
||||
$substitutionarray['__CHECK_READ__'] = (is_object($object) && is_object($object->thirdparty)) ? '<img src="'.DOL_MAIN_URL_ROOT.'/public/emailing/mailing-read.php?tag='.urlencode($object->thirdparty->tag).'&securitykey='.urlencode($conf->global->MAILING_EMAIL_UNSUBSCRIBE_KEY).'" width="1" height="1" style="width:1px;height:1px" border="0"/>' : '';
|
||||
$substitutionarray['__PERSONALIZED__'] = ''; // deprecated
|
||||
$substitutionarray['__CONTACTCIVNAME__'] = '';
|
||||
|
||||
$parameters = array(
|
||||
'mode' => 'formemail'
|
||||
);
|
||||
complete_substitutions_array($substitutionarray, $langs, $object, $parameters);
|
||||
|
||||
// Tableau des substitutions
|
||||
$formmail->substit = $substitutionarray;
|
||||
|
||||
// Tableau des parametres complementaires du post
|
||||
$formmail->param['action'] = $action;
|
||||
$formmail->param['models'] = $modelmail;
|
||||
$formmail->param['models_id'] = empty(GETPOST('modelmailselected', 'int'))?$conf->global->EVENTORGANIZATION_TEMPLATE_EMAIL_BULK_ATTENDES:GETPOST('modelmailselected', 'int');
|
||||
$formmail->param['id'] = join(',', $arrayofselected);
|
||||
// $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id;
|
||||
if (!empty($conf->global->MAILING_LIMIT_SENDBYWEB) && count($listofselectedid) > $conf->global->MAILING_LIMIT_SENDBYWEB) {
|
||||
$langs->load("errors");
|
||||
print img_warning().' '.$langs->trans('WarningNumberOfRecipientIsRestrictedInMassAction', $conf->global->MAILING_LIMIT_SENDBYWEB);
|
||||
print ' - <a href="javascript: window.history.go(-1)">'.$langs->trans("GoBack").'</a>';
|
||||
$arrayofmassactions = array();
|
||||
} else {
|
||||
print $formmail->get_form();
|
||||
}
|
||||
|
||||
print dol_get_fiche_end();
|
||||
}
|
||||
// Allow Pre-Mass-Action hook (eg for confirmation dialog)
|
||||
$parameters = array(
|
||||
'toselect' => $toselect,
|
||||
'uploaddir' => isset($uploaddir) ? $uploaddir : null
|
||||
);
|
||||
@ -1126,16 +1126,19 @@ if ($action == 'create') {
|
||||
$product_static->status_buy = $line->product_tobuy;
|
||||
$product_static->status_batch = $line->product_tobatch;
|
||||
|
||||
$showdescinproductdesc = (getDolGlobalString('PRODUIT_DESC_IN_FORM') == 2 ? 1 : 0);
|
||||
|
||||
$text = $product_static->getNomUrl(1);
|
||||
$text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
|
||||
$description = ($conf->global->PRODUIT_DESC_IN_FORM ? '' : dol_htmlentitiesbr($line->desc));
|
||||
$description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc));
|
||||
|
||||
print $form->textwithtooltip($text, $description, 3, '', '', $i);
|
||||
|
||||
// Show range
|
||||
print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
|
||||
|
||||
// Add description in form
|
||||
if (!empty($conf->global->PRODUIT_DESC_IN_FORM)) {
|
||||
if ($showdescinproductdesc) {
|
||||
print ($line->desc && $line->desc != $line->product_label) ? '<br>'.dol_htmlentitiesbr($line->desc) : '';
|
||||
}
|
||||
|
||||
|
||||
@ -635,7 +635,16 @@ class PaymentExpenseReport extends CommonObject
|
||||
if (empty($this->ref)) {
|
||||
$this->ref = $this->label;
|
||||
}
|
||||
$label = $langs->trans("ShowPayment").': '.$this->ref;
|
||||
$label = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Payment").'</u>';
|
||||
if (isset($this->status)) {
|
||||
$label .= ' '.$this->getLibStatut(5);
|
||||
}
|
||||
if (!empty($this->ref)) {
|
||||
$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
|
||||
}
|
||||
if (!empty($this->datep)) {
|
||||
$label .= '<br><b>'.$langs->trans('Date').':</b> '.dol_print_date($this->datep, 'dayhour');
|
||||
}
|
||||
|
||||
if (!empty($this->id)) {
|
||||
$link = '<a href="'.DOL_URL_ROOT.'/expensereport/payment/card.php?id='.$this->id.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
|
||||
|
||||
@ -95,11 +95,39 @@ if ($idprod > 0) {
|
||||
if (!empty($conf->stock->enabled)) {
|
||||
// Add price for pmp
|
||||
$price = $producttmp->pmp;
|
||||
$prices[] = array("id" => 'pmpprice', "price" => price2num($price), "label" => $langs->trans("PMPValueShort").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency), "title" => $langs->trans("PMPValueShort").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency)); // For price field, we must use price2num(), for label or title, price()
|
||||
if (empty($price) && !empty($conf->global->PRODUCT_USE_SUB_COST_PRICES_IF_COST_PRICE_EMPTY)) {
|
||||
// get pmp for subproducts if any
|
||||
$producttmp->get_sousproduits_arbo();
|
||||
$prods_arbo=$producttmp->get_arbo_each_prod();
|
||||
if (!empty($prods_arbo)) {
|
||||
$price = 0;
|
||||
foreach ($prods_arbo as $child) {
|
||||
$sousprod = new Product($db);
|
||||
$sousprod->fetch($child['id']);
|
||||
$price += $sousprod->pmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$prices[] = array("id" => 'pmpprice', "price" => price2num($price), "label" => $langs->trans("PMPValueShort").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency), "title" => $langs->trans("PMPValueShort").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency)); // For price field, we must use price2num(), for label or title, price()
|
||||
}
|
||||
|
||||
// Add price for costprice (at end)
|
||||
$price = $producttmp->cost_price;
|
||||
if (empty($price) && ! empty($conf->global->PRODUCT_USE_SUB_COST_PRICES_IF_COST_PRICE_EMPTY)) {
|
||||
// get costprice for subproducts if any
|
||||
$producttmp->get_sousproduits_arbo();
|
||||
$prods_arbo=$producttmp->get_arbo_each_prod();
|
||||
if (!empty($prods_arbo)) {
|
||||
$price = 0;
|
||||
foreach ($prods_arbo as $child) {
|
||||
$sousprod = new Product($db);
|
||||
$sousprod->fetch($child['id']);
|
||||
$price += $sousprod->cost_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$prices[] = array("id" => 'costprice', "price" => price2num($price), "label" => $langs->trans("CostPrice").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency), "title" => $langs->trans("PMPValueShort").': '.price($price, 0, $langs, 0, 0, -1, $conf->currency)); // For price field, we must use price2num(), for label or title, price()
|
||||
}
|
||||
|
||||
|
||||
@ -369,6 +369,189 @@ class SupplierOrders extends DolibarrApi
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve an order
|
||||
*
|
||||
* @param int $id Order ID
|
||||
* @param int $idwarehouse Warehouse ID
|
||||
* @param int $secondlevel 1=Does not execute triggers, 0= execute triggers
|
||||
*
|
||||
* @url POST {id}/approve
|
||||
*
|
||||
* @return array
|
||||
* FIXME An error 403 is returned if the request has an empty body.
|
||||
* Error message: "Forbidden: Content type `text/plain` is not supported."
|
||||
* Workaround: send this in the body
|
||||
* {
|
||||
* "idwarehouse": 0,
|
||||
* "secondlevel": 0
|
||||
* }
|
||||
*/
|
||||
public function approve($id, $idwarehouse = 0, $secondlevel = 0)
|
||||
{
|
||||
if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->creer) && empty(DolibarrApiAccess::$user->rights->supplier_order->creer)) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->order->fetch($id);
|
||||
if (!$result) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
$result = $this->order->approve(DolibarrApiAccess::$user, $idwarehouse, $secondlevel);
|
||||
if ($result == 0) {
|
||||
throw new RestException(304, 'Error nothing done. May be object is already approved');
|
||||
}
|
||||
if ($result < 0) {
|
||||
throw new RestException(500, 'Error when approve Order: '.$this->order->error);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Order approved (Ref='.$this->order->ref.')'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends an order to the vendor
|
||||
*
|
||||
* @param int $id Order ID
|
||||
* @param integer $date Date (unix timestamp in sec)
|
||||
* @param int $method Method
|
||||
* @param string $comment Comment
|
||||
*
|
||||
* @url POST {id}/makeorder
|
||||
*
|
||||
* @return array
|
||||
* FIXME An error 403 is returned if the request has an empty body.
|
||||
* Error message: "Forbidden: Content type `text/plain` is not supported."
|
||||
* Workaround: send this in the body
|
||||
* {
|
||||
* "date": 0,
|
||||
* "method": 0,
|
||||
* "comment": ""
|
||||
* }
|
||||
*/
|
||||
public function makeOrder($id, $date, $method, $comment = '')
|
||||
{
|
||||
if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->creer) && empty(DolibarrApiAccess::$user->rights->supplier_order->creer)) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->order->fetch($id);
|
||||
if (!$result) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
$result = $this->order->commande(DolibarrApiAccess::$user, $date, $method, $comment);
|
||||
if ($result == 0) {
|
||||
throw new RestException(304, 'Error nothing done. May be object is already sent');
|
||||
}
|
||||
if ($result < 0) {
|
||||
throw new RestException(500, 'Error when sending Order: '.$this->order->error);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Order sent (Ref='.$this->order->ref.')'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives the order, dispatches products.
|
||||
*
|
||||
* Example:
|
||||
* <code> {
|
||||
* "closeopenorder": 1,
|
||||
* "comment": "",
|
||||
* "lines": [{
|
||||
* "id": 14,
|
||||
* "fk_product": 112,
|
||||
* "qty": 18,
|
||||
* "warehouse": 1,
|
||||
* "price": 114,
|
||||
* "comment": "",
|
||||
* "eatby": 0,
|
||||
* "sellby": 0,
|
||||
* "batch": 0,
|
||||
* "notrigger": 0
|
||||
* }]
|
||||
* }</code>
|
||||
*
|
||||
* @param int $id Order ID
|
||||
* @param integer $closeopenorder Close order if everything is received {@required false}
|
||||
* @param string $comment Comment {@required false}
|
||||
* @param array $lines Array of product dispatches
|
||||
*
|
||||
* @url POST {id}/receive
|
||||
*
|
||||
* @return array
|
||||
* FIXME An error 403 is returned if the request has an empty body.
|
||||
* Error message: "Forbidden: Content type `text/plain` is not supported."
|
||||
*
|
||||
*/
|
||||
public function receiveOrder($id, $closeopenorder, $comment, $lines)
|
||||
{
|
||||
if (empty(DolibarrApiAccess::$user->rights->fournisseur->commande->creer) && empty(DolibarrApiAccess::$user->rights->supplier_order->creer)) {
|
||||
throw new RestException(401);
|
||||
}
|
||||
$result = $this->order->fetch($id);
|
||||
if (!$result) {
|
||||
throw new RestException(404, 'Order not found');
|
||||
}
|
||||
|
||||
if (!DolibarrApi::_checkAccessToResource('fournisseur', $this->order->id, 'commande_fournisseur', 'commande')) {
|
||||
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
|
||||
}
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$lineObj =(object) $line;
|
||||
|
||||
$result=$this->order->dispatchProduct(DolibarrApiAccess::$user,
|
||||
$lineObj->fk_product,
|
||||
$lineObj->qty,
|
||||
$lineObj->warehouse,
|
||||
$lineObj->price,
|
||||
$lineObj->comment,
|
||||
$lineObj->eatby,
|
||||
$lineObj->sellby,
|
||||
$lineObj->batch,
|
||||
$lineObj->id,
|
||||
$lineObj->notrigger);
|
||||
|
||||
if ($result < 0) {
|
||||
throw new RestException(500, 'Error dispatch order line '.$line->id.': '.$this->order->error);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->order->calcAndSetStatusDispatch(DolibarrApiAccess::$user, $closeopenorder, $comment);
|
||||
|
||||
if ($result == 0) {
|
||||
throw new RestException(304, 'Error nothing done. May be object is already dispatched');
|
||||
}
|
||||
if ($result < 0) {
|
||||
throw new RestException(500, 'Error when receivce order: '.$this->order->error);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => array(
|
||||
'code' => 200,
|
||||
'message' => 'Order received (Ref='.$this->order->ref.')'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
|
||||
/**
|
||||
* Clean sensible object datas
|
||||
|
||||
@ -1370,29 +1370,35 @@ class CommandeFournisseur extends CommonOrder
|
||||
|
||||
// insert products details into database
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
$this->special_code = $this->lines[$i]->special_code; // TODO : remove this in 9.0 and add special_code param to addline()
|
||||
$line = $this->lines[$i];
|
||||
if (!is_object($line)) {
|
||||
$line = (object) $line;
|
||||
}
|
||||
|
||||
|
||||
$this->special_code = $line->special_code; // TODO : remove this in 9.0 and add special_code param to addline()
|
||||
|
||||
// This include test on qty if option SUPPLIER_ORDER_WITH_NOPRICEDEFINED is not set
|
||||
$result = $this->addline(
|
||||
$this->lines[$i]->desc,
|
||||
$this->lines[$i]->subprice,
|
||||
$this->lines[$i]->qty,
|
||||
$this->lines[$i]->tva_tx,
|
||||
$this->lines[$i]->localtax1_tx,
|
||||
$this->lines[$i]->localtax2_tx,
|
||||
$this->lines[$i]->fk_product,
|
||||
$line->desc,
|
||||
$line->subprice,
|
||||
$line->qty,
|
||||
$line->tva_tx,
|
||||
$line->localtax1_tx,
|
||||
$line->localtax2_tx,
|
||||
$line->fk_product,
|
||||
0,
|
||||
$this->lines[$i]->ref_fourn, // $this->lines[$i]->ref_fourn comes from field ref into table of lines. Value may ba a ref that does not exists anymore, so we first try with value of product
|
||||
$this->lines[$i]->remise_percent,
|
||||
$line->ref_fourn, // $line->ref_fourn comes from field ref into table of lines. Value may ba a ref that does not exists anymore, so we first try with value of product
|
||||
$line->remise_percent,
|
||||
'HT',
|
||||
0,
|
||||
$this->lines[$i]->product_type,
|
||||
$this->lines[$i]->info_bits,
|
||||
$line->product_type,
|
||||
$line->info_bits,
|
||||
false,
|
||||
$this->lines[$i]->date_start,
|
||||
$this->lines[$i]->date_end,
|
||||
$this->lines[$i]->array_options,
|
||||
$this->lines[$i]->fk_unit
|
||||
$line->date_start,
|
||||
$line->date_end,
|
||||
$line->array_options,
|
||||
$line->fk_unit
|
||||
);
|
||||
if ($result < 0) {
|
||||
dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING); // do not use dol_print_error here as it may be a functionnal error
|
||||
|
||||
@ -101,6 +101,10 @@ $extrafields = new ExtraFields($db);
|
||||
// fetch optionals attributes and labels
|
||||
$extrafields->fetch_name_optionals_label($object->table_element);
|
||||
|
||||
if ($user->socid) {
|
||||
$socid = $user->socid;
|
||||
}
|
||||
|
||||
// Load object
|
||||
if ($id > 0 || !empty($ref)) {
|
||||
$ret = $object->fetch($id, $ref);
|
||||
@ -124,7 +128,9 @@ if ($id > 0 || !empty($ref)) {
|
||||
}
|
||||
}
|
||||
|
||||
$result = restrictedArea($user, 'fournisseur', $id, 'commande_fournisseur', 'commande');
|
||||
// Security check
|
||||
$isdraft = (isset($object->statut) && ($object->statut == $object::STATUS_DRAFT) ? 1 : 0);
|
||||
$result = restrictedArea($user, 'fournisseur', $id, 'commande_fournisseur', 'commande', 'fk_soc', 'rowid', $isdraft);
|
||||
|
||||
// Common permissions
|
||||
$usercanread = ($user->rights->fournisseur->commande->lire || $user->rights->supplier_order->lire);
|
||||
@ -842,8 +848,7 @@ if (empty($reshook)) {
|
||||
} else {
|
||||
$db->rollback();
|
||||
|
||||
dol_print_error($db, $object->error);
|
||||
exit;
|
||||
setEventMessages($object->error, $object->errors, 'errors');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
* Copyright (C) 2017 Alexandre Spangaro <aspangaro@open-dsi.fr>
|
||||
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
|
||||
* Copyright (C) 2021 Charlene Benke <charlene@patas-monkey.com>
|
||||
* Copyright (C) 2022 Udo Tamm <dev@dolibit.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -54,11 +55,11 @@ $day = GETPOST('day', 'int');
|
||||
$month = GETPOST('month', 'int');
|
||||
$year = GETPOST('year', 'int');
|
||||
|
||||
$search_ref = GETPOST("search_ref", "alpha");
|
||||
$search_account = GETPOST("search_account", "int");
|
||||
$search_paymenttype = GETPOST("search_paymenttype");
|
||||
$search_amount = GETPOST("search_amount", 'alpha'); // alpha because we must be able to search on "< x"
|
||||
$search_company = GETPOST("search_company", 'alpha');
|
||||
$search_ref = GETPOST('search_ref', 'alpha');
|
||||
$search_account = GETPOST('search_account', 'int');
|
||||
$search_paymenttype = GETPOST('search_paymenttype');
|
||||
$search_amount = GETPOST('search_amount', 'alpha'); // alpha because we must be able to search on "< x"
|
||||
$search_company = GETPOST('search_company', 'alpha');
|
||||
$search_payment_num = GETPOST('search_payment_num', 'alpha');
|
||||
|
||||
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
|
||||
@ -773,10 +774,13 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
|
||||
}
|
||||
}
|
||||
|
||||
// Save Button
|
||||
// Save + Cancel Buttons
|
||||
if ($action != 'add_paiement') {
|
||||
print '<br><div class="center"><input type="checkbox" checked name="closepaidinvoices"> '.$langs->trans("ClosePaidInvoicesAutomatically");
|
||||
print '<br><input type="submit" class="button" value="'.$langs->trans('ToMakePayment').'"></div>';
|
||||
print '<p> </p>';
|
||||
print '<br><input type="submit" class="button" value="'.$langs->trans('ToMakePayment').'">';
|
||||
print '<p> </p>';
|
||||
print '<br><input type="button" class="button button-cancel" value="'.$langs->trans("Cancel").'" onClick="javascript:history.go(-1)"></div>';
|
||||
}
|
||||
|
||||
// Form to confirm payment
|
||||
|
||||
@ -109,7 +109,7 @@ class Position extends CommonObject
|
||||
'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>'1', 'position'=>500, 'notnull'=>1, 'visible'=>-2,),
|
||||
'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>'1', 'position'=>501, 'notnull'=>0, 'visible'=>-2,),
|
||||
'fk_contrat' => array('type'=>'integer:Contrat:contrat/class/contrat.class.php', 'label'=>'fk_contrat', 'enabled'=>'1', 'position'=>50, 'notnull'=>0, 'visible'=>0,),
|
||||
'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Employee', 'enabled'=>'1', 'position'=>55, 'notnull'=>1, 'visible'=>1,),
|
||||
'fk_user' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Employee', 'enabled'=>'1', 'position'=>55, 'notnull'=>0, 'visible'=>1,),
|
||||
'fk_job' => array('type'=>'integer:Job:/hrm/class/job.class.php', 'label'=>'Job', 'enabled'=>'1', 'position'=>56, 'notnull'=>1, 'visible'=>1,),
|
||||
'date_start' => array('type'=>'date', 'label'=>'DateStart', 'enabled'=>'1', 'position'=>51, 'notnull'=>1, 'visible'=>1,),
|
||||
'date_end' => array('type'=>'date', 'label'=>'DateEnd', 'enabled'=>'1', 'position'=>52, 'notnull'=>0, 'visible'=>1,),
|
||||
|
||||
@ -264,7 +264,7 @@ if (($id || $ref) && $action == 'edit') {
|
||||
if (is_array($SkilldetRecords) && count($SkilldetRecords) > 0) {
|
||||
print '<table>';
|
||||
foreach ($SkilldetRecords as $sk) {
|
||||
if ($sk->rank > $MaxNumberSkill) {
|
||||
if ($sk->rankorder > $MaxNumberSkill) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -291,7 +291,7 @@ if (($id || $ref) && $action == 'edit') {
|
||||
// if (!empty($val['help'])) {
|
||||
// print $form->textwithpicto($langs->trans($val['label']), $langs->trans($val['help']));
|
||||
// } else {
|
||||
print $langs->trans($val['label']).' '.$langs->trans('rank').' '.$sk->rank;
|
||||
print $langs->trans($val['label']).' '.$langs->trans('rank').' '.$sk->rankorder;
|
||||
// }
|
||||
print '</td>';
|
||||
print '<td class="valuefieldcreate">';
|
||||
@ -696,7 +696,7 @@ if ($action != "create" && $action != "edit") {
|
||||
break; // Should not happen
|
||||
}
|
||||
|
||||
if ($obj->rank > $MaxNumberSkill) {
|
||||
if ($obj->rankorder > $MaxNumberSkill) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -11,17 +11,28 @@ use OAuth\Common\Http\Exception\TokenResponseException;
|
||||
use OAuth\OAuth2\Service\Exception\InvalidAccessTypeException;
|
||||
use OAuth\Common\Http\Uri\Uri;
|
||||
|
||||
/**
|
||||
* Class For WordPress OAuth
|
||||
*/
|
||||
class WordPress extends AbstractService
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $accessType = 'online';
|
||||
|
||||
public function __construct(
|
||||
CredentialsInterface $credentials,
|
||||
ClientInterface $httpClient,
|
||||
TokenStorageInterface $storage,
|
||||
$scopes = array(),
|
||||
UriInterface $baseApiUri = null
|
||||
) {
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param CredentialsInterface $credentials credentials
|
||||
* @param ClientInterface $httpClient httpClient
|
||||
* @param TokenStorageInterface $storage storage
|
||||
* @param $scopes scope
|
||||
* @param UriInterface|null $baseApiUri baseApiUri
|
||||
* @throws Exception\InvalidScopeException
|
||||
*/
|
||||
public function __construct(CredentialsInterface $credentials, ClientInterface $httpClient, TokenStorageInterface $storage, $scopes = array(), UriInterface $baseApiUri = null)
|
||||
{
|
||||
parent::__construct($credentials, $httpClient, $storage, $scopes, $baseApiUri, true);
|
||||
|
||||
if (null === $baseApiUri) {
|
||||
@ -41,7 +52,7 @@ class WordPress extends AbstractService
|
||||
}*/
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return Uri
|
||||
*/
|
||||
public function getAuthorizationEndpoint()
|
||||
{
|
||||
@ -49,7 +60,7 @@ class WordPress extends AbstractService
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return Uri
|
||||
*/
|
||||
public function getAccessTokenEndpoint()
|
||||
{
|
||||
@ -57,7 +68,7 @@ class WordPress extends AbstractService
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return int
|
||||
*/
|
||||
protected function getAuthorizationMethod()
|
||||
{
|
||||
@ -66,7 +77,9 @@ class WordPress extends AbstractService
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param $responseBody responseBody
|
||||
* @return StdOAuth2Token
|
||||
* @throws TokenResponseException
|
||||
*/
|
||||
protected function parseAccessTokenResponse($responseBody)
|
||||
{
|
||||
|
||||
@ -13,6 +13,8 @@ class EmailLexer extends AbstractLexer
|
||||
const S_BACKSLASH = 92;
|
||||
const S_DOT = 46;
|
||||
const S_DQUOTE = 34;
|
||||
const S_SQUOTE = 39;
|
||||
const S_BACKTICK = 96;
|
||||
const S_OPENPARENTHESIS = 49;
|
||||
const S_CLOSEPARENTHESIS = 261;
|
||||
const S_OPENBRACKET = 262;
|
||||
@ -58,6 +60,8 @@ class EmailLexer extends AbstractLexer
|
||||
'/' => self::S_SLASH,
|
||||
',' => self::S_COMMA,
|
||||
'.' => self::S_DOT,
|
||||
"'" => self::S_SQUOTE,
|
||||
"`" => self::S_BACKTICK,
|
||||
'"' => self::S_DQUOTE,
|
||||
'-' => self::S_HYPHEN,
|
||||
'::' => self::S_DOUBLECOLON,
|
||||
@ -73,25 +77,73 @@ class EmailLexer extends AbstractLexer
|
||||
'\0' => self::C_NUL,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $hasInvalidTokens = false;
|
||||
|
||||
protected $previous;
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @psalm-var array{value:string, type:null|int, position:int}|array<empty, empty>
|
||||
*/
|
||||
protected $previous = [];
|
||||
|
||||
/**
|
||||
* The last matched/seen token.
|
||||
*
|
||||
* @var array
|
||||
*
|
||||
* @psalm-var array{value:string, type:null|int, position:int}
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* The next token in the input.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
public $lookahead;
|
||||
|
||||
/**
|
||||
* @psalm-var array{value:'', type:null, position:0}
|
||||
*/
|
||||
private static $nullToken = [
|
||||
'value' => '',
|
||||
'type' => null,
|
||||
'position' => 0,
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->previous = $this->token = self::$nullToken;
|
||||
$this->lookahead = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->hasInvalidTokens = false;
|
||||
parent::reset();
|
||||
$this->previous = $this->token = self::$nullToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasInvalidTokens()
|
||||
{
|
||||
return $this->hasInvalidTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param int $type
|
||||
* @throws \UnexpectedValueException
|
||||
* @return boolean
|
||||
*
|
||||
* @psalm-suppress InvalidScalarArgument
|
||||
*/
|
||||
public function find($type)
|
||||
{
|
||||
@ -107,7 +159,7 @@ class EmailLexer extends AbstractLexer
|
||||
/**
|
||||
* getPrevious
|
||||
*
|
||||
* @return array token
|
||||
* @return array
|
||||
*/
|
||||
public function getPrevious()
|
||||
{
|
||||
@ -122,8 +174,10 @@ class EmailLexer extends AbstractLexer
|
||||
public function moveNext()
|
||||
{
|
||||
$this->previous = $this->token;
|
||||
$hasNext = parent::moveNext();
|
||||
$this->token = $this->token ?: self::$nullToken;
|
||||
|
||||
return parent::moveNext();
|
||||
return $hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,6 +233,11 @@ class EmailLexer extends AbstractLexer
|
||||
return self::GENERIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isValid($value)
|
||||
{
|
||||
if (isset($this->charValue[$value])) {
|
||||
@ -189,7 +248,7 @@ class EmailLexer extends AbstractLexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function isNullType($value)
|
||||
@ -202,7 +261,7 @@ class EmailLexer extends AbstractLexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUTF8Invalid($value)
|
||||
@ -214,6 +273,9 @@ class EmailLexer extends AbstractLexer
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getModifiers()
|
||||
{
|
||||
return 'iu';
|
||||
|
||||
@ -17,11 +17,33 @@ class EmailParser
|
||||
{
|
||||
const EMAIL_MAX_LENGTH = 254;
|
||||
|
||||
protected $warnings;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $warnings = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $domainPart = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $localPart = '';
|
||||
/**
|
||||
* @var EmailLexer
|
||||
*/
|
||||
protected $lexer;
|
||||
|
||||
/**
|
||||
* @var LocalPart
|
||||
*/
|
||||
protected $localPartParser;
|
||||
|
||||
/**
|
||||
* @var DomainPart
|
||||
*/
|
||||
protected $domainPartParser;
|
||||
|
||||
public function __construct(EmailLexer $lexer)
|
||||
@ -29,11 +51,10 @@ class EmailParser
|
||||
$this->lexer = $lexer;
|
||||
$this->localPartParser = new LocalPart($this->lexer);
|
||||
$this->domainPartParser = new DomainPart($this->lexer);
|
||||
$this->warnings = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @param string $str
|
||||
* @return array
|
||||
*/
|
||||
public function parse($str)
|
||||
@ -57,6 +78,9 @@ class EmailParser
|
||||
return array('local' => $this->localPart, 'domain' => $this->domainPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Warning\Warning[]
|
||||
*/
|
||||
public function getWarnings()
|
||||
{
|
||||
$localPartWarnings = $this->localPartParser->getWarnings();
|
||||
@ -68,11 +92,17 @@ class EmailParser
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getParsedDomainPart()
|
||||
{
|
||||
return $this->domainPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
*/
|
||||
protected function setParts($email)
|
||||
{
|
||||
$parts = explode('@', $email);
|
||||
@ -80,6 +110,9 @@ class EmailParser
|
||||
$this->localPart = $parts[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasAtToken()
|
||||
{
|
||||
$this->lexer->moveNext();
|
||||
|
||||
@ -13,12 +13,12 @@ class EmailValidator
|
||||
private $lexer;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @var Warning\Warning[]
|
||||
*/
|
||||
protected $warnings;
|
||||
protected $warnings = [];
|
||||
|
||||
/**
|
||||
* @var InvalidEmail
|
||||
* @var InvalidEmail|null
|
||||
*/
|
||||
protected $error;
|
||||
|
||||
@ -28,7 +28,7 @@ class EmailValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @param string $email
|
||||
* @param EmailValidation $emailValidation
|
||||
* @return bool
|
||||
*/
|
||||
@ -58,7 +58,7 @@ class EmailValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InvalidEmail
|
||||
* @return InvalidEmail|null
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
class DomainAcceptsNoMail extends InvalidEmail
|
||||
{
|
||||
const CODE = 154;
|
||||
const REASON = 'Domain accepts no mail (Null MX, RFC7505)';
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
class ExpectedQPair extends InvalidEmail
|
||||
class ExpectingQPair extends InvalidEmail
|
||||
{
|
||||
const CODE = 136;
|
||||
const REASON = "Expecting QPAIR";
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
class LocalOrReservedDomain extends InvalidEmail
|
||||
{
|
||||
const CODE = 153;
|
||||
const REASON = 'Local, mDNS or reserved domain (RFC2606, RFC6762)';
|
||||
}
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
use Egulias\EmailValidator\Exception\InvalidEmail;
|
||||
|
||||
class NoDNSRecord extends InvalidEmail
|
||||
{
|
||||
const CODE = 5;
|
||||
|
||||
@ -5,5 +5,5 @@ namespace Egulias\EmailValidator\Exception;
|
||||
class UnclosedComment extends InvalidEmail
|
||||
{
|
||||
const CODE = 146;
|
||||
const REASON = "No colosing comment token found";
|
||||
const REASON = "No closing comment token found";
|
||||
}
|
||||
|
||||
@ -35,27 +35,18 @@ use Egulias\EmailValidator\Warning\TLD;
|
||||
class DomainPart extends Parser
|
||||
{
|
||||
const DOMAIN_MAX_LENGTH = 254;
|
||||
const LABEL_MAX_LENGTH = 63;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $domainPart = '';
|
||||
|
||||
public function parse($domainPart)
|
||||
{
|
||||
$this->lexer->moveNext();
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
|
||||
throw new NoDomainPart();
|
||||
}
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
|
||||
throw new DomainHyphened();
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
|
||||
$this->parseDomainComments();
|
||||
}
|
||||
$this->performDomainStartChecks();
|
||||
|
||||
$domain = $this->doParseDomainPart();
|
||||
|
||||
@ -77,11 +68,50 @@ class DomainPart extends Parser
|
||||
$this->domainPart = $domain;
|
||||
}
|
||||
|
||||
private function performDomainStartChecks()
|
||||
{
|
||||
$this->checkInvalidTokensAfterAT();
|
||||
$this->checkEmptyDomain();
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
|
||||
$this->parseDomainComments();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkEmptyDomain()
|
||||
{
|
||||
$thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY ||
|
||||
($this->lexer->token['type'] === EmailLexer::S_SP &&
|
||||
!$this->lexer->isNextToken(EmailLexer::GENERIC));
|
||||
|
||||
if ($thereIsNoDomain) {
|
||||
throw new NoDomainPart();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkInvalidTokensAfterAT()
|
||||
{
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
|
||||
throw new DomainHyphened();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDomainPart()
|
||||
{
|
||||
return $this->domainPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $addressLiteral
|
||||
* @param int $maxGroups
|
||||
*/
|
||||
public function checkIPV6Tag($addressLiteral, $maxGroups = 8)
|
||||
{
|
||||
$prev = $this->lexer->getPrevious();
|
||||
@ -125,9 +155,13 @@ class DomainPart extends Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function doParseDomainPart()
|
||||
{
|
||||
$domain = '';
|
||||
$label = '';
|
||||
$openedParenthesis = 0;
|
||||
do {
|
||||
$prev = $this->lexer->getPrevious();
|
||||
@ -158,7 +192,12 @@ class DomainPart extends Parser
|
||||
$this->parseDomainLiteral();
|
||||
}
|
||||
|
||||
$this->checkLabelLength($prev);
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
|
||||
$this->checkLabelLength($label);
|
||||
$label = '';
|
||||
} else {
|
||||
$label .= $this->lexer->token['value'];
|
||||
}
|
||||
|
||||
if ($this->isFWS()) {
|
||||
$this->parseFWS();
|
||||
@ -166,12 +205,17 @@ class DomainPart extends Parser
|
||||
|
||||
$domain .= $this->lexer->token['value'];
|
||||
$this->lexer->moveNext();
|
||||
} while ($this->lexer->token);
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_SP) {
|
||||
throw new CharNotAllowed();
|
||||
}
|
||||
} while (null !== $this->lexer->token['type']);
|
||||
|
||||
$this->checkLabelLength($label);
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
private function checkNotAllowedChars($token)
|
||||
private function checkNotAllowedChars(array $token)
|
||||
{
|
||||
$notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true];
|
||||
if (isset($notAllowed[$token['type']])) {
|
||||
@ -179,6 +223,9 @@ class DomainPart extends Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
protected function parseDomainLiteral()
|
||||
{
|
||||
if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
|
||||
@ -195,6 +242,9 @@ class DomainPart extends Parser
|
||||
return $this->doParseDomainLiteral();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
protected function doParseDomainLiteral()
|
||||
{
|
||||
$IPv6TAG = false;
|
||||
@ -262,6 +312,11 @@ class DomainPart extends Parser
|
||||
return $addressLiteral;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $addressLiteral
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
protected function checkIPV4Tag($addressLiteral)
|
||||
{
|
||||
$matchesIP = array();
|
||||
@ -279,16 +334,18 @@ class DomainPart extends Parser
|
||||
return false;
|
||||
}
|
||||
// Convert IPv4 part to IPv6 format for further testing
|
||||
$addressLiteral = substr($addressLiteral, 0, $index) . '0:0';
|
||||
$addressLiteral = substr($addressLiteral, 0, (int) $index) . '0:0';
|
||||
}
|
||||
|
||||
return $addressLiteral;
|
||||
}
|
||||
|
||||
protected function checkDomainPartExceptions($prev)
|
||||
protected function checkDomainPartExceptions(array $prev)
|
||||
{
|
||||
$invalidDomainTokens = array(
|
||||
EmailLexer::S_DQUOTE => true,
|
||||
EmailLexer::S_SQUOTE => true,
|
||||
EmailLexer::S_BACKTICK => true,
|
||||
EmailLexer::S_SEMICOLON => true,
|
||||
EmailLexer::S_GREATERTHAN => true,
|
||||
EmailLexer::S_LOWERTHAN => true,
|
||||
@ -320,6 +377,9 @@ class DomainPart extends Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBrackets()
|
||||
{
|
||||
if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) {
|
||||
@ -335,16 +395,31 @@ class DomainPart extends Parser
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkLabelLength($prev)
|
||||
/**
|
||||
* @param string $label
|
||||
*/
|
||||
protected function checkLabelLength($label)
|
||||
{
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
|
||||
$prev['type'] === EmailLexer::GENERIC &&
|
||||
strlen($prev['value']) > 63
|
||||
) {
|
||||
if ($this->isLabelTooLong($label)) {
|
||||
$this->warnings[LabelTooLong::CODE] = new LabelTooLong();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $label
|
||||
* @return bool
|
||||
*/
|
||||
private function isLabelTooLong($label)
|
||||
{
|
||||
if (preg_match('/[^\x00-\x7F]/', $label)) {
|
||||
idn_to_ascii($label, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46, $idnaInfo);
|
||||
|
||||
return (bool) ($idnaInfo['errors'] & IDNA_ERROR_LABEL_TOO_LONG);
|
||||
}
|
||||
|
||||
return strlen($label) > self::LABEL_MAX_LENGTH;
|
||||
}
|
||||
|
||||
protected function parseDomainComments()
|
||||
{
|
||||
$this->isUnclosedComment();
|
||||
|
||||
@ -5,7 +5,6 @@ namespace Egulias\EmailValidator\Parser;
|
||||
use Egulias\EmailValidator\Exception\DotAtEnd;
|
||||
use Egulias\EmailValidator\Exception\DotAtStart;
|
||||
use Egulias\EmailValidator\EmailLexer;
|
||||
use Egulias\EmailValidator\EmailValidator;
|
||||
use Egulias\EmailValidator\Exception\ExpectingAT;
|
||||
use Egulias\EmailValidator\Exception\ExpectingATEXT;
|
||||
use Egulias\EmailValidator\Exception\UnclosedQuotedString;
|
||||
@ -20,9 +19,10 @@ class LocalPart extends Parser
|
||||
$parseDQuote = true;
|
||||
$closingQuote = false;
|
||||
$openedParenthesis = 0;
|
||||
$totalLength = 0;
|
||||
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
|
||||
@ -35,12 +35,13 @@ class LocalPart extends Parser
|
||||
$this->parseComments();
|
||||
$openedParenthesis += $this->getOpenedParenthesis();
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
|
||||
if ($openedParenthesis === 0) {
|
||||
throw new UnopenedComment();
|
||||
} else {
|
||||
$openedParenthesis--;
|
||||
}
|
||||
|
||||
$openedParenthesis--;
|
||||
}
|
||||
|
||||
$this->checkConsecutiveDots();
|
||||
@ -58,15 +59,18 @@ class LocalPart extends Parser
|
||||
$this->parseFWS();
|
||||
}
|
||||
|
||||
$totalLength += strlen($this->lexer->token['value']);
|
||||
$this->lexer->moveNext();
|
||||
}
|
||||
|
||||
$prev = $this->lexer->getPrevious();
|
||||
if (strlen($prev['value']) > LocalTooLong::LOCAL_PART_LENGTH) {
|
||||
if ($totalLength > LocalTooLong::LOCAL_PART_LENGTH) {
|
||||
$this->warnings[LocalTooLong::CODE] = new LocalTooLong();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function parseDoubleQuote()
|
||||
{
|
||||
$parseAgain = true;
|
||||
@ -86,7 +90,7 @@ class LocalPart extends Parser
|
||||
|
||||
$this->lexer->moveNext();
|
||||
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) {
|
||||
$parseAgain = false;
|
||||
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
|
||||
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
|
||||
@ -118,7 +122,10 @@ class LocalPart extends Parser
|
||||
return $parseAgain;
|
||||
}
|
||||
|
||||
protected function isInvalidToken($token, $closingQuote)
|
||||
/**
|
||||
* @param bool $closingQuote
|
||||
*/
|
||||
protected function isInvalidToken(array $token, $closingQuote)
|
||||
{
|
||||
$forbidden = array(
|
||||
EmailLexer::S_COMMA,
|
||||
|
||||
@ -8,7 +8,7 @@ use Egulias\EmailValidator\Exception\ConsecutiveDot;
|
||||
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
|
||||
use Egulias\EmailValidator\Exception\CRLFX2;
|
||||
use Egulias\EmailValidator\Exception\CRNoLF;
|
||||
use Egulias\EmailValidator\Exception\ExpectedQPair;
|
||||
use Egulias\EmailValidator\Exception\ExpectingQPair;
|
||||
use Egulias\EmailValidator\Exception\ExpectingATEXT;
|
||||
use Egulias\EmailValidator\Exception\ExpectingCTEXT;
|
||||
use Egulias\EmailValidator\Exception\UnclosedComment;
|
||||
@ -21,8 +21,19 @@ use Egulias\EmailValidator\Warning\QuotedString;
|
||||
|
||||
abstract class Parser
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $warnings = [];
|
||||
|
||||
/**
|
||||
* @var EmailLexer
|
||||
*/
|
||||
protected $lexer;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $openedParenthesis = 0;
|
||||
|
||||
public function __construct(EmailLexer $lexer)
|
||||
@ -30,11 +41,17 @@ abstract class Parser
|
||||
$this->lexer = $lexer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Egulias\EmailValidator\Warning\Warning[]
|
||||
*/
|
||||
public function getWarnings()
|
||||
{
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*/
|
||||
abstract public function parse($str);
|
||||
|
||||
/** @return int */
|
||||
@ -50,7 +67,7 @@ abstract class Parser
|
||||
{
|
||||
if (!($this->lexer->token['type'] === EmailLexer::INVALID
|
||||
|| $this->lexer->token['type'] === EmailLexer::C_DEL)) {
|
||||
throw new ExpectedQPair();
|
||||
throw new ExpectingQPair();
|
||||
}
|
||||
|
||||
$this->warnings[QuotedPart::CODE] =
|
||||
@ -80,6 +97,9 @@ abstract class Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUnclosedComment()
|
||||
{
|
||||
try {
|
||||
@ -122,6 +142,9 @@ abstract class Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function isFWS()
|
||||
{
|
||||
if ($this->escaped()) {
|
||||
@ -140,11 +163,14 @@ abstract class Parser
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function escaped()
|
||||
{
|
||||
$previous = $this->lexer->getPrevious();
|
||||
|
||||
if ($previous['type'] === EmailLexer::S_BACKSLASH
|
||||
if ($previous && $previous['type'] === EmailLexer::S_BACKSLASH
|
||||
&&
|
||||
$this->lexer->token['type'] !== EmailLexer::GENERIC
|
||||
) {
|
||||
@ -154,6 +180,9 @@ abstract class Parser
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function warnEscaping()
|
||||
{
|
||||
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
|
||||
@ -174,6 +203,11 @@ abstract class Parser
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $hasClosingQuote
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkDQUOTE($hasClosingQuote)
|
||||
{
|
||||
if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) {
|
||||
|
||||
@ -4,6 +4,8 @@ namespace Egulias\EmailValidator\Validation;
|
||||
|
||||
use Egulias\EmailValidator\EmailLexer;
|
||||
use Egulias\EmailValidator\Exception\InvalidEmail;
|
||||
use Egulias\EmailValidator\Exception\LocalOrReservedDomain;
|
||||
use Egulias\EmailValidator\Exception\DomainAcceptsNoMail;
|
||||
use Egulias\EmailValidator\Warning\NoDNSMXRecord;
|
||||
use Egulias\EmailValidator\Exception\NoDNSRecord;
|
||||
|
||||
@ -15,10 +17,23 @@ class DNSCheckValidation implements EmailValidation
|
||||
private $warnings = [];
|
||||
|
||||
/**
|
||||
* @var InvalidEmail
|
||||
* @var InvalidEmail|null
|
||||
*/
|
||||
private $error;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $mxRecords = [];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (!function_exists('idn_to_ascii')) {
|
||||
throw new \LogicException(sprintf('The %s class requires the Intl extension.', __CLASS__));
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid($email, EmailLexer $emailLexer)
|
||||
{
|
||||
// use the input to check DNS if we cannot extract something similar to a domain
|
||||
@ -29,7 +44,40 @@ class DNSCheckValidation implements EmailValidation
|
||||
$host = substr($email, $lastAtPos + 1);
|
||||
}
|
||||
|
||||
return $this->checkDNS($host);
|
||||
// Get the domain parts
|
||||
$hostParts = explode('.', $host);
|
||||
|
||||
// Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2),
|
||||
// mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G)
|
||||
$reservedTopLevelDnsNames = [
|
||||
// Reserved Top Level DNS Names
|
||||
'test',
|
||||
'example',
|
||||
'invalid',
|
||||
'localhost',
|
||||
|
||||
// mDNS
|
||||
'local',
|
||||
|
||||
// Private DNS Namespaces
|
||||
'intranet',
|
||||
'internal',
|
||||
'private',
|
||||
'corp',
|
||||
'home',
|
||||
'lan',
|
||||
];
|
||||
|
||||
$isLocalDomain = count($hostParts) <= 1;
|
||||
$isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], $reservedTopLevelDnsNames, true);
|
||||
|
||||
// Exclude reserved top level DNS names
|
||||
if ($isLocalDomain || $isReservedTopLevel) {
|
||||
$this->error = new LocalOrReservedDomain();
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->checkDns($host);
|
||||
}
|
||||
|
||||
public function getError()
|
||||
@ -42,20 +90,77 @@ class DNSCheckValidation implements EmailValidation
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
protected function checkDNS($host)
|
||||
/**
|
||||
* @param string $host
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkDns($host)
|
||||
{
|
||||
$host = rtrim($host, '.') . '.';
|
||||
$variant = INTL_IDNA_VARIANT_UTS46;
|
||||
|
||||
$Aresult = true;
|
||||
$MXresult = checkdnsrr($host, 'MX');
|
||||
$host = rtrim(idn_to_ascii($host, IDNA_DEFAULT, $variant), '.') . '.';
|
||||
|
||||
if (!$MXresult) {
|
||||
$this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord();
|
||||
$Aresult = checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA');
|
||||
if (!$Aresult) {
|
||||
$this->error = new NoDNSRecord();
|
||||
return $this->validateDnsRecords($host);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the DNS records for given host.
|
||||
*
|
||||
* @param string $host A set of DNS records in the format returned by dns_get_record.
|
||||
*
|
||||
* @return bool True on success.
|
||||
*/
|
||||
private function validateDnsRecords($host)
|
||||
{
|
||||
// Get all MX, A and AAAA DNS records for host
|
||||
// Using @ as workaround to fix https://bugs.php.net/bug.php?id=73149
|
||||
$dnsRecords = @dns_get_record($host, DNS_MX + DNS_A + DNS_AAAA);
|
||||
|
||||
|
||||
// No MX, A or AAAA DNS records
|
||||
if (empty($dnsRecords)) {
|
||||
$this->error = new NoDNSRecord();
|
||||
return false;
|
||||
}
|
||||
|
||||
// For each DNS record
|
||||
foreach ($dnsRecords as $dnsRecord) {
|
||||
if (!$this->validateMXRecord($dnsRecord)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $MXresult || $Aresult;
|
||||
|
||||
// No MX records (fallback to A or AAAA records)
|
||||
if (empty($this->mxRecords)) {
|
||||
$this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an MX record
|
||||
*
|
||||
* @param array $dnsRecord Given DNS record.
|
||||
*
|
||||
* @return bool True if valid.
|
||||
*/
|
||||
private function validateMxRecord($dnsRecord)
|
||||
{
|
||||
if ($dnsRecord['type'] !== 'MX') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// "Null MX" record indicates the domain accepts no mail (https://tools.ietf.org/html/rfc7505)
|
||||
if (empty($dnsRecord['target']) || $dnsRecord['target'] === '.') {
|
||||
$this->error = new DomainAcceptsNoMail();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mxRecords[] = $dnsRecord;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,9 @@ use Exception;
|
||||
|
||||
class EmptyValidationList extends \InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* @param int $code
|
||||
*/
|
||||
public function __construct($code = 0, Exception $previous = null)
|
||||
{
|
||||
parent::__construct("Empty validation list is not allowed", $code, $previous);
|
||||
|
||||
@ -9,16 +9,22 @@ class MultipleErrors extends InvalidEmail
|
||||
const CODE = 999;
|
||||
const REASON = "Accumulated errors for multiple validations";
|
||||
/**
|
||||
* @var array
|
||||
* @var InvalidEmail[]
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @param InvalidEmail[] $errors
|
||||
*/
|
||||
public function __construct(array $errors)
|
||||
{
|
||||
$this->errors = $errors;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InvalidEmail[]
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
|
||||
@ -30,12 +30,12 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
private $warnings = [];
|
||||
|
||||
/**
|
||||
* @var MultipleErrors
|
||||
* @var MultipleErrors|null
|
||||
*/
|
||||
private $error;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
* @var int
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
@ -62,7 +62,8 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
$errors = [];
|
||||
foreach ($this->validations as $validation) {
|
||||
$emailLexer->reset();
|
||||
$result = $result && $validation->isValid($email, $emailLexer);
|
||||
$validationResult = $validation->isValid($email, $emailLexer);
|
||||
$result = $result && $validationResult;
|
||||
$this->warnings = array_merge($this->warnings, $validation->getWarnings());
|
||||
$errors = $this->addNewError($validation->getError(), $errors);
|
||||
|
||||
@ -78,6 +79,12 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Egulias\EmailValidator\Exception\InvalidEmail|null $possibleError
|
||||
* @param \Egulias\EmailValidator\Exception\InvalidEmail[] $errors
|
||||
*
|
||||
* @return \Egulias\EmailValidator\Exception\InvalidEmail[]
|
||||
*/
|
||||
private function addNewError($possibleError, array $errors)
|
||||
{
|
||||
if (null !== $possibleError) {
|
||||
@ -87,13 +94,20 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $result
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function shouldStop($result)
|
||||
{
|
||||
return !$result && $this->mode === self::STOP_ON_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Returns the validation errors.
|
||||
*
|
||||
* @return MultipleErrors|null
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
|
||||
@ -9,7 +9,7 @@ use Egulias\EmailValidator\Validation\Error\RFCWarnings;
|
||||
class NoRFCWarningsValidation extends RFCValidation
|
||||
{
|
||||
/**
|
||||
* @var InvalidEmail
|
||||
* @var InvalidEmail|null
|
||||
*/
|
||||
private $error;
|
||||
|
||||
@ -22,8 +22,7 @@ class NoRFCWarningsValidation extends RFCValidation
|
||||
return false;
|
||||
}
|
||||
|
||||
$ret = $this->getWarnings();
|
||||
if (empty($ret)) {
|
||||
if (empty($this->getWarnings())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ use Egulias\EmailValidator\Exception\InvalidEmail;
|
||||
class RFCValidation implements EmailValidation
|
||||
{
|
||||
/**
|
||||
* @var EmailParser
|
||||
* @var EmailParser|null
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
@ -19,7 +19,7 @@ class RFCValidation implements EmailValidation
|
||||
private $warnings = [];
|
||||
|
||||
/**
|
||||
* @var InvalidEmail
|
||||
* @var InvalidEmail|null
|
||||
*/
|
||||
private $error;
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ use \Spoofchecker;
|
||||
class SpoofCheckValidation implements EmailValidation
|
||||
{
|
||||
/**
|
||||
* @var InvalidEmail
|
||||
* @var InvalidEmail|null
|
||||
*/
|
||||
private $error;
|
||||
|
||||
@ -21,6 +21,9 @@ class SpoofCheckValidation implements EmailValidation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress InvalidArgument
|
||||
*/
|
||||
public function isValid($email, EmailLexer $emailLexer)
|
||||
{
|
||||
$checker = new Spoofchecker();
|
||||
@ -33,6 +36,9 @@ class SpoofCheckValidation implements EmailValidation
|
||||
return $this->error === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InvalidEmail|null
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
|
||||
@ -6,6 +6,10 @@ class QuotedPart extends Warning
|
||||
{
|
||||
const CODE = 36;
|
||||
|
||||
/**
|
||||
* @param scalar $prevToken
|
||||
* @param scalar $postToken
|
||||
*/
|
||||
public function __construct($prevToken, $postToken)
|
||||
{
|
||||
$this->message = "Deprecated Quoted String found between $prevToken and $postToken";
|
||||
|
||||
@ -6,6 +6,10 @@ class QuotedString extends Warning
|
||||
{
|
||||
const CODE = 11;
|
||||
|
||||
/**
|
||||
* @param scalar $prevToken
|
||||
* @param scalar $postToken
|
||||
*/
|
||||
public function __construct($prevToken, $postToken)
|
||||
{
|
||||
$this->message = "Quoted String found between $prevToken and $postToken";
|
||||
|
||||
@ -5,19 +5,36 @@ namespace Egulias\EmailValidator\Warning;
|
||||
abstract class Warning
|
||||
{
|
||||
const CODE = 0;
|
||||
protected $message;
|
||||
protected $rfcNumber;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $rfcNumber = 0;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function code()
|
||||
{
|
||||
return self::CODE;
|
||||
return static::CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function RFCNumber()
|
||||
{
|
||||
return $this->rfcNumber;
|
||||
|
||||
@ -258,6 +258,11 @@ abstract class AbstractLexer
|
||||
$flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
|
||||
$matches = preg_split($regex, $input, -1, $flags);
|
||||
|
||||
if (false === $matches) {
|
||||
// Work around https://bugs.php.net/78122
|
||||
$matches = array(array($input, 0));
|
||||
}
|
||||
|
||||
foreach ($matches as $match) {
|
||||
// Must remain before 'value' assignment since it can change content
|
||||
$type = $this->getType($match[0]);
|
||||
|
||||
@ -11,15 +11,14 @@
|
||||
/**
|
||||
* General utility class in Swift Mailer, not to be instantiated.
|
||||
*
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
abstract class Swift
|
||||
{
|
||||
const VERSION = '6.0.2';
|
||||
const VERSION = '6.3.0';
|
||||
|
||||
public static $initialized = false;
|
||||
public static $inits = array();
|
||||
public static $inits = [];
|
||||
|
||||
/**
|
||||
* Registers an initializer callable that will be called the first time
|
||||
@ -57,7 +56,7 @@ abstract class Swift
|
||||
if (self::$inits && !self::$initialized) {
|
||||
self::$initialized = true;
|
||||
foreach (self::$inits as $init) {
|
||||
call_user_func($init);
|
||||
\call_user_func($init);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,6 +73,6 @@ abstract class Swift
|
||||
if (null !== $callable) {
|
||||
self::$inits[] = $callable;
|
||||
}
|
||||
spl_autoload_register(array('Swift', 'autoload'));
|
||||
spl_autoload_register(['Swift', 'autoload']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Email address encoder.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
interface Swift_AddressEncoder
|
||||
{
|
||||
/**
|
||||
* Encodes an email address.
|
||||
*
|
||||
* @throws Swift_AddressEncoderException if the email cannot be represented in
|
||||
* the encoding implemented by this class
|
||||
*/
|
||||
public function encodeString(string $address): string;
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An IDN email address encoder.
|
||||
*
|
||||
* Encodes the domain part of an address using IDN. This is compatible will all
|
||||
* SMTP servers.
|
||||
*
|
||||
* This encoder does not support email addresses with non-ASCII characters in
|
||||
* local-part (the substring before @). To send to such addresses, use
|
||||
* Swift_AddressEncoder_Utf8AddressEncoder together with
|
||||
* Swift_Transport_Esmtp_SmtpUtf8Handler. Your outbound SMTP server must support
|
||||
* the SMTPUTF8 extension.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
class Swift_AddressEncoder_IdnAddressEncoder implements Swift_AddressEncoder
|
||||
{
|
||||
/**
|
||||
* Encodes the domain part of an address using IDN.
|
||||
*
|
||||
* @throws Swift_AddressEncoderException If local-part contains non-ASCII characters
|
||||
*/
|
||||
public function encodeString(string $address): string
|
||||
{
|
||||
$i = strrpos($address, '@');
|
||||
if (false !== $i) {
|
||||
$local = substr($address, 0, $i);
|
||||
$domain = substr($address, $i + 1);
|
||||
|
||||
if (preg_match('/[^\x00-\x7F]/', $local)) {
|
||||
throw new Swift_AddressEncoderException('Non-ASCII characters not supported in local-part', $address);
|
||||
}
|
||||
|
||||
if (preg_match('/[^\x00-\x7F]/', $domain)) {
|
||||
$address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46));
|
||||
}
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A UTF-8 email address encoder.
|
||||
*
|
||||
* Returns the email address verbatimly in UTF-8 as permitted by RFC 6531 and
|
||||
* RFC 6532. It supports addresses containing non-ASCII characters in both
|
||||
* local-part and domain (i.e. on both sides of @).
|
||||
*
|
||||
* This encoder must be used together with Swift_Transport_Esmtp_SmtpUtf8Handler
|
||||
* and requires that the outbound SMTP server supports the SMTPUTF8 extension.
|
||||
*
|
||||
* If your outbound SMTP server does not support SMTPUTF8, use
|
||||
* Swift_AddressEncoder_IdnAddressEncoder instead. This allows sending to email
|
||||
* addresses with non-ASCII characters in the domain, but not in local-part.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
class Swift_AddressEncoder_Utf8AddressEncoder implements Swift_AddressEncoder
|
||||
{
|
||||
/**
|
||||
* Returns the address verbatimly.
|
||||
*/
|
||||
public function encodeString(string $address): string
|
||||
{
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* AddressEncoderException when the specified email address is in a format that
|
||||
* cannot be encoded by a given address encoder.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
class Swift_AddressEncoderException extends Swift_RfcComplianceException
|
||||
{
|
||||
protected $address;
|
||||
|
||||
public function __construct(string $message, string $address)
|
||||
{
|
||||
parent::__construct($message);
|
||||
|
||||
$this->address = $address;
|
||||
}
|
||||
|
||||
public function getAddress(): string
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
}
|
||||
@ -26,17 +26,14 @@ class Swift_Attachment extends Swift_Mime_Attachment
|
||||
*/
|
||||
public function __construct($data = null, $filename = null, $contentType = null)
|
||||
{
|
||||
call_user_func_array(
|
||||
array($this, 'Swift_Mime_Attachment::__construct'),
|
||||
\call_user_func_array(
|
||||
[$this, 'Swift_Mime_Attachment::__construct'],
|
||||
Swift_DependencyContainer::getInstance()
|
||||
->createDependenciesFor('mime.attachment')
|
||||
);
|
||||
|
||||
$this->setBody($data);
|
||||
$this->setBody($data, $contentType);
|
||||
$this->setFilename($filename);
|
||||
if ($contentType) {
|
||||
$this->setContentType($contentType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,7 +42,7 @@ class Swift_Attachment extends Swift_Mime_Attachment
|
||||
* @param string $path
|
||||
* @param string $contentType optional
|
||||
*
|
||||
* @return Swift_Mime_Attachment
|
||||
* @return self
|
||||
*/
|
||||
public static function fromPath($path, $contentType = null)
|
||||
{
|
||||
|
||||
@ -25,7 +25,7 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
*
|
||||
* @var Swift_StreamFilter[]
|
||||
*/
|
||||
private $filters = array();
|
||||
private $filters = [];
|
||||
|
||||
/**
|
||||
* A buffer for writing.
|
||||
@ -37,7 +37,7 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
*
|
||||
* @var Swift_InputByteStream[]
|
||||
*/
|
||||
private $mirrors = array();
|
||||
private $mirrors = [];
|
||||
|
||||
/**
|
||||
* Commit the given bytes to the storage medium immediately.
|
||||
@ -54,8 +54,7 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
/**
|
||||
* Add a StreamFilter to this InputByteStream.
|
||||
*
|
||||
* @param Swift_StreamFilter $filter
|
||||
* @param string $key
|
||||
* @param string $key
|
||||
*/
|
||||
public function addFilter(Swift_StreamFilter $filter, $key)
|
||||
{
|
||||
@ -110,8 +109,6 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
*
|
||||
* The stream acts as an observer, receiving all data that is written.
|
||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function bind(Swift_InputByteStream $is)
|
||||
{
|
||||
@ -124,14 +121,12 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
* If $is is not bound, no errors will be raised.
|
||||
* If the stream currently has any buffered data it will be written to $is
|
||||
* before unbinding occurs.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function unbind(Swift_InputByteStream $is)
|
||||
{
|
||||
foreach ($this->mirrors as $k => $stream) {
|
||||
if ($is === $stream) {
|
||||
if ($this->writeBuffer !== '') {
|
||||
if ('' !== $this->writeBuffer) {
|
||||
$stream->write($this->writeBuffer);
|
||||
}
|
||||
unset($this->mirrors[$k]);
|
||||
@ -147,7 +142,7 @@ abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_I
|
||||
*/
|
||||
public function flushBuffers()
|
||||
{
|
||||
if ($this->writeBuffer !== '') {
|
||||
if ('' !== $this->writeBuffer) {
|
||||
$this->doWrite($this->writeBuffer);
|
||||
}
|
||||
$this->flush();
|
||||
|
||||
@ -20,7 +20,7 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $array = array();
|
||||
private $array = [];
|
||||
|
||||
/**
|
||||
* The size of the stack.
|
||||
@ -41,7 +41,7 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
*
|
||||
* @var Swift_InputByteStream[]
|
||||
*/
|
||||
private $mirrors = array();
|
||||
private $mirrors = [];
|
||||
|
||||
/**
|
||||
* Create a new ArrayByteStream.
|
||||
@ -52,13 +52,13 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
*/
|
||||
public function __construct($stack = null)
|
||||
{
|
||||
if (is_array($stack)) {
|
||||
if (\is_array($stack)) {
|
||||
$this->array = $stack;
|
||||
$this->arraySize = count($stack);
|
||||
} elseif (is_string($stack)) {
|
||||
$this->arraySize = \count($stack);
|
||||
} elseif (\is_string($stack)) {
|
||||
$this->write($stack);
|
||||
} else {
|
||||
$this->array = array();
|
||||
$this->array = [];
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
foreach ($to_add as $value) {
|
||||
$this->array[] = $value;
|
||||
}
|
||||
$this->arraySize = count($this->array);
|
||||
$this->arraySize = \count($this->array);
|
||||
|
||||
foreach ($this->mirrors as $stream) {
|
||||
$stream->write($bytes);
|
||||
@ -121,8 +121,6 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
*
|
||||
* The stream acts as an observer, receiving all data that is written.
|
||||
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function bind(Swift_InputByteStream $is)
|
||||
{
|
||||
@ -135,8 +133,6 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
* If $is is not bound, no errors will be raised.
|
||||
* If the stream currently has any buffered data it will be written to $is
|
||||
* before unbinding occurs.
|
||||
*
|
||||
* @param Swift_InputByteStream $is
|
||||
*/
|
||||
public function unbind(Swift_InputByteStream $is)
|
||||
{
|
||||
@ -172,7 +168,7 @@ class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_O
|
||||
public function flushBuffers()
|
||||
{
|
||||
$this->offset = 0;
|
||||
$this->array = array();
|
||||
$this->array = [];
|
||||
$this->arraySize = 0;
|
||||
|
||||
foreach ($this->mirrors as $stream) {
|
||||
|
||||
@ -81,7 +81,7 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
|
||||
|
||||
// If we read one byte after reaching the end of the file
|
||||
// feof() will return false and an empty string is returned
|
||||
if ($bytes === '' && feof($fp)) {
|
||||
if ((false === $bytes || '' === $bytes) && feof($fp)) {
|
||||
$this->resetReadHandle();
|
||||
|
||||
return false;
|
||||
@ -131,7 +131,7 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
|
||||
throw new Swift_IoException('Unable to open file for reading ['.$this->path.']');
|
||||
}
|
||||
$this->reader = $pointer;
|
||||
if ($this->offset != 0) {
|
||||
if (0 != $this->offset) {
|
||||
$this->getReadStreamSeekableStatus();
|
||||
$this->seekReadStreamToPosition($this->offset);
|
||||
}
|
||||
@ -145,9 +145,7 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
|
||||
{
|
||||
if (!isset($this->writer)) {
|
||||
if (!$this->writer = fopen($this->path, $this->mode)) {
|
||||
throw new Swift_IoException(
|
||||
'Unable to open file for writing ['.$this->path.']'
|
||||
);
|
||||
throw new Swift_IoException('Unable to open file for writing ['.$this->path.']');
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,10 +171,10 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
|
||||
/** Streams in a readOnly stream ensuring copy if needed */
|
||||
private function seekReadStreamToPosition($offset)
|
||||
{
|
||||
if ($this->seekable === null) {
|
||||
if (null === $this->seekable) {
|
||||
$this->getReadStreamSeekableStatus();
|
||||
}
|
||||
if ($this->seekable === false) {
|
||||
if (false === $this->seekable) {
|
||||
$currentPos = ftell($this->reader);
|
||||
if ($currentPos < $offset) {
|
||||
$toDiscard = $offset - $currentPos;
|
||||
@ -194,7 +192,7 @@ class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterabl
|
||||
{
|
||||
if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
|
||||
/* We have opened a php:// Stream Should work without problem */
|
||||
} elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
|
||||
} elseif (\function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
|
||||
/* We have opened a tmpfile */
|
||||
} else {
|
||||
throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
|
||||
|
||||
@ -17,7 +17,7 @@ class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByte
|
||||
{
|
||||
$filePath = tempnam(sys_get_temp_dir(), 'FileByteStream');
|
||||
|
||||
if ($filePath === false) {
|
||||
if (false === $filePath) {
|
||||
throw new Swift_IoException('Failed to retrieve temporary file name.');
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByte
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
if (($content = file_get_contents($this->getPath())) === false) {
|
||||
if (false === ($content = file_get_contents($this->getPath()))) {
|
||||
throw new Swift_IoException('Failed to get temporary file content.');
|
||||
}
|
||||
|
||||
@ -39,4 +39,14 @@ class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByte
|
||||
@unlink($this->getPath());
|
||||
}
|
||||
}
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
|
||||
}
|
||||
|
||||
public function __wakeup()
|
||||
{
|
||||
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterRe
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
$strlen = strlen($string);
|
||||
$strlen = \strlen($string);
|
||||
// % and / are CPU intensive, so, maybe find a better way
|
||||
$ignored = $strlen % $this->width;
|
||||
$ignoredChars = $ignored ? substr($string, -$ignored) : '';
|
||||
|
||||
@ -27,7 +27,7 @@ class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader
|
||||
*/
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
$strlen = strlen($string);
|
||||
$strlen = \strlen($string);
|
||||
$ignoredChars = '';
|
||||
for ($i = 0; $i < $strlen; ++$i) {
|
||||
if ($string[$i] > "\x07F") {
|
||||
@ -65,7 +65,7 @@ class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader
|
||||
public function validateByteSequence($bytes, $size)
|
||||
{
|
||||
$byte = reset($bytes);
|
||||
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
|
||||
if (1 == \count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@
|
||||
class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
|
||||
{
|
||||
/** Pre-computed for optimization */
|
||||
private static $length_map = array(
|
||||
// N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
|
||||
private static $length_map = [
|
||||
// N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N
|
||||
@ -34,10 +34,10 @@ class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN
|
||||
);
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN
|
||||
];
|
||||
|
||||
private static $s_length_map = array(
|
||||
private static $s_length_map = [
|
||||
"\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1,
|
||||
"\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1,
|
||||
"\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1,
|
||||
@ -70,7 +70,7 @@ class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
|
||||
"\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3,
|
||||
"\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4,
|
||||
"\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0,
|
||||
);
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns the complete character map.
|
||||
@ -85,22 +85,22 @@ class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
|
||||
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
|
||||
{
|
||||
if (!isset($currentMap['i']) || !isset($currentMap['p'])) {
|
||||
$currentMap['p'] = $currentMap['i'] = array();
|
||||
$currentMap['p'] = $currentMap['i'] = [];
|
||||
}
|
||||
|
||||
$strlen = strlen($string);
|
||||
$charPos = count($currentMap['p']);
|
||||
$strlen = \strlen($string);
|
||||
$charPos = \count($currentMap['p']);
|
||||
$foundChars = 0;
|
||||
$invalid = false;
|
||||
for ($i = 0; $i < $strlen; ++$i) {
|
||||
$char = $string[$i];
|
||||
$size = self::$s_length_map[$char];
|
||||
if ($size == 0) {
|
||||
if (0 == $size) {
|
||||
/* char is invalid, we must wait for a resync */
|
||||
$invalid = true;
|
||||
continue;
|
||||
} else {
|
||||
if ($invalid == true) {
|
||||
if (true === $invalid) {
|
||||
/* We mark the chars as invalid and start a new char */
|
||||
$currentMap['p'][$charPos + $foundChars] = $startOffset + $i;
|
||||
$currentMap['i'][$charPos + $foundChars] = true;
|
||||
|
||||
@ -20,14 +20,14 @@ class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $map = array();
|
||||
private static $map = [];
|
||||
|
||||
/**
|
||||
* Factories which have already been loaded.
|
||||
*
|
||||
* @var Swift_CharacterReaderFactory[]
|
||||
*/
|
||||
private static $loaded = array();
|
||||
private static $loaded = [];
|
||||
|
||||
/**
|
||||
* Creates a new CharacterReaderFactory.
|
||||
@ -44,32 +44,32 @@ class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift
|
||||
|
||||
public function init()
|
||||
{
|
||||
if (count(self::$map) > 0) {
|
||||
if (\count(self::$map) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$prefix = 'Swift_CharacterReader_';
|
||||
|
||||
$singleByte = array(
|
||||
$singleByte = [
|
||||
'class' => $prefix.'GenericFixedWidthReader',
|
||||
'constructor' => array(1),
|
||||
);
|
||||
'constructor' => [1],
|
||||
];
|
||||
|
||||
$doubleByte = array(
|
||||
$doubleByte = [
|
||||
'class' => $prefix.'GenericFixedWidthReader',
|
||||
'constructor' => array(2),
|
||||
);
|
||||
'constructor' => [2],
|
||||
];
|
||||
|
||||
$fourBytes = array(
|
||||
$fourBytes = [
|
||||
'class' => $prefix.'GenericFixedWidthReader',
|
||||
'constructor' => array(4),
|
||||
);
|
||||
'constructor' => [4],
|
||||
];
|
||||
|
||||
// Utf-8
|
||||
self::$map['utf-?8'] = array(
|
||||
self::$map['utf-?8'] = [
|
||||
'class' => $prefix.'Utf8Reader',
|
||||
'constructor' => array(),
|
||||
);
|
||||
'constructor' => [],
|
||||
];
|
||||
|
||||
//7-8 bit charsets
|
||||
self::$map['(us-)?ascii'] = $singleByte;
|
||||
@ -103,11 +103,11 @@ class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift
|
||||
*/
|
||||
public function getReaderFor($charset)
|
||||
{
|
||||
$charset = strtolower(trim($charset));
|
||||
$charset = strtolower(trim($charset ?? ''));
|
||||
foreach (self::$map as $pattern => $spec) {
|
||||
$re = '/^'.$pattern.'$/D';
|
||||
if (preg_match($re, $charset)) {
|
||||
if (!array_key_exists($pattern, self::$loaded)) {
|
||||
if (!\array_key_exists($pattern, self::$loaded)) {
|
||||
$reflector = new ReflectionClass($spec['class']);
|
||||
if ($reflector->getConstructor()) {
|
||||
$reader = $reflector->newInstanceArgs($spec['constructor']);
|
||||
|
||||
@ -28,8 +28,6 @@ interface Swift_CharacterStream
|
||||
|
||||
/**
|
||||
* Set the CharacterReaderFactory for multi charset support.
|
||||
*
|
||||
* @param Swift_CharacterReaderFactory $factory
|
||||
*/
|
||||
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user