diff --git a/ChangeLog b/ChangeLog
index 9cd6f11d1b8..3cfc257bbb2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,12 +2,134 @@
English Dolibarr ChangeLog
--------------------------------------------------------------
+
+***** ChangeLog for 7.0.0 compared to 6.0.* *****
+
+
+
***** ChangeLog for 6.0.0 compared to 5.0.* *****
+NEW: Add experimental BlockeLog module (to log business events in a non reversible log file).
+NEW: Add a payment module for Stripe.
+NEW: Add module "Product variant" (like red, blue for the product shoes)
+NEW: Accountancy - Activate multi-journal & Add journal_label to database (FEC)
+NEW: Add a tracking id into mass emailing.
+NEW: Tax system more compatible with the new tax roollout in India (IGST / CGST / SGST).
+NEW: Add calculation function for Loan schedule
+NEW: Add "depends on" and "required by" into module informations
+NEW: Add hidden option THIRDPARTY_INCLUDE_PARENT_IN_LINKTO
+NEW: Add key __USERID__ and __ENTITYID__ as key for dynamic filters.
+NEW: Add last activation author and ip of modules
+NEW: Add mass actions (pdf merge and delete) for interventions
+NEW: Add module resources import/export
+NEW: Add option PROJECT_THIRDPARTY_REQUIRED
+NEW: Add page statistics for project tasks
+NEW: add property to show warnings when activating modules
+NEW: add rapport file for supplier paiement
+NEW: Add statistics on supplier tab.
+NEW: Add tooltip help on shipment weight and volume calculation
+NEW: An external module can hook and add mass actions
+NEW: Better reponsive design
+NEW: Bookmarks are into a combo list.
+NEW: Bulk actions available on supplier orders
+NEW: Can add a background image on login page
+NEW: Can change customer from POS
+NEW: Can clone expense report on another user
+NEW: Can control constants values into file integrity checker
+NEW: Can define default values for create forms.
+NEW: Can define default filters for list pages.
+NEW: Can define default sort order for list pages.
+NEW: Can deploy an external module from the module setup area.
+NEW: Can disable all overwrote translations in one click.
+NEW: Can edit background color for odd and even lines in tables
+NEW: Can filter on code in dictionnaries
+NEW: Can filter on year and product tags on the product statistic page
+NEW: Can import users
+NEW: Can read time spent of others (hierarchy only or all if granted)
+NEW: Can send an email to a user from its card.
+NEW: Can send email to multiple destinaries from the mailform combo list.
+NEW: Can set margins of PDFs
+NEW: Can set number of dump to keep with job "local database backup"
+NEW: Can sort customer balance summary on date.
+NEW: Can sort thumbs visible on product card.
+NEW: Can use a credit note into a "down payment/deposit".
+NEW: Can use dol_fiche_end without showing bottom border.
+NEW: Can use translations into all substitutions (watermark, freetext...)
+NEW: Change to allow a specific numbering rule for invoice with POS module.
+NEW: convert exceiss received to reduc
+NEW: custom dir is enabled dy default on first install.
+NEW: Description of feature of a module visible into a dedicated popup.
+NEW: Direct open of card after a search if one record only found.
+NEW: download button
+NEW: Enable bulk actions delete on supplier invoices.
+NEW: Extrafields support formulas to be computed using PHP expressions.
+NEW: Feature to crop/resize images available on user and expense reports.
+NEW: Filechecker can include custom dir and report added files.
+NEW: fix listview class and add a demo for product list
+NEW: [FP17] Accountancy - Add select field in list of accounts
+NEW: get amount base on hourly rate for ficheinter
+NEW: hidden Easter egg to display commitstrip strip on login page
+NEW: Include an hourglass icon when we click on online payment button
+NEW: Index upload files into database.
+NEW: Introduce mass action on product list ('delete' for the moment)
+NEW: Introduce mass actions on contacts
+NEW: Introduce option MAIN_HTTP_CONTENT_SECURITY_POLICY
+NEW: It's easier to switch between sandbox and live for paypal
+NEW: Mass action delete available on project and tasks
+NEW: Move login information on home page into a widget
+NEW: new demo entry page
+NEW: No external check of version without explicit click in about page.
+NEW: ODT docs for USER USERGROUP CONTRACT and PRODUCT class
+NEW: odt usergroup
+NEW: On invoices generated by template, we save if invoice come from a source template.
+NEW: option to copy into attachement files of events, files send by mail (with auto event creation)
+NEW: PDF with numbertoword
+NEW: Permit multiple file upload in linked documents
+NEW: PHP 7.1 compatibility
+NEW: Reduce memory usage by removing deprecated constant loading.
+NEW: Report page and menu for suppliers paiements
+NEW: Show by default README.md file found into root dir of ext module.
+NEW: Show company into combo list of projects
+NEW: show files in the bank statement + download
+NEW: Show local taxes in facture list
+NEW: Show local taxes in supplier facture list
+NEW: Small PDF template for products
+NEW: Option SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT
+NEW: The substitution keys available for emailing edition are now visible into a popup.
+NEW: Uniformize behaviour: Action to make order is an action button.
+NEW: Use autocompletion on the "Add widget list".
+NEW: Use html5 type "number" on select field for year and duration.
+NEW: Can use pdktk to concat mass pdf because tcpdf generate avoid to split large file into multiple smaller file (all have same size) encounter issue with mailer provider virtual delivery service
+NEW: Default theme of v6 is cleaner.
+NEW: When down payment is entered, discount to reuse into final invoice is automatically created. This save one click into invoice workflow.
+NEW: Add UI to configure MEMBER_NEWFORM_FORCETYPE
+NEW: #2763 Go to document block after clicking in Generate document button
+NEW: #6280: Generate PDF after creating an invoice from a customer order
+NEW: #6915 Simplest change.
+NEW: Uniformize the look and feel with v6 new look.
+
For developers:
NEW: Add a lot of API REST: dictionaryevents, memberstypes, ...
NEW: Big refactorization of multicompany transverse mode.
NEW: getEntity function use true $shared value by default.
+NEW: Add font-awesome css.
+NEW: Add function ajax_autoselect
+NEW: Add function dolMd2Html
+NEW: Add hook doUpgrade2
+NEW: Add hook "formatNotificationMessage"
+NEW: Add index and constraints keys on supplier proposal detail table
+NEW: Add phpunit to check the engine is defined into sql create files.
+NEW: Add project and Hook to Loan
+NEW: Add REST API to push a file.
+NEW: Allow extrafields list select to be dependands on other standard list and not only other extrafields list
+NEW: Architecture to manage search criteria persistance (using save_lastsearch_values=1 on exit links and restore_lastsearch_values=1 in entry links)
+NEW: data files are now also parsed by phpunit for sql syntax
+NEW: Hook to allow inserting custom product head #6001
+NEW: Introduce fields that can be computed during export in export profiles.
+NEW: Introduce function dol_compress_dir
+NEW: Removed commande_pdf_create, contract_pdf_create,expedition_pdf_create, facture_pdf_create, delivery_order_pdf_create, task_pdf_create, project_pdf_create, propale_pdf_create, supplier_invoice_pdf_create, supplier_order_pdf_create, supplier_proposal_pdf_create deprecated functions
+NEW: tooltip can be on hover or on click with textwithpicto function.
+NEW: Upgrade jquery to 3.3.1 and jquery-ui to 1.12
WARNING:
diff --git a/build/exe/doliwamp/doliwamp.iss b/build/exe/doliwamp/doliwamp.iss
index 34757a5123a..2ef8ab32f22 100644
--- a/build/exe/doliwamp/doliwamp.iss
+++ b/build/exe/doliwamp/doliwamp.iss
@@ -353,10 +353,12 @@ begin
begin
// TODO Copy file or ask to install package ?
//CustomMessage('YouWillInstallDoliWamp')+#13#13
- MsgBox('The package vcredist_x86.exe must have been installed first. It seems it is not. Please install it first from http://www.microsoft.com/en-us/download/details.aspx?id=30679 then restart DoliWamp installation/upgrade.',mbInformation,MB_OK);
+ MsgBox('The package vcredist_x86.exe must have been installed first. It seems it is not. Please install it first from http://www.microsoft.com/en-us/download/details.aspx?id=30679 then restart DoliWamp installation/upgrade.',mbInformation,MB_OK);
end;
-
-
+ // Pb seems similar with msvcp110.dll
+ //vcredist_x64.exe
+
+
// If we have a new database version, we should only copy old my.ini file into new directory
// and change only all basedir= strings to use new version. Like this, data dir is still correct.
// Install of service and stop/start scripts are already rebuild by installer.
diff --git a/build/makepack-dolibarr.pl b/build/makepack-dolibarr.pl
index c2d983653cb..1843f3c8cfd 100755
--- a/build/makepack-dolibarr.pl
+++ b/build/makepack-dolibarr.pl
@@ -592,6 +592,8 @@ if ($nboftargetok) {
print "Remove subdir of custom dir\n";
print "find $BUILDROOT/$PROJECT/htdocs/custom/* -type d -exec rm -fr {} \\;\n";
$ret=`find $BUILDROOT/$PROJECT/htdocs/custom/* -type d -exec rm -fr {} \\; >/dev/null 2>&1`; # For custom we want to remove all subdirs but not files
+ print "find $BUILDROOT/$PROJECT/htdocs/custom/* -type l -exec rm -fr {} \\;\n";
+ $ret=`find $BUILDROOT/$PROJECT/htdocs/custom/* -type l -exec rm -fr {} \\; >/dev/null 2>&1`; # For custom we want to remove all subdirs, even symbolic links, but not files
}
# Build package for each target
@@ -972,9 +974,11 @@ if ($nboftargetok) {
$ret=`$cmd`;
$ret=`chmod 755 $BUILDROOT/$PROJECT.tmp/debian/rules`;
$ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/dev/translation/autotranslator.class.php`;
+ $ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/class/actions_mymodule.class.php`;
+ $ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/class/api_myobject.class.php`;
$ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/class/myobject.class.php`;
- $ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/class/myobject_api_class.class.php`;
$ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/core/modules/modMyModule.class.php`;
+ $ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/mymoduleindex.php`;
$ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/myobject_card.php`;
$ret=`chmod -R 644 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/myobject_list.php`;
$ret=`chmod -R 755 $BUILDROOT/$PROJECT.tmp/htdocs/modulebuilder/template/scripts/myobject.php`;
diff --git a/build/rpm/dolibarr_fedora.spec b/build/rpm/dolibarr_fedora.spec
index 33dc951309d..55898481691 100755
--- a/build/rpm/dolibarr_fedora.spec
+++ b/build/rpm/dolibarr_fedora.spec
@@ -162,6 +162,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/api
%_datadir/dolibarr/htdocs/asterisk
%_datadir/dolibarr/htdocs/barcode
+%_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/cashdesk
%_datadir/dolibarr/htdocs/categories
diff --git a/build/rpm/dolibarr_generic.spec b/build/rpm/dolibarr_generic.spec
index 42a89675abf..e5b346278ab 100755
--- a/build/rpm/dolibarr_generic.spec
+++ b/build/rpm/dolibarr_generic.spec
@@ -242,6 +242,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/api
%_datadir/dolibarr/htdocs/asterisk
%_datadir/dolibarr/htdocs/barcode
+%_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/cashdesk
%_datadir/dolibarr/htdocs/categories
diff --git a/build/rpm/dolibarr_mandriva.spec b/build/rpm/dolibarr_mandriva.spec
index 9dd2100b02c..04a3138d9f9 100755
--- a/build/rpm/dolibarr_mandriva.spec
+++ b/build/rpm/dolibarr_mandriva.spec
@@ -159,6 +159,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/api
%_datadir/dolibarr/htdocs/asterisk
%_datadir/dolibarr/htdocs/barcode
+%_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/cashdesk
%_datadir/dolibarr/htdocs/categories
diff --git a/build/rpm/dolibarr_opensuse.spec b/build/rpm/dolibarr_opensuse.spec
index d780c47da99..c77661fe420 100755
--- a/build/rpm/dolibarr_opensuse.spec
+++ b/build/rpm/dolibarr_opensuse.spec
@@ -170,6 +170,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/api
%_datadir/dolibarr/htdocs/asterisk
%_datadir/dolibarr/htdocs/barcode
+%_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/cashdesk
%_datadir/dolibarr/htdocs/categories
diff --git a/dev/resources/iso-normes/world_tax_rates.txt b/dev/resources/iso-normes/world_tax_rates.txt
index e5bb64a86f2..740062288dc 100644
--- a/dev/resources/iso-normes/world_tax_rates.txt
+++ b/dev/resources/iso-normes/world_tax_rates.txt
@@ -1 +1,4 @@
-http://www.taxrates.cc/index.html
\ No newline at end of file
+http://www.taxrates.cc/index.html
+
+For India: VAT=IGST/CGST=Localtax1/SGST=Localtax2: https://cleartax.in/s/what-is-sgst-cgst-igst
+
diff --git a/dev/translation/sanity_check_en_langfiles.php b/dev/translation/sanity_check_en_langfiles.php
index 9136c192739..f65cefd7f94 100755
--- a/dev/translation/sanity_check_en_langfiles.php
+++ b/dev/translation/sanity_check_en_langfiles.php
@@ -25,7 +25,7 @@ $path=dirname(__FILE__).'/';
$web=0;
// Test if batch mode
-if (substr($sapi_type, 0, 3) == 'cgi')
+if (substr($sapi_type, 0, 3) == 'cgi')
{
$web=1;
}
@@ -35,9 +35,9 @@ if ($web)
{
echo "";
echo "
";
-
+
echo "";
-
+
echo "";
}
@@ -142,9 +142,9 @@ foreach ($files AS $file) {
}
}
-foreach ($langstrings_3d AS $filename => $file)
+foreach ($langstrings_3d AS $filename => $file)
{
- foreach ($file AS $linenum => $value)
+ foreach ($file AS $linenum => $value)
{
$keys = array_keys($langstrings_full, $value);
if (count($keys)>1)
@@ -173,11 +173,11 @@ $sininstallandadmin='';
$sother='';
$count = 0;
-foreach ($dups as $string => $pages)
+foreach ($dups as $string => $pages)
{
$count++;
$s='';
-
+
// Keyword $string
if ($web) $s.="
";
if ($web) $s.="
";
@@ -188,32 +188,32 @@ foreach ($dups as $string => $pages)
if ($web) $s.="
";
if ($web) $s.="
";
if (! $web) $s.= ' : ';
-
+
// Loop on each files keyword was found
$duplicateinsamefile=0;
$inmain=0;
$inadmin=0;
- foreach ($pages AS $file => $lines)
+ foreach ($pages AS $file => $lines)
{
if ($file == 'main.lang') { $inmain=1; $inadmin=0; }
if ($file == 'admin.lang' && ! $inmain) { $inadmin=1; }
-
+
$s.=$file." ";
-
+
// Loop on each line keword was found into file.
$listoffilesforthisentry=array();
- foreach ($lines as $line => $translatedvalue)
+ foreach ($lines as $line => $translatedvalue)
{
if (! empty($listoffilesforthisentry[$file])) $duplicateinsamefile=1;
$listoffilesforthisentry[$file]=1;
-
+
$s.= "(".$line." - ".htmlentities($translatedvalue).") ";
}
if ($web) $s.=" ";
}
if ($web) $s.="
';
// Ref
diff --git a/htdocs/core/actions_fetchobject.inc.php b/htdocs/core/actions_fetchobject.inc.php
index 520d3c2d6da..7c25fbe7981 100644
--- a/htdocs/core/actions_fetchobject.inc.php
+++ b/htdocs/core/actions_fetchobject.inc.php
@@ -28,9 +28,9 @@
// $cancel must be defined
// $id or $ref must be defined (object is loaded in this file with fetch)
-if (($id > 0 || (! empty($ref) && ! in_array($action, array('create','createtask')))) && empty($cancel))
+if (($id > 0 || (! empty($ref) && ! in_array($action, array('create', 'createtask', 'add')))) && empty($cancel))
{
- $ret = $object->fetch($id,$ref);
+ $ret = $object->fetch($id, $ref);
if ($ret > 0)
{
$object->fetch_thirdparty();
@@ -38,7 +38,8 @@ if (($id > 0 || (! empty($ref) && ! in_array($action, array('create','createtask
}
else
{
- setEventMessages($object->error, $object->errors, 'errors');
+ if (empty($object->error) && ! count($object->errors)) setEventMessages('Fetch on object return an error without filling $object->error nor $object->errors', null, 'errors');
+ else setEventMessages($object->error, $object->errors, 'errors');
$action='';
}
}
diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php
index be6f13a22c7..f4a55352f96 100644
--- a/htdocs/core/actions_massactions.inc.php
+++ b/htdocs/core/actions_massactions.inc.php
@@ -594,7 +594,7 @@ if (! $error && $massaction == 'delete' && $permtodelete)
$nbok = 0;
foreach($toselect as $toselectid)
{
- $result=$objecttmp->fetch($toselectid);
+ $result=$objecttmp->fetch($toselectid);
if ($result > 0)
{
if (in_array($objecttmp->element, array('societe','member'))) $result = $objecttmp->delete($objecttmp->id, $user, 1);
diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php
index a796a94c68c..1998808bf11 100644
--- a/htdocs/core/actions_sendmails.inc.php
+++ b/htdocs/core/actions_sendmails.inc.php
@@ -391,6 +391,9 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
$object->trackid = $trackid;
$object->fk_element = $object->id;
$object->elementtype = $object->element;
+ if (is_array($attachedfiles) && count($attachedfiles)>0) {
+ $object->attachedfiles = $attachedfiles;
+ }
// Call of triggers
if (! empty($trigger_name))
diff --git a/htdocs/core/ajax/selectsearchbox.php b/htdocs/core/ajax/selectsearchbox.php
index 2e837fcbaae..2d92bc8f938 100644
--- a/htdocs/core/ajax/selectsearchbox.php
+++ b/htdocs/core/ajax/selectsearchbox.php
@@ -31,8 +31,17 @@ if (! isset($usedbyinclude) || empty($usedbyinclude))
if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
+ if (! defined('NOREDIRECTBYMAINTOLOGIN')) define('NOREDIRECTBYMAINTOLOGIN','1');
$res=@include '../../main.inc.php';
+ if ($res == 'ERROR_NOT_LOGGED')
+ {
+ $langs->load("other");
+ $arrayresult['jumptologin']=array('img'=>'object_generic', 'label'=>$langs->trans("JumpToLogin"), 'text'=>' '.$langs->trans("JumpToLogin"), 'url'=>DOL_URL_ROOT.'/index.php');
+ print json_encode($arrayresult);
+ if (is_object($db)) $db->close();
+ exit;
+ }
}
include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index ddfb2780f3f..53de8e56eb8 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -334,23 +334,23 @@ abstract class CommonObject
// No constructor as it is an abstract class
- /**
- * Check an object id/ref exists
- * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
- *
+ /**
+ * Check an object id/ref exists
+ * If you don't need/want to instantiate object and just need to know if object exists, use this method instead of fetch
+ *
* @param string $element String of element ('product', 'facture', ...)
* @param int $id Id of object
* @param string $ref Ref of object to check
* @param string $ref_ext Ref ext of object to check
* @return int <0 if KO, 0 if OK but not found, >0 if OK and exists
- */
- static function isExistingObject($element, $id, $ref='', $ref_ext='')
- {
- global $db,$conf;
+ */
+ static function isExistingObject($element, $id, $ref='', $ref_ext='')
+ {
+ global $db,$conf;
$sql = "SELECT rowid, ref, ref_ext";
$sql.= " FROM ".MAIN_DB_PREFIX.$element;
- $sql.= " WHERE entity IN (".getEntity($element, true).")" ;
+ $sql.= " WHERE entity IN (".getEntity($element).")" ;
if ($id > 0) $sql.= " AND rowid = ".$db->escape($id);
else if ($ref) $sql.= " AND ref = '".$db->escape($ref)."'";
@@ -371,17 +371,17 @@ abstract class CommonObject
else return 0;
}
return -1;
- }
+ }
- /**
- * Method to output saved errors
- *
- * @return string String with errors
- */
- function errorsToString()
- {
- return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
- }
+ /**
+ * Method to output saved errors
+ *
+ * @return string String with errors
+ */
+ function errorsToString()
+ {
+ return $this->error.(is_array($this->errors)?(($this->error!=''?', ':'').join(', ',$this->errors)):'');
+ }
/**
* Return full name (civility+' '+name+' '+lastname)
@@ -1309,7 +1309,7 @@ abstract class CommonObject
* Load properties id_previous and id_next
*
* @param string $filter Optional filter. Example: " AND (t.field1 = 'aa' OR t.field2 = 'bb')"
- * @param int $fieldid Name of field to use for the select MAX and MIN
+ * @param string $fieldid Name of field to use for the select MAX and MIN
* @param int $nodbprefix Do not include DB prefix to forge table name
* @return int <0 if KO, >0 if OK
*/
@@ -1322,6 +1322,7 @@ abstract class CommonObject
dol_print_error('',get_class($this)."::load_previous_next_ref was called on objet with property table_element not defined");
return -1;
}
+ if ($fieldid == 'none') return 1;
// this->ismultientitymanaged contains
// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
@@ -3947,7 +3948,7 @@ abstract class CommonObject
// Now we add first model found in directories scanned
$listofdir=explode(',',$dirtoscan);
- foreach($listofdir as $key=>$tmpdir)
+ foreach($listofdir as $key => $tmpdir)
{
$tmpdir=trim($tmpdir);
$tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir);
@@ -4736,19 +4737,6 @@ abstract class CommonObject
-
- /**
- * Function test if type is date
- *
- * @param array $info content informations of field
- * @return bool
- */
- protected function isDate($info)
- {
- if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
- else return false;
- }
-
/**
* Function test if type is array
*
@@ -4781,13 +4769,26 @@ abstract class CommonObject
else return false;
}
+
+ /**
+ * Function test if type is date
+ *
+ * @param array $info content informations of field
+ * @return bool
+ */
+ public function isDate($info)
+ {
+ if(isset($info['type']) && ($info['type']=='date' || $info['type']=='datetime' || $info['type']=='timestamp')) return true;
+ else return false;
+ }
+
/**
* Function test if type is integer
*
* @param array $info content informations of field
* @return bool
*/
- protected function isInt($info)
+ public function isInt($info)
{
if(is_array($info))
{
@@ -4803,11 +4804,11 @@ abstract class CommonObject
* @param array $info content informations of field
* @return bool
*/
- protected function isFloat($info)
+ public function isFloat($info)
{
if(is_array($info))
{
- if(isset($info['type']) && $info['type']=='float') return true;
+ if (isset($info['type']) && (preg_match('/^(double|real)/i', $info['type']))) return true;
else return false;
}
else return false;
@@ -4819,7 +4820,7 @@ abstract class CommonObject
* @param array $info content informations of field
* @return bool
*/
- protected function isText($info)
+ public function isText($info)
{
if(is_array($info))
{
@@ -4846,49 +4847,58 @@ abstract class CommonObject
}
/**
- * Function to prepare the values to insert
+ * Function to prepare the values to insert.
+ * Note $this->${field} are set by the page that make the createCommon or the updateCommon.
*
* @return array
*/
private function set_save_query()
{
- $query=array();
- foreach ($this->fields as $field=>$info)
+ global $conf;
+
+ $queryarray=array();
+ foreach ($this->fields as $field=>$info) // Loop on definition of fields
{
+ // Depending on field type ('datetime', ...)
if($this->isDate($info))
{
if(empty($this->{$field}))
{
- $query[$field] = NULL;
+ $queryarray[$field] = NULL;
}
else
{
- $query[$field] = $this->db->idate($this->{$field});
+ $queryarray[$field] = $this->db->idate($this->{$field});
}
}
else if($this->isArray($info))
{
- $query[$field] = serialize($this->{$field});
+ $queryarray[$field] = serialize($this->{$field});
}
else if($this->isInt($info))
{
- $query[$field] = (int) price2num($this->{$field});
+ if ($field == 'entity' && is_null($this->{$field})) $queryarray[$field]=$conf->entity;
+ else
+ {
+ $queryarray[$field] = (int) price2num($this->{$field});
+ if (empty($queryarray[$field])) $queryarray[$field]=0; // May be rest to null later if property 'nullifempty' is on for this field.
+ }
}
else if($this->isFloat($info))
{
- $query[$field] = (double) price2num($this->{$field});
- }
- elseif($this->isNull($info))
- {
- $query[$field] = (is_null($this->{$field}) || (empty($this->{$field}) && $this->{$field}!==0 && $this->{$field}!=='0') ? null : $this->{$field});
+ $queryarray[$field] = (double) price2num($this->{$field});
+ if (empty($queryarray[$field])) $queryarray[$field]=0;
}
else
{
- $query[$field] = $this->{$field};
+ $queryarray[$field] = $this->{$field};
}
+
+ if ($info['type'] == 'timestamp' && empty($queryarray[$field])) unset($queryarray[$field]);
+ if (! empty($info['nullifempty']) && empty($queryarray[$field])) $queryarray[$field] = null;
}
- return $query;
+ return $queryarray;
}
/**
@@ -4896,7 +4906,7 @@ abstract class CommonObject
*
* @param stdClass $obj Contain data of object from database
*/
- private function set_vars_by_db(&$obj)
+ private function setVarsFromFetchObj(&$obj)
{
foreach ($this->fields as $field => $info)
{
@@ -4913,7 +4923,8 @@ abstract class CommonObject
}
elseif($this->isInt($info))
{
- $this->{$field} = (int) $obj->{$field};
+ if ($field == 'rowid') $this->id = (int) $obj->{$field};
+ else $this->{$field} = (int) $obj->{$field};
}
elseif($this->isFloat($info))
{
@@ -4947,15 +4958,14 @@ abstract class CommonObject
/**
* Add quote to field value if necessary
*
- * @param string|int $value value to protect
- * @return string|int
+ * @param string|int $value Value to protect
+ * @param array $fieldsentry Properties of field
+ * @return string
*/
- protected function quote($value) {
-
- if(is_null($value)) return 'NULL';
- else if(is_numeric($value)) return $value;
- else return "'".$this->db->escape( $value )."'";
-
+ protected function quote($value, $fieldsentry) {
+ if (is_null($value)) return 'NULL';
+ else if (preg_match('/^(int|double|real)/i', $fieldsentry['type'])) return $this->db->escape("$value");
+ else return "'".$this->db->escape($value)."'";
}
@@ -4970,23 +4980,29 @@ abstract class CommonObject
{
$error = 0;
- $fields = array_merge(array('datec'=>$this->db->idate(dol_now())), $this->set_save_query());
+ $now=dol_now();
+
+ $fieldvalues = $this->set_save_query();
+ if (array_key_exists('date_creation', $fieldvalues) && empty($fieldvalues['date_creation'])) $fieldvalues['date_creation']=$this->db->idate($now);
+ if (array_key_exists('fk_user_creat', $fieldvalues) && ! ($fieldvalues['fk_user_creat'] > 0)) $fieldvalues['fk_user_creat']=$user->id;
+ unset($fieldvalues['rowid']); // We suppose the field rowid is reserved field for autoincrement field.
$keys=array();
$values = array();
- foreach ($fields as $k => $v) {
+ foreach ($fieldvalues as $k => $v) {
$keys[] = $k;
- $values[] = $this->quote($v);
+ $values[] = $this->quote($v, $this->fields[$k]);
}
$this->db->begin();
if (! $error)
{
- $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'
- ( '.implode( ",", $keys ).' )
- VALUES ( '.implode( ",", $values ).' ) ';
- $res = $this->db->query( $sql );
+ $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element;
+ $sql.= ' ('.implode( ", ", $keys ).')';
+ $sql.= ' VALUES ('.implode( ", ", $values ).')';
+
+ $res = $this->db->query( $sql );
if ($res===false) {
$error++;
$this->errors[] = $this->db->lasterror();
@@ -4998,7 +5014,7 @@ abstract class CommonObject
if (!$notrigger) {
// Call triggers
- $result=$this->call_trigger(strtoupper(get_class(self)).'_CREATE',$user);
+ $result=$this->call_trigger(strtoupper(get_class($this)).'_CREATE',$user);
if ($result < 0) { $error++; }
// End call triggers
}
@@ -5023,7 +5039,7 @@ abstract class CommonObject
*/
public function createFromCloneCommon(User $user, $fromid)
{
- global $user;
+ global $user, $langs;
$error = 0;
@@ -5035,10 +5051,14 @@ abstract class CommonObject
// Load source object
$object->fetchCommon($fromid);
- // Reset object
- $object->id = 0;
+ // Reset some properties
+ unset($object->id);
+ unset($object->fk_user_creat);
+ unset($object->import_key);
// Clear fields
+ $object->ref = "copy_of_".$object->ref;
+ $object->title = $langs->trans("CopyOf")." ".$object->title;
// ...
// Create clone
@@ -5046,7 +5066,8 @@ abstract class CommonObject
// Other options
if ($result < 0) {
- $error ++;
+ $error++;
+ $this->error = $object->error;
$this->errors = $object->errors;
dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
}
@@ -5072,11 +5093,11 @@ abstract class CommonObject
{
if (empty($id) && empty($ref)) return false;
- $sql = 'SELECT '.$this->get_field_list().', datec, tms';
+ $sql = 'SELECT '.$this->get_field_list();
$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
if(!empty($id)) $sql.= ' WHERE rowid = '.$id;
- else $sql.= ' WHERE ref = \''.$this->quote($ref).'\'';
+ else $sql.= " WHERE ref = ".$this->quote($ref, $this->fields['ref']);
$res = $this->db->query($sql);
if ($res)
@@ -5085,12 +5106,7 @@ abstract class CommonObject
{
if ($obj)
{
- $this->id = $id;
- $this->set_vars_by_db($obj);
-
- $this->datec = $this->db->idate($obj->datec);
- $this->tms = $this->db->idate($obj->tms);
-
+ $this->setVarsFromFetchObj($obj);
return $this->id;
}
else
@@ -5124,27 +5140,27 @@ abstract class CommonObject
{
$error = 0;
- $fields = $this->set_save_query();
+ $fieldvalues = $this->set_save_query();
+ unset($fieldvalues['rowid']); // We don't update this field, it is the key to define which record to update.
- foreach ($fields as $k => $v) {
+ foreach ($fieldvalues as $k => $v) {
if (is_array($key)){
$i=array_search($k, $key);
if ( $i !== false) {
- $where[] = $key[$i].'=' . $this->quote( $v ) ;
+ $where[] = $key[$i].'=' . $this->quote($v, $this->fields[$k]);
continue;
}
} else {
if ( $k == $key) {
- $where[] = $k.'=' .$this->quote( $v ) ;
+ $where[] = $k.'=' .$this->quote($v, $this->fields[$k]);
continue;
}
}
- $tmp[] = $k.'='.$this->quote($v);
+ $tmp[] = $k.'='.$this->quote($v, $this->fields[$k]);
}
$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
$this->db->begin();
-
if (! $error)
{
$res = $this->db->query($sql);
@@ -5157,7 +5173,7 @@ abstract class CommonObject
if (! $error && ! $notrigger) {
// Call triggers
- $result=$this->call_trigger(strtoupper(get_class(self)).'_MODIFY',$user);
+ $result=$this->call_trigger(strtoupper(get_class($this)).'_MODIFY',$user);
if ($result < 0) { $error++; } //Do also here what you must do to rollback action if trigger fail
// End call triggers
}
@@ -5188,7 +5204,7 @@ abstract class CommonObject
if (! $error) {
if (! $notrigger) {
// Call triggers
- $result=$this->call_trigger(strtoupper(get_class(self)).'_DELETE', $user);
+ $result=$this->call_trigger(strtoupper(get_class($this)).'_DELETE', $user);
if ($result < 0) { $error++; } // Do also here what you must do to rollback action if trigger fail
// End call triggers
}
diff --git a/htdocs/core/class/doleditor.class.php b/htdocs/core/class/doleditor.class.php
index db768b4c630..eaf72ffff71 100644
--- a/htdocs/core/class/doleditor.class.php
+++ b/htdocs/core/class/doleditor.class.php
@@ -82,7 +82,7 @@ class DolEditor
// Check if extended editor is ok. If not we force textarea
if ((empty($conf->fckeditor->enabled) && $okforextendededitor != 'ace') || empty($okforextendededitor)) $this->tool = 'textarea';
if ($okforextendededitor === 'ace') $this->tool='ace';
- if ($conf->dol_use_jmobile) $this->tool = 'textarea'; // TODO ckeditor ko with mobile ? ace ko with mobile ?
+ //if ($conf->dol_use_jmobile) $this->tool = 'textarea'; // ckeditor and ace seems ok with mobile
// Define content and some properties
if ($this->tool == 'ckeditor')
diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php
index e44fa8a5aec..966f3f859c0 100644
--- a/htdocs/core/class/extrafields.class.php
+++ b/htdocs/core/class/extrafields.class.php
@@ -281,7 +281,7 @@ class ExtraFields
*/
private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list=0, $ishidden=0, $default='', $computed='')
{
- global $conf;
+ global $conf,$user;
if ($elementtype == 'thirdparty') $elementtype='societe';
if ($elementtype == 'contact') $elementtype='socpeople';
@@ -305,7 +305,27 @@ class ExtraFields
$params='';
}
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype, fieldunique, fieldrequired, param, alwayseditable, perms, list, ishidden, fielddefault, fieldcomputed)";
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
+ $sql.= " name,";
+ $sql.= " label,";
+ $sql.= " type,";
+ $sql.= " pos,";
+ $sql.= " size,";
+ $sql.= " entity,";
+ $sql.= " elementtype,";
+ $sql.= " fieldunique,";
+ $sql.= " fieldrequired,";
+ $sql.= " param,";
+ $sql.= " alwayseditable,";
+ $sql.= " perms,";
+ $sql.= " list,";
+ $sql.= " ishidden,";
+ $sql.= " fielddefault,";
+ $sql.= " fieldcomputed,";
+ $sql.= " fk_user_author,";
+ $sql.= " fk_user_modif,";
+ $sql.= " datec";
+ $sql.= " )";
$sql.= " VALUES('".$attrname."',";
$sql.= " '".$this->db->escape($label)."',";
$sql.= " '".$type."',";
@@ -321,9 +341,12 @@ class ExtraFields
$sql.= " ".$list.",";
$sql.= " ".$ishidden.",";
$sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
- $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
+ $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
+ $sql .= " " . $user->id . ",";
+ $sql .= " " . $user->id . ",";
+ $sql .= "'" . $this->db->idate(dol_now()) . "'";
$sql.=')';
-
+
dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
if ($this->db->query($sql))
{
@@ -562,7 +585,7 @@ class ExtraFields
*/
private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list=0,$ishidden=0,$default='',$computed='')
{
- global $conf;
+ global $conf, $user;
dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$ishidden.", ".$default.", ".$computed);
// Clean parameters
@@ -603,7 +626,10 @@ class ExtraFields
$sql.= " list,";
$sql.= " ishidden,";
$sql.= " fielddefault,";
- $sql.= " fieldcomputed";
+ $sql.= " fieldcomputed,";
+ $sql.= " fk_user_author,";
+ $sql.= " fk_user_modif,";
+ $sql.= " datec";
$sql.= ") VALUES (";
$sql.= "'".$attrname."',";
$sql.= " ".$conf->entity.",";
@@ -620,7 +646,10 @@ class ExtraFields
$sql.= " ".$list.", ";
$sql.= " ".$ishidden.", ";
$sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
- $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
+ $sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null").",";
+ $sql .= " " . $user->id . ",";
+ $sql .= " " . $user->id . ",";
+ $sql .= "'" . $this->db->idate(dol_now()) . "'";
$sql.= ")";
$resql2=$this->db->query($sql);
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index 0f16a25c43f..880f32cc580 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -4417,7 +4417,7 @@ class Form
dol_syslog(__METHOD__, LOG_DEBUG);
- $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.recuperableonly";
+ $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
$sql.= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
$sql.= " WHERE t.fk_pays = c.rowid";
$sql.= " AND t.active > 0";
@@ -4436,8 +4436,20 @@ class Form
$this->cache_vatrates[$i]['rowid'] = $obj->rowid;
$this->cache_vatrates[$i]['code'] = $obj->code;
$this->cache_vatrates[$i]['txtva'] = $obj->taux;
- $this->cache_vatrates[$i]['libtva'] = $obj->taux.'%'.($obj->code?' ('.$obj->code.')':''); // Label must contains only 0-9 , . % or *
$this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
+ $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
+ $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
+ $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
+ $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
+
+ $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code?' ('.$obj->code.')':''); // Label must contains only 0-9 , . % or *
+ $this->cache_vatrates[$i]['labelallrates'] = $obj->taux.'/'.($obj->localtax1?$obj->localtax1:'0').'/'.($obj->localtax2?$obj->localtax2:'0').($obj->code?' ('.$obj->code.')':''); // Must never be used as key, only label
+ $positiverates='';
+ if ($obj->taux) $positiverates.=($positiverates?'/':'').$obj->taux;
+ if ($obj->localtax1) $positiverates.=($positiverates?'/':'').$obj->localtax1;
+ if ($obj->localtax2) $positiverates.=($positiverates?'/':'').$obj->localtax2;
+ if (empty($positiverates)) $positiverates='0';
+ $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code?' ('.$obj->code.')':''); // Must never be used as key, only label
}
return $num;
@@ -4611,7 +4623,16 @@ class Form
$selectedfound=true;
}
}
- $return.= '>'.vatrate($rate['libtva']);
+ $return.= '>';
+ //if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
+ if ($mysoc->country_code == 'IN' || ! empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
+ {
+ $return.= $rate['labelpositiverates'];
+ }
+ else
+ {
+ $return.= vatrate($rate['label']);
+ }
//$return.=($rate['code']?' '.$rate['code']:'');
$return.= (empty($rate['code']) && $rate['nprtva']) ? ' *': ''; // We show the * (old behaviour only if new vat code is not used)
@@ -5604,6 +5625,14 @@ class Form
{
$listofidcompanytoscan=$object->thirdparty->id;
if (($object->thirdparty->parent > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan.=','.$object->thirdparty->parent;
+ if (($object->fk_project > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
+ {
+ include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
+ $tmpproject=new Project($this->db);
+ $tmpproject->fetch($object->fk_project);
+ if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan.=','.$tmpproject->socid;
+ unset($tmpproject);
+ }
$possiblelinks=array(
'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('propal').')'),
@@ -5835,7 +5864,7 @@ class Form
* @param string $paramid Name of parameter to use to name the id into the URL next/previous link.
* @param string $morehtml More html content to output just before the nav bar.
* @param int $shownav Show Condition (navigation is shown if value is 1).
- * @param string $fieldid Name of field id into database to use for select next and previous (we make the select max and min on this field).
+ * @param string $fieldid Name of field id into database to use for select next and previous (we make the select max and min on this field). Use 'none' to disable next/prev.
* @param string $fieldref Name of field ref of object (object->ref) to show or 'none' to not show ref.
* @param string $morehtmlref More html to show after ref.
* @param string $moreparam More param to add in nav link url. Must start with '&...'.
diff --git a/htdocs/core/class/html.formwebsite.class.php b/htdocs/core/class/html.formwebsite.class.php
new file mode 100644
index 00000000000..666311d1744
--- /dev/null
+++ b/htdocs/core/class/html.formwebsite.class.php
@@ -0,0 +1,1254 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file htdocs/core/class/html.formwebsite.class.php
+ * \ingroup core
+ * \brief File of class to manage component html for module website
+ */
+
+
+/**
+ * Class to manage component html for module website
+ */
+class FormWebsite
+{
+ private $db;
+ public $error;
+
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ function __construct($db)
+ {
+ $this->db = $db;
+
+ return 1;
+ }
+
+
+ /**
+ * Return HTML select list of export models
+ *
+ * @param string $selected Id modele pre-selectionne
+ * @param string $htmlname Name of HTML select
+ * @param int $useempty Show empty value or not
+ * @return string Html component
+ */
+ function selectWebsite($selected='',$htmlname='exportmodelid',$useempty=0)
+ {
+ $out='';
+
+ $sql = "SELECT rowid, ref";
+ $sql.= " FROM ".MAIN_DB_PREFIX."website";
+ $sql.= " WHERE 1 = 1";
+ $sql.= " ORDER BY rowid";
+ $result = $this->db->query($sql);
+ if ($result)
+ {
+ $out.='";
+ }
+ else {
+ dol_print_error($this->db);
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Return list of export models
+ *
+ * @param string $selected Id modele pre-selectionne
+ * @param string $htmlname Nom de la zone select
+ * @param string $type Type des modeles recherches
+ * @param int $useempty Affiche valeur vide dans liste
+ * @return void
+ */
+ function select_import_model($selected='',$htmlname='importmodelid',$type='',$useempty=0)
+ {
+ $sql = "SELECT rowid, label";
+ $sql.= " FROM ".MAIN_DB_PREFIX."import_model";
+ $sql.= " WHERE type = '".$type."'";
+ $sql.= " ORDER BY rowid";
+ $result = $this->db->query($sql);
+ if ($result)
+ {
+ print '";
+ }
+ else {
+ dol_print_error($this->db);
+ }
+ }
+
+
+ /**
+ * Return list of ecotaxes with label
+ *
+ * @param string $selected Preselected ecotaxes
+ * @param string $htmlname Name of combo list
+ * @return integer
+ */
+ function select_ecotaxes($selected='',$htmlname='ecotaxe_id')
+ {
+ global $langs;
+
+ $sql = "SELECT e.rowid, e.code, e.libelle, e.price, e.organization,";
+ $sql.= " c.label as country";
+ $sql.= " FROM ".MAIN_DB_PREFIX."c_ecotaxe as e,".MAIN_DB_PREFIX."c_country as c";
+ $sql.= " WHERE e.active = 1 AND e.fk_pays = c.rowid";
+ $sql.= " ORDER BY country, e.organization ASC, e.code ASC";
+
+ dol_syslog(get_class($this).'::select_ecotaxes', LOG_DEBUG);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ print '';
+ return 0;
+ }
+ else
+ {
+ dol_print_error($this->db);
+ return 1;
+ }
+ }
+
+
+ /**
+ * Return list of revenue stamp for country
+ *
+ * @param string $selected Value of preselected revenue stamp
+ * @param string $htmlname Name of combo list
+ * @param string $country_code Country Code
+ * @return string HTML select list
+ */
+ function select_revenue_stamp($selected='',$htmlname='revenuestamp',$country_code='')
+ {
+ global $langs;
+
+ $out='';
+
+ $sql = "SELECT r.taux";
+ $sql.= " FROM ".MAIN_DB_PREFIX."c_revenuestamp as r,".MAIN_DB_PREFIX."c_country as c";
+ $sql.= " WHERE r.active = 1 AND r.fk_pays = c.rowid";
+ $sql.= " AND c.code = '".$country_code."'";
+
+ dol_syslog(get_class($this).'::select_revenue_stamp', LOG_DEBUG);
+ $resql=$this->db->query($sql);
+ if ($resql)
+ {
+ $out.='';
+ return $out;
+ }
+ else
+ {
+ dol_print_error($this->db);
+ return '';
+ }
+ }
+
+
+ /**
+ * Return a HTML select list to select a percent
+ *
+ * @param integer $selected pourcentage pre-selectionne
+ * @param string $htmlname nom de la liste deroulante
+ * @param int $disabled Disabled or not
+ * @param int $increment increment value
+ * @param int $start start value
+ * @param int $end end value
+ * @param int $showempty Add also an empty line
+ * @return string HTML select string
+ */
+ function select_percent($selected=0,$htmlname='percent',$disabled=0,$increment=5,$start=0,$end=100,$showempty=0)
+ {
+ $return = '';
+
+ return $return;
+ }
+
+ /**
+ * Return select list for categories (to use in form search selectors)
+ *
+ * @param int $type Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
+ * @param integer $selected Preselected value
+ * @param string $htmlname Name of combo list
+ * @param int $nocateg Show also an entry "Not categorized"
+ * @param int $showempty Add also an empty line
+ * @param string $morecss More CSS
+ * @return string Html combo list code
+ * @see select_all_categories
+ */
+ function select_categories($type, $selected=0, $htmlname='search_categ', $nocateg=0, $showempty=1, $morecss='')
+ {
+ global $conf, $langs;
+ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+
+ // For backward compatibility
+ if (is_numeric($type))
+ {
+ dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
+ }
+
+ // Load list of "categories"
+ $static_categs = new Categorie($this->db);
+ $tab_categs = $static_categs->get_full_arbo($type);
+
+ $moreforfilter = '';
+ // Enhance with select2
+ if ($conf->use_javascript_ajax)
+ {
+ include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
+ $comboenhancement = ajax_combobox('select_categ_'.$htmlname);
+ $moreforfilter.=$comboenhancement;
+ }
+
+ // Print a select with each of them
+ $moreforfilter.='';
+
+ return $moreforfilter;
+ }
+
+
+ /**
+ * Return select list for categories (to use in form search selectors)
+ *
+ * @param string $selected Preselected value
+ * @param string $htmlname Name of combo list (example: 'search_sale')
+ * @param User $user Object user
+ * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
+ * @param int $showempty 1=show also an empty value
+ * @param string $morecss More CSS
+ * @return string Html combo list code
+ */
+ function select_salesrepresentatives($selected,$htmlname,$user,$showstatus=0,$showempty=1,$morecss='')
+ {
+ global $conf,$langs;
+ $langs->load('users');
+
+ $out = '';
+ // Enhance with select2
+ if ($conf->use_javascript_ajax)
+ {
+ include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
+
+ $comboenhancement = ajax_combobox($htmlname);
+ if ($comboenhancement)
+ {
+ $out.=$comboenhancement;
+ }
+ }
+ // Select each sales and print them in a select input
+ $out.='';
+
+ return $out;
+ }
+
+ /**
+ * Return list of project and tasks
+ *
+ * @param int $selectedtask Pre-selected task
+ * @param int $projectid Project id
+ * @param string $htmlname Name of html select
+ * @param int $modeproject 1 to restrict on projects owned by user
+ * @param int $modetask 1 to restrict on tasks associated to user
+ * @param int $mode 0=Return list of tasks and their projects, 1=Return projects and tasks if exists
+ * @param int $useempty 0=Allow empty values
+ * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id
+ * @return void
+ */
+ function selectProjectTasks($selectedtask='', $projectid=0, $htmlname='task_parent', $modeproject=0, $modetask=0, $mode=0, $useempty=0, $disablechildoftaskid=0)
+ {
+ global $user, $langs;
+
+ require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
+
+ //print $modeproject.'-'.$modetask;
+ $task=new Task($this->db);
+ $tasksarray=$task->getTasksArray($modetask?$user:0, $modeproject?$user:0, $projectid, 0, $mode);
+ if ($tasksarray)
+ {
+ print '';
+ }
+ else
+ {
+ print '
'.$langs->trans("NoProject").'
';
+ }
+ }
+
+ /**
+ * Write lines of a project (all lines of a project if parent = 0)
+ *
+ * @param int $inc Cursor counter
+ * @param int $parent Id of parent task we want to see
+ * @param array $lines Array of task lines
+ * @param int $level Level
+ * @param int $selectedtask Id selected task
+ * @param int $selectedproject Id selected project
+ * @param int $disablechildoftaskid 1=Disable task that are child of the provided task id
+ * @return void
+ */
+ private function _pLineSelect(&$inc, $parent, $lines, $level=0, $selectedtask=0, $selectedproject=0, $disablechildoftaskid=0)
+ {
+ global $langs, $user, $conf;
+
+ $lastprojectid=0;
+
+ $numlines=count($lines);
+ for ($i = 0 ; $i < $numlines ; $i++)
+ {
+ if ($lines[$i]->fk_parent == $parent)
+ {
+ $var = !$var;
+
+ //var_dump($selectedproject."--".$selectedtask."--".$lines[$i]->fk_project."_".$lines[$i]->id); // $lines[$i]->id may be empty if project has no lines
+
+ // Break on a new project
+ if ($parent == 0) // We are on a task at first level
+ {
+ if ($lines[$i]->fk_project != $lastprojectid) // Break found on project
+ {
+ if ($i > 0) print '';
+ print '\n";
+
+ $lastprojectid=$lines[$i]->fk_project;
+ $inc++;
+ }
+ }
+
+ $newdisablechildoftaskid=$disablechildoftaskid;
+
+ // Print task
+ if (isset($lines[$i]->id)) // We use isset because $lines[$i]->id may be null if project has no task and are on root project (tasks may be caught by a left join). We enter here only if '0' or >0
+ {
+ // Check if we must disable entry
+ $disabled=0;
+ if ($disablechildoftaskid && (($lines[$i]->id == $disablechildoftaskid || $lines[$i]->fk_parent == $disablechildoftaskid)))
+ {
+ $disabled++;
+ if ($lines[$i]->fk_parent == $disablechildoftaskid) $newdisablechildoftaskid=$lines[$i]->id; // If task is child of a disabled parent, we will propagate id to disable next child too
+ }
+
+ print '\n";
+ $inc++;
+ }
+
+ $level++;
+ if ($lines[$i]->id) $this->_pLineSelect($inc, $lines[$i]->id, $lines, $level, $selectedtask, $selectedproject, $newdisablechildoftaskid);
+ $level--;
+ }
+ }
+ }
+
+
+ /**
+ * Output a HTML thumb of color or a text if not defined.
+ *
+ * @param string $color String with hex (FFFFFF) or comma RGB ('255,255,255')
+ * @param string $textifnotdefined Text to show if color not defined
+ * @return string HTML code for color thumb
+ * @see selectColor
+ */
+ static function showColor($color, $textifnotdefined='')
+ {
+ $textcolor='FFF';
+ if ($color)
+ {
+ $tmp=explode(',', $color);
+ if (count($tmp) > 1) // This is a comma RGB ('255','255','255')
+ {
+ $r = $tmp[0];
+ $g = $tmp[1];
+ $b = $tmp[2];
+ }
+ else
+ {
+ $hexr=$color[0].$color[1];
+ $hexg=$color[2].$color[3];
+ $hexb=$color[4].$color[5];
+ $r = hexdec($hexr);
+ $g = hexdec($hexg);
+ $b = hexdec($hexb);
+ }
+ $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
+ if ($bright > 0.6) $textcolor='000';
+ }
+
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+ $color = colorArrayToHex(colorStringToArray($color,array()),'');
+
+ if ($color) print '';
+ else print $textifnotdefined;
+ }
+
+ /**
+ * Output a HTML code to select a color
+ *
+ * @param string $set_color Pre-selected color
+ * @param string $prefix Name of HTML field
+ * @param string $form_name Deprecated. Not used.
+ * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code
+ * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813')
+ * @return void
+ * @deprecated Use instead selectColor
+ * @see selectColor()
+ */
+ function select_color($set_color='', $prefix='f_color', $form_name='', $showcolorbox=1, $arrayofcolors='')
+ {
+ print $this->selectColor($set_color, $prefix, $form_name, $showcolorbox, $arrayofcolors);
+ }
+
+ /**
+ * Output a HTML code to select a color. Field will return an hexa color like '334455'.
+ *
+ * @param string $set_color Pre-selected color
+ * @param string $prefix Name of HTML field
+ * @param string $form_name Deprecated. Not used.
+ * @param int $showcolorbox 1=Show color code and color box, 0=Show only color code
+ * @param array $arrayofcolors Array of colors. Example: array('29527A','5229A3','A32929','7A367A','B1365F','0D7813')
+ * @param string $morecss Add css style into input field
+ * @return string
+ * @see showColor
+ */
+ static function selectColor($set_color='', $prefix='f_color', $form_name='', $showcolorbox=1, $arrayofcolors='', $morecss='')
+ {
+ // Deprecation warning
+ if ($form_name) {
+ dol_syslog(__METHOD__ . ": form_name parameter is deprecated", LOG_WARNING);
+ }
+
+ global $langs,$conf;
+
+ $out='';
+
+ if (! is_array($arrayofcolors) || count($arrayofcolors) < 1)
+ {
+ $langs->load("other");
+ if (empty($conf->dol_use_jmobile))
+ {
+ $out.= '';
+ $out.= '';
+ $out.= '';
+ }
+ $out.= '';
+ }
+ else // In most cases, this is not used. We used instead function with no specific list of colors
+ {
+ if (empty($conf->dol_use_jmobile))
+ {
+ $out.= '';
+ $out.= '';
+ $out.= '';
+ }
+ $out.= '';
+ }
+
+ return $out;
+ }
+
+ /**
+ * Creation d'un icone de couleur
+ *
+ * @param string $color Couleur de l'image
+ * @param string $module Nom du module
+ * @param string $name Nom de l'image
+ * @param int $x Largeur de l'image en pixels
+ * @param int $y Hauteur de l'image en pixels
+ * @return void
+ */
+ function CreateColorIcon($color,$module,$name,$x='12',$y='12')
+ {
+ global $conf;
+
+ $file = $conf->$module->dir_temp.'/'.$name.'.png';
+
+ // On cree le repertoire contenant les icones
+ if (! file_exists($conf->$module->dir_temp))
+ {
+ dol_mkdir($conf->$module->dir_temp);
+ }
+
+ // On cree l'image en vraies couleurs
+ $image = imagecreatetruecolor($x,$y);
+
+ $color = substr($color,1,6);
+
+ $rouge = hexdec(substr($color,0,2)); //conversion du canal rouge
+ $vert = hexdec(substr($color,2,2)); //conversion du canal vert
+ $bleu = hexdec(substr($color,4,2)); //conversion du canal bleu
+
+ $couleur = imagecolorallocate($image,$rouge,$vert,$bleu);
+ //print $rouge.$vert.$bleu;
+ imagefill($image,0,0,$couleur); //on remplit l'image
+ // On cree la couleur et on l'attribue a une variable pour ne pas la perdre
+ ImagePng($image,$file); //renvoie une image sous format png
+ ImageDestroy($image);
+ }
+
+ /**
+ * Return HTML combo list of week
+ *
+ * @param string $selected Preselected value
+ * @param string $htmlname Nom de la zone select
+ * @param int $useempty Affiche valeur vide dans liste
+ * @return string
+ */
+ function select_dayofweek($selected='',$htmlname='weekid',$useempty=0)
+ {
+ global $langs;
+
+ $week = array( 0=>$langs->trans("Day0"),
+ 1=>$langs->trans("Day1"),
+ 2=>$langs->trans("Day2"),
+ 3=>$langs->trans("Day3"),
+ 4=>$langs->trans("Day4"),
+ 5=>$langs->trans("Day5"),
+ 6=>$langs->trans("Day6"));
+
+ $select_week = '';
+ return $select_week;
+ }
+
+ /**
+ * Return HTML combo list of month
+ *
+ * @param string $selected Preselected value
+ * @param string $htmlname Name of HTML select object
+ * @param int $useempty Show empty in list
+ * @param int $longlabel Show long label
+ * @return string
+ */
+ function select_month($selected='',$htmlname='monthid',$useempty=0,$longlabel=0)
+ {
+ global $langs;
+
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+
+ if ($longlabel) $montharray = monthArray($langs, 0); // Get array
+ else $montharray = monthArray($langs, 1);
+
+ $select_month = '';
+ return $select_month;
+ }
+
+ /**
+ * Return HTML combo list of years
+ *
+ * @param string $selected Preselected value (''=current year, -1=none, year otherwise)
+ * @param string $htmlname Name of HTML select object
+ * @param int $useempty Affiche valeur vide dans liste
+ * @param int $min_year Offset of minimum year into list (by default current year -10)
+ * @param int $max_year Offset of maximum year into list (by default current year + 5)
+ * @param int $offset Offset
+ * @param int $invert Invert
+ * @param string $option Option
+ * @return string
+ */
+ function select_year($selected='',$htmlname='yearid',$useempty=0, $min_year=10, $max_year=5, $offset=0, $invert=0, $option='')
+ {
+ print $this->selectyear($selected,$htmlname,$useempty,$min_year,$max_year,$offset,$invert,$option);
+ }
+
+ /**
+ * Return HTML combo list of years
+ *
+ * @param string $selected Preselected value (''=current year, -1=none, year otherwise)
+ * @param string $htmlname Name of HTML select object
+ * @param int $useempty Affiche valeur vide dans liste
+ * @param int $min_year Offset of minimum year into list (by default current year -10)
+ * @param int $max_year Offset of maximum year into list (by default current year + 5)
+ * @param int $offset Offset
+ * @param int $invert Invert
+ * @param string $option Option
+ * @return string
+ */
+ function selectyear($selected='',$htmlname='yearid',$useempty=0, $min_year=10, $max_year=5, $offset=0, $invert=0, $option='')
+ {
+ $out='';
+
+ $currentyear = date("Y")+$offset;
+ $max_year = $currentyear+$max_year;
+ $min_year = $currentyear-$min_year;
+ if(empty($selected) && empty($useempty)) $selected = $currentyear;
+
+ $out.= '\n";
+
+ return $out;
+ }
+
+ /**
+ * Show form to select address
+ *
+ * @param int $page Page
+ * @param string $selected Id condition pre-selectionne
+ * @param int $socid Id of third party
+ * @param string $htmlname Nom du formulaire select
+ * @param string $origin Origine de l'appel pour pouvoir creer un retour
+ * @param int $originid Id de l'origine
+ * @return void
+ */
+ function form_address($page, $selected, $socid, $htmlname='address_id', $origin='', $originid='')
+ {
+ global $langs,$conf;
+ global $form;
+
+ if ($htmlname != "none")
+ {
+ print '';
+ }
+ else
+ {
+ if ($selected)
+ {
+ require_once DOL_DOCUMENT_ROOT .'/societe/class/address.class.php';
+ $address=new Address($this->db);
+ $result=$address->fetch_address($selected);
+ print 'socid.'&id='.$address->id.'&action=edit&origin='.$origin.'&originid='.$originid.'>'.$address->label.'';
+ }
+ else
+ {
+ print " ";
+ }
+ }
+ }
+
+
+
+ /**
+ * Get array with HTML tabs with boxes of a particular area including personalized choices of user.
+ * Class 'Form' must be known.
+ *
+ * @param User $user Object User
+ * @param String $areacode Code of area for pages ('0'=value for Home page)
+ * @return array array('selectboxlist'=>, 'boxactivated'=>, 'boxlista'=>, 'boxlistb'=>)
+ */
+ static function getBoxesArea($user,$areacode)
+ {
+ global $conf,$langs,$db;
+
+ include_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php';
+
+ $confuserzone='MAIN_BOXES_'.$areacode;
+
+ // $boxactivated will be array of boxes enabled into global setup
+ // $boxidactivatedforuser will be array of boxes choosed by user
+
+ $selectboxlist='';
+ $boxactivated=InfoBox::listBoxes($db, 'activated', $areacode, (empty($user->conf->$confuserzone)?null:$user), array(), 0); // Search boxes of common+user (or common only if user has no specific setup)
+
+ $boxidactivatedforuser=array();
+ foreach($boxactivated as $box)
+ {
+ if (empty($user->conf->$confuserzone) || $box->fk_user == $user->id) $boxidactivatedforuser[$box->id]=$box->id; // We keep only boxes to show for user
+ }
+
+ // Define selectboxlist
+ $arrayboxtoactivatelabel=array();
+ if (! empty($user->conf->$confuserzone))
+ {
+ $boxorder='';
+ $langs->load("boxes"); // Load label of boxes
+ foreach($boxactivated as $box)
+ {
+ if (! empty($boxidactivatedforuser[$box->id])) continue; // Already visible for user
+ $label=$langs->transnoentitiesnoconv($box->boxlabel);
+ if (preg_match('/graph/',$box->class)) $label.=' ('.$langs->trans("Graph").')';
+ //$label = ''.$label; KO with select2. No html rendering.
+ $arrayboxtoactivatelabel[$box->id]=$label; // We keep only boxes not shown for user, to show into combo list
+ }
+ foreach($boxidactivatedforuser as $boxid)
+ {
+ if (empty($boxorder)) $boxorder.='A:';
+ $boxorder.=$boxid.',';
+ }
+
+ //var_dump($boxidactivatedforuser);
+
+ // Class Form must have been already loaded
+ $selectboxlist.='';
+ $selectboxlist.=ajax_combobox("boxcombo");
+ }
+
+ // Javascript code for dynamic actions
+ if (! empty($conf->use_javascript_ajax))
+ {
+ $selectboxlist.=''."\n";
+ }
+
+ // Define boxlista and boxlistb
+ $nbboxactivated=count($boxidactivatedforuser);
+
+ if ($nbboxactivated)
+ {
+ $langs->load("boxes");
+ $langs->load("projects");
+
+ $emptybox=new ModeleBoxes($db);
+
+ $boxlista.="\n\n";
+ $boxlista.='
'."\n";
+
+ // Define $box_max_lines
+ $box_max_lines=5;
+ if (! empty($conf->global->MAIN_BOXES_MAXLINES)) $box_max_lines=$conf->global->MAIN_BOXES_MAXLINES;
+
+ $ii=0;
+ foreach ($boxactivated as $key => $box)
+ {
+ if ((! empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue;
+ if (empty($box->box_order) && $ii < ($nbboxactivated / 2)) $box->box_order='A'.sprintf("%02d",($ii+1)); // When box_order was not yet set to Axx or Bxx and is still 0
+ if (preg_match('/^A/i',$box->box_order)) // column A
+ {
+ $ii++;
+ //print 'box_id '.$boxactivated[$ii]->box_id.' ';
+ //print 'box_order '.$boxactivated[$ii]->box_order.' ';
+ // Show box
+ $box->loadBox($box_max_lines);
+ $boxlista.= $box->outputBox();
+ }
+ }
+
+ if (empty($conf->browser->phone))
+ {
+ $emptybox->box_id='A';
+ $emptybox->info_box_head=array();
+ $emptybox->info_box_contents=array();
+ $boxlista.= $emptybox->outputBox(array(),array());
+ }
+ $boxlista.= "
'."\n";
+
+ $ii=0;
+ foreach ($boxactivated as $key => $box)
+ {
+ if ((! empty($user->conf->$confuserzone) && $box->fk_user == 0) || (empty($user->conf->$confuserzone) && $box->fk_user != 0)) continue;
+ if (empty($box->box_order) && $ii < ($nbboxactivated / 2)) $box->box_order='B'.sprintf("%02d",($ii+1)); // When box_order was not yet set to Axx or Bxx and is still 0
+ if (preg_match('/^B/i',$box->box_order)) // colonne B
+ {
+ $ii++;
+ //print 'box_id '.$boxactivated[$ii]->box_id.' ';
+ //print 'box_order '.$boxactivated[$ii]->box_order.' ';
+ // Show box
+ $box->loadBox($box_max_lines);
+ $boxlistb.= $box->outputBox();
+ }
+ }
+
+ if (empty($conf->browser->phone))
+ {
+ $emptybox->box_id='B';
+ $emptybox->info_box_head=array();
+ $emptybox->info_box_contents=array();
+ $boxlistb.= $emptybox->outputBox(array(),array());
+ }
+ $boxlistb.= "
\n";
+ $boxlistb.= "\n";
+
+ }
+
+ return array('selectboxlist'=>count($boxactivated)?$selectboxlist:'', 'boxactivated'=>$boxactivated, 'boxlista'=>$boxlista, 'boxlistb'=>$boxlistb);
+ }
+
+
+ /**
+ * Return a HTML select list of bank accounts
+ *
+ * @param string $htmlname Name of select zone
+ * @param string $dictionarytable Dictionary table
+ * @param string $keyfield Field for key
+ * @param string $labelfield Label field
+ * @param string $selected Selected value
+ * @param int $useempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
+ * @param string $moreattrib More attributes on HTML select tag
+ * @return void
+ */
+ function select_dictionary($htmlname,$dictionarytable,$keyfield='code',$labelfield='label',$selected='',$useempty=0,$moreattrib='')
+ {
+ global $langs, $conf;
+
+ $langs->load("admin");
+
+ $sql = "SELECT rowid, ".$keyfield.", ".$labelfield;
+ $sql.= " FROM ".MAIN_DB_PREFIX.$dictionarytable;
+ $sql.= " ORDER BY ".$labelfield;
+
+ dol_syslog(get_class($this)."::select_dictionary", LOG_DEBUG);
+ $result = $this->db->query($sql);
+ if ($result)
+ {
+ $num = $this->db->num_rows($result);
+ $i = 0;
+ if ($num)
+ {
+ print '";
+ }
+ else
+ {
+ print $langs->trans("DictionaryEmpty");
+ }
+ }
+ else {
+ dol_print_error($this->db);
+ }
+ }
+
+}
+
diff --git a/htdocs/core/class/smtps.class.php b/htdocs/core/class/smtps.class.php
index 9e6250f9f8d..c92558bf1d3 100644
--- a/htdocs/core/class/smtps.class.php
+++ b/htdocs/core/class/smtps.class.php
@@ -271,7 +271,7 @@ class SMTPs
{
$this->_moreinheader = $_val;
}
-
+
/**
* get trackid
*
@@ -291,7 +291,7 @@ class SMTPs
{
return $this->_moreinheader;
}
-
+
/**
* Set errors to
*
@@ -411,7 +411,7 @@ class SMTPs
function _server_authenticate()
{
global $conf;
-
+
// Send the RFC2554 specified EHLO.
// This improvment as provided by 'SirSir' to
// accomodate both SMTP AND ESMTP capable servers
@@ -462,7 +462,7 @@ class SMTPs
{
$this->_setErr(126, '"' . $host . '" does not support authenticated connections.');
return $_retVal;
- }
+ }
}
// Send Authentication to Server
// Check for errors along the way
@@ -903,7 +903,7 @@ class SMTPs
if ( $_strReplyTo )
$this->_msgReplyTo = $this->_strip_email($_strReplyTo);
}
-
+
/**
* Retrieves the Address from which mail will be the reply-to
*
@@ -913,15 +913,15 @@ class SMTPs
function getReplyTo($_part = true)
{
$_retValue = '';
-
+
if ( $_part === true )
$_retValue = $this->_msgReplyTo;
else
$_retValue = $this->_msgReplyTo[$_part];
-
+
return $_retValue;
}
-
+
/**
* Inserts given addresses into structured format.
* This method takes a list of given addresses, via an array
@@ -1217,6 +1217,8 @@ class SMTPs
*/
function getHeader()
{
+ global $conf;
+
$_header = 'From: ' . $this->getFrom('org') . "\r\n"
. 'To: ' . $this->getTO() . "\r\n";
@@ -1233,13 +1235,13 @@ class SMTPs
if ( $this->getBCC() )
$_header .= 'Bcc: ' . $this->getBCC() . "\r\n";
*/
-
+
$host=$this->getHost();
$host=preg_replace('@tcp://@i','',$host); // Remove prefix
$host=preg_replace('@ssl://@i','',$host); // Remove prefix
$host=dol_getprefix('email');
-
+
//NOTE: Message-ID should probably contain the username of the user who sent the msg
$_header .= 'Subject: ' . $this->getSubject() . "\r\n";
$_header .= 'Date: ' . date("r") . "\r\n";
@@ -1258,7 +1260,7 @@ class SMTPs
}
if ( $this->getMoreInHeader() )
$_header .= $this->getMoreInHeader(); // Value must include the "\r\n";
-
+
//$_header .=
// 'Read-Receipt-To: ' . $this->getFrom( 'org' ) . "\r\n"
// 'Return-Receipt-To: ' . $this->getFrom( 'org' ) . "\r\n";
@@ -1279,9 +1281,10 @@ class SMTPs
$_header .= "Reply-To: ".$this->getReplyTo('addr') ."\r\n";
$_header .= 'X-Mailer: Dolibarr version ' . DOL_VERSION .' (using SMTPs Mailer)' . "\r\n";
+ $_header .= 'X-Dolibarr-Option: '.($conf->global->MAIN_MAIL_USE_MULTI_PART?'MAIN_MAIL_USE_MULTI_PART':'No MAIN_MAIL_USE_MULTI_PART') . "\r\n";
$_header .= 'Mime-Version: 1.0' . "\r\n";
-
+
return $_header;
}
@@ -1310,17 +1313,17 @@ class SMTPs
$strContentAltText = html_entity_decode(strip_tags($strContent));
$strContentAltText = rtrim(wordwrap($strContentAltText, 75, "\r\n"));
}
-
+
// Make RFC2045 Compliant
//$strContent = rtrim(chunk_split($strContent)); // Function chunck_split seems ko if not used on a base64 content
$strContent = rtrim(wordwrap($strContent, 75, "\r\n")); // TODO Using this method creates unexpected line break on text/plain content.
-
+
$this->_msgContent[$strType] = array();
$this->_msgContent[$strType]['mimeType'] = $strMimeType;
$this->_msgContent[$strType]['data'] = $strContent;
$this->_msgContent[$strType]['dataText'] = $strContentAltText;
-
+
if ( $this->getMD5flag() )
$this->_msgContent[$strType]['md5'] = dol_hash($strContent, 3);
//}
@@ -1334,7 +1337,7 @@ class SMTPs
function getBodyContent()
{
global $conf;
-
+
// Generate a new Boundary string
$this->_setBoundary();
@@ -1382,7 +1385,7 @@ class SMTPs
$content .= "\r\n";
$content .= "--" . $this->_getBoundary('mixed') . "\r\n";
-
+
if (key_exists('image', $this->_msgContent)) // If inline image found
{
$content.= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"' . "\r\n";
@@ -1390,7 +1393,7 @@ class SMTPs
$content .= "--" . $this->_getBoundary('alternative') . "\r\n";
}
-
+
// $this->_msgContent must be sorted with key 'text' or 'html' first then 'image' then 'attachment'
@@ -1450,18 +1453,18 @@ class SMTPs
$content.= "\r\n";
$content.= "--" . $this->_getBoundary('related') . "\r\n";
}
-
+
if (! key_exists('image', $this->_msgContent) && $_content['dataText'] && ! empty($conf->global->MAIN_MAIL_USE_MULTI_PART)) // Add plain text message part before html part
{
$content.= 'Content-Type: multipart/alternative; boundary="'.$this->_getBoundary('alternative').'"' . "\r\n";
$content .= "\r\n";
$content .= "--" . $this->_getBoundary('alternative') . "\r\n";
-
+
$content.= "Content-Type: text/plain; charset=" . $this->getCharSet() . "\r\n";
$content.= "\r\n". $_content['dataText'] . "\r\n";
$content.= "--" . $this->_getBoundary('alternative') . "\r\n";
- }
-
+ }
+
$content .= 'Content-Type: ' . $_content['mimeType'] . '; '
// . 'charset="' . $this->getCharSet() . '"';
. 'charset=' . $this->getCharSet() . '';
@@ -1483,7 +1486,7 @@ class SMTPs
{
$content.= "--" . $this->_getBoundary('alternative') . "--". "\r\n";
}
-
+
$content .= "\r\n";
}
}
diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
index 77502f1737c..0b8282ad5b6 100644
--- a/htdocs/core/lib/files.lib.php
+++ b/htdocs/core/lib/files.lib.php
@@ -393,6 +393,7 @@ function dol_dir_is_emtpy($folder)
*
* @param string $file Filename
* @return int <0 if KO, Number of lines in files if OK
+ * @see dol_nboflines
*/
function dol_count_nb_of_line($file)
{
@@ -448,12 +449,12 @@ function dol_filemtime($pathoffile)
* Make replacement of strings into a file.
*
* @param string $srcfile Source file (can't be a directory)
- * @param array $arrayreplacement Array with strings to replace
+ * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...)
* @param string $destfile Destination file (can't be a directory). If empty, will be same than source file.
* @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666'
* @param int $indexdatabase Index new file into database.
* @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK
- * @see dolCopyr
+ * @see dolCopyr dolReplaceRegExInFile
*/
function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0)
{
@@ -514,6 +515,23 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0,
return 1;
}
+/**
+ * Make replacement of strings into a file.
+ *
+ * @param string $srcfile Source file (can't be a directory)
+ * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...)
+ * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file.
+ * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666'
+ * @param int $indexdatabase Index new file into database.
+ * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK
+ * @see dolCopyr dolReplaceInFile
+ */
+function dolReplaceRegExInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0)
+{
+ // TODO
+
+}
+
/**
* Copy a file to another file.
*
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index fae3c4eae5e..85f3ed199e9 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -624,18 +624,26 @@ function dol_buildpath($path, $type=0)
/**
* Create a clone of instance of object (new instance with same value for properties)
- * Property that are reference are also new object (true clone)
+ * With native = 0: Property that are reference are also new object (true clone). This means $this->db is not valid.
+ * With native = 1: Use PHP clone. Property that are reference are same pointer. This means $this->db is still valid.
*
* @param object $object Object to clone
+ * @param int $native Native method or true method
* @return object Object clone
* @see https://php.net/manual/language.oop5.cloning.php
*/
-function dol_clone($object)
+function dol_clone($object, $native=0)
{
//dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING);
- //$myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep references (refer to the same target/variable
- $myclone=unserialize(serialize($object));
+ if (empty($native))
+ {
+ $myclone=unserialize(serialize($object));
+ }
+ else
+ {
+ $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep references (refer to the same target/variable)
+ }
return $myclone;
}
@@ -1127,7 +1135,7 @@ function dol_get_fiche_end($notab=0)
* @param string $paramid Name of parameter to use to name the id into the URL next/previous link
* @param string $morehtml More html content to output just before the nav bar
* @param int $shownav Show Condition (navigation is shown if value is 1)
- * @param string $fieldid Nom du champ en base a utiliser pour select next et previous (we make the select max and min on this field)
+ * @param string $fieldid Nom du champ en base a utiliser pour select next et previous (we make the select max and min on this field). Use 'none' for no prev/next search.
* @param string $fieldref Nom du champ objet ref (object->ref) a utiliser pour select next et previous
* @param string $morehtmlref More html to show after ref
* @param string $moreparam More param to add in nav link url.
@@ -1278,7 +1286,8 @@ function dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='r
if ($object->element == 'project' && ! $object->public) $picto = 'project'; // instead of projectpub
$nophoto=img_picto('', 'object_'.$picto, '', false, 1);
}
- $morehtmlleft.='
';
+ $morehtmlleft.='';
+ $morehtmlleft.='
';
$morehtmlleft.='';
}
}
@@ -2545,7 +2554,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
if ($pictoisfullpath)
{
// Clean parameters
- if (! preg_match('/(\.png|\.gif)$/i',$picto)) $picto .= '.png';
+ if (! preg_match('/(\.png|\.gif|\.svg)$/i',$picto)) $picto .= '.png';
$fullpathpicto = $picto;
}
else
@@ -2567,7 +2576,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
}
// Clean parameters
- if (! preg_match('/(\.png|\.gif)$/i',$picto)) $picto .= '.png';
+ if (! preg_match('/(\.png|\.gif|\.svg)$/i',$picto)) $picto .= '.png';
// If alt path are defined, define url where img file is, according to physical path
foreach ($conf->file->dol_document_root as $type => $dirroot) // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
{
@@ -4766,22 +4775,57 @@ function dol_string_nohtmltag($StringHtml,$removelinefeed=1,$pagecodeto='UTF-8')
* Return first line of text. Cut will depends if content is HTML or not.
*
* @param string $text Input text
+ * @param int $nboflines Nb of lines to get (default is 1 = first line only)
* @return string Output text
* @see dol_nboflines_bis, dol_string_nohtmltag, dol_escape_htmltag
*/
-function dolGetFirstLineOfText($text)
+function dolGetFirstLineOfText($text, $nboflines=1)
{
- if (dol_textishtml($text))
+ if ($nboflines == 1)
{
- $firstline=preg_replace('/ ]*>.*$/s','',$text); // The s pattern modifier means the . can match newline characters
- $firstline=preg_replace('/
]*>.*$/s','',$firstline); // The s pattern modifier means the . can match newline characters
+ if (dol_textishtml($text))
+ {
+ $firstline=preg_replace('/ ]*>.*$/s','',$text); // The s pattern modifier means the . can match newline characters
+ $firstline=preg_replace('/
';
-
+
if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0)
{
// Model for creation
@@ -252,7 +252,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales
if (! is_object($object))
{
$id = $object;
- $object = new Propale($this->db);
+ $object = new Propal($this->db);
$result=$object->fetch($id);
if ($result < 0)
{
diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
index 3eb284ec7fc..250796dd9d5 100644
--- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php
+++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
@@ -273,7 +273,7 @@ class pdf_azur extends ModelePDFPropales
$pdf=pdf_getInstance($this->format);
$default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance
$pdf->SetAutoPageBreak(1,0);
-
+
if (class_exists('TCPDF'))
{
$pdf->setPrintHeader(false);
@@ -292,10 +292,10 @@ class pdf_azur extends ModelePDFPropales
$pdf->SetDrawColor(128,128,128);
$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
- $pdf->SetSubject($outputlangs->transnoentities("CommercialProposal"));
+ $pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle"));
$pdf->SetCreator("Dolibarr ".DOL_VERSION);
$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
- $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("CommercialProposal")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
+ $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
$pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right
@@ -322,19 +322,19 @@ class pdf_azur extends ModelePDFPropales
$pdf->AddPage();
if (! empty($tplidx)) $pdf->useTemplate($tplidx);
$pagenb++;
-
+
$heightforinfotot = 40; // Height reserved to output the info and total part
$heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE)?(pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature"))+10):0;
$heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page
$heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)
- //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
-
+ //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
+
$this->_pagehead($pdf, $object, 1, $outputlangs);
$pdf->SetFont('','', $default_font_size - 1);
$pdf->MultiCell(0, 3, ''); // Set interline to 3
$pdf->SetTextColor(0,0,0);
-
+
$tab_top = 90;
$tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42:10);
$tab_height = 130;
@@ -383,7 +383,7 @@ class pdf_azur extends ModelePDFPropales
$notetoshow.='Affaire suivi par '.$tmpuser->getFullName($langs);
if ($tmpuser->email) $notetoshow.=', Mail: '.$tmpuser->email;
if ($tmpuser->office_phone) $notetoshow.=', Tel: '.$tmpuser->office_phone;
- }
+ }
if ($notetoshow)
{
$tab_top = 88 + $height_incoterms;
@@ -452,7 +452,7 @@ class pdf_azur extends ModelePDFPropales
$curX = $this->posxdesc-1;
$showpricebeforepagebreak=1;
-
+
$pdf->startTransaction();
pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxpicture-$curX,3,$curX,$curY,$hideref,$hidedesc);
$pageposafter=$pdf->getPage();
@@ -554,14 +554,14 @@ class pdf_azur extends ModelePDFPropales
// Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva;
else $tvaligne=$object->lines[$i]->total_tva;
-
+
$localtax1ligne=$object->lines[$i]->total_localtax1;
$localtax2ligne=$object->lines[$i]->total_localtax2;
$localtax1_rate=$object->lines[$i]->localtax1_tx;
$localtax2_rate=$object->lines[$i]->localtax2_tx;
$localtax1_type=$object->lines[$i]->localtax1_type;
- $localtax2_type=$object->lines[$i]->localtax2_type;
-
+ $localtax2_type=$object->lines[$i]->localtax2_type;
+
if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100;
if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100;
if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100;
@@ -669,7 +669,7 @@ class pdf_azur extends ModelePDFPropales
{
$posy=$this->_signature_area($pdf, $object, $posy, $outputlangs);
}
-
+
// Pied de page
$this->_pagefoot($pdf,$object,$outputlangs);
if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages();
@@ -1428,7 +1428,7 @@ class pdf_azur extends ModelePDFPropales
$pdf->SetFont('','B',$default_font_size + 3);
$pdf->SetXY($posx,$posy);
$pdf->SetTextColor(0,0,60);
- $title=$outputlangs->transnoentities("CommercialProposal");
+ $title=$outputlangs->transnoentities("PdfCommercialProposalTitle");
$pdf->MultiCell(100, 4, $title, '', 'R');
$pdf->SetFont('','B',$default_font_size);
@@ -1481,7 +1481,7 @@ class pdf_azur extends ModelePDFPropales
$pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
}
}
-
+
$posy+=2;
// Show list of linked objects
diff --git a/htdocs/core/tpl/bloc_showhide.tpl.php b/htdocs/core/tpl/bloc_showhide.tpl.php
index 2c5d71c79d5..80b928815cb 100644
--- a/htdocs/core/tpl/bloc_showhide.tpl.php
+++ b/htdocs/core/tpl/bloc_showhide.tpl.php
@@ -21,43 +21,45 @@ if (isset($parameters['showblocbydefault'])) $hide=(empty($parameters['showblocb
if (isset($object->extraparams[$blocname]['showhide'])) $hide = (empty($object->extraparams[$blocname]['showhide']) ? true : false);
?>
+
-
+'."\n";
+print '$(document).ready(function() {'."\n";
+print '$("#hide-'.$blocname.'").click(function(){'."\n";
+print ' setShowHide(0);'."\n";
+print ' $("#'.$blocname.'_bloc").hide("blind", {direction: "vertical"}, 300).removeClass("nohideobject");'."\n";
+print ' $(this).hide();'."\n";
+print ' $("#show-'.$blocname.'").show();'."\n";
+print '});'."\n";
-
+print 'function setShowHide(status) {'."\n";
+print ' var id = '.$object->id.";\n";
+print " var element = '".$object->element."';\n";
+print " var htmlelement = '".$blocname."';\n";
+print ' var type = "showhide";'."\n";
+print ' $.get("'.dol_buildpath('/core/ajax/extraparams.php', 1);
+print '?id="+id+"&element="+element+"&htmlelement="+htmlelement+"&type="+type+"&value="+status);'."\n";
+print '}'."\n";
-
-
-
+print '});'."\n";
+print ''."\n";
-
+print '
'.img_picto('', '1uparrow.png').'
'."\n";
+print '
'.img_picto('', '1downarrow.png').'
'."\n";
+print '
'.$title.'
'."\n";
+print '
'."\n";
-
-
-
-
-
-
\ No newline at end of file
+include DOL_DOCUMENT_ROOT.'/core/tpl/'.$blocname.'.tpl.php';
+print '
';
+?>
+
diff --git a/htdocs/core/tpl/notes.tpl.php b/htdocs/core/tpl/notes.tpl.php
index 2538e052ae4..87071e94203 100644
--- a/htdocs/core/tpl/notes.tpl.php
+++ b/htdocs/core/tpl/notes.tpl.php
@@ -1,7 +1,7 @@
- * Copyright (C) 2013 Florian Henry
- * Copyright (C) 2014 Laurent Destailleur
+/* Copyright (C) 2012 Regis Houssin
+ * Copyright (C) 2013 Florian Henry
+ * Copyright (C) 2014-2017 Laurent Destailleur
*
* 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
@@ -17,9 +17,10 @@
* along with this program. If not, see .
*/
-// $cssclass must be defined by caller. For example cssclass='fieldtitle"
-$module = $object->element;
-$note_public = 'note_public';
+// $permission must be defined by caller.
+// $cssclass must be defined by caller. For example cssclass='fieldtitle"
+$module = $object->element;
+$note_public = 'note_public';
$note_private = 'note_private';
$colwidth=(isset($colwidth)?$colwidth:(empty($cssclass)?'25':''));
diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php
new file mode 100644
index 00000000000..65db787734a
--- /dev/null
+++ b/htdocs/core/website.inc.php
@@ -0,0 +1,28 @@
+
+ *
+* 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 .
+* or see http://www.gnu.org/
+*/
+
+/**
+ * \file htdocs/core/website.inc.php
+ * \brief Common file loaded used by all website pages (after master.inc.php)
+ * The global variable $website must be defined.
+ */
+
+
+include_once DOL_DOCUMENT_ROOT.'/websites/class/website.class.php';
+$website=new Website($db);
+$website->fetch(0,$websitekey);
diff --git a/htdocs/cron/card.php b/htdocs/cron/card.php
index a371069d7cf..dce56ff5468 100644
--- a/htdocs/cron/card.php
+++ b/htdocs/cron/card.php
@@ -380,7 +380,7 @@ if (($action=="create") || ($action=="edit"))
print '