diff --git a/.editorconfig b/.editorconfig
index 5b3e0d6a8df..2df455f0d4f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -15,3 +15,5 @@ indent_style = tab
indent_style = tab
[*.xml]
indent_style = tab
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.travis.yml b/.travis.yml
index 37c04fecd7a..8655b27d4ed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -285,7 +285,7 @@ script:
php upgrade2.php 3.8.0 3.9.0 > $TRAVIS_BUILD_DIR/upgrade380390-2.log
php step5.php 3.8.0 3.9.0 > $TRAVIS_BUILD_DIR/upgrade380390-3.log
php upgrade.php 3.9.0 4.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade390400.log
- php upgrade2.php 3.9.0 4.0.0 MAIN_MODULE_API > $TRAVIS_BUILD_DIR/upgrade390400-2.log
+ php upgrade2.php 3.9.0 4.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL > $TRAVIS_BUILD_DIR/upgrade390400-2.log
php step5.php 3.9.0 4.0.0 > $TRAVIS_BUILD_DIR/upgrade390400-3.log
cd -
set +e
diff --git a/ChangeLog b/ChangeLog
index 21d3ebc66b3..e3d40f3a04c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,8 +15,134 @@ make a Dolibarr upgrade.
***** ChangeLog for 4.0 compared to 3.9.* *****
For users:
+NEW: Add reccuring invoice feature and automatic generation of invoices.
+NEW: Add module "Loan" as stable.
+NEW: Add module "Supplier commercial proposal" (price request) is set to stable status.
+NEW: Experimental module Accountancy Expert
+NEW: Experimental module Multicurency
+NEW: Show into badge on tab head the number of dedicated contacts for all objects.
+NEW: Add a checkbox to select/unselect all lines on page that support mass actions (like invoice list page)
+NEW: Add a new method for margin calculation. Added margin on "cost price" to margin on WAP price and margin on "best supplier price".
+NEW: Add an explanation message on shipment page to explain you can't make shipment if order is not validated
+NEW: Add date_rum into table of thirdparty bank account.
+NEW: The probability of lead/opportunity can be defined per lead.
+NEW: Added Malta VAT into migration script
+NEW: #4972 Translated Charges sociales (type 0) and Charges sociales (type 1) in reports page
+NEW: Add Expense report into accountancy report
+NEW: Add Expense report to approve into workboard
+NEW: Selection of boxes is move on top of home page
+NEW: Add filter on a keyword, status and nature into list of modules
+NEW: Add hidden option BANK_DISABLE_CHECK_DEPOSIT to disable check deposit feature.
+NEW: Add option MAIN_PUBLIC_NOTE_IN_ADDRESS
+NEW: add html id/class to locate value in the DOM html
+NEW: Add index on invoice status
+NEW: Add constant MAIN_LOGTOHTML to 0 into other setup by default to save time when we need to make debug on hosted instance.
+NEW: Add list of billed
+NEW: Add minimum stock and desired stock into import/export profiles.
+NEW: Add state into thirdparty export fields
+NEW: Add more trackable events (create, submit and receive supplier order).
+NEW: Add option MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN
+NEW: Add picto on module list to show warning and if module is an external module.
+NEW: add product type filter on turnover report
+NEW: Add state into list of fields available for personalized fields of thirdparties
+NEW: Add statistics for interventions module
+NEW: Add statistics on number of projets on home page
+NEW: Add stats and late records into dashboard for supplier proposals.
+NEW: Add the admin info on combo of type of contact
+NEW: Add the event BILL_PAYED to list of supported events for module notification.
+NEW: Add total weight and volume on PDF
+NEW: Add hidden option to hide column qty ordered on shipments.
+NEW: Add view of virtual stock into product list (when appropriate)
+NEW: Add warning on tasks when they are late (add also the warning tolerance parameter)
+NEW: Add weight/volume for one product into shipment export
+NEW: Add width and height on product card
+NEW: allow a document to be linked to project from another customer on config
+NEW: allow project to be shared across entities (for multicompany module)
+NEW: All variant of ckeditor config can be tested into the setup page of module.
+NEW: Can change dynamically number of records visible into lists.
+NEW: Can change type of extrafields for some combinations.
+NEW: Can define number of first and last line into import wizard.
+NEW: Can edit next execution date of a cron job.
+NEW: Can edit value date of a vat payment after recording it.
+NEW: Can filter modules on publisher
+NEW: Can filter on employee status when building emailing from users
+NEW: Can reopen an closed shipment
+NEW: Can search on shipments into the quick search box
+NEW: Can select dynamicaly number of lines to show on page on product, shipment, contact, orders, thirdparties
+NEW: Can select fields to show on supplier orders list.
+NEW: Can select fields to show on list also for list of customer orders, shipments and invoices.
+NEW: Can select fields to show on proposal lists.
+NEW: Can select language from combo list on page to overwrite a translation
+NEW: Can select number of lines on page list for projects and tasks.
+NEW: Can use ^ and $ (to say start with or end with like regex syntax) into search fields when search field is text. Bonus: ^$ can filter all lines with field not defined.
+NEW: Clean and enhance code for cron engine
+NEW: Can decrease stock on shipment closing/classifying (only if module lot is not enabled for the moment)
+NEW: Disabled users are striked.
+NEW: Enhance navigation of project module
+NEW: fichinter lines ordered by rang AND DATE
+NEW: hidden conf to use input file multiple from mail form
+NEW: hidden feature: SUPPLIERORDER_WITH_NOPRICEDEFINED allow supplier order even if no supplier price defined
+NEW: Hidden option MAIN_LANDING_PAGE to choose the first page to show after login works as a "global" option (llx_const) and as a "per user" option (llx_user_param).
+NEW: Holiday is a now a RH module. All RH module provides by default visilibity on users of its hierarchy.
+NEW: If error is reported during migration process, you can ignore it to avoid to be locked.
+NEW: if nb total of lines provided in print barre_liste, display in title
+NEW: If option to see non stable modules is on, add a filter into module list to filter on level (deprecated, experimental, development)
+NEW: Include number of linked files into badge counter of "Linked files" tab.
+NEW: Include sales representative into export of thirdparties
+NEW: Indicator on workboard are red/green if late or not.
+NEW: Into GED module, filename is truncated only if there is not enough space into table
+NEW: Introduce a predefined job to run database backup
+NEW: Introduce option MAIN_WEIGHT_DEFAULT_UNIT and MAIN_VOLUME_DEFAULT_UNIT to force output unit for weight and volume.
+NEW: Introduce position of records into dictionnary of type of contacts
+NEW: Link on user in leave context reach to leave tab.
+NEW: List of user in agenda view per user show photo thumb
+NEW: Margins module - Check/update buying price on invoice lines
+NEW: Merge all admin tools (system and module admin tools) into same entry "Admin tools", so now things are clear: All features restricted to an admin user is inside "setup" (for setup) or "admin tools" (for action tools) instead of 3 different entries.
+NEW: Merge all boxes "related objects" into one. This save a lot of room on most card and avoid often horizontal scoll.
+NEW: Moved code that deals with bank categories to BankCateg. Created BankCateg::fetchAll function
+NEW: Move Expense report menu from module to menu files
+NEW: Move HRM dictionary from module to core dictionaries
+NEW: Mutualize code to manage email substitution variables. Show available variables into page to edit email templates.
+NEW: Mutualize code: Use one call of function "addThumbs", when possible, to generate thumbs files instead of several call of "vignette" function.
+NEW: On translation admin page, admin can overwrite a translation value.
+NEW: Option MAIN_LIST_FILTER_ON_DAY is supported on proposal list
+NEW: Add reputation field for price supplier
+NEW: Rest API token is no more reset at each call. We can reset it with param reset=1 on login call.
+NEW: Selection of fields is available on member list.
+NEW: Show a badge with number of withdraw requests done on the withdraw tab of invoice.
+NEW: Add option to show detail per warehouse into reassort
+NEW: Show total number of modules into the module list
+NEW: Survey system has now a status like other objects. You can close or reopen a survey.
+NEW: The note on time spent can be entered when using the view per day.
+NEW: Use ellipsis truncation on too large left menu text
+NEW: When a new field to show into lists is selected, the form is automatically submited and field added.
+NEW: When creating a template invoice from a draft invoice, if there is link to contract on draft invoice, link is kept on template invoice.
+NEW: When emailing is not sent completely, show progression.
+
For developers:
+NEW: Add a css class style called 'reposition', so when clicking on a link with this class will move scrollbarr to be placed at same page location.
+NEW: TimeZone can be supplied to mktime
+NEW: hook in shipment card
+NEW: Deprecated Societe::set_prospect_level, Societe::set_commnucation_level, Societe::set_OutstandingBill functions
+NEW: A module can add, into its import profiles, a sql request to execute at end of import. This allow to update dernormalized data after import.
+NEW: Add hook pdf_build_address
+NEW: Add a parameter on graph function to show a generic graph when no data are available.
+NEW: Add $object in parameter of pdf_build_address so we could include hook into the function.
+NEW: Add a tool for developers to purge database with no loose of setup
+NEW: Can disable a module by renaming dir of module into module.disabled (this save time for maintenance when working with FTP).
+NEW: Created AccountLine::insert function and started using it for transaction creation
+NEW: Created Account::__toString, Account::getFieldsToShow and Account::getAccountNumberOrder to refactor the way account number was shown
+NEW: Created FormBank::getIBANLabel function to get the label of "IBAN" depending on bank account country
+NEW: prepare for additional warehouse statuses
+NEW: project sharing in select_projetcs_list function
+NEW: Removed deprecated CommonObject::client property. Please use CommonObject::thirdparty instead
+NEW: Removed unused FormOrder::selectSourcesCommande function
+NEW: Renamed ActionComm::add function to ActionComm::create
+NEW: Rename Form::select_date to Form::selectDate and Form::form_date to Form::formDate
+NEW: Rename path for generiN
+NEW: More phpunit tests. Include some REST API into automatic tests.
+
WARNING:
@@ -35,6 +161,48 @@ So if you included it into your module, change your code like this to be compati
if (! $res) include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_pre_headers.tpl.php';
+
+
+***** ChangeLog for 3.9.2 compared to 3.9.1 *****
+FIX: #4813 Won translation for the key OppStatusWON instead OppStatusWIN
+FIX: #5008 SQL error when editing the reference of a supplier invoice that already exists
+FIX: #5236 Cron module activated but "Modules tools" does not appear in the left menu.
+FIX: Accountancy - 3.9 - Chart of accounts are limited on only one country
+FIX: bug on email template
+FIX: Can't create a stock transfer from product card
+FIX: can't fetch by siret or siren because of first "if"
+FIX: Check stock of product by warehouse if $entrepot_id defined on shippings
+FIX: Compatible with multicompany
+FIX: Creation of the second ressource type fails.
+FIX: end of select when no fournprice
+FIX: Filter on assigned to was preselected on current user on list "All events" (instead of no filtering)
+FIX: Filter on category tag for suppliers
+FIX: hook on group card called but not initialized
+FIX: Infinite loop on menu tree output for edition
+FIX: Can show tree of entries added by external modules using fk_mainmenu and fk_leftmenu instead of fk_menu.
+FIX: init var at wrong place report incorrect "shippable" flag on draft order.
+FIX: It doesn't check if there is enough stock to update the lines of orders/invoices
+FIX: Menu statistics was not visible if module proposal was not enabled
+FIX: Merge manually PR #5161 - Bad translation key
+FIX: missing column when module was installed before standard integration
+FIX: Missing number total of modules
+FIX: Not filtering correctly when coming from dashboard
+FIX: PROPAL_MERGE_PDF with PRODUCT_USE_OLD_PATH
+FIX: Remove PHP Warning: Creating default object from empty value.
+FIX: same page added several times on mergepropal option
+FIX: search on date into supplier invoice list dont work because of status -1
+FIX: Search supplier ref on contract
+FIX: Split of credit note into discount page generates records not correctly recognised as credit note.
+FIX: SQL error function on getAvailableDiscounts function, on bill create mode if socid is empty
+FIX: #5087
+FIX: #5108
+FIX: #5163
+FIX: #5195
+FIX: #5203
+FIX: #5207
+FIX: #5209
+FIX: #5230
+
***** ChangeLog for 3.9.1 compared to 3.9.* *****
FIX: #3815 Call to undefined function local_by_date()
FIX: #4424 Missing email of user popup in supplier orders area
diff --git a/README.md b/README.md
index 8758ff8fc77..a3a542b194e 100644
--- a/README.md
+++ b/README.md
@@ -151,7 +151,7 @@ Administrator, user, developer and translator's documentations are available alo
## CONTRIBUTING
-See file [CONTRIBUTING](https://github.com/Dolibarr/dolibarr/blob/develop/CONTRIBUTING.md)
+See file [CONTRIBUTING](https://github.com/Dolibarr/dolibarr/blob/develop/.github/CONTRIBUTING.md)
## CREDITS
diff --git a/build/debian/apache/.htaccess b/build/debian/apache/.htaccess
index a59829d970b..3c3d2e02683 100644
--- a/build/debian/apache/.htaccess
+++ b/build/debian/apache/.htaccess
@@ -5,4 +5,17 @@ Require all denied
Order deny, allow
Denied from all
-
\ No newline at end of file
+
+
+
+# OPTIMIZE: To use cache on static pages (A259200 = 1 month, A7200 = 2 hours, A691600 = 8 days = recommanded for static resources).
+# Note that you must also enable the module mod_expires.
+#ExpiresActive On
+#ExpiresByType image/x-icon A2592000
+#ExpiresByType image/gif A2592000
+#ExpiresByType image/png A2592000
+#ExpiresByType image/jpeg A2592000
+#ExpiresByType text/css A2592000
+#ExpiresByType text/javascript A2592000
+#ExpiresByType application/x-javascript A2592000
+#ExpiresByType application/javascript A2592000
diff --git a/build/exe/doliwamp/httpd.conf.install b/build/exe/doliwamp/httpd.conf.install
index 64aff6d42a2..bfe17b07d42 100644
--- a/build/exe/doliwamp/httpd.conf.install
+++ b/build/exe/doliwamp/httpd.conf.install
@@ -745,7 +745,7 @@ SSLCertificateKeyFile "WAMPROOT/myserver.key"
# You can also set this with constant MAIN_OPTIMIZE_SPEED and bit 2 set.
#TODO
-# OPTIMIZE: To use cache on static pages (A259200 = 1 month).
+# OPTIMIZE: To use cache on static pages (A259200 = 1 month, A7200 = 2 hours, A691600 = 8 days = recommanded for static resources).
# Note that you must also enable the module mod_expires.
#ExpiresActive On
#ExpiresByType image/x-icon A2592000
diff --git a/build/makepack-howto.txt b/build/makepack-howto.txt
index b4a13badbf4..76a290708a9 100644
--- a/build/makepack-howto.txt
+++ b/build/makepack-howto.txt
@@ -9,7 +9,8 @@ beta version of Dolibarr, step by step.
- Check all files are commited.
- Update version/info in ChangeLog.
-To generate a changelog of a major new version x.y.0, you can do "cd ~/git/dolibarr_x.y; git log `git rev-list --boundary x.y..origin/develop | grep ^- | cut -c2- | head -n 1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
+To generate a changelog of a major new version x.y.0 (from develop repo), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
+To generate a changelog of a major new version x.y.0 (from x.y repo), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
- Update version number with x.y.z-w in htdocs/filefunc.inc.php
- Commit all changes.
@@ -31,7 +32,8 @@ complete release of Dolibarr, step by step.
- Check all files are commited.
- Update version/info in ChangeLog.
-To generate a changelog of a major new version x.y.0, you can do "cd ~/git/dolibarr_x.y; git log `git rev-list --boundary x.y..origin/develop | grep ^- | cut -c2- | head -n 1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
+To generate a changelog of a major new version x.y.0 (from develop repo), you can do "cd ~/git/dolibarr; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent develop) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
+To generate a changelog of a major new version x.y.0 (from x.y repo), you can do "cd ~/git/dolibarr_x.y; git log `diff -u <(git rev-list --first-parent x.(y-1).0) <(git rev-list --first-parent x.y.0) | sed -ne 's/^ //p' | head -1`.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
To generate a changelog of a maintenance version x.y.z, you can do "cd ~/git/dolibarr_x.y; git log x.y.z-1.. --no-merges --pretty=short --oneline | sed -e "s/^[0-9a-z]* //" | grep -e '^FIX\|NEW' | sort -u | sed 's/FIXED:/FIX:/g' | sed 's/FIXED :/FIX:/g' | sed 's/FIX :/FIX:/g' | sed 's/FIX /FIX: /g' | sed 's/NEW :/NEW:/g' | sed 's/NEW /NEW: /g' > /tmp/aaa"
- Update version number with x.y.z in htdocs/filefunc.inc.php
- Commit all changes.
diff --git a/dev/fixdosfiles.sh b/dev/fixdosfiles.sh
index ae04977d624..d6b9555efa6 100755
--- a/dev/fixdosfiles.sh
+++ b/dev/fixdosfiles.sh
@@ -17,14 +17,14 @@ fi
# To detec
if [ "x$1" = "xlist" ]
then
- find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep CRLF
-# find . \( -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep -v 'htdocs\/includes' | grep CRLF
+ find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep CRLF
+# find . \( -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep -v 'htdocs\/includes' | grep CRLF
fi
# To convert
if [ "x$1" = "xfix" ]
then
- for fic in `find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep CRLF | awk -F':' '{ print $1 }' `
+ for fic in `find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep CRLF | awk -F':' '{ print $1 }' `
do
echo "Fix file $fic"
dos2unix "$fic"
diff --git a/dev/translation/sanity_check_en_langfiles.php b/dev/translation/sanity_check_en_langfiles.php
index 5eb92509eb1..562ede506f4 100755
--- a/dev/translation/sanity_check_en_langfiles.php
+++ b/dev/translation/sanity_check_en_langfiles.php
@@ -85,7 +85,7 @@ if ($web)
echo "
";
}
-echo "If you call this file with the argument \"?unused=true\" it searches for the translation strings that exist in en_US but are never used.\n";
+echo "If you call this with argument \"unused=true\" it searches for the translation strings that exist in en_US but are never used.\n";
if ($web) print " ";
echo "IMPORTANT: that can take quite a lot of time (up to 10 minutes), you need to tune the max_execution_time on your php.ini accordingly.\n";
if ($web) print " ";
@@ -96,10 +96,11 @@ if ($web) print " ";
// directory containing the php and lang files
-$htdocs = $path."/../../htdocs/";
+$htdocs = $path."../../htdocs/";
+$scripts = $path."../../scripts/";
// directory containing the english lang files
-$workdir = $htdocs."langs/en_US/";
+$workdir = $htdocs."langs/en_US/";
$files = scandir($workdir);
@@ -109,8 +110,14 @@ if (empty($files))
exit;
}
+$dups=array();
$exludefiles = array('.','..','README');
$files = array_diff($files,$exludefiles);
+// To force a file: $files=array('myfile.lang');
+if (isset($argv[2]))
+{
+ $files = array($argv[2]);
+}
$langstrings_3d = array();
$langstrings_full = array();
foreach ($files AS $file) {
@@ -127,7 +134,7 @@ foreach ($files AS $file) {
$langstrings_3d[$path_file['basename']][$line+1]=$row_array[0];
$langstrings_3dtrans[$path_file['basename']][$line+1]=$row_array[1];
$langstrings_full[]=$row_array[0];
- $langstrings_dist[$row_array[0]]=$row_array[0];
+ $langstrings_dist[$row_array[0]]=$row;
}
}
}
@@ -241,26 +248,115 @@ if ($web)
// STEP 2 - Search key not used
-
-if (! empty($_REQUEST['unused']) && $_REQUEST['unused'] == 'true')
+if ((! empty($_REQUEST['unused']) && $_REQUEST['unused'] == 'true') || (isset($argv[1]) && $argv[1]=='unused=true'))
{
- foreach ($langstrings_dist AS $value)
+ print "***** Strings in en_US that are never used:\n";
+
+ $unused=array();
+ foreach ($langstrings_dist AS $value => $line)
{
- $search = '\'trans("'.$value.'")\'';
- $string = 'grep -R -m 1 -F --exclude=includes/* --include=*.php '.$search.' '.$htdocs.'*';
+ $qualifiedforclean=1;
+ // Check if we must keep this key to be into file for removal
+ if (preg_match('/^Module\d+/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Permission\d+/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^PermissionAdvanced\d+/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^ProfId\d+/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Delays_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^BarcodeDesc/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Extrafield/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^LocalTax/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Country/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Civility/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Currency/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^DemandReasonTypeSRC/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^PaperFormat/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Duration/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^AmountLT/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^TotalLT/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Month/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^MonthShort/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Day\d/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Short/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^ExportDataset_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^ImportDataset_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^ActionAC_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^TypeLocaltax/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^StatusProspect/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^PL_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^TE_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^JuridicalStatus/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^CalcMode/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^newLT/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^LT\d/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^TypeContact_contrat_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^ErrorPriceExpression/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^Language_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^DescADHERENT_/', $value)) $qualifiedforclean=0;
+ // main.lang
+ if (preg_match('/^Duration/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^FormatDate/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^DateFormat/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^.b$/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^.*Bytes$/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^(DoTest|Under|Limits|Cards|CurrentValue|DateLimit|DateAndHour|NbOfLines|NbOfObjects|NbOfReferes|TotalTTCShort|VATs)/', $value)) $qualifiedforclean=0;
+ // orders
+ if (preg_match('/^OrderSource/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^TypeContact_/', $value)) $qualifiedforclean=0;
+ // other.lang
+ if (preg_match('/^Notify_/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^PredefinedMail/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^DemoCompany/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^WeightUnit/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^LengthUnit/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^SurfaceUnit/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^VolumeUnit/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^SizeUnit/', $value)) $qualifiedforclean=0;
+ if (preg_match('/^EMailText/', $value)) $qualifiedforclean=0;
+ if (preg_match('/ById$/', $value)) $qualifiedforclean=0;
+ if (preg_match('/ByLogin$/', $value)) $qualifiedforclean=0;
+ // products
+ if (preg_match('/GlobalVariableUpdaterType$/', $value)) $qualifiedforclean=0;
+ if (preg_match('/GlobalVariableUpdaterHelp$/', $value)) $qualifiedforclean=0;
+ if (preg_match('/OppStatus/', $value)) $qualifiedforclean=0;
+ if (preg_match('/AvailabilityType/', $value)) $qualifiedforclean=0;
+
+ if (preg_match('/sms/i', $value)) $qualifiedforclean=0;
+ if (preg_match('/TF_/i', $value)) $qualifiedforclean=0;
+ if (preg_match('/WithBankUsing/i', $value)) $qualifiedforclean=0;
+ if (preg_match('/descWORKFLOW_/i', $value)) $qualifiedforclean=0;
+
+ if (! $qualifiedforclean)
+ {
+ continue;
+ }
+
+ //$search = '\'trans("'.$value.'")\'';
+ $search = '-e "\''.$value.'\'" -e \'"'.$value.'"\' -e "('.$value.')"';
+ $string = 'grep -R -m 1 -F --exclude=includes/* --include=*.php '.$search.' '.$htdocs.'* '.$scripts.'*';
+ //print $string." \n";
exec($string,$output);
if (empty($output)) {
- $unused[$value] = true;
- echo $value.' ';
+ $unused[$value] = $line;
+ echo $line; // $trad contains the \n
+ }
+ else
+ {
+ unset($output);
+ //print 'X'.$output.'Y';
}
}
- if ($web) print "
\n";
- print "Strings in en_US that are never used\n";
- if ($web) print "
\n";
- if ($web) echo "
";
- print_r($unused);
- if ($web) echo "
\n";
+ if (empty($unused)) print "No string not used found.\n";
+ else
+ {
+ $filetosave='/tmp/'.($argv[2]?$argv[2]:"").'notused.lang';
+ print "Strings in en_US that are never used are saved into file ".$filetosave.":\n";
+ file_put_contents($filetosave, join("",$unused));
+ print "To remove from original file, run command :\n";
+ if (($argv[2]?$argv[2]:"")) print 'cd htdocs/langs/en_US; mv '.($argv[2]?$argv[2]:"")." ".($argv[2]?$argv[2]:"").".tmp; ";
+ print "diff ".($argv[2]?$argv[2]:"").".tmp ".$filetosave." | grep \< | cut -b 3- > ".($argv[2]?$argv[2]:"");
+ if (($argv[2]?$argv[2]:"")) print "; rm ".($argv[2]?$argv[2]:"").".tmp;\n";
+ }
}
echo "\n";
diff --git a/htdocs/accountancy/admin/categories.php b/htdocs/accountancy/admin/categories.php
index f0013632b53..b1836836e84 100644
--- a/htdocs/accountancy/admin/categories.php
+++ b/htdocs/accountancy/admin/categories.php
@@ -138,7 +138,7 @@ if ($action == 'display' || $action == 'delete') {
if(!empty($obj)){
foreach ( $obj as $cpt ) {
$var = ! $var;
- print "
";
+ print '
';
print '
' . length_accountg($cpt->account_number) . '
';
print '
' . $cpt->label . '
';
print $form->formconfirm($_SERVER["PHP_SELF"]."?account_category=$cat_id&cptid=".$cpt->rowid, $langs->trans("DeleteCptCategory"), $langs->trans("ConfirmDeleteCptCategory"), "delete", '', 0, "action-delete".$j);
diff --git a/htdocs/accountancy/admin/fiscalyear.php b/htdocs/accountancy/admin/fiscalyear.php
index 00cf70b9e73..638e9794fe8 100644
--- a/htdocs/accountancy/admin/fiscalyear.php
+++ b/htdocs/accountancy/admin/fiscalyear.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2013-2016 Alexandre Spangaro
*
* 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
@@ -42,12 +42,15 @@ if (! $sortorder) $sortorder="ASC";
$langs->load("admin");
$langs->load("compta");
-if (! $user->admin)
+// Security check
+if ($user->societe_id > 0)
+ accessforbidden();
+if (! $user->rights->accounting->fiscalyear)
accessforbidden();
$error = 0;
-// List of statut
+// List of status
static $tmpstatut2label = array (
'0' => 'OpenFiscalYear',
'1' => 'CloseFiscalYear'
@@ -132,7 +135,7 @@ if ($result) {
$i ++;
}
} else {
- print '
\n";
}
diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php
index 66de3be2cc5..49048cfaf1f 100644
--- a/htdocs/adherents/card.php
+++ b/htdocs/adherents/card.php
@@ -4,7 +4,7 @@
* Copyright (C) 2004-2012 Laurent Destailleur
* Copyright (C) 2005-2012 Regis Houssin
* Copyright (C) 2012 Marcos García
- * Copyright (C) 2012-2015 Philippe Grand
+ * Copyright (C) 2012-2016 Philippe Grand
* Copyright (C) 2015 Alexandre Spangaro
*
* This program is free software; you can redistribute it and/or modify
@@ -94,7 +94,7 @@ if ($rowid > 0)
// Define variables to know what current user can do on properties of user linked to edited member
if ($object->user_id)
{
- // $user est le user qui edite, $object->user_id est l'id de l'utilisateur lies au membre edite
+ // $ User is the user who edits, $ object->user_id is the id of the related user in the edited member
$caneditfielduser=((($user->id == $object->user_id) && $user->rights->user->self->creer)
|| (($user->id != $object->user_id) && $user->rights->user->user->creer));
$caneditpassworduser=((($user->id == $object->user_id) && $user->rights->user->self->password)
@@ -209,7 +209,7 @@ if (empty($reshook))
{
if ($result > 0)
{
- // Creation user
+ // User creation
$company = new Societe($db);
$result=$company->create_from_member($object,GETPOST('companyname'));
@@ -253,7 +253,8 @@ if (empty($reshook))
}
$lastname=$_POST["lastname"];
$firstname=$_POST["firstname"];
- $morphy=$morphy=$_POST["morphy"];
+ $morphy=$_POST["morphy"];
+ $login=$_POST["login"];
if ($morphy != 'mor' && empty($lastname)) {
$error++;
$langs->load("errors");
@@ -264,7 +265,19 @@ if (empty($reshook))
$langs->load("errors");
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Firstname")), null, 'errors');
}
-
+ if ($morphy == 'mor' && empty($societe)) {
+ $error++;
+ $langs->load("errors");
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Company")), null, 'errors');
+ }
+ // Test si le login existe deja
+ if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED))
+ {
+ if (empty($login)) {
+ $error++;
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->trans("Login")), null, 'errors');
+ }
+ }
// Create new object
if ($result > 0 && ! $error)
{
@@ -482,7 +495,7 @@ if (empty($reshook))
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Nature")), null, 'errors');
}
- // Test si le login existe deja
+ // Tests if the login already exists
if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED))
{
if (empty($login)) {
@@ -506,6 +519,11 @@ if (empty($reshook))
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Password")), null, 'errors');
}
}
+ if ($morphy == 'mor' && empty($societe)) {
+ $error++;
+ $langs->load("errors");
+ setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Company")), null, 'errors');
+ }
if ($morphy != 'mor' && empty($lastname)) {
$error++;
$langs->load("errors");
@@ -532,11 +550,11 @@ if (empty($reshook))
{
$db->begin();
- // Email a peu pres correct et le login n'existe pas
+ // Email about right and login does not exist
$result=$object->create($user);
if ($result > 0)
{
- // Categories association
+ // Foundation categories
$memcats = GETPOST('memcats', 'array');
$object->setCategories($memcats);
@@ -597,7 +615,7 @@ if (empty($reshook))
if ($result >= 0 && ! count($object->errors))
{
- // Send confirmation Email (selon param du type adherent sinon generique)
+ // Send confirmation email (according to parameters of member type. Otherwise generic)
if ($object->email && GETPOST("send_mail"))
{
$result=$object->send_an_email($adht->getMailOnValid(),$conf->global->ADHERENT_MAIL_VALID_SUBJECT,array(),array(),array(),"","",0,2);
@@ -846,7 +864,7 @@ else
// Address
print '
'.$langs->trans("Address").'
';
- print '';
+ print '';
print '
';
// Zip / Town
@@ -1107,7 +1125,7 @@ else
// Address
print '
'.$langs->trans("Address").'
';
- print '';
+ print '';
print '
';
// Zip / Town
@@ -1361,7 +1379,7 @@ else
$helpcontent.=dol_htmlentitiesbr($texttosend)."\n";
$label=$form->textwithpicto($tmp,$helpcontent,1,'help');
- // Cree un tableau formulaire
+ // Create an array
$formquestion=array();
if ($object->email) $formquestion[]=array('type' => 'checkbox', 'name' => 'send_mail', 'label' => $label, 'value' => (! empty($conf->global->ADHERENT_DEFAULT_SENDINFOBYMAIL)?'true':'false'));
if ($backtopage) $formquestion[]=array('type' => 'hidden', 'name' => 'backtopage', 'value' => ($backtopage != '1' ? $backtopage : $_SERVER["HTTP_REFERER"]));
@@ -1549,12 +1567,12 @@ else
if (! $adht->cotisation)
{
print $langs->trans("SubscriptionNotRecorded");
- if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
+ if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
}
else
{
print $langs->trans("SubscriptionNotReceived");
- if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
+ if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
}
}
print '
';
diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php
index 93b013cd29f..87ceb66f9d1 100644
--- a/htdocs/adherents/class/adherent.class.php
+++ b/htdocs/adherents/class/adherent.class.php
@@ -1737,7 +1737,7 @@ class Adherent extends CommonObject
$response = new WorkboardResponse();
$response->warning_delay=$conf->adherent->cotisation->warning_delay/60/60/24;
$response->label=$langs->trans("MembersWithSubscriptionToReceive");
- $response->url=DOL_URL_ROOT.'/adherents/list.php?mainmenu=members&statut=1';
+ $response->url=DOL_URL_ROOT.'/adherents/list.php?mainmenu=members&statut=1&filter=outofdate';
$response->img=img_object($langs->trans("Members"),"user");
$adherentstatic = new Adherent($this->db);
@@ -2006,14 +2006,18 @@ class Adherent extends CommonObject
return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
}
+ /**
+ * Return if a member is late (subscription late) or not
+ *
+ * @return boolean True if late, False if not late
+ */
public function hasDelay()
{
global $conf;
//Only valid members
- if ($this->statut <= 0) {
- return false;
- }
+ if ($this->statut <= 0) return false;
+ if (! $this->datefin) return false;
$now = dol_now();
diff --git a/htdocs/adherents/cotisations.php b/htdocs/adherents/cotisations.php
index d0f8206f269..2e4f4b1994f 100644
--- a/htdocs/adherents/cotisations.php
+++ b/htdocs/adherents/cotisations.php
@@ -128,9 +128,10 @@ if ($result)
if (! empty($date_select)) $title.=' ('.$langs->trans("Year").' '.$date_select.')';
$param='';
+ if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
+ if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
if ($statut != '') $param.="&statut=".$statut;
if ($date_select) $param.="&date_select=".$date_select;
- if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
if ($search_lastname) $param.="&search_lastname=".$search_lastname;
if ($search_login) $param.="&search_login=".$search_login;
if ($search_acount) $param.="&search_account=".$search_account;
diff --git a/htdocs/adherents/ldap.php b/htdocs/adherents/ldap.php
index 4d9a779d579..a5f61a45642 100644
--- a/htdocs/adherents/ldap.php
+++ b/htdocs/adherents/ldap.php
@@ -191,12 +191,12 @@ if ($result > 0)
}
else
{
- $records=$ldap->getAttribute($dn,$search);
+ $records = $ldap->getAttribute($dn,$search);
//print_r($records);
// Affichage arbre
- if (count($records) && $records != false && (! isset($records['count']) || $records['count'] > 0))
+ if ((! is_numeric($records) || $records != 0) && (! isset($records['count']) || $records['count'] > 0))
{
if (! is_array($records))
{
diff --git a/htdocs/adherents/stats/index.php b/htdocs/adherents/stats/index.php
index 83ceea04698..6acdd1e56b7 100644
--- a/htdocs/adherents/stats/index.php
+++ b/htdocs/adherents/stats/index.php
@@ -176,7 +176,7 @@ print '
'.$langs->trans("AmountAverage").'
';
print '';
$oldyear=0;
-$var=false;
+$var=true;
foreach ($data as $val)
{
$year = $val['year'];
diff --git a/htdocs/admin/commande.php b/htdocs/admin/commande.php
index 9e55369dac9..c91c2fb8c75 100644
--- a/htdocs/admin/commande.php
+++ b/htdocs/admin/commande.php
@@ -166,8 +166,8 @@ else if ($action == 'setdoc')
{
if (dolibarr_set_const($db, "COMMANDE_ADDON_PDF",$value,'chaine',0,'',$conf->entity))
{
- // La constante qui a ete lue en avant du nouveau set
- // on passe donc par une variable pour avoir un affichage coherent
+ // The constant that was read before the new set
+ // We therefore requires a variable to have a coherent view
$conf->global->COMMANDE_ADDON_PDF = $value;
}
@@ -181,8 +181,8 @@ else if ($action == 'setdoc')
else if ($action == 'setmod')
{
- // TODO Verifier si module numerotation choisi peut etre active
- // par appel methode canBeActivated
+ // TODO Check if numbering module chosen can be activated
+ // by calling method canBeActivated
dolibarr_set_const($db, "COMMANDE_ADDON",$value,'chaine',0,'',$conf->entity);
}
diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php
index ee6cbac057f..cb79e6ff401 100644
--- a/htdocs/admin/company.php
+++ b/htdocs/admin/company.php
@@ -314,7 +314,7 @@ if ($action == 'edit' || $action == 'updateedit')
$var=!$var;
print '
';
+ $valtouse=$menu->fk_menu;
+ if ($menu->fk_mainmenu) $valtouse='fk_mainmenu='.$menu->fk_mainmenu;
+ if ($menu->fk_leftmenu) $valtouse.='&fk_leftmenu='.$menu->fk_leftmenu;
+ print '
';
print '
'.$langs->trans('DetailMenuIdParent').'
';
// Niveau
diff --git a/htdocs/admin/menus/index.php b/htdocs/admin/menus/index.php
index 28d8d353905..cba8d45c8f3 100644
--- a/htdocs/admin/menus/index.php
+++ b/htdocs/admin/menus/index.php
@@ -289,17 +289,18 @@ if ($conf->use_javascript_ajax)
- la chaine a afficher
ie: data[]= array (index, index parent, chaine )
*/
+
//il faut d'abord declarer un element racine de l'arbre
- $data[] = array('rowid'=>0,'fk_menu'=>-1,'title'=>"racine",'mainmenu'=>'','leftmenu'=>'','fk_mainmenu'=>'','fk_leftmenu'=>'');
-
+ $data[] = array('rowid'=>0,'fk_menu'=>-1,'title'=>"racine",'mainmenu'=>'','leftmenu'=>'','fk_mainmenu'=>'','fk_leftmenu'=>'');
+
//puis tous les elements enfants
- $sql = "SELECT m.rowid, m.titre, m.langs, m.mainmenu, m.leftmenu, m.fk_menu, m.fk_mainmenu, m.fk_leftmenu";
+ $sql = "SELECT m.rowid, m.titre, m.langs, m.mainmenu, m.leftmenu, m.fk_menu, m.fk_mainmenu, m.fk_leftmenu, m.module";
$sql.= " FROM ".MAIN_DB_PREFIX."menu as m";
$sql.= " WHERE menu_handler = '".$menu_handler_to_search."'";
$sql.= " AND entity = ".$conf->entity;
- $sql.= " AND fk_menu >= 0";
+ //$sql.= " AND fk_menu >= 0";
$sql.= " ORDER BY m.position, m.rowid"; // Order is position then rowid (because we need a sort criteria when position is same)
$res = $db->query($sql);
@@ -314,9 +315,10 @@ if ($conf->use_javascript_ajax)
$titre = $langs->trans($menu['titre']);
$data[] = array(
'rowid'=>$menu['rowid'],
+ 'module'=>$menu['module'],
'fk_menu'=>$menu['fk_menu'],
'title'=>$titre,
- 'mainmenu'=>$menu['mainmenu'],
+ 'mainmenu'=>$menu['mainmenu'],
'leftmenu'=>$menu['leftmenu'],
'fk_mainmenu'=>$menu['fk_mainmenu'],
'fk_leftmenu'=>$menu['fk_leftmenu'],
@@ -334,17 +336,54 @@ if ($conf->use_javascript_ajax)
}
}
+ global $tree_recur_alreadyadded; // This var was def into tree_recur
+
// Appelle de la fonction recursive (ammorce)
// avec recherche depuis la racine.
//var_dump($data);
- tree_recur($data,$data[0],0);
+ tree_recur($data, $data[0], 0, 'iddivjstree'); // $data[0] is virtual record 'racine'
+
print '';
-
+
print '';
-
+
print '';
-
+
+
+ // Process remaining records (records that are not linked to root by any path)
+ $remainingdata = array();
+ foreach($data as $datar)
+ {
+ if (empty($datar['rowid']) || $tree_recur_alreadyadded[$datar['rowid']]) continue;
+ $remainingdata[] = $datar;
+ }
+
+ if (count($remainingdata))
+ {
+ print '
';
if ($supported)
{
diff --git a/htdocs/admin/receiptprinter.php b/htdocs/admin/receiptprinter.php
index 87fce1f6087..b86023aa49a 100644
--- a/htdocs/admin/receiptprinter.php
+++ b/htdocs/admin/receiptprinter.php
@@ -1,6 +1,7 @@
* Copyright (C) 2015 Frederic France
+ * Copyright (C) 2016 Juanjo Menent
*
* 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
@@ -377,7 +378,8 @@ if ($mode == 'template' && $user->admin)
if ($ret > 0) {
setEventMessages($printer->error, $printer->errors, 'errors');
} else {
- for ($line=0; $line < count($printer->listprinterstemplates); $line++) {
+ $max = count($printer->listprinterstemplates);
+ for ($line=0; $line < $max; $line++) {
$var = !$var;
print '
';
if ($action=='edittemplate' && $printer->listprinterstemplates[$line]['rowid']==$templateid) {
@@ -422,7 +424,8 @@ if ($mode == 'template' && $user->admin)
print '
';
-// Optio to force stock to be enough before adding a line into document
+// Option to force stock to be enough before adding a line into document
if ($conf->invoice->enabled || $conf->order->enabled || $conf->expedition->enabled)
{
print ' ';
diff --git a/htdocs/admin/supplier_payment.php b/htdocs/admin/supplier_payment.php
index 41737f7a9d5..bc960c7bd2c 100644
--- a/htdocs/admin/supplier_payment.php
+++ b/htdocs/admin/supplier_payment.php
@@ -1,5 +1,6 @@
+ * Copyright (C) 2016 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
@@ -16,9 +17,9 @@
*/
/**
- * \file htdocs/admin/payment.php
- * \ingroup facture
- * \brief Page to setup invoices payments
+ * \file htdocs/admin/supplier_payment.php
+ * \ingroup supplier
+ * \brief Page to setup supplier invoices payments
*/
require '../main.inc.php';
@@ -30,6 +31,8 @@ $langs->load("admin");
$langs->load("errors");
$langs->load('other');
$langs->load('bills');
+$langs->load('orders');
+
if (! $user->admin) accessforbidden();
@@ -80,16 +83,18 @@ $form=new Form($db);
$linkback=''.$langs->trans("BackToModuleList").'';
print load_fiche_titre($langs->trans("SupplierPaymentSetup"),$linkback,'title_setup');
-print " ";
+print " ";
$head = supplierorder_admin_prepare_head();
-dol_fiche_head($head, 'supplierpayment', $langs->trans("SupplierPayment"), 0, 'invoice');
+dol_fiche_head($head, 'supplierpayment', $langs->trans("Suppliers"), 0, 'company');
/*
* Numbering module
*/
-print load_fiche_titre($langs->trans("SupplierPaymentsNumberingModule"));
+if (empty($conf->global->SUPPLIER_PAYMENT_ADDON)) $conf->global->SUPPLIER_PAYMENT_ADDON = 'mod_supplier_payment_bronan';
+
+print load_fiche_titre($langs->trans("PaymentsNumberingModule"));
print '
';
$form->select_conditions_paiements(isset($_POST['cond_reglement_id']) ? $_POST['cond_reglement_id'] : $cond_reglement_id, 'cond_reglement_id');
@@ -2678,8 +2712,8 @@ else if ($id > 0 || ! empty($ref))
$filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
$filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
} else {
- $filterabsolutediscount = "fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description='(DEPOSIT)')";
- $filtercreditnote = "fk_facture_source IS NOT NULL AND description <> '(DEPOSIT)'";
+ $filterabsolutediscount = "fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description LIKE '(DEPOSIT)%')";
+ $filtercreditnote = "fk_facture_source IS NOT NULL AND description NOT LIKE '(DEPOSIT)%'";
}
$absolute_discount = $soc->getAvailableDiscounts('', $filterabsolutediscount);
@@ -3097,9 +3131,9 @@ else if ($id > 0 || ! empty($ref))
// Remise dispo de type avoir
if (! $absolute_discount)
print ' ';
- // $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote,
- // $filtercreditnote, $resteapayer);
- $form->form_remise_dispo($_SERVER["PHP_SELF"] . '?facid=' . $object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, 0); // We allow credit note even if amount is higher
+ // $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, $resteapayer
+ $more=' ('.$addcreditnote.')';
+ $form->form_remise_dispo($_SERVER["PHP_SELF"] . '?facid=' . $object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, 0, $more); // We allow credit note even if amount is higher
}
}
if (! $absolute_discount && ! $absolute_creditnote) {
@@ -3320,7 +3354,7 @@ else if ($id > 0 || ! empty($ref))
$i ++;
}
} else {
- print '
";
diff --git a/htdocs/compta/tva/quadri_detail.php b/htdocs/compta/tva/quadri_detail.php
index 28ce4e50e24..6ebaee8ecd5 100644
--- a/htdocs/compta/tva/quadri_detail.php
+++ b/htdocs/compta/tva/quadri_detail.php
@@ -479,7 +479,7 @@ else
//print table headers for this quadri - expenses now
//imprime les en-tete de tables pour ce quadri - maintenant les d�penses
- print '
';
+ print '
';
print '
'.$elementsup.'
';
print '
'.$productsup.'
';
if ($modetax == 0)
diff --git a/htdocs/compta/tva/reglement.php b/htdocs/compta/tva/reglement.php
index f6dd0be53c2..5484be65a32 100644
--- a/htdocs/compta/tva/reglement.php
+++ b/htdocs/compta/tva/reglement.php
@@ -134,7 +134,8 @@ if ($result)
$var=true;
$param='';
- if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
+ if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
+ if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
if ($typeid) $param.='&typeid='.$typeid;
@@ -211,7 +212,7 @@ if ($result)
$i++;
}
- print '
'.$langs->trans("Total").'
';
+ print '
'.$langs->trans("Total").'
';
print "
".price($total)."
";
print "
";
diff --git a/htdocs/contact/ldap.php b/htdocs/contact/ldap.php
index a626c57b6af..af8fccfd7b9 100644
--- a/htdocs/contact/ldap.php
+++ b/htdocs/contact/ldap.php
@@ -170,12 +170,12 @@ if ($result > 0)
$info=$object->_load_ldap_info();
$dn=$object->_load_ldap_dn($info,1);
$search = "(".$object->_load_ldap_dn($info,2).")";
- $records=$ldap->getAttribute($dn,$search);
+ $records = $ldap->getAttribute($dn,$search);
//var_dump($records);
// Affichage arbre
- if (count($records) && $records != false && (! isset($records['count']) || $records['count'] > 0))
+ if ((! is_numeric($records) || $records != 0) && (! isset($records['count']) || $records['count'] > 0))
{
if (! is_array($records))
{
diff --git a/htdocs/contact/list.php b/htdocs/contact/list.php
index ac54e1aaa5f..a66c1dab946 100644
--- a/htdocs/contact/list.php
+++ b/htdocs/contact/list.php
@@ -369,6 +369,7 @@ if ($result)
$i = 0;
$param='';
+ if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
$param.='&begin='.urlencode($begin).'&view='.urlencode($view).'&userid='.urlencode($userid).'&contactname='.urlencode($sall);
$param.='&type='.urlencode($type).'&view='.urlencode($view);
diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php
index 0a34723e2ce..5a87d3b3d51 100644
--- a/htdocs/contrat/card.php
+++ b/htdocs/contrat/card.php
@@ -1060,7 +1060,7 @@ if ($action == 'create')
$projectid = (!empty($objectsrc->fk_project)?$objectsrc->fk_project:'');
- $soc = $objectsrc->client;
+ $soc = $objectsrc->thirdparty;
$note_private = (! empty($objectsrc->note_private) ? $objectsrc->note_private : '');
$note_public = (! empty($objectsrc->note_public) ? $objectsrc->note_public : '');
diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php
index 8f3c87725fa..47cde8e3f40 100644
--- a/htdocs/contrat/class/contrat.class.php
+++ b/htdocs/contrat/class/contrat.class.php
@@ -2147,8 +2147,11 @@ class Contrat extends CommonObject
$line->total_ht=90;
$line->total_ttc=107.64; // 90 * 1.196
$line->total_tva=17.64;
- $prodid = mt_rand(1, $num_prods);
- $line->fk_product=$prodids[$prodid];
+ if ($num_prods > 0)
+ {
+ $prodid = mt_rand(1, $num_prods);
+ $line->fk_product=$prodids[$prodid];
+ }
$this->lines[$xnbp]=$line;
$xnbp++;
}
@@ -2217,18 +2220,18 @@ class Contrat extends CommonObject
*/
class ContratLigne extends CommonObjectLine
{
-
+ public $element='contratdet';
+ public $table_element='contratdet';
+
var $id;
var $ref;
var $tms;
+
var $fk_contrat;
var $fk_product;
var $statut; // 0 inactive, 4 active, 5 closed
+ var $type; // 0 for product, 1 for service
var $label;
-
- public $element='contratdet';
- public $table_element='contratdet';
-
/**
* @var string
* @deprecated Use $label instead
@@ -2237,6 +2240,10 @@ class ContratLigne extends CommonObjectLine
public $libelle;
var $description;
+
+ var $product_ref;
+ var $product_label;
+
var $date_commande;
var $date_ouverture_prevue; // date start planned
var $date_ouverture; // date start real
@@ -2376,16 +2383,17 @@ class ContratLigne extends CommonObjectLine
$result='';
$label=$langs->trans("ShowContractOfService").': '.$this->label;
-
+ if (empty($label)) $label=$this->description;
+
$link = '';
$linkend='';
- $picto='contract';
-
+ $picto='service';
+ if ($this->type == 0) $picto='product';
if ($withpicto) $result.=($link.img_object($label, $picto, 'class="classfortooltip"').$linkend);
if ($withpicto && $withpicto != 2) $result.=' ';
- if ($withpicto != 2) $result.=$link.$this->label.$linkend;
+ if ($withpicto != 2) $result.=$link.($this->product_ref?$this->product_ref.' ':'').($this->label?$this->label:$this->description).$linkend;
return $result;
}
@@ -2414,6 +2422,7 @@ class ContratLigne extends CommonObjectLine
$sql.= " p.ref as product_ref,";
$sql.= " p.label as product_label,";
$sql.= " p.description as product_desc,";
+ $sql.= " p.type as product_type,";
$sql.= " t.description,";
$sql.= " t.date_commande,";
$sql.= " t.date_ouverture_prevue as date_ouverture_prevue,";
@@ -2464,6 +2473,7 @@ class ContratLigne extends CommonObjectLine
$this->product_ref = $obj->product_ref;
$this->product_label = $obj->product_label;
$this->product_description = $obj->product_description;
+ $this->product_type = $obj->product_type;
$this->label = $obj->label; // deprecated. We do not use this field. Only ref and label of product, and description of contract line
$this->description = $obj->description;
$this->date_commande = $this->db->jdate($obj->date_commande);
diff --git a/htdocs/contrat/list.php b/htdocs/contrat/list.php
index 11d05c60a49..350a0435d38 100644
--- a/htdocs/contrat/list.php
+++ b/htdocs/contrat/list.php
@@ -170,6 +170,7 @@ if ($resql)
$i = 0;
$param='';
+ if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
$param.='&search_contract='.$search_contract;
$param.='&search_name='.$search_name;
@@ -256,7 +257,7 @@ if ($resql)
print '';
print '';
print '
';
@@ -3887,7 +3895,7 @@ class Form
}
else
{
- if (! $filter || $filter=="fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description='(DEPOSIT)')") print $langs->trans("CompanyHasAbsoluteDiscount",price($amount,0,$langs,0,0,-1,$conf->currency)).': ';
+ if (! $filter || $filter=="fk_facture_source IS NULL OR (fk_facture_source IS NOT NULL AND description LIKE '(DEPOSIT)%')") print $langs->trans("CompanyHasAbsoluteDiscount",price($amount,0,$langs,0,0,-1,$conf->currency)).': ';
else print $langs->trans("CompanyHasCreditNote",price($amount,0,$langs,0,0,-1,$conf->currency)).': ';
}
$newfilter='fk_facture IS NULL AND fk_facture_line IS NULL'; // Remises disponibles
@@ -3898,7 +3906,7 @@ class Form
if ($nbqualifiedlines > 0)
{
print ' ';
}
if ($more) print $more;
@@ -4084,7 +4092,7 @@ class Form
$out='';
$out.= '