Merge branch '14.0' into 14a35

This commit is contained in:
Alexandre SPANGARO 2022-06-01 23:12:02 +02:00
commit 7b55676b56
6622 changed files with 267523 additions and 136134 deletions

15
.gitattributes vendored
View File

@ -11,12 +11,14 @@
*.htm text eol=lf
*.html text eol=lf
*.js text eol=lf
*.json text eol=lf
*.css text eol=lf
*.lang text eol=lf
*.txt text eol=lf
*.md text eol=lf
*.pp text eol=lf
*.sh text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.conf text eol=lf
@ -24,15 +26,16 @@
# Denote all files that are truly binary and should not be modified.
*.bmp binary
*.ico binary
*.png binary
*.jpg binary
*.jpeg binary
*.odt binary
*.odf binary
*.frm binary
*.ico binary
*.jpeg binary
*.jpg binary
*.MYD binary
*.MYI binary
*.odf binary
*.odt binary
*.png binary
# Export ignores to generate clean production tarballs
/build export-ignore

1
.gitignore vendored
View File

@ -55,3 +55,4 @@ yarn.lock
package-lock.json
doc/install.lock
/factory/

View File

@ -1,6 +1,6 @@
# This script is used by Travis CI to run automatically Continuous test integration
# from Dolibarr GitHub repository.
# For syntax, see http://about.travis-ci.org/docs/user/languages/php/
# For syntax, see https://docs.travis-ci.com/user/languages/php/
# We use dist: xenial to have php 5.6+ available
os: linux
@ -9,6 +9,9 @@ dist: xenial
language: php
git:
depth: 1
# Start on every boot
services:
- memcached
@ -41,16 +44,20 @@ jobs:
#allow_failures:
#- php: nightly
include:
- if: type = push
- stage: PHP 5.6-7.4
if: type = push
php: '5.6'
env: DB=postgresql
- if: type = pull_request OR type = push
php: '7.4'
- stage: PHP 5.6-7.4
if: type = pull_request OR type = push
php: '7.4.22'
env: DB=mysql
- if: type = push AND branch = develop
- stage: PHP Dev
if: type = push AND branch = develop
php: nightly
env: DB=mysql
- if: type = push AND branch = 14.0
- stage: PHP Dev
if: type = push AND branch = 14.0
php: nightly
env: DB=mysql
@ -99,7 +106,7 @@ install:
php-parallel-lint/php-console-highlighter ^0 \
squizlabs/php_codesniffer ^3
fi
if [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ]; then
if [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = '7.4.22' ]; then
composer -n require phpunit/phpunit ^7 \
php-parallel-lint/php-parallel-lint ^1.2 \
php-parallel-lint/php-console-highlighter ^0 \
@ -234,7 +241,7 @@ before_script:
# enable php-fpm
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf
- |
if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then
if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ] || [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = '7.4.22' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then
# Copy the included pool
sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.d/www.conf
fi
@ -264,24 +271,27 @@ script:
echo
- |
echo "Checking PHP syntax errors"
echo "Checking PHP syntax errors (only 1 version to not overload travis and avoid duplicate tests)"
# Ensure we catch errors
set -e
#parallel-lint --exclude htdocs/includes --blame .
parallel-lint --exclude dev/tools/test/namespacemig --exclude htdocs/includes/composer --exclude htdocs/includes/myclabs --exclude htdocs/includes/phpspec --exclude dev/initdata/dbf/includes \
--exclude htdocs/includes/sabre --exclude htdocs/includes/phpoffice/PhpSpreadsheet --exclude htdocs/includes/sebastian \
--exclude htdocs/includes/squizlabs/php_codesniffer --exclude htdocs/includes/jakub-onderka --exclude htdocs/includes/php-parallel-lint --exclude htdocs/includes/symfony \
--exclude htdocs/includes/mike42/escpos-php/example --exclude htdocs/includes/maximebf \
--exclude htdocs/includes/phpunit/ --exclude htdocs/includes/tecnickcom/tcpdf/include/barcodes --exclude htdocs/includes/webmozart --blame .
# Exclusions are defined in the ruleset.xml file
if [ "$TRAVIS_PHP_VERSION" = "7.4.22" ]; then
parallel-lint -e php --exclude dev/tools/test/namespacemig --exclude htdocs/includes/composer --exclude htdocs/includes/myclabs --exclude htdocs/includes/phpspec --exclude dev/initdata/dbf/includes \
--exclude htdocs/includes/sabre --exclude htdocs/includes/phpoffice/PhpSpreadsheet --exclude htdocs/includes/sebastian \
--exclude htdocs/includes/squizlabs/php_codesniffer --exclude htdocs/includes/jakub-onderka --exclude htdocs/includes/php-parallel-lint --exclude htdocs/includes/symfony \
--exclude htdocs/includes/mike42/escpos-php/example --exclude htdocs/includes/maximebf \
--exclude htdocs/includes/phpunit/ --exclude htdocs/includes/tecnickcom/tcpdf/include/barcodes --exclude htdocs/includes/webmozart --blame .
fi
set +e
echo
- |
echo "Checking coding style (excluding Pull Requests builds to not overload travis, excluding also some jobs to avoid duplicate tests)"
echo "Checking coding style (only for Pull Requests builds and 1 version to not overload travis and avoid duplicate tests)"
# Ensure we catch errors
set -e
# Exclusions are defined in the ruleset.xml file
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "7.4" ] && [ "$DB" = "mysql" ]; then
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "7.4.22" ]; then
phpcs -s -p -d memory_limit=-1 --extensions=php --colors --tab-width=4 --standard=dev/setup/codesniffer/ruleset.xml --encoding=utf-8 --runtime-set ignore_warnings_on_exit true .;
fi
set +e
@ -401,11 +411,16 @@ script:
php upgrade.php 13.0.0 14.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade13001400.log
php upgrade2.php 13.0.0 14.0.0 > $TRAVIS_BUILD_DIR/upgrade13001400-2.log
php step5.php 13.0.0 14.0.0 > $TRAVIS_BUILD_DIR/upgrade13001400-3.log
ls -alrt $TRAVIS_BUILD_DIR/
- |
echo "Enabling new modules"
# Enable modules not enabled into original dump
php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_API,MAIN_MODULE_PRODUCTBATCH,MAIN_MODULE_SUPPLIERPROPOSAL,MAIN_MODULE_STRIPE > $TRAVIS_BUILD_DIR/enablemodule.log
set -e
php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_API,MAIN_MODULE_PRODUCTBATCH,MAIN_MODULE_SUPPLIERPROPOSAL,MAIN_MODULE_STRIPE,MAIN_MODULE_EXPENSEREPORT > $TRAVIS_BUILD_DIR/enablemodule.log
php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_WEBSITE,MAIN_MODULE_TICKET,MAIN_MODULE_ACCOUNTING,MAIN_MODULE_MRP >> $TRAVIS_BUILD_DIR/enablemodule.log
php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_RECEPTION,MAIN_MODULE_RECRUITMENT >> $TRAVIS_BUILD_DIR/enablemodule.log
php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_KNOWLEDGEMANAGEMENT,MAIN_MODULE_EVENTORGANIZATION,MAIN_MODULE_PARTNERSHIP >> $TRAVIS_BUILD_DIR/enablemodule.log
echo $?
cd -
set +e

View File

@ -128,6 +128,12 @@ source_file = htdocs/langs/en_US/errors.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.eventorganization]
file_filter = htdocs/langs/<lang>/eventorganization.lang
source_file = htdocs/langs/en_US/eventorganization.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.exports]
file_filter = htdocs/langs/<lang>/exports.lang
source_file = htdocs/langs/en_US/exports.lang
@ -182,6 +188,12 @@ source_file = htdocs/langs/en_US/interventions.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.knowledgemanagement]
file_filter = htdocs/langs/<lang>/knowledgemanagement.lang
source_file = htdocs/langs/en_US/knowledgemanagement.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.languages-not-res]
file_filter = htdocs/langs/<lang>/languages.lang
source_file = htdocs/langs/en_US/languages.lang
@ -278,6 +290,12 @@ source_file = htdocs/langs/en_US/other.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.partnership]
file_filter = htdocs/langs/<lang>/partnership.lang
source_file = htdocs/langs/en_US/partnership.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[dolibarr.paybox]
file_filter = htdocs/langs/<lang>/paybox.lang
source_file = htdocs/langs/en_US/paybox.lang

View File

@ -1,52 +1,63 @@
License
-------
Copyright and license
----------------------
Dolibarr is released 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 (GPL-3+).
More information: https://www.gnu.org/licenses/gpl-3.0.txt
The Dolibarr software as a whole is distributed under 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 (GPL-3+). More information: https://www.gnu.org/licenses/gpl-3.0.txt.
A copy of this license is available in the COPYING file.
Dolibarr depends on third-party components and code snippets released under their own license (obviously, all compatible with the one of Dolibarr).
These dependencies are listed in the bottom of this file.
Dolibarr uses some external libraries released under different licenses. This is compatibility summary:
The Dolibarr images resources (available in the doc directory) is distributed under the Creative Commons Attribution 4.0 International license (CC BY 4.0).
The name Dolibarr is a trademark initially registered by Laurent Destailleur and ceased to the Dolibarr foundation. You can use the name Dolibarr
for your own need as long as you follow the rules defined on the page https://wiki.dolibarr.org/index.php/Rules_to_use_the_brand_name_%22Dolibarr%22
The use of the name DoliStore is also restricted to the same rules defined on https://wiki.dolibarr.org/index.php/Rules_to_use_the_brand_name_%22Dolibarr%22
Licence of dependencies of third-party components used by Dolibarr (all compatible with the Licence of Dolibarr):
Component Version License GPL Compatible Usage
-------------------------------------------------------------------------------------
PHP libraries:
AdoDb-Date 0.36 Modified BSD License Yes Date convertion (not into rpm package)
ADOdb-Date 0.36 Modified BSD License Yes Date convertion (not into rpm package)
CKEditor 4.12.1 LGPL-2.1+ Yes Editor WYSIWYG
EvalMath 1.0 BSD Yes Safe math expressions evaluation
Escpos-php 2.2 MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers
GeoIP2 0.2.0 LGPL-2.1+ Yes Lib to make geoip convert
GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert
Mobiledetect 2.8.34 MIT License Yes Detect mobile devices browsers
NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package)
PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency
ParseDown 1.6 MIT License Yes Markdown parser
PCLZip 2.8.4 LGPL-3+ Yes Library to zip/unzip files
PHPDebugBar 1.15.1 MIT License Yes Used only by the module "debugbar" for developers
PHPSpreadSheet ? LGPL-2.1+ Yes Read/Write XLS files, read ODS files
PHPDebugBar 1.15.1 MIT License Yes Used only by the module "debugbar" for developers
PHPSpreadSheet 1.8.2 LGPL-2.1+ Yes Read/Write XLS files, read ODS files
php-iban 1.4.7 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP
PHPoAuthLib 0.8.2 MIT License Yes Library to provide oauth1 and oauth2 to different service
PHPPrintIPP 1.3 GPL-2+ Yes Library to send print IPP requests
PSR/Logs 1.0 Library for logs (used by DebugBar)
PSR/simple-cache ? Library for cache (used by PHPSpreadSheet)
PSR/Logs 1.0 Library for logs (used by DebugBar)
PSR/simple-cache ? MIT License Yes Library for cache (used by PHPSpreadSheet)
Restler 3.1.1 LGPL-3+ Yes Library to develop REST Web services (+ swagger-ui js lib into dir explorer)
Sabre 3.2.2 BSD Yes DAV support
Swift Mailer 5.4.2-DEV MIT license Yes Comprehensive mailing tools for PHP
Stripe 7.67.0 MIT licence Yes Library for Stripe module
Swift Mailer 5.4.2-DEV MIT License Yes Comprehensive mailing tools for PHP
Stripe 7.67.0 MIT Licence Yes Library for Stripe module
TCPDF 6.3.2 LGPL-3+ Yes PDF generation
TCPDI 1.0.0 LGPL-3+ / Apache 2.0 Yes FPDI replacement
JS libraries:
Ace 1.4.8 BSD Yes JS library to get code syntaxique coloration in a textarea.
ChartJS 2.9.4 MIT License Yes JS library for graph
ChartJS 2.9.4 MIT License Yes JS library for graph
jQuery 3.5.1 MIT License Yes JS library
jQuery UI 1.12.1 GPL and MIT License Yes JS library plugin UI
jQuery select2 4.0.13 GPL and Apache License Yes JS library plugin for sexier multiselect. Warning: 4.0.6+ create troubles without patching css
jQuery select2 4.0.13 GPL and Apache License Yes JS library plugin for sexier multiselect. Warning: 4.0.6+ create troubles without patching css
jQuery blockUI 2.70.0 GPL and MIT License Yes JS library plugin blockUI (to use ajax popups)
jQuery Colorpicker 1.1 MIT License Yes JS library for color picker for a defined list of colors
jQuery JCrop 0.9.8 GPL and MIT License Yes JS library plugin Crop (to crop images)
jQuery Jeditable 1.7.1 GPL and MIT License Yes JS library plugin jeditable (to edit in place)
jQuery jNotify 1.1.00 Apache Software License 2.0 Yes JS library plugin jNotify (to use ajax popups)
jQuery jNotify 1.1.00 Apache License 2.0 Yes JS library plugin jNotify (to use ajax popups)
jQuery jPicker 1.1.6 GPL and MIT License Yes JS library for color picker with not defined list of colors
jQuery jqueryFileTree 1.0.1 GPL and MIT License Yes JS library for filetree
jQuery jquerytreeview 1.4.1 MIT License Yes JS library for filetree
@ -54,20 +65,19 @@ jQuery TableDnD 0.6 GPL and MIT License Yes
jQuery Timepicker 1.1.0 GPL and MIT License Yes JS library Timepicker addon for Datepicker
jsGanttImproved 2.7.3 BSD License Yes JS library (to build Gantt reports)
JsTimezoneDetect 1.0.6 MIT License Yes JS library to detect user timezone
SwaggerUI 2.0.24 GPL-2+ Yes JS library to offer the REST API explorer
SwaggerUI 2.2.10 GPL-2+ Yes JS library to offer the REST API explorer
Image libraries:
Octicons 8.1 MIT Yes
Font libraries:
Fontawesome 5.13 Font Awesome Free licence Yes
Fontawesome 5.13 Font Awesome Free Licence Yes
For licenses compatibility informations:
https://www.gnu.org/licenses/licenses.en.html
For more licenses compatibility informations: https://www.gnu.org/licenses/licenses.en.html
Copyright / Authors
Authors
-------------------
See page https://github.com/Dolibarr/dolibarr/graphs/contributors

611
ChangeLog
View File

@ -3,28 +3,627 @@ English Dolibarr ChangeLog
--------------------------------------------------------------
***** ChangeLog for 14.0.5 compared to 14.0.4 *****
FIX: 13.0: printFieldListWhere called twice on same query
FIX: 14.0.4 fatal error on cron list.
FIX: #19476
FIX: #19564
FIX: #19651
FIX: Accountancy - SQL error on subledger account search in journal
FIX: apply eldy's suggestion to not overwrite existing extrafields of $line
FIX: Can't close a down payment if paid with credit notes.
FIX: better compatibility with multicompany
FIX: contact card: bad colspan value for separator extrafield in creation/modification form
FIX: discounts are applied both when fetching the best supplier price and when displaying it
FIX: double display for contact categorie on societe create card
FIX: fatal error on cron list.
FIX: holiday list: only mass delete if leave request is not in draft, canceled or refused, like in card
FIX: holiday mass deletion: correct return of record deleted
FIX: Holiday month report
FIX: info tab on customer invoice record not found
FIX: line extrafields are inoperative in dispatch cards even when they exist
FIX: list of categories in stats of supplier invoices
FIX: missing default value for more comprehensive
FIX: multicurrency: fields in discount unitialized when creating deposit
FIX: Navigation on bank transaction list
FIX: Can't edit a bank transaction due to bad permission check.
FIX: Option MAIN_DIRECT_STATUS_UPDATE broken. Ajax on/off not saving value in DB after updating to version >=12
FIX: postgresql compatibility, "" as is not authorized
FIX: printFieldListWhere called twice (at different locations) for the same SQL query, can result in syntax errors
FIX: select too large into addrights (pb of missing parenthesis)
FIX: set optional from post, we can't untick boolean field on product card
FIX: Take into consideration work leave over serveral months
FIX: test if method exist on wrong object
FIX: title for nature of third party in company list
FIX: Urgent onglet contact inaccessible depuis une facture
FIX: wrong syntax of sql request
***** ChangeLog for 14.0.4 compared to 14.0.3 *****
FIX: $totalarray is overwritten, totals were lost
FIX: 13.0 - due to a typo in the 'mode' parameter, the "first name" column of the list of members displays the full name
FIX: 13.0: end date required to edit a ticket message
FIX: 13.0 feedback of PR #18993: make ticket messages punctual events with attr percentage = -1
FIX: 13.0 PR #18993: add comment on modified part
FIX: 13.0: sometimes firstname was mistyped as fistname
FIX: 14.0 - civility field of private third party creation form has inadequate width
FIX: 14.0 - civility field width inadequate due to select2 calculating the width while the field has no width (display: none)
FIX: 14.0 - due to a typo in the 'mode' parameter, the "first name" co…
FIX: #18634 : Problem of virtual stock with reception module enabled
FIX: #18695 Added ref_ext to supplier invoice
FIX: #18698 Supplier invoice list - "alert" checkbox not working
FIX: #18735
FIX: #18767 : Adherent delete
FIX: #18797
FIX: #18854
FIX: #18875 in v14
FIX: #18910
FIX: #18910 : MRP List SQL query syntax error with more than one extrafileds.
FIX: #18912 Accountancy - SQL error when custom group is added without country defined
FIX: #18934 on-registration in the extrafieldsline database for deliveries
FIX: #18968
FIX: #19008
FIX: #19014 - the properties of some fields are not updated when you submit the form
FIX: #19210
FIX: #19214 : PostgreSQL error on admin/limits.php
FIX: #19241 Project - Fix display salary in overview
FIX: #19305
FIX: 2 columns for total labels
FIX: Accountancy - Format Quadra export - Missing line type C to create automaticly a subledger account with label
FIX: Accountancy - If deposit invoice is used, force binding in deposit accounting account to solve transaction
FIX: Accountancy - Missing specific filename for export on format FEC2, Ciel & repare it
FIX: Accountancy - Option of export popup are inverted
FIX: Accountancy - PHP8
FIX: Accountancy - Product admin - SQL error when we affect accounting account with product_perentity activated
FIX: Accountancy simplified - Salaries are not present in report
FIX: Accountancy - Some correction on export name
FIX: Accountancy - Trunc code_journal to 2 in format XIMPORT (Ciel, Sage50)
FIX: add warehouse in projects' overview count
FIX: also on customer index for automatic binding
FIX: Attachment of pdf into shipment when sending email
FIX: autocalculation of the supplier price in main currency.
FIX: avoid warning if $categories is an id
FIX: bad sign of amount stored for multicurrency columns on credit notes
FIX: Bad use of a forced contact of another company on PDF/ODT documents
FIX: Bad use of dol_concatdesc()
FIX: Button text on proposal card for create a invoice
FIX: calculateCosts of BOM must not be included into fetch
FIX: calculation of balance in conciliation page on desc sorting.
FIX: card.php
FIX: Change date format of the inventorycode to be equal as mass stock transfert
FIX: check if greater 0
FIX: close cash with some terminals in TakePOS
FIX: compatibility with Multicompany
FIX: consistent UX when calling a tab from the invoice card with empty ref/id
FIX: default language defined for IN country
FIX: Expense report - In edit mode, field qty doesn't accept decimal unlike the create mode
FIX: fetch of product with modulebuilder load too much data
FIX: filter for export of accounting documents
FIX: Filter on categories
FIX: generate documents with PDF options
FIX: indentation
FIX: init hookmanager after loading $conf values
FIX: invoice: inpossible to create an invoice because of very bad check + warnings when trying to print tabs for invoice with no ID
FIX: legal issue on expense report pdf (must also show price without tax)
FIX: list of categories in stats of supplier invoices
FIX: load tranlate array after setting lang
FIX: lost superadmin grade after edit user card
FIX: missing filter status=1 on rss feeds
FIX: missing permission check reported by me@lainwir3d.net on product api
FIX: missing return status
FIX: missing sql filter by entity
FIX: move fetch_optionnal into $ac_static->fetch()
FIX: only a superadmin can modify entity
FIX: only ones value is return for dictionaries
FIX: optional visibility on create card
FIX: payment style and html5 tags
FIX: payment using wrong type in takepos when too many payment mode
FIX: PR#18931 Remove useless explicit call to dol_shutdown
FIX: Product accountancy affectation with product_perentity activated (PR #18620)
FIX: products/services card: hidden extrafields were overridden
FIX: project task list: extrafields could not be displayed
FIX: Propal list - Problem of pagination on date
FIX: reload user lang
FIX: Remove not complete order from the virtual stock
FIX: Replenish: SQL error when no warehouse has been created + Warning when there are no warehouses
FIX: resource list : Use standard code to handle list filters
FIX: restrictedArea for payment delete
FIX: Ret PR
FIX: second approval back in stable feature as is the setting for minimum amount (last part from PR#14286)
FIX: selected lines on supplier invoice create
FIX: Selection of type "people" for membership must hide the company
FIX: select list of orders not complete when field type of company is on
FIX: show end hours in events linked to objects
FIX: support of localtax on expense report
FIX: task time: can't filter by user with pgsql + show error message
FIX: task time: keep on using natural_search
FIX: tcpdf vulnerability to roman numeral bomb, cf. tecnickom/TCPDF issue #315
FIX: Test when date of invoie is in future (pb with TZ and offset)
FIX: Ticket - Card - Wrong font awesome library
FIX: Ticket - Duplicate field project when we create ticket from project
FIX: translation into email for member at membership validation.
FIX: Travis Sanitize SQL
FIX: unprivileged user can see task associated with a not allowed project
FIX: URGENT: impossible to create an invoice
FIX: Use of accent into filename of GED
FIX: user date timezone offset
FIX: User salary card - translation problem
FIX: user without permission can set ticket subject
FIX: We need a default price base type in variant creation case with multiprices when parent has been created with only one level price
FIX: wrong array key value
FIX: wrong check
FIX: wrong position of error message
Sync transifex.
***** ChangeLog for 14.0.3 compared to 14.0.2 *****
FIX: #18698 Supplier invoice list - "alert" checkbox not working
FIX: #18735
FIX: #18767 : Member delete
FIX: #18854
FIX: #18910 : MRP List SQL query syntax error with more than one extrafileds.
FIX: Accountancy - Format Quadra export - Missing line type C to create automaticly a subledger account with label
FIX: Accountancy - Missing specific filename for export on format FEC2, Ciel & repare it
FIX: Accountancy - Option of export popup are inverted
FIX: Accountancy - Some correction on export name
FIX: Accountancy - Trunc code_journal to 2 in format XIMPORT (Ciel, Sage50)
FIX: add warehouse in projects' overview count
FIX: autocalculation of the supplier price in main currency.
FIX: avoid warning if $categories is an id
FIX: Bad use of a forced contact of another company on PDF/ODT documents
FIX: Button text on proposal card to create a invoice
FIX: calculateCosts of BOM must not be included into fetch
FIX: check if greater 0
FIX: default language defined for IN country
FIX: fetch of product with modulebuilder load too much data
FIX: Filter on categories
FIX: indentation
FIX: init hookmanager after loading $conf values
FIX: legal issue on expense report pdf (must also show price without tax)
FIX: missing filter status=1 on rss feeds
FIX: move fetch_optionnal into $ac_static->fetch()
FIX: payment using wrong type in takepos when too many payment mode
FIX: Product accountancy affectation with product_perentity activated (PR #18620)
FIX: products/services card: hidden extrafields were overridden
FIX: Propal list - Problem of pagination on date
FIX: selected lines on supplier invoice create
FIX: Selection of type "people" for membership must hide the company
FIX: select list of orders not complete when field type of company is on
FIX: support of localtax on expense report
FIX: task time: can't filter by user with pgsql + show error message
FIX: task time: keep on using natural_search
FIX: Test when date of invoie is in future (pb with TZ and offset)
FIX: translation into email for member at membership validation.
FIX: unprivileged user can see task associated with a not allowed project
FIX: user without permission can set ticket subject
***** ChangeLog for 14.0.2 compared to 14.0.1 *****
FIX: #18353 Invoice list translation issue
FIX: #18375 SQL Error on tasks statistics
FIX: #18465
FIX: #18484
FIX: #18531
FIX: #18542 REST API: set global $user variable to DolibarrApiAccess::user.
FIX: #18544 Shipment REST API: load thirdparty object into the shipment before validating.
FIX: #18544 Shipment rest api: load thirdparty object when validating
FIX: #18565
FIX: #18589 #18617
FIX: #18591 : Remove double quotes of SQL Queries for postgresql compatibility
FIX: #18666 Order / Shipment list: Don't SQL JOIN category table when not necessary.
FIX: Accountancy - Some problems of length with general & subledger account
FIX: add DISTINCT
FIX: Add option $noescapecommand in executeCLI for better compatibility
FIX: Add token to remove error when removing widget
FIX: Add token when remove the last widget on home page
FIX: an approved holiday can be canceled by an admin.
FIX: better sql request
FIX: change LOG_DEBUG with LOG_WARNING in syslog and remove sql error in syslog (already done)
FIX: Collapsing of extrafields has disappeared.
FIX: Date of payment of subscription must not be set to 1970-01-01.
FIX: Export of website generates a package that contains a sql error
FIX: Field already present in SQL request
FIX: increase maxlength of password input
FIX: invoice fetch not found syslog debug level instead of error
FIX: Invoice list - Wrong name for column total_tva
FIX: invoice validation: when checking if any vat rate has a negative amount, prevent false positives with -1E-14 amounts
FIX: Manage credit note on situation invoice for calculate margin
FIX: Menu List of project was not visible.
FIX: migration script
FIX: multicompany transverse mode compatibility
FIX: option "Default value for field 'Refuse bulk emailings'"
FIX: Recommended session.cookie_samesite must be 'Lax' not 'Strict'.
FIX: Relative discount with high nb of decimals
FIX: salary extrafields don't work and table is not well named
FIX: Supplier invoice list - Wrong language key used
FIX: wrong table_element_line
FIX: wrong users count in multicompany transverse mode
FIX: #yogosha6944 Protection against traversal path.
***** ChangeLog for 14.0.1 compared to 14.0.0 *****
FIX: $conf->task used but it does not exist, use $conf->projet instead
FIX: #18181
FIX: #18212 : Add url field
FIX: #18267
FIX: #18289 #18294
FIX: #18341 lang not loaded
FIX: #18389 Accountancy - Bug on LDcompta10 export for supplier invoice
FIX: #18399 Fix shipment validation email template override.
FIX: Accountancy - Debug Export Sage50 / CIEL Compta / CIEL Compta Evo (Format XIMPORT)
FIX: Accountancy - Rules to delete & modify transaction not applied in ledger & subledger
FIX: Accountancy - Search date on journal
FIX: Accountancy - SQL error on select journal on journal
FIX: Accountancy - SQL error when insert a manuel transaction
FIX: add include missing file '/core/actions_dellink.inc.php' in project card
FIX: avoid to have link to create bookmark on page to create bookmark
FIX: bad approver shown on holiday once approved
FIX: bad closing div on error message
FIX: cannot add time spentd when column ref is not displayed
FIX: Can't remove a permission of a group
FIX: Can't set cost price when product is not on purchase
FIX: compatibility postgresql
FIX: filter on status Draft in modulebuilder
FIX: holiday card: hooks uninitialized
FIX: Invoice - Missing button to reopen an abandoned situation invoice
FIX: Link of download main doc on vat list
FIX: look and field v14
FIX: Missing column Date validation in ledger & subledger
FIX: on admin/pdf.php (with javascript enabled) if you set some boolean confs then click on "save", all boolean values are reset
FIX: on supplier order, JOIN with product fourn price table must be done with fk_soc too to avoid display several times a same line (because of same supplier product ref)
FIX: postgresql filter select search extrafield
FIX: shipping validation workflow: 'ORDER_NEW' trigger called from wrong object
FIX: show info of company into user dropdown
FIX: totalDayAll hours in tasks
FIX: update product lot
FIX: using Tulip, deposit mask was not saved
FIX: #yogosha6907
***** ChangeLog for 14.0.0 compared to 13.0.0 *****
For users:
----------
NEW: Several security issues after a second private bug bounty campaign.
NEW: Module Recruitment to follow application to job positions is now stable.
NEW: Feature to make Stock Inventories
NEW: Several security issues after a second private bug hunting campaign.
NEW: A lot of fix into english text after a small proofreading campaign (still not perfect, but really better)
NEW: All main menu entries are using the picto of the module
NEW: Add a copy to clipboard button on some fields
NEW: Add an example of scheduled job to send email reminder for unpaid invoices
NEW: Add some color and picto for the direction of movement
NEW: add the column "Channel" into the list of orders
NEW: Add the column "alias" of company in the list of proposal, order, invoice
NEW: Add the column "Office phone" and "User mobile" in user list
NEW: Add the column "Price level" in thirdparty list
NEW: Add some company information in the dropdown login menu
NEW: Add edit/delete action icons on categories list pages
NEW: Add hidden option to auto load input line extrafield into new lines
NEW: Add import profile to import BOM
NEW: Add link picto to the stock movement on the detail of production
NEW: Add mass action "Set tag" for product/service, user, thirdparty, warehouse, project, bank account, members
NEW: Add bulk action Validate and Set to billed on order list.
NEW: Add possibility to exports userGroups fields on user exports
NEW: Can search on lots or serials into the quick search bar
NEW: Add support for Friday as a non working day
NEW: auto notification with module Notification can use templated emails
NEW: Can clone a cron job
NEW: Can create a lot from the list view (Look and feel standardization).
NEW: Can filter on extrafields date on lists
NEW: Can filter on rowid in list of blocked logs
NEW: Can hide columns "time consumed" on timesheet per week
NEW: Can set an employee on each social contribution
NEW: Can set order of execution of hooks
NEW: Can toggle FCKeditor on public/private notes
NEW: Check update availability for externals modules using a button on module page
NEW: Choose lines to use while creating intervention card from origin
NEW: Columns shipment method, payment mode, payment term in proposal and order list
NEW: Conf for default actioncomm status
NEW: Dictionary for availability - Add a column position
NEW: Can set a user related to a social contribution
NEW: ICS Direct debit can be set with a different value for each bank account
NEW: LDAP: usergroup search can be filtered
NEW: Make public bookmarks editable by admin users only
NEW: If main logo not defined, can use the squarred logo on login page
NEW: The manifest file can use the squared image if available
NEW: Enhance the multicurrency rate editor
NEW: Normalise Type company field with ajax combobox
NEW: preload product description on selection for customer propal/order/invoice
NEW: Search usergroups & resources
NEW: Setup Page for module creation with module builder enhancement #FoundationFunding
NEW: Show picto of module into the list of dictionaries
NEW: Show the total of payment on the payment confirmation page
NEW: The global setup for Mandatory fields can now be done on combo list too.
NEW: translate in "en_US" to complete PR 16980
NEW: Update the list of taxes available by default for France
NEW: Salary payment request and Salary payment are 2 different steps in workflow on Salary payment recording
NEW: VAT payment request and VAT payment are now 2 different steps in workflow on VAT payment recording
NEW: VAT report - Optimisation & collapse by rate
NEW: When a doc file is shared, link is visible from the main page of doc.
NEW: #16378 more E-Mail Contact substitution Values for better salutation
NEW: option to keep the "Automatically create the payment" checkbox empty on the tax creation page
Accountancy
NEW: Add FEC import
NEW: Add a confirmation form with options on export (for notified export and validate operations)
NEW: Add select date from/to in already bind customer and supplier list
NEW: FEC / FEC2 export - Add new field DateLimitReglmt
NEW: In ledger & journals, show link on bank transaction
NEW: Possibility to filter on journals in balance
NEW: Add a page to list subledger accounts
NEW: Multiselect journal code filter on journal / balance / ledger
NEW: Add first step to close fiscal year
Agenda
NEW: add support for Friday as a non working day
NEW: can show the leave dates/holidays on the agenda view
NEW: Support color for types of event
Bank
NEW: Bank Entries : display user linked to a salary or a taxes
NEW: Add bulk actions for Bank Transfer
ECM/GED
NEW: add DB fields note_public and note_private for ECM module
NEW: can filter files in ECM/GED on status Shared / Not shared
Invoices
NEW: add a check to avoid an invoice date in the future
NEW: add the total of margin in invoice list
NEW: can set a percentage when creating an invoice from another object
NEW: Support down payment on supplier invoice (& some adjustments)
Margin
NEW: add the total of margin in invoice list
NEW: add the total of margin in page by user
Members
NEW: #17292 default subscription amount by adherent type
NEW: option to automatically create a login/user when a new subscription of a member is done online
NEW: option to select membership type on the online payment page for membership subscription or renewal
Products
NEW: Add price min and price min including tax into product export
NEW: Add a ref in product customer price
NEW: customer ref for product customer prices
NEW: Set status of all variants when changing status of parent
Projects/Tasks
NEW: option to automatically close an open project when all its tasks are done (=progress 100%)
NEW: can show the project ref into PDF documents
NEW: when we add contacts/users to a project, ask to also affect them on tasks
NEW: Can hide columns "time consumed" on timesheet per week
Proposals
NEW: add bulk action to set a commercial proposal to status "Refused"
NEW: can set a warehouse in a proposal
NEW: date and user signature on proposal (Issue 16062) #16980
Shipment
NEW: add option in Workflow module to set a shipment as closed
TakePOS
NEW: delayed payment in TakePOS #14456?
NEW: display date range if exist in TakePOS
NEW: display resiliate status in TakePOS for member
NEW: edit sales lines rights in TakePOS
NEW: option for TakePOS to show the total price without tax
NEW: more permissions in TakePOS (can edit added line, can modify once order sent to kitchen)
Third Party / Contacts
NEW: add contact tag and bulk email status on the thirdparty + contact create form
NEW: can set a warehouse on a thirdparty
Tickets
NEW: can use captcha on public page to create a ticket #16347
NEW: can set if a ticket group is visible on public interface or not
Warehouse/Stock
NEW: Feature to make Stock Inventories
NEW: can make massive stock transfers from a CSV file
NEW: Stock movement list - add more complete date field
NEW: can set a warehouse in a proposal
NEW: can set a warehouse on a thirdparty
Website Module
NEW: #17113 Can upload a favicon in website module
NEW: add a new permission "Export website"
NEW: add last date of modification for website pages in the list of pages
NEW: Save old page with .old extension on disk when editing a website page
Workflows
NEW: add option in Workflow module to set a shipment as closed
for Admins
NEW: Add a security center page with all information and advices related to the security of your instance
NEW: Add a performance center page with all information and advices related to the performance of your instance
Modules
NEW: Module Recruitment is now stable
NEW: start new experimental module Event Organization Management
NEW: start new experimental module Partnership Management
NEW: start new experimental module Knowledge Management
NEW: start new experimental module Workstations Management
NEW: Check update availability for externals modules using a button on module page
Module SimplePOS is deprecated - TakePOS is recommended for the future
new Options
NEW: add option CONTRACT_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
NEW: add option SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
NEW: add option MAIN_SECURITY_ANTI_SSRF_SERVER_IP to define list of IPs that are local IPs
NEW: add option SOCIETE_DISABLE_WORKFORCE to hide staff field
NEW: add constant MAIN_BUGTRACK_URL to set a custom url to redirect to when clicking on link "declare a bug"
NEW: add constant ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY to manage binding with accountancy account declared on thirdparty card
NEW: add constant MAIN_PRODUCT_PERENTITY_SHARED to manage some informations (Accounting account) when product is shared on several entities
NEW: add constant MAIN_COMPANY_PERENTITY_SHARED to manage some informations (Accounting account) when company is shared on several entities
For developers:
---------------
NEW: Can edit an object property in module builder
NEW: Add data-eec=1 for EEC countries on select for js interaction
NEW: Add experimental repair script to switch to dynamic row format and utf8mb4 encoding
NEW: Add function showValueWithClipboardCPButton() to add a copy/paste
NEW: Upgrade Stripe PHP lib to 7.67.0
NEW: Support sepa_debit in stripe paymentmethods list
NEW: Update doleditor.class.php for easily activate SCAYT
NEW: Add triggers in the function add_object_linked(), updateObjectLinked() and deleteObjectLinked()
NEW: Add triggers OBJECT_LINK_INSERT, OBJECT_LINK_UPDATE et OBJECT_LINK_DELETE in the function add_object_linked(), updateObjectLinked() and deleteObjectLinked()
NEW: can set a target image in dolcropresize function
NEW: can set a label as placeholder for combo lists
NEW: Add pagination on Get Products response API
NEW: Add the DefaultValues CRUD class
NEW: Extrafields of documents lines are inside the lines, not any more on separate TR
NEW: unit selection on object edit line
APIs
NEW: API add option $includeifobjectisused to get a product
NEW: API get the list of product ids only
NEW: add link to OpenAPI specifications XML file in REST API module setup: swagger.json file can be included into external tools like redoc
NEW: add native compression in REST APIs
NEW: Product Variants API, add variant stock to response by parameter
NEW: Product API route added to get product stock and product with or without variants #13739 #17390
Hooks
NEW: hook printFieldListTitle for cabyprodserv.php
NEW: hook to allow external modules to add their own shortlist of recent objects
NEW: SQL-altering hooks in the turnover by product report
NEW: add form confirm hook on company card
NEW: add hook addSectionECMAuto method to add custom directory into ECM auto files
WARNING:
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
* The ICS value for direct debit or credit transfer is now store on each bank account instead of into the global setup.
* Module SimplePOS is deprecated. If you need a POS module, please use the module TakePOS.
* The ICS value for direct debit or credit transfer is now stored on each bank account instead of into the global setup.
* API /setup/shipment_methods has been replaced with API /setup/shipping_methods
* Field "tva" renamed into "total_tva" for table llx_propal, llx_supplier_proposal, llx_commande, llx_commande_fournisseur for better field name consistency
* Field "total" renamed into "total_ttc" for table lx_propal, llx_supplier_proposal for better field name consistency
* If your database is PostgreSql, you must use version 9.1.0 or more (Dolibarr need the SQL function CONCAT)
* If your database is MySql or MariaDB, you need at least version 5.1
* Field "total" renamed into "total_ht" for table llx_facture, llx_facture_rec for better field name consistency
* Field "tva" renamed into "total_tva" for table llx_propal, llx_supplier_proposal, llx_commande, llx_commande_fournisseur for better field name consistency
* Field "total" renamed into "total_ttc" for table llx_propal, llx_supplier_proposal for better field name consistency
* If your database is PostgreSQL, you must use version 9.1.0 or more (Dolibarr need the SQL function CONCAT)
* If your database is MySQL or MariaDB, you need at least version 5.1
* Function set_price_level() has been renamed into setPriceLevel() to follow camelcase rules
* Removed deprecated substitution key __REFCLIENT__ (replaced with __REF_CLIENT__)
* Removed constant MAIN_COUNTRIES_IN_EEC. You can now set if country is in Europe or not from the dictionary of countries.
* v14 seems to work correctly on PHP v8 but it generates a lot of verbose warnings. Currently, v14 i snot yet officialy supported with PHP 8.
* To execute shell or command line command, your code must never use method like exec, shell_exec, popen, .. but must use the built-in
method executeCLI() available into core/class/utils.class.php
***** ChangeLog for 13.0.5 compared to 13.0.4 *****
FIX: 13.0: class CommandeFournisseurDispatch provides trigger for UPDATE but not for CREATE / DELETE
FIX: #18389 Accountancy - Bug on LDcompta10 export for supplier invoice
FIX: #18591 : Remove double quotes of SQL Queries for postgresql compatibility
FIX: Accountancy - Debug Export Sage50 / CIEL Compta / CIEL Compta Evo (Format XIMPORT)
FIX: Accountancy - Some problems of length with general & subledger account
FIX: add DISTINCT
FIX: an approved holiday can be canceled by an admin.
FIX: autocalculation of the supplier price in main currency.
FIX: better sql request
FIX: cannot add time spend when column ref is not displayed
FIX: compatibility postgre sql
FIX: holiday card: hooks uninitialized
FIX: Invoice - Missing button to reopen an abandoned situation invoice
FIX: invoice validation: when checking if any VAT rate has a negative amount, prevent false positives with -1.0E-14 amounts
FIX: list of categories in stats of supplier invoices
FIX: Manage credit note on situation invoice for calculate margin
FIX: method_exists needs object at first param
FIX: move fetch_optionnal into $ac_static->fetch()
FIX: multicompany transverse mode compatibility
FIX: on supplier order, JOIN with product fourn price table must be done with fk_soc too to avoid display several times a same line (because of same supplier product ref)
FIX: postgre filter select search extrafield
FIX: products/services card: hidden extrafields were overridden
FIX: shipping validation workflow: 'ORDER_NEW' trigger called from wrong object
FIX: task time: can't filter by user with pgsql + show error message
FIX: task time: keep on using natural_search
FIX: wrong users count in multicompany transverse mode
***** ChangeLog for 13.0.4 compared to 13.0.3 *****
FIX: Allow disabling of a module (not a dangerous action) even if there is problem with token (due to bugged modules).
FIX: 13.0 - fatal - missing inclusion of ajax.lib.php for calling `ajax_autocompleter()`
FIX: #17919 pictures in docs.
FIX: #18006
FIX: Accountancy - if we define a date start, automatic binding try to continue to solve old binding
FIX: Accoutancy Limit date payment not registered on purchases operations
FIX: Can't edit replacement invoice
FIX: deposit can create credit note in payment conf
FIX: division by zero on create
FIX: holiday: balances not updated correctly with pgsql because of case sensitivity field
FIX: holiday: status filter parameter has been renamed but not in links it was used
FIX: List and Create Companies Left Menus
FIX: method exists
FIX: need to add payment sum to getlibstatus function in object linked block
FIX: permission to close a proposal when using advanced permissions
FIX: Problem of z-index with popup and top menu
FIX: same thing on supplier orders
FIX: Status of invoice when making a replacement invoice
FIX: update contact birthday alert
***** ChangeLog for 13.0.3 compared to 13.0.2 *****
FIX: 13.0 warning - missing quotes around 'label'
FIX: #16143 Old PG requires "()" on DROP FUNCTION
FIX: #16843
FIX: #17060
FIX: #17192 - With tz < 0, event is show in bad day on calendar views
FIX: #17363
FIX: #17476 releve.php: Fix SQL statement
FIX: #17967
Fix: #17906 : fix access denied
FIX: Accountancy - Import in general ledger
FIX: Accountancy - Quadra export - wrong data on credit
FIX: Accountancy - Warning on the pages of the preparatory statements of accounting entries
FIX: Add function price2num for rounding values in productAlertStock box
FIX: Add parameter to function price2num()
FIX: Cannot delete a batch material from item receipts
FIX: cast int
FIX: Change parameters MF to MS for price2num() function
FIX: create event from contact card preselect contact correctly
FIX: create sociales : keep values error form
FIX: dol_print_date for %a and %b with some timezone
FIX: email is not case sensitive
FIX: error for duplicate thirdparty found correctly returned by ws
FIX: Espadon PDF shippment model with long public note now working
FIX: esupplier order: error 500 when using packaging with product where it is not defined
FIX: Filter on debit/credit
FIX: Filter on supplier payment list
FIX: fix checkbox displayed according to module project setup parameters - work in progress
FIX: inconsistency in margin recording with option "Force to sale price"
FIX: invoice PDF generation after payment
FIX: mask selector fournisseur if module not activate
FIX: merge thirparty also work for bank URL entry
FIX: Missing extrafields into export of agenda record
FIX: missing parameter in select for POP
FIX: missing return edit if update error
FIX: missing token on dolGetButtonAction for action delete
FIX: payment creation: re-generate invoice PDF with correct display options
FIX: payment validation: invoices PDF were no re-generated, make it with correct display options
FIX: Periodicity by default on fiscal year, according to the now date, we have plus 1 year added
FIX: pgsql: prevent 'WHERE 1'
FIX: PHP version requirement in composer.json
FIX: project visibility field with two option
FIX: saving template email
FIX: search accented words in product description (consumption page)
FIX: Search on date in accountancy
FIX: selection of project for reception must use
FIX: shhhhhh ! There is nothing here...
FIX: Show input field checkbox selection
FIX: Show Ref.Supplier in LinkToObjectBlock
FIX: SQL Error show_contacts : socialnetworks
FIX: Start hour on ACCOUNTING_DATE_START_BINDING
FIX: supplier order: error 500 when using packaging with product where it is not defined
FIX: test must be === and not ==
FIX: test on link type
FIX: type link extrafield case for advanced target emailing
FIX: Write right on document
***** ChangeLog for 13.0.2 compared to 13.0.1 *****

View File

@ -8,10 +8,12 @@ Il est simple d'utilisation et modulaire, vous permettant de n'activez que les f
![ScreenShot](https://www.dolibarr.org/medias/dolibarr_screenshot1_1920x1080.jpg)
## LICENCE
Dolibarr est distribué sous les termes de la licence GNU General Public License v3+ ou supérieure.
## INSTALLER DOLIBARR
### Configuration simple
@ -52,6 +54,7 @@ Vous pouvez aussi utiliser un serveur Web et une base de données prise en charg
- Suivez les instructions de l'installateur
## METTRE A JOUR DOLIBARR
Pour mettre à jour Dolibarr depuis une vieille version vers celle ci:
@ -64,9 +67,11 @@ Pour mettre à jour Dolibarr depuis une vieille version vers celle ci:
*Note: Le processus de migration peut être lancé manuellement et plusieurs fois, sans risque, en appelant la page /install/*
## CE QUI EST NOUVEAU
Voir fichier ChangeLog.
See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog) file.
## CE QUE DOLIBARR PEUT FAIRE
@ -82,15 +87,17 @@ Voir fichier ChangeLog.
- Calendrier/Agenda partagé (avec export ical, vcal)
- Suivi des opportunités et/ou projets (suivi de rentabilité incluant les factures, notes de frais, temps consommé valorisé, ...)
- Gestion de contrats de services
- Gestion de stock
- Gestion de stock et inventaires
- Gestion des expéditions
- Gestion des demandes de congès
- Gestion des notes de frais
- Gestion de recrutement
- GED (Gestion Electronique de Documents)
- EMailings de masse
- Réalisation de sondages
- Gestion d'adhérents
- Point de vente/Caisse enregistreuse
- …
- … (près de 100 modules disponibles en standard, près de 1000 autre sur la place de marché d'extensions)
### Autres modules
@ -135,31 +142,36 @@ Voir fichier ChangeLog.
Dolibarr peut aussi être étendu à volonté avec l'ajout de module/applications externes développées par des développeus tiers, disponible sur [DoliStore](https://www.dolistore.com).
## CE QUE DOLIBARR NE PEUT PAS (ENCORE) FAIRE
Voici un liste de fonctionnalités pas encore gérées par Dolibarr:
- Dolibarr ne contient pas de module de Gestion de la paie.
- Dolibarr ne contient pas de module de génération de feuille de paie.
- Les tâches du module de gestion de projets n'ont pas de dépendances entre elle.
- Dolibarr n'embarque pas de Webmail intégré nativement.
- Dolibarr ne fait pas le café (pas encore).
## DOCUMENTATION
La documentation utilisateur, développeur et traducteur est disponible sous forme de ressources de la communauté via le site [Wiki](https://wiki.dolibarr.org).
## CONTRIBUER
Ce projet existe grâce à ses nombreux contributeurs [[Contribuer](https://github.com/Dolibarr/dolibarr/blob/develop/.github/CONTRIBUTING.md)].
<a href="https://github.com/Dolibarr/dolibarr/graphs/contributors"><img src="https://opencollective.com/dolibarr/contributors.svg?width=890&button=false" /></a>
## CREDITS
Dolibarr est le résultat du travail de nombreux contributeurs depuis des années et utilise des librairies d'autres contributeurs.
Voir le fichier [COPYRIGHT](https://github.com/Dolibarr/dolibarr/blob/develop/COPYRIGHT)
## ACTUALITES ET RESEAUX SOCIAUX
Suivez le projet Dolibarr project sur les réseaux francophones

102
README.md
View File

@ -13,7 +13,7 @@ You can freely use, study, modify or distribute it according to its licence.
You can use it as a standalone application or as a web application to access it from the Internet or a LAN.
Dolibarr has a large community ready to help you, free forums and [officially preferred partners ready to offer commercial support should you need it](https://partners.dolibarr.org)
Dolibarr has a large community ready to help you, free forums and [preferred partners ready to offer commercial support should you need it](https://partners.dolibarr.org)
![ScreenShot](https://www.dolibarr.org/medias/dolibarr_screenshot1_1920x1080.jpg)
@ -97,48 +97,80 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog)
### Main application/modules (all optional)
- Customers, Prospects (Leads) and/or Suppliers directory + Contacts
- Members/Membership management
- Products and/or Services catalog
- Commercial proposals management
- Customer & Supplier Orders management
- Invoices and payment management
- Shipping management
- Warehouse/Stock management
- Manufacturing Orders
- Bank accounts management
- Direct debit orders management (European SEPA)
- Accounting management
- Shared calendar/agenda (with ical and vcal export for third party tools integration)
- Opportunities or Leads management
- Projects & Tasks management
- Ticket System
- Contracts management
- Interventions management
- Employee's leave requests management
- Expense reports
- Timesheets
- Electronic Document Management (EDM)
- Foundations members management
- Point of Sale (POS)
- …
- Third-Parties Management: Customers, Prospects (Leads) and/or Suppliers + Contacts
- Members/Membership/Foundation management
Product Management
- Products and/or Services catalog
- Stock / Warehouse management + Inventory
- Barcodes
- Batches / Lots / Serials
- Product Variants
- Bill of Materials (BOM)
- Manufacturing Orders
Customer/Sales Management
- Customers/Prospects + Contacts management
- Opportunities or Leads management
- Commercial proposals management
- Customer Orders management
- Contracts/Subscription management
- Interventions management
- Ticket System
- Shipping management
- Customer Invoices/Credit notes and payment management
- Point of Sale (POS)
Supplier/Purchase Management
- Suppliers/Vendors + Contacts
- Supplier (price) requests
- Purchase Orders management
- Delivery/Receiption
- Supplier Invoices/credit notes and payment management
- INCOTERMS
Finance / Accounting
- Invoices / Payments
- Bank accounts management
- Direct debit orders management (European SEPA)
- Accounting management
- Donations management
- Loan management
- Margins
- Reports
Collaboration
- Shared calendar/agenda (with ical and vcal export for third party tools integration)
- Projects & Tasks management
- Ticket System
- Surveys
HR
- Employee's leave requests management
- Expense reports
- Recruitment management
- Timesheets
### Other application/modules
- Electronic Document Management (EDM)
- Bookmarks management
- Donations management
- Reporting
- Surveys
- Data export/import
- Barcodes support
- Barcodes
- Margin calculations
- LDAP connectivity
- ClickToDial integration
- Mass emailing
- RSS integration
- Skype integration
- Social platforms linking
- Payment platforms integration (PayPal, Stripe, Paybox...)
- …
- Email-Collector
(around 100 modules available by default, 1000+ on the addon market place)
### Other general features
@ -147,14 +179,11 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog)
- Multi-Users and groups with finely grained rights
- Multi-Currency
- Multi-Company (by adding of an external module)
- Very user friendly and easy to use
- customizable Dashboard
- Highly customizable: enable only the modules you need, add user personalized fields, choose your skin, several menu managers (can be used by internal users as a back-office with a particular menu, or by external users as a front-office with another one)
- APIs (REST, SOAP)
- Code that is easy to understand, maintain and develop (PHP with no heavy framework; trigger and hook architecture)
- Support a lot of country specific features:
- Spanish Tax RE and ISPF
- French NPR VAT rate (VAT called "Non Perçue Récupérable" for DOM-TOM)
@ -165,14 +194,17 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog)
- Compatible with European GDPR rules
- ...
- Flexible PDF & ODT generation for invoices, proposals, orders...
-
- ...
### System Environment / Requirements
- Works with PHP 5.6+ and MariaDB 5.0.3+, MySQL 5.0.3+ or PostgreSQL 8.1.4+ (See requirements on the [Wiki](https://wiki.dolibarr.org/index.php/Prerequisite))
- PHP
- MariaDB, MySQL or PostgreSQL
- Compatible with all Cloud solutions that match PHP & MySQL or PostgreSQL prerequisites.
See exact requirements on the [Wiki](https://wiki.dolibarr.org/index.php/Prerequisite)
### Extending

View File

@ -51,16 +51,17 @@ export DEBEMAIL="eldy@destailleur.fr"
export QUILT_PATCHES=debian/patches
# To use Alioth.debian.org
* Create an account login
* Update your ~/.ssh/config file to add:
Host svn.debian.org git.debian.org bzr.debian.org hg.debian.org darcs.debian.org arch.debian.org
# Note: alioth.debian.org is outdated --> https://alioth-archive.debian.org/ --> https://salsa.debian.org/public
* Create an account login
* Update your ~/.ssh/config file to add:
Host svn.debian.org git.debian.org bzr.debian.org hg.debian.org darcs.debian.org arch.debian.org
User eldy-guest
IdentityFile ~/.ssh/id_rsa
* Check login on page https://alioth.debian.org/users/login
Ex: https://alioth.debian.org/users/eldy-guest
* Setup your ssh as described into page: http://wiki.debian.org/Alioth/SSH
* Ask to be included into project collab-maint: http://alioth.debian.org/projects/collab-maint/
* Check login on page https://alioth.debian.org/users/login
Ex: https://alioth.debian.org/users/eldy-guest
* Setup your ssh as described into page: http://wiki.debian.org/Alioth/SSH
* Ask to be included into project collab-maint: http://alioth.debian.org/projects/collab-maint/
@ -82,7 +83,7 @@ Ex: https://alioth.debian.org/users/eldy-guest
# dpkg -c package.deb List content of package
# dpkg -I package.deb Give informations on package
# dpkg -i package.deb Install a package
# dpkg-reconfigure -plow package Reconfigure package
# dpkg-reconfigure -plow package Reconfigure package
# dpkg -L packagename List content of installed package
# dpkg -r packagename Remove config files and interactive saved answers
# dpkg -s packagename Give status of installed package
@ -90,7 +91,7 @@ Ex: https://alioth.debian.org/users/eldy-guest
#
# dpkg-buildpackage -us -uc Build a source and binary package
#
# gdebi package.deb Install a package + dependencies
# gdebi package.deb Install a package + dependencies
@ -98,21 +99,21 @@ Ex: https://alioth.debian.org/users/eldy-guest
- Post an ITP with reportbugs :
> reportbug -B debian --email username@domain.tld wnpp
See page http://www.debian.org/devel/wnpp/#l1 for example of ITP requests contents.
See page https://www.debian.org/devel/wnpp/#l1 for example of ITP requests contents.
- Wait until you received bug number.
For first ITP submission of Dolibarr, bug id was 634783.
- Check bug is into database by searching with id on
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634783
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634783
- Add a line for upstream into file changelog with bug number
- Call for a mentor on ML debian-mentors to upload packages
- Once package is uploaded, following URL are available:
http://packages.qa.debian.org/package.html
http://bugs.debian.org/package
https://packages.qa.debian.org/package.html
https://bugs.debian.org/package
##### Modify severity of a bug ticket

View File

@ -39,15 +39,13 @@ RUN chmod +x /usr/local/bin/docker-run.sh
RUN pecl install xdebug && docker-php-ext-enable xdebug
RUN echo 'zend_extension="/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so"' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.remote_autostart=1' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.remote_enable=1' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.default_enable=1' >> ${PHP_INI_DIR}/php.ini
#RUN echo 'xdebug.remote_host=docker.host' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.remote_port=9000' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.remote_connect_back=1' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.profiler_enable=0' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.remote_log="/tmp/xdebug.log"' >> ${PHP_INI_DIR}/php.ini
#RUN echo 'localhost docker.host' >> /etc/hosts
RUN echo 'xdebug.mode=debug' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.start_with_request=yes' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.client_host=host.docker.internal' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.client_port=9003' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.discover_client_host=true' >> ${PHP_INI_DIR}/php.ini
#RUN echo 'xdebug.log="/tmp/xdebug.log"' >> ${PHP_INI_DIR}/php.ini
RUN echo 'xdebug.idekey="netbeans-xdebug"' >> ${PHP_INI_DIR}/php.ini
# set up sendmail config, to use maildev
RUN echo "account default" > /etc/msmtprc

View File

@ -46,6 +46,9 @@ services:
networks:
- internal-pod
- external-pod
extra_hosts:
- "localhost.localdomain:127.0.0.1"
- "host.docker.internal:host-gateway"
mail:
image: maildev/maildev

View File

@ -542,7 +542,7 @@ $cfg['ThemePerServer'] = FALSE; // allow diferent theme for each co
* %f will be replaced by a list of field names.
* (%t and %f only applies to DefaultQueryTable)
*/
$cfg['DefaultQueryTable'] = 'SELECT * FROM %t WHERE 1';
$cfg['DefaultQueryTable'] = 'SELECT * FROM %t WHERE 1 = 1';
$cfg['DefaultQueryDatabase'] = '';
/**

View File

@ -48,17 +48,16 @@ $includecustom=0;
$includeconstants=array();
if (empty($argv[1])) {
print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n";
print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value] [buildzip=1]\n";
print "Example: ".$script_file." release=6.0.0 includecustom=1 includeconstant=FR:INVOICE_CAN_ALWAYS_BE_REMOVED:0 includeconstant=all:MAILING_NO_USING_PHPMAIL:1\n";
exit -1;
}
parse_str($argv[1]);
$i=0;
while ($i < $argc) {
if (! empty($argv[$i])) {
parse_str($argv[$i]);
parse_str($argv[$i]); // set all params $release, $includecustom, $includeconstant, $buildzip ...
}
if (preg_match('/includeconstant=/', $argv[$i])) {
$tmp=explode(':', $includeconstant, 3); // $includeconstant has been set with previous parse_str()
@ -125,8 +124,8 @@ print "\n";
//$outputfile=dirname(__FILE__).'/../htdocs/install/filelist-'.$release.'.xml';
$outputdir=dirname(dirname(__FILE__)).'/htdocs/install';
print 'Delete current files '.$outputdir.'/filelist*.xml'."\n";
dol_delete_file($outputdir.'/filelist*.xml', 0, 1, 1);
print 'Delete current files '.$outputdir.'/filelist*.xml*'."\n";
dol_delete_file($outputdir.'/filelist*.xml*', 0, 1, 1);
$checksumconcat=array();
@ -157,8 +156,9 @@ $iterator1 = new RecursiveIteratorIterator($dir_iterator1);
// Need to ignore document custom etc. Note: this also ignore natively symbolic links.
$files = new RegexIterator($iterator1, '#^(?:[A-Z]:)?(?:/(?!(?:'.($includecustom?'':'custom\/|').'documents\/|conf\/|install\/))[^/]+)+/[^/]+\.(?:php|css|html|js|json|tpl|jpg|png|gif|sql|lang)$#i');
*/
$regextoinclude='\.(php|php3|php4|php5|phtml|phps|phar|inc|css|scss|html|xml|js|json|tpl|jpg|jpeg|png|gif|ico|sql|lang|txt|yml|md|mp3|mp4|wav|mkv|z|gz|zip|rar|tar|less|svg|eot|woff|woff2|ttf|manifest)$';
$regextoexclude='('.($includecustom?'':'custom|').'documents|conf|install|dejavu-fonts-ttf-.*|public\/test|sabre\/sabre\/.*\/tests|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
// Define qualified files (must be same than into generate_filelist_xml.php and in api_setup.class.php)
$regextoinclude = '\.(php|php3|php4|php5|phtml|phps|phar|inc|css|scss|html|xml|js|json|tpl|jpg|jpeg|png|gif|ico|sql|lang|txt|yml|bak|md|mp3|mp4|wav|mkv|z|gz|zip|rar|tar|less|svg|eot|woff|woff2|ttf|manifest)$';
$regextoexclude = '('.($includecustom?'':'custom|').'documents|conf|install|dejavu-fonts-ttf-.*|public\/test|sabre\/sabre\/.*\/tests|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
$files = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude, 'fullname');
$dir='';
@ -236,6 +236,22 @@ fputs($fp, '</dolibarr_script_dir_checksum>'."\n");
fputs($fp, '</checksum_list>'."\n");
fclose($fp);
print "File ".$outputfile." generated\n";
if (empty($buildzip)) {
print "File ".$outputfile." generated\n";
} else {
if ($buildzip == '1' || $buildzip == 'zip') {
$result = dol_compress_file($outputfile, $outputfile.'.zip', 'zip');
if ($result > 0) {
dol_delete_file($outputfile);
print "File ".$outputfile.".zip generated\n";
}
} elseif ($buildzip == '2' || $buildzip == 'gz') {
$result = dol_compress_file($outputfile, $outputfile.'.gz', 'gz');
if ($result > 0) {
dol_delete_file($outputfile);
print "File ".$outputfile.".gz generated\n";
}
}
}
exit(0);

9
build/phpstan/README Normal file
View File

@ -0,0 +1,9 @@
PHPStan
https://phpstan.org
PHPStan requires PHP >= 7.1
Install: composer require --dev phpstan/phpstan
Config File: phpstan.neon

View File

@ -3,48 +3,54 @@ README (English)
RPM Package tools
##################################################
This directory contains files used by makepack-dolibarr.pl
script to build a package, ready to be distributed,
with format RPM (for Redhat, OpenSuse, Mandriva, ...).
This directory contains files used by makepack-dolibarr.pl script to build a package,
ready to be distributed with format RPM (https://rpm.org)
for Linux Distributions like Redhat, Fedora, CentOS, OpenSuse, OpenMandriva, Mageia ...
# This is standard command to work on RPM packaging:
#
# To install all packagers tools:
# Fedora: yum -y install rpmlint fedora-packager mock koji hunspell-en hunspell-es hunspell-fr hunspell-it
# OpenSuse: yast --install update-desktop-files
#
- Fedora: yum -y install rpmlint fedora-packager mock koji hunspell-en hunspell-es hunspell-fr hunspell-it
- OpenSuse: yast --install update-desktop-files
# rpmlint file.rpm Test a package
# mock -r fedora-15-i386 --rebuild ../SRPMS/hello-2.7-1.fc15.src.rpm
#
# On Fedora
# rpm -i --test dolibarr-...rpm To list dependencies of RPM
# yum -v install dolibarr-...rpm To install package and dependencies
# yum -v erase dolibarr To remove package
# chcon -R -h -t httpd_sys_script_rw_t /file To add temporary context rw for httpd on /file
# semanage fcontext -a -t httpd_sys_script_rw_t "/dir/(.*)?" To add persistent context rw for httpd on /dir (this add file_contexts.local)
# restorecon -R -v /file Restore values into files (cancel chcon, validate semanage)
#
# =========
# rpm -i --test dolibarr-...rpm to list dependencies of RPM
# yum -v install dolibarr-...rpm to install package and dependencies
# yum -v erase dolibarr to remove package
# chcon -R -h -t httpd_sys_script_rw_t /file to add temporary context rw for httpd on /file
# restorecon -R -v /file to restore values into files (cancel chcon, validate semanage)
# semanage fcontext -a -t httpd_sys_script_rw_t "/dir/(.*)?" to add persistent context rw for httpd on /dir (this add file_contexts.local)
# On OpenSuse
# zypper install dolibarr-...rpm To install package and dependencies
# zypper remove dolibarr To remove package
# zypper search xxx To search a package
#
# ===========
# zypper install dolibarr-...rpm to install package and dependencies
# zypper remove dolibarr to remove package
# zypper search xxx to search a package
# On Mageia (after su - root)
# urpmi dolibarr-...rpm To install package and dependencies
# urpme dolibarr To remove package
# ===========================
# urpmi dolibarr-...rpm to install package and dependencies
# urpme dolibarr to remove package
#
# More on rpm on page http://www.trustonme.net/didactels/273.html
To submit a package to Fedora:
- Create account on bugzilla.redhat.com
- Create account on fedoraproject.org
- Create SRPMS package.
- Upload package onf http://fedorapeople.org
- Create a bug with form https://bugzilla.redhat.com/bugzilla/enter_bug.cgi?product=Fedora&format=fedora-review
- Create account on https://bugzilla.redhat.com
- Create account on https://developer.fedoraproject.org/
- Create SRPMS package
- Upload package on https://fedorapeople.org
- Create a bug with form https://bugzilla.redhat.com/bugzilla/enter_bug.cgi?product=Fedora&format=fedora-review
This is example of content of review field (used for Bug 723326 - https://bugzilla.redhat.com/show_bug.cgi?id=723326):
SRPMS URL: http://www.dolibarr.org/files/fedora/dolibarr-x.y.z-xxx.src.rpm
SRPMS URL: https://www.dolibarr.org/files/fedora/dolibarr-x.y.z-xxx.src.rpm
Description: Dolibarr ERP & CRM is an easy to use open source/free software
for small and medium companies, foundations or freelances. It includes
different features for Enterprise Resource Planning (ERP) and Customer
@ -56,4 +62,4 @@ is my first package to maintain myself. So i'm seeking a sponsor.
- Install fedora packager tools: yum install fedora-packager
- Setup fedora packagers tools: fedora-packager-setup
- Send your package: koji build --scratch f16 path_to_source_RPM
- Check if package is available: http://koji.fedoraproject.org/koji/
- Check if package is available: https://koji.fedoraproject.org/koji/

View File

@ -185,6 +185,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/don
%_datadir/dolibarr/htdocs/ecm
%_datadir/dolibarr/htdocs/emailcollector
%_datadir/dolibarr/htdocs/eventorganization
%_datadir/dolibarr/htdocs/expedition
%_datadir/dolibarr/htdocs/expensereport
%_datadir/dolibarr/htdocs/exports
@ -198,6 +199,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/includes
%_datadir/dolibarr/htdocs/install
%_datadir/dolibarr/htdocs/intracommreport
%_datadir/dolibarr/htdocs/knowledgemanagement
%_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt
%_datadir/dolibarr/htdocs/loan
%_datadir/dolibarr/htdocs/mailmanspip
@ -206,6 +208,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/mrp
%_datadir/dolibarr/htdocs/multicurrency
%_datadir/dolibarr/htdocs/opensurvey
%_datadir/dolibarr/htdocs/partnership
%_datadir/dolibarr/htdocs/paybox
%_datadir/dolibarr/htdocs/paypal
%_datadir/dolibarr/htdocs/printing
@ -227,6 +230,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/variants
%_datadir/dolibarr/htdocs/webservices
%_datadir/dolibarr/htdocs/website
%_datadir/dolibarr/htdocs/workstation
%_datadir/dolibarr/htdocs/zapier
%_datadir/dolibarr/htdocs/*.ico
%_datadir/dolibarr/htdocs/*.patch

View File

@ -67,7 +67,8 @@ Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mbstring
Requires: mysql-server, mysql
Requires: php-mysqli >= 4.1.0
%endif
%endif
%endif%_datadir/dolibarr/htdocs/eventorganization
%endif
# Set yes to build test package, no for release (this disable need of /usr/bin/php not found by OpenSuse)
@ -265,6 +266,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/don
%_datadir/dolibarr/htdocs/ecm
%_datadir/dolibarr/htdocs/emailcollector
%_datadir/dolibarr/htdocs/eventorganization
%_datadir/dolibarr/htdocs/expedition
%_datadir/dolibarr/htdocs/expensereport
%_datadir/dolibarr/htdocs/exports
@ -278,6 +280,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/includes
%_datadir/dolibarr/htdocs/install
%_datadir/dolibarr/htdocs/intracommreport
%_datadir/dolibarr/htdocs/knowledgemanagement
%_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt
%_datadir/dolibarr/htdocs/loan
%_datadir/dolibarr/htdocs/mailmanspip
@ -286,6 +289,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/mrp
%_datadir/dolibarr/htdocs/multicurrency
%_datadir/dolibarr/htdocs/opensurvey
%_datadir/dolibarr/htdocs/partnership
%_datadir/dolibarr/htdocs/paybox
%_datadir/dolibarr/htdocs/paypal
%_datadir/dolibarr/htdocs/printing
@ -307,6 +311,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/variants
%_datadir/dolibarr/htdocs/webservices
%_datadir/dolibarr/htdocs/website
%_datadir/dolibarr/htdocs/workstation
%_datadir/dolibarr/htdocs/zapier
%_datadir/dolibarr/htdocs/*.ico
%_datadir/dolibarr/htdocs/*.patch

View File

@ -182,6 +182,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/don
%_datadir/dolibarr/htdocs/ecm
%_datadir/dolibarr/htdocs/emailcollector
%_datadir/dolibarr/htdocs/eventorganization
%_datadir/dolibarr/htdocs/expedition
%_datadir/dolibarr/htdocs/expensereport
%_datadir/dolibarr/htdocs/exports
@ -195,6 +196,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/includes
%_datadir/dolibarr/htdocs/install
%_datadir/dolibarr/htdocs/intracommreport
%_datadir/dolibarr/htdocs/knowledgemanagement
%_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt
%_datadir/dolibarr/htdocs/loan
%_datadir/dolibarr/htdocs/mailmanspip
@ -203,6 +205,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/mrp
%_datadir/dolibarr/htdocs/multicurrency
%_datadir/dolibarr/htdocs/opensurvey
%_datadir/dolibarr/htdocs/partnership
%_datadir/dolibarr/htdocs/paybox
%_datadir/dolibarr/htdocs/paypal
%_datadir/dolibarr/htdocs/printing
@ -224,6 +227,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/variants
%_datadir/dolibarr/htdocs/webservices
%_datadir/dolibarr/htdocs/website
%_datadir/dolibarr/htdocs/workstation
%_datadir/dolibarr/htdocs/zapier
%_datadir/dolibarr/htdocs/*.ico
%_datadir/dolibarr/htdocs/*.patch

View File

@ -193,6 +193,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/don
%_datadir/dolibarr/htdocs/ecm
%_datadir/dolibarr/htdocs/emailcollector
%_datadir/dolibarr/htdocs/eventorganization
%_datadir/dolibarr/htdocs/expedition
%_datadir/dolibarr/htdocs/expensereport
%_datadir/dolibarr/htdocs/exports
@ -206,6 +207,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/includes
%_datadir/dolibarr/htdocs/install
%_datadir/dolibarr/htdocs/intracommreport
%_datadir/dolibarr/htdocs/knowledgemanagement
%_datadir/dolibarr/htdocs/langs/HOWTO-Translation.txt
%_datadir/dolibarr/htdocs/loan
%_datadir/dolibarr/htdocs/mailmanspip
@ -214,6 +216,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/mrp
%_datadir/dolibarr/htdocs/multicurrency
%_datadir/dolibarr/htdocs/opensurvey
%_datadir/dolibarr/htdocs/partnership
%_datadir/dolibarr/htdocs/paybox
%_datadir/dolibarr/htdocs/paypal
%_datadir/dolibarr/htdocs/printing
@ -235,6 +238,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/variants
%_datadir/dolibarr/htdocs/webservices
%_datadir/dolibarr/htdocs/website
%_datadir/dolibarr/htdocs/workstation
%_datadir/dolibarr/htdocs/zapier
%_datadir/dolibarr/htdocs/*.ico
%_datadir/dolibarr/htdocs/*.patch

View File

@ -29,6 +29,7 @@
"ckeditor/ckeditor" : "4.12.1",
"mike42/escpos-php" : "2.2",
"mobiledetect/mobiledetectlib" : "2.8.34",
"phpoffice/phpexcel" : "1.8.2",
"restler/framework" : "3.0.0-RC6",
"tecnickcom/tcpdf" : "6.3.2",
"nnnick/chartjs" : "^2.9",

57
composer.lock generated
View File

@ -328,6 +328,63 @@
},
"time": "2020-03-23T09:12:05+00:00"
},
{
"name": "phpoffice/phpexcel",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/PHPOffice/PHPExcel.git",
"reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPOffice/PHPExcel/zipball/1441011fb7ecdd8cc689878f54f8b58a6805f870",
"reference": "1441011fb7ecdd8cc689878f54f8b58a6805f870",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"php": "^5.2|^7.0"
},
"require-dev": {
"squizlabs/php_codesniffer": "2.*"
},
"type": "library",
"autoload": {
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Maarten Balliauw",
"homepage": "http://blog.maartenballiauw.be"
},
{
"name": "Erik Tilt"
},
{
"name": "Franck Lefevre",
"homepage": "http://rootslabs.net"
},
{
"name": "Mark Baker",
"homepage": "http://markbakeruk.net"
}
],
"description": "PHPExcel - OpenXML - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
"homepage": "https://github.com/PHPOffice/PHPExcel",
"keywords": [
"OpenXML",
"excel",
"xlsx"
],
"abandoned": "phpoffice/phpspreadsheet",
"time": "2018-11-22T23:07:24+00:00"
},
{
"name": "restler/framework",
"version": "3.0.0-RC6",

View File

@ -168,6 +168,18 @@ In htdocs/includes/tecnickcom/tcpdf/tcpdf.php
- protected $default_monospaced_font = 'courier';
+ protected $default_monospaced_font = 'freemono';
* In tecnickcom/tcpdf/include/tcpdf_static, in function intToRoman, right at the beginning
of the function, replace:
$roman = '';
with:
$roman = '';
if ($number >= 4000) {
// do not represent numbers above 4000 in Roman numerals
return strval($number);
}
@ -225,9 +237,6 @@ JQUERYFILETREE:
RESTLER:
--------
Change content of file htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html
+With swagger 2:
* Add line into Util.php to complete function
@ -248,6 +257,21 @@ Change content of file htdocs/includes/restler/framework/Luracast/Restler/explor
// @CHANGE LDR
if (!is_string($haystack)) return false;
* Replace
$loaders = array_unique(static::$rogueLoaders);
with
$loaders = array_unique(static::$rogueLoaders, SORT_REGULAR);
+With swagger 2 provided into /explorer:
----------------------------------------
Change content of file htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html
PARSEDOWN
---------

View File

@ -3,11 +3,26 @@
#
# Use this sample to search into a ldap
#
# ldapsearch -h hostname -x
# ldapsearch -h hostname -x -b "ou=people,dc=teclib,dc=infra"
# ldapsearch -h hostname -x -z 0 -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)"
# ldapsearch -h hostname -x -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)"
# Anonymous access
# ldapsearch -h hostname -p 389
#
# Login access (using a Bind DN)
# ldapsearch -h hostname -p 389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
# ldapsearch -d1 -H ldap://hostname:389 -x -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
#
# Login access in SSL (using a Bind DN)
# ldapsearch -H ldaps://hostnamme:636 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local
# If it fails, you may try to use "hostname" that is real name of certificate.
# You must also check that /etc/ldap/ldap.conf contains the line TLS_CACERT /etc/ssl/certs/ca-certificates.crt
# What to search
# ldapsearch -h hostname -p 389 -x -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local"
# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "ou=people,dc=teclib,dc=infra"
# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "o=somecompany.com" "(objectclass=*)"
#
# Example to test a ldap search:
# ldapsearch -h hostname -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password
# ldapsearch -h hostname -p 389 -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password

View File

@ -0,0 +1,74 @@
/*jshint esversion: 6 */
// create a particular contact by name
const createContact = async (z, bundle) => {
const apiurl = bundle.authData.url + '/api/index.php/contacts';
const response = await z.request({
method: 'POST',
url: apiurl,
body: {
name: bundle.inputData.name,
name_alias: bundle.inputData.name_alias,
ref_ext: bundle.inputData.ref_ext,
ref_int: bundle.inputData.ref_int,
address: bundle.inputData.address,
zip: bundle.inputData.zip,
town: bundle.inputData.town,
country_code: bundle.inputData.country_code,
country_id: bundle.inputData.country_id,
country: bundle.inputData.country,
phone: bundle.inputData.phone,
email: bundle.inputData.email,
sens: 'fromzapier'
}
});
const result = z.JSON.parse(response.content);
// api returns an integer when ok, a json when ko
return result.response || {id: response};
};
module.exports = {
key: 'contact',
noun: 'Contact',
display: {
label: 'Create Contact',
description: 'Creates a contact.'
},
operation: {
inputFields: [
{key: 'name', required: true},
{key: 'name_alias', required: false},
{key: 'address', required: false},
{key: 'zip', required: false},
{key: 'town', required: false},
{key: 'email', required: false}
],
perform: createContact,
sample: {
id: 1,
name: 'DUPOND',
name_alias: 'DUPOND Ltd',
address: 'Rue des Canaries',
zip: '34090',
town: 'MONTPELLIER',
phone: '0123456789',
fax: '2345678901',
email: 'robot@domain.com'
},
outputFields: [
{key: 'id', type: "integer", label: 'ID'},
{key: 'name', label: 'Name'},
{key: 'name_alias', label: 'Name alias'},
{key: 'address', label: 'Address'},
{key: 'zip', label: 'Zip'},
{key: 'town', label: 'Town'},
{key: 'phone', label: 'Phone'},
{key: 'fax', label: 'Fax'},
{key: 'email', label: 'Email'}
]
}
};

View File

@ -0,0 +1,74 @@
/*jshint esversion: 6 */
// create a particular member by name
const createMember = async (z, bundle) => {
const apiurl = bundle.authData.url + '/api/index.php/members';
const response = await z.request({
method: 'POST',
url: apiurl,
body: {
name: bundle.inputData.name,
name_alias: bundle.inputData.name_alias,
ref_ext: bundle.inputData.ref_ext,
ref_int: bundle.inputData.ref_int,
address: bundle.inputData.address,
zip: bundle.inputData.zip,
town: bundle.inputData.town,
country_code: bundle.inputData.country_code,
country_id: bundle.inputData.country_id,
country: bundle.inputData.country,
phone: bundle.inputData.phone,
email: bundle.inputData.email,
sens: 'fromzapier'
}
});
const result = z.JSON.parse(response.content);
// api returns an integer when ok, a json when ko
return result.response || {id: response};
};
module.exports = {
key: 'member',
noun: 'Member',
display: {
label: 'Create Member',
description: 'Creates a member.'
},
operation: {
inputFields: [
{key: 'name', required: true},
{key: 'name_alias', required: false},
{key: 'address', required: false},
{key: 'zip', required: false},
{key: 'town', required: false},
{key: 'email', required: false}
],
perform: createMember,
sample: {
id: 1,
name: 'DUPOND',
name_alias: 'DUPOND Ltd',
address: 'Rue des Canaries',
zip: '34090',
town: 'MONTPELLIER',
phone: '0123456789',
fax: '2345678901',
email: 'robot@domain.com'
},
outputFields: [
{key: 'id', type: "integer", label: 'ID'},
{key: 'name', label: 'Name'},
{key: 'name_alias', label: 'Name alias'},
{key: 'address', label: 'Address'},
{key: 'zip', label: 'Zip'},
{key: 'town', label: 'Town'},
{key: 'phone', label: 'Phone'},
{key: 'fax', label: 'Fax'},
{key: 'email', label: 'Email'}
]
}
};

View File

@ -6,7 +6,7 @@ const createThirdparty = async (z, bundle) => {
const response = await z.request({
method: 'POST',
url: apiurl,
body: JSON.stringify({
body: {
name: bundle.inputData.name,
name_alias: bundle.inputData.name_alias,
ref_ext: bundle.inputData.ref_ext,
@ -24,7 +24,7 @@ const createThirdparty = async (z, bundle) => {
code_client: bundle.inputData.code_client,
code_fournisseur: bundle.inputData.code_fournisseur,
sens: 'fromzapier'
})
}
});
const result = z.JSON.parse(response.content);
// api returns an integer when ok, a json when ko

View File

@ -2,12 +2,18 @@
const triggerAction = require('./triggers/action');
const triggerOrder = require('./triggers/order');
const triggerThirdparty = require('./triggers/thirdparty');
const triggerContact = require('./triggers/contact');
const triggerTicket = require('./triggers/ticket');
const triggerUser = require('./triggers/user');
const triggerMember = require('./triggers/member');
const searchThirdparty = require('./searches/thirdparty');
const searchContact = require('./searches/contact');
const searchMember = require('./searches/member');
const createThirdparty = require('./creates/thirdparty');
const createContact = require('./creates/contact');
const createMember = require('./creates/member');
const {
config: authentication,
@ -62,18 +68,24 @@ const App = {
[triggerAction.key]: triggerAction,
[triggerOrder.key]: triggerOrder,
[triggerThirdparty.key]: triggerThirdparty,
[triggerContact.key]: triggerContact,
[triggerTicket.key]: triggerTicket,
[triggerUser.key]: triggerUser,
[triggerMember.key]: triggerMember,
},
// If you want your searches to show up, you better include it here!
searches: {
[searchThirdparty.key]: searchThirdparty,
[searchContact.key]: searchContact,
[searchMember.key]: searchMember,
},
// If you want your creates to show up, you better include it here!
creates: {
[createThirdparty.key]: createThirdparty,
[createContact.key]: createContact,
[createMember.key]: createMember,
}
};

View File

@ -1,6 +1,6 @@
{
"name": "dolibarr",
"version": "1.13.0",
"version": "1.14.0",
"description": "An app for connecting Dolibarr to the Zapier platform.",
"repository": "Dolibarr/dolibarr",
"homepage": "https://www.dolibarr.org/",
@ -11,11 +11,11 @@
"test": "mocha --recursive"
},
"engines": {
"node": "8.10.0",
"node": "14.0.0",
"npm": ">=5.6.0"
},
"dependencies": {
"zapier-platform-core": "10.1.2"
"zapier-platform-core": "11.0.1"
},
"devDependencies": {
"mocha": "^5.2.0",

View File

@ -0,0 +1,95 @@
module.exports = {
key: 'contact',
// You'll want to provide some helpful display labels and descriptions
// for users. Zapier will put them into the UX.
noun: 'Contact',
display: {
label: 'Find a Contact',
description: 'Search for contact.'
},
// `operation` is where we make the call to your API to do the search
operation: {
// This search only has one search field. Your searches might have just one, or many
// search fields.
inputFields: [
{
key: 'lastname',
type: 'string',
label: 'Lastname',
helpText: 'Lastname to limit to the search to (i.e. The company or %company%).'
},
{
key: 'email',
type: 'string',
label: 'Email',
helpText: 'Email to limit to the search to.'
}
],
perform: async (z, bundle) => {
const url = bundle.authData.url + '/api/index.php/contacts/';
// Put the search value in a query param. The details of how to build
// a search URL will depend on how your API works.
let filter = '';
if (bundle.inputData.lastname) {
filter = "t.lastname like \'%"+bundle.inputData.name+"%\'";
}
if (bundle.inputData.email) {
if (bundle.inputData.lastname) {
filter += " and ";
}
filter += "t.email like \'"+bundle.inputData.email+"\'";
}
const response = await z.request({
url: url,
// this parameter avoid throwing errors and let us manage them
skipThrowForStatus: true,
params: {
sqlfilters: filter
}
});
//z.console.log(response);
if (response.status != 200) {
return [];
}
return response.json;
},
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
createdAt: 1472069465,
name: 'DOE',
firstname: 'John',
authorId: 1,
directions: '1. Boil Noodles\n2.Serve with sauce',
style: 'italian'
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{
key: 'id',
type: "integer",
label: 'ID'
},
{key: 'createdAt', type: "integer", label: 'Created At'},
{key: 'name', label: 'Name'},
{key: 'firstname', label: 'Firstname'},
{key: 'directions', label: 'Directions'},
{key: 'authorId', type: "integer", label: 'Author ID'},
{
key: 'style',
label: 'Style'
}
]
}
};

View File

@ -0,0 +1,88 @@
module.exports = {
key: 'member',
// You'll want to provide some helpful display labels and descriptions
// for users. Zapier will put them into the UX.
noun: 'Member',
display: {
label: 'Find a Member',
description: 'Search for member.'
},
// `operation` is where we make the call to your API to do the search
operation: {
// This search only has one search field. Your searches might have just one, or many
// search fields.
inputFields: [
{
key: 'lastname',
type: 'string',
label: 'Lastname',
helpText: 'Lastname to limit to the search to (i.e. The company or %company%).'
},
{
key: 'email',
type: 'string',
label: 'Email',
helpText: 'Email to limit to the search to.'
}
],
perform: async (z, bundle) => {
const url = bundle.authData.url + '/api/index.php/members/';
// Put the search value in a query param. The details of how to build
// a search URL will depend on how your API works.
let filter = '';
if (bundle.inputData.lastname) {
filter = "t.lastname like \'%" + bundle.inputData.name + "%\'";
}
if (bundle.inputData.email) {
if (bundle.inputData.lastname) {
filter += " and ";
}
filter += "t.email like \'" + bundle.inputData.email + "\'";
}
const response = await z.request({
url: url,
// this parameter avoid throwing errors and let us manage them
skipThrowForStatus: true,
params: {
sqlfilters: filter
}
});
//z.console.log(response);
if (response.status != 200) {
return [];
}
return response.json;
},
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
createdAt: 1472069465,
name: 'DOE',
firstname: 'John',
authorId: 1,
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{
key: 'id',
type: "integer",
label: 'ID'
},
{ key: 'createdAt', type: "integer", label: 'Created At' },
{ key: 'name', label: 'Name' },
{ key: 'firstname', label: 'Firstname' },
{ key: 'authorId', type: "integer", label: 'Author ID' },
]
}
};

View File

@ -19,21 +19,43 @@ module.exports = {
type: 'string',
label: 'Name',
helpText: 'Name to limit to the search to (i.e. The company or %company%).'
},
{
key: 'email',
type: 'string',
label: 'Email',
helpText: 'Email to limit to the search to.'
}
],
perform: (z, bundle) => {
perform: async (z, bundle) => {
const url = bundle.authData.url + '/api/index.php/thirdparties/';
// Put the search value in a query param. The details of how to build
// a search URL will depend on how your API works.
const options = {
params: {
sqlfilters: "t.nom like \'%"+bundle.inputData.name+"%\'"
let filter = '';
if (bundle.inputData.name) {
filter = "t.nom like \'%"+bundle.inputData.name+"%\'";
}
if (bundle.inputData.email) {
if (bundle.inputData.name) {
filter += " and ";
}
};
return z.request(url, options).then(response => JSON.parse(response.content));
filter += "t.email like \'"+bundle.inputData.email+"\'";
}
const response = await z.request({
url: url,
// this parameter avoid throwing errors and let us manage them
skipThrowForStatus: true,
params: {
sqlfilters: filter
}
});
//z.console.log(response);
if (response.status != 200) {
return [];
}
return response.json;
},
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example

View File

@ -0,0 +1,171 @@
const subscribeHook = (z, bundle) => {
// `z.console.log()` is similar to `console.log()`.
z.console.log('suscribing hook!');
// bundle.targetUrl has the Hook URL this app should call when an action is created.
const data = {
url: bundle.targetUrl,
event: bundle.event,
module: 'contact',
action: bundle.inputData.action
};
const url = bundle.authData.url + '/api/index.php/zapierapi/hook';
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: url,
method: 'POST',
body: data,
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const unsubscribeHook = (z, bundle) => {
// bundle.subscribeData contains the parsed response JSON from the subscribe
// request made initially.
z.console.log('unsuscribing hook!');
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id,
method: 'DELETE',
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const getContact = (z, bundle) => {
// bundle.cleanedRequest will include the parsed JSON object (if it's not a
// test poll) and also a .querystring property with the URL's query string.
const contact = {
id: bundle.cleanedRequest.id,
name: bundle.cleanedRequest.name,
name_alias: bundle.cleanedRequest.name_alias,
firstname: bundle.cleanedRequest.firstname,
address: bundle.cleanedRequest.address,
zip: bundle.cleanedRequest.zip,
town: bundle.cleanedRequest.town,
email: bundle.cleanedRequest.email,
phone_pro: bundle.cleanedRequest.phone_pro,
phone_perso: bundle.cleanedRequest.phone_perso,
phone_mobile: bundle.cleanedRequest.phone_mobile,
authorId: bundle.cleanedRequest.authorId,
createdAt: bundle.cleanedRequest.createdAt,
action: bundle.cleanedRequest.action
};
return [contact];
};
const getFallbackRealContact = (z, bundle) => {
// For the test poll, you should get some real data, to aid the setup process.
const module = bundle.inputData.module;
const options = {
url: bundle.authData.url + '/api/index.php/contacts/0',
};
return z.request(options).then((response) => [JSON.parse(response.content)]);
};
// const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices',
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// const getModulesChoices = () => {
// return {
// orders: "Order",
// invoices: "Invoice",
// contacts: "Contact",
// contacts: "Contacts"
// };
// };
// const getActionsChoices = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module;
// const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`,
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// We recommend writing your triggers separate like this and rolling them
// into the App definition at the end.
module.exports = {
key: 'contact',
// You'll want to provide some helpful display labels and descriptions
// for users. Zapier will put them into the UX.
noun: 'Contact',
display: {
label: 'New Contact',
description: 'Triggers when a new contact action is done in Dolibarr.'
},
// `operation` is where the business logic goes.
operation: {
// `inputFields` can define the fields a user could provide,
// we'll pass them in as `bundle.inputData` later.
inputFields: [
{
key: 'action',
required: true,
type: 'string',
helpText: 'Which action of contact this should trigger on.',
choices: {
create: "Create",
modify: "Modify",
validate: "Validate",
}
}
],
type: 'hook',
performSubscribe: subscribeHook,
performUnsubscribe: unsubscribeHook,
perform: getContact,
performList: getFallbackRealContact,
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
createdAt: 1472069465,
lastname: 'DOE',
firstname: 'John',
authorId: 1,
action: 'create'
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{key: 'id', type: "integer", label: 'ID'},
{key: 'createdAt', label: 'Created At'},
{key: 'lastname', label: 'Lastname'},
{key: 'firstname', label: 'Firstname'},
{key: 'phone', label: 'Phone pro'},
{key: 'phone_perso', label: 'Phone perso'},
{key: 'phone_mobile', label: 'Phone mobile'},
{key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'action', label: 'Action'}
]
}
};

View File

@ -0,0 +1,171 @@
const subscribeHook = (z, bundle) => {
// `z.console.log()` is similar to `console.log()`.
z.console.log('suscribing hook!');
// bundle.targetUrl has the Hook URL this app should call when an action is created.
const data = {
url: bundle.targetUrl,
event: bundle.event,
module: 'member',
action: bundle.inputData.action
};
const url = bundle.authData.url + '/api/index.php/zapierapi/hook';
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: url,
method: 'POST',
body: data,
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const unsubscribeHook = (z, bundle) => {
// bundle.subscribeData contains the parsed response JSON from the subscribe
// request made initially.
z.console.log('unsuscribing hook!');
// You can build requests and our client will helpfully inject all the variables
// you need to complete. You can also register middleware to control this.
const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id,
method: 'DELETE',
};
// You may return a promise or a normal data structure from any perform method.
return z.request(options).then((response) => JSON.parse(response.content));
};
const getMember = (z, bundle) => {
// bundle.cleanedRequest will include the parsed JSON object (if it's not a
// test poll) and also a .querystring property with the URL's query string.
const member = {
id: bundle.cleanedRequest.id,
name: bundle.cleanedRequest.name,
name_alias: bundle.cleanedRequest.name_alias,
firstname: bundle.cleanedRequest.firstname,
address: bundle.cleanedRequest.address,
zip: bundle.cleanedRequest.zip,
town: bundle.cleanedRequest.town,
email: bundle.cleanedRequest.email,
phone_pro: bundle.cleanedRequest.phone_pro,
phone_perso: bundle.cleanedRequest.phone_perso,
phone_mobile: bundle.cleanedRequest.phone_mobile,
authorId: bundle.cleanedRequest.authorId,
createdAt: bundle.cleanedRequest.createdAt,
action: bundle.cleanedRequest.action
};
return [member];
};
const getFallbackRealMember = (z, bundle) => {
// For the test poll, you should get some real data, to aid the setup process.
const module = bundle.inputData.module;
const options = {
url: bundle.authData.url + '/api/index.php/members/0',
};
return z.request(options).then((response) => [JSON.parse(response.content)]);
};
// const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices',
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// const getModulesChoices = () => {
// return {
// orders: "Order",
// invoices: "Invoice",
// members: "Member",
// members: "Members"
// };
// };
// const getActionsChoices = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module;
// const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`,
// };
// return z.request(options).then((response) => JSON.parse(response.content));
// };
// We recommend writing your triggers separate like this and rolling them
// into the App definition at the end.
module.exports = {
key: 'member',
// You'll want to provide some helpful display labels and descriptions
// for users. Zapier will put them into the UX.
noun: 'Member',
display: {
label: 'New Member',
description: 'Triggers when a new member action is done in Dolibarr.'
},
// `operation` is where the business logic goes.
operation: {
// `inputFields` can define the fields a user could provide,
// we'll pass them in as `bundle.inputData` later.
inputFields: [
{
key: 'action',
required: true,
type: 'string',
helpText: 'Which action of member this should trigger on.',
choices: {
create: "Create",
modify: "Modify",
validate: "Validate",
}
}
],
type: 'hook',
performSubscribe: subscribeHook,
performUnsubscribe: unsubscribeHook,
perform: getMember,
performList: getFallbackRealMember,
// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example
// from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of
// returned records, and have obviously dummy values that we can show to any user.
sample: {
id: 1,
createdAt: 1472069465,
lastname: 'DOE',
firstname: 'John',
authorId: 1,
action: 'create'
},
// If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom
// field definitions. The result will be used to augment the sample.
// outputFields: () => { return []; }
// Alternatively, a static field definition should be provided, to specify labels for the fields
outputFields: [
{key: 'id', type: "integer", label: 'ID'},
{key: 'createdAt', label: 'Created At'},
{key: 'lastname', label: 'Lastname'},
{key: 'firstname', label: 'Firstname'},
{key: 'phone', label: 'Phone pro'},
{key: 'phone_perso', label: 'Phone perso'},
{key: 'phone_mobile', label: 'Phone mobile'},
{key: 'authorId', type: "integer", label: 'Author ID'},
{key: 'action', label: 'Action'}
]
}
};

View File

@ -56,6 +56,12 @@ const getThirdparty = (z, bundle) => {
fournisseur: bundle.cleanedRequest.fournisseur,
code_client: bundle.cleanedRequest.code_client,
code_fournisseur: bundle.cleanedRequest.code_fournisseur,
idprof1: bundle.cleanedRequest.idprof1,
idprof2: bundle.cleanedRequest.idprof2,
idprof3: bundle.cleanedRequest.idprof3,
idprof4: bundle.cleanedRequest.idprof4,
idprof5: bundle.cleanedRequest.idprof5,
idprof6: bundle.cleanedRequest.idprof6,
authorId: bundle.cleanedRequest.authorId,
createdAt: bundle.cleanedRequest.createdAt,
action: bundle.cleanedRequest.action
@ -112,7 +118,7 @@ module.exports = {
noun: 'Thirdparty',
display: {
label: 'New Thirdparty',
description: 'Triggers when a new thirdpaty action is done in Dolibarr.'
description: 'Triggers when a new thirdparty action is done in Dolibarr.'
},
// `operation` is where the business logic goes.
@ -170,7 +176,13 @@ module.exports = {
{key: 'client', label: 'Customer/Prospect 0/1/2/3'},
{key: 'fournisseur', label: 'Supplier 0/1'},
{key: 'code_client', label: 'Customer code'},
{key: 'code_fournisseur', label: 'Supplier code'}
{key: 'code_fournisseur', label: 'Supplier code'},
{key: 'idprof1', label: 'Id Prof 1'},
{key: 'idprof2', label: 'Id Prof 2'},
{key: 'idprof3', label: 'Id Prof 3'},
{key: 'idprof4', label: 'Id Prof 4'},
{key: 'idprof5', label: 'Id Prof 5'},
{key: 'idprof6', label: 'Id Prof 6'}
]
}
};

View File

@ -1,234 +0,0 @@
#!/usr/bin/env php
<?php
/* Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
*/
/**
* \file dev/initdata/import-dbf.php
* \brief Script example to create a table from a large DBF file (openoffice)
* To purge data, you can have a look at purge-data.php
*/
// Test si mode batch
$sapi_type = php_sapi_name();
$script_file = basename(__FILE__);
$path = dirname(__FILE__) . '/';
if (substr($sapi_type, 0, 3) == 'cgi') {
echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
exit;
}
// Recupere root dolibarr
$path = dirname($_SERVER["PHP_SELF"]);
require $path . "./../htdocs/master.inc.php";
require $path . "/includes/dbase.class.php";
// Global variables
$version = DOL_VERSION;
$confirmed = 1;
$error = 0;
/*
* Main
*/
@set_time_limit(0);
print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
dol_syslog($script_file . " launched with arg " . implode(',', $argv));
$filepath = $argv[1];
$filepatherr = $filepath . '.err';
$startchar = empty($argv[2]) ? 0 : (int) $argv[2];
$deleteTable = empty($argv[3]) ? 1 : 0;
$startlinenb = empty($argv[3]) ? 1 : (int) $argv[3];
$endlinenb = empty($argv[4]) ? 0 : (int) $argv[4];
if (empty($filepath)) {
print "Usage: php $script_file myfilepath.dbf [removeChatColumnName] [startlinenb] [endlinenb]\n";
print "Example: php $script_file myfilepath.dbf 0 2 1002\n";
print "\n";
exit(-1);
}
if (!file_exists($filepath)) {
print "Error: File " . $filepath . " not found.\n";
print "\n";
exit(-1);
}
$ret = $user->fetch('', 'admin');
if (!$ret > 0) {
print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
exit;
}
$user->getrights();
// Ask confirmation
if (!$confirmed) {
print "Hit Enter to continue or CTRL+C to stop...\n";
$input = trim(fgets(STDIN));
}
// Open input and output files
$fhandle = dbase_open($filepath, 0);
if (!$fhandle) {
print 'Error: Failed to open file ' . $filepath . "\n";
exit(1);
}
$fhandleerr = fopen($filepatherr, 'w');
if (!$fhandleerr) {
print 'Error: Failed to open file ' . $filepatherr . "\n";
exit(1);
}
$langs->setDefaultLang($defaultlang);
$record_numbers = dbase_numrecords($fhandle);
$table_name = substr(basename($filepath), 0, strpos(basename($filepath), '.'));
print 'Info: ' . $record_numbers . " lines in file \n";
$header = dbase_get_header_info($fhandle);
if ($deleteTable) {
$db->query("DROP TABLE IF EXISTS `$table_name`");
}
$sqlCreate = "CREATE TABLE IF NOT EXISTS `$table_name` ( `id` INT(11) NOT NULL AUTO_INCREMENT ";
$fieldArray = array("`id`");
foreach ($header as $value) {
$fieldName = substr(str_replace('_', '', $value['name']), $startchar);
$fieldArray[] = "`$fieldName`";
$sqlCreate .= ", `" . $fieldName . "` VARCHAR({$value['length']}) NULL DEFAULT NULL ";
}
$sqlCreate .= ", PRIMARY KEY (`id`)) ENGINE = InnoDB";
$resql = $db->query($sqlCreate);
if ($resql !== false) {
print "Table $table_name created\n";
} else {
var_dump($db->errno());
print "Impossible : " . $sqlCreate . "\n";
die();
}
$i = 0;
$nboflines++;
$fields = implode(',', $fieldArray);
//var_dump($fieldArray);die();
$maxLength = 0;
for ($i = 1; $i <= $record_numbers; $i++) {
if ($startlinenb && $i < $startlinenb) {
continue;
}
if ($endlinenb && $i > $endlinenb) {
continue;
}
$row = dbase_get_record_with_names($fhandle, $i);
if ($row === false || (isset($row["deleted"]) && $row["deleted"] == '1')) {
continue;
}
$sqlInsert = "INSERT INTO `$table_name`($fields) VALUES (null,";
array_shift($row); // remove delete column
foreach ($row as $value) {
$sqlInsert .= "'" . $db->escape(utf8_encode($value)) . "', ";
}
replaceable_echo(implode("\t", $row));
$sqlInsert = rtrim($sqlInsert, ', ');
$sqlInsert .= ")";
$resql = $db->query($sqlInsert);
if ($resql === false) {
print "Impossible : " . $sqlInsert . "\n";
var_dump($row, $db->errno());
die();
}
// $fields = (object) $row;
// var_dump($fields);
continue;
}
die();
// commit or rollback
print "Nb of lines qualified: " . $nboflines . "\n";
print "Nb of errors: " . $error . "\n";
if ($mode != 'confirmforced' && ($error || $mode != 'confirm')) {
print "Rollback any changes.\n";
$db->rollback();
} else {
print "Commit all changes.\n";
$db->commit();
}
$db->close();
fclose($fhandle);
fclose($fhandleerr);
exit($error);
/**
* replaceable_echo
*
* @param string $message Message
* @param int $force_clear_lines Force clear messages
* @return void
*/
function replaceable_echo($message, $force_clear_lines = null)
{
static $last_lines = 0;
if (!is_null($force_clear_lines)) {
$last_lines = $force_clear_lines;
}
$toss = array();
$status = 0;
$term_width = exec('tput cols', $toss, $status);
if ($status) {
$term_width = 64; // Arbitrary fall-back term width.
}
$line_count = 0;
foreach (explode("\n", $message) as $line) {
$line_count += count(str_split($line, $term_width));
}
// Erasure MAGIC: Clear as many lines as the last output had.
for ($i = 0; $i < $last_lines; $i++) {
// Return to the beginning of the line
echo "\r";
// Erase to the end of the line
echo "\033[K";
// Move cursor Up a line
echo "\033[1A";
// Return to the beginning of the line
echo "\r";
// Erase to the end of the line
echo "\033[K";
// Return to the beginning of the line
echo "\r";
// Can be consolodated into
// echo "\r\033[K\033[1A\r\033[K\r";
}
$last_lines = $line_count;
echo $message . "\n";
}

View File

@ -1,248 +0,0 @@
#!/usr/bin/env php
<?php
/* Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
*/
/**
* \file dev/initdata/import-product.php
* \brief Script example to insert products from a csv file.
* To purge data, you can have a look at purge-data.php
*/
// Test si mode batch
$sapi_type = php_sapi_name();
$script_file = basename(__FILE__);
$path = dirname(__FILE__) . '/';
if (substr($sapi_type, 0, 3) == 'cgi') {
echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
exit;
}
// Recupere root dolibarr
$path = preg_replace('/importdb-products.php/i', '', $_SERVER["PHP_SELF"]);
require $path . "../../htdocs/master.inc.php";
require $path . "includes/dbase.class.php";
include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
//$delimiter = ',';
//$enclosure = '"';
//$linelength = 10000;
//$escape = '/';
// Global variables
$version = DOL_VERSION;
$confirmed = 1;
$error = 0;
$tvas = [
'1' => "20.00",
'2' => "5.50",
'3' => "0.00",
'4' => "20.60",
'5' => "19.60",
];
$tvasD = [
'1' => "20",
'2' => "5.5",
'3' => "0",
'4' => "20",
'5' => "20",
];
/*
* Main
*/
@set_time_limit(0);
print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
dol_syslog($script_file . " launched with arg " . implode(',', $argv));
$table = $argv[1];
if (empty($argv[1])) {
print "Error: Which table ?\n";
print "\n";
exit(-1);
}
$ret = $user->fetch('', 'admin');
if (!$ret > 0) {
print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
exit;
}
$sql = "SELECT * FROM `$table` WHERE 1";
$resql = $db->query($sql);
if ($resql) {
while ($fields = $db->fetch_array($resql)) {
$errorrecord = 0;
if ($fields === false) {
continue;
}
$nboflines++;
$produit = new Product($db);
$produit->type = 0;
$produit->status = 1;
$produit->ref = trim($fields['REF']);
if ($produit->ref == '') {
continue;
}
print "Process line nb " . $j . ", ref " . $produit->ref;
$produit->label = trim($fields['LIBELLE']);
if ($produit->label == '') {
$produit->label = $produit->ref;
}
if (empty($produit->label)) {
continue;
}
//$produit->description = trim($fields[4] . "\n" . ($fields[5] ? $fields[5] . ' x ' . $fields[6] . ' x ' . $fields[7] : ''));
// $produit->volume = price2num($fields[8]);
// $produit->volume_unit = 0;
$produit->weight = price2num($fields['MASSE']);
$produit->weight_units = 0; // -3 = g
//$produit->customcode = $fields[10];
$produit->barcode = str_pad($fields['CODE'], 12, "0", STR_PAD_LEFT);
$produit->barcode_type = '2';
$produit->import_key = $fields['CODE'];
$produit->status = 1;
$produit->status_buy = 1;
$produit->finished = 1;
// $produit->multiprices[0] = price2num($fields['TARIF0']);
// $produit->multiprices[1] = price2num($fields['TARIF1']);
// $produit->multiprices[2] = price2num($fields['TARIF2']);
// $produit->multiprices[3] = price2num($fields['TARIF3']);
// $produit->multiprices[4] = price2num($fields['TARIF4']);
// $produit->multiprices[5] = price2num($fields['TARIF5']);
// $produit->multiprices[6] = price2num($fields['TARIF6']);
// $produit->multiprices[7] = price2num($fields['TARIF7']);
// $produit->multiprices[8] = price2num($fields['TARIF8']);
// $produit->multiprices[9] = price2num($fields['TARIF9']);
// $produit->price_min = null;
// $produit->price_min_ttc = null;
// $produit->price = price2num($fields[11]);
// $produit->price_ttc = price2num($fields[12]);
// $produit->price_base_type = 'TTC';
// $produit->tva_tx = price2num($fields[13]);
$produit->tva_tx = (int) ($tvas[$fields['CODTVA']]);
$produit->tva_npr = 0;
// $produit->cost_price = price2num($fields[16]);
//compta
$produit->accountancy_code_buy = trim($fields['COMACH']);
$produit->accountancy_code_sell = trim($fields['COMVEN']);
// $produit->accountancy_code_sell_intra=trim($fields['COMVEN']);
// $produit->accountancy_code_sell_export=trim($fields['COMVEN']);
// Extrafields
// $produit->array_options['options_ecotaxdeee'] = price2num($fields[17]);
$produit->seuil_stock_alerte = $fields['STALERTE'];
$ret = $produit->create($user, 0);
if ($ret < 0) {
print " - Error in create result code = " . $ret . " - " . $produit->errorsToString();
$errorrecord++;
} else {
print " - Creation OK with ref " . $produit->ref . " - id = " . $ret;
}
dol_syslog("Add prices");
// If we use price level, insert price for each level
if (!$errorrecord && 1) {
//$ret1 = $produit->updatePrice($produit->price_ttc, $produit->price_base_type, $user, $produit->tva_tx, $produit->price_min, 1, $produit->tva_npr, 0, 0, array());
$ret1 = false;
for ($i = 0; $i < 10; $i++) {
if ($fields['TARIF' . ($i)] == 0) {
continue;
}
$ret1 = $ret1 || $produit->updatePrice(price2num($fields['TARIF' . ($i)]), 'HT', $user, $produit->tva_tx, $produit->price_min, $i + 1, $produit->tva_npr, 0, 0, array()) < 0;
}
if ($ret1) {
print " - Error in updatePrice result " . $produit->errorsToString();
$errorrecord++;
} else {
print " - updatePrice OK";
}
}
// dol_syslog("Add multilangs");
// Add alternative languages
// if (!$errorrecord && 1) {
// $produit->multilangs['fr_FR'] = array('label' => $produit->label, 'description' => $produit->description, 'note' => $produit->note_private);
// $produit->multilangs['en_US'] = array('label' => $fields[3], 'description' => $produit->description, 'note' => $produit->note_private);
//
// $ret = $produit->setMultiLangs($user);
// if ($ret < 0) {
// print " - Error in setMultiLangs result code = " . $ret . " - " . $produit->errorsToString();
// $errorrecord++;
// } else {
// print " - setMultiLangs OK";
// }
// }
dol_syslog("Add stocks");
// stocks
if (!$errorrecord && $fields['STOCK'] != 0) {
$rets = $produit->correct_stock($user, 1, $fields['STOCK'], 0, 'Stock importé');
if ($rets < 0) {
print " - Error in correct_stock result " . $produit->errorsToString();
$errorrecord++;
} else {
print " - correct_stock OK";
}
}
//update date créa
if (!$errorrecord) {
$date = substr($fields['DATCREA'], 0, 4) . '-' . substr($fields['DATCREA'], 4, 2) . '-' . substr($fields['DATCREA'], 6, 2);
$retd = $db->query("UPDATE `llx_product` SET `datec` = '$date 00:00:00' WHERE `llx_product`.`rowid` = $produit->id");
if ($retd < 1) {
print " - Error in update date créa result " . $produit->errorsToString();
$errorrecord++;
} else {
print " - update date créa OK";
}
}
print "\n";
if ($errorrecord) {
print( 'Error on record nb ' . $i . " - " . $produit->errorsToString() . "\n");
var_dump($db);
die();
$error++; // $errorrecord will be reset
}
$j++;
}
} else {
die("error : $sql");
}
// commit or rollback
print "Nb of lines qualified: " . $nboflines . "\n";
print "Nb of errors: " . $error . "\n";
$db->close();
exit($error);

View File

@ -1,365 +0,0 @@
#!/usr/bin/env php
<?php
/* Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
*/
/**
* \file dev/initdata/import-product.php
* \brief Script example to insert products from a csv file.
* To purge data, you can have a look at purge-data.php
*/
// Test si mode batch
$sapi_type = php_sapi_name();
$script_file = basename(__FILE__);
$path = dirname(__FILE__) . '/';
if (substr($sapi_type, 0, 3) == 'cgi') {
echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
exit;
}
// Recupere root dolibarr
$path = preg_replace('/importdb-thirdparties.php/i', '', $_SERVER["PHP_SELF"]);
require $path . "../../htdocs/master.inc.php";
require $path . "includes/dbase.class.php";
include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
//$delimiter = ',';
//$enclosure = '"';
//$linelength = 10000;
//$escape = '/';
// Global variables
$version = DOL_VERSION;
$confirmed = 1;
$error = 0;
$civilPrivate = array("MLLE",
"MM",
"MM/MADAME",
"MME",
"MME.",
"MME²",
"MMONSIEUR",
"MMR",
"MOBNSIEUR",
"MOMSIEUR",
"MON SIEUR",
"MONDIAL",
"MONIEUR",
"MONJSIEUR",
"MONNSIEUR",
"MONRIEUR",
"MONS",
"MONSIEÕR",
"MONSIER",
"MONSIERU",
"MONSIEU",
"monsieue",
"MONSIEUR",
"Monsieur     \"",
"MONSIEUR    \"",
"MONSIEUR   E",
"MONSIEUR  DENIS",
"MONSIEUR ET MME",
"MONSIEUR!",
"MONSIEUR.",
"MONSIEUR.MADAME",
"MONSIEUR3",
"MONSIEURN",
"MONSIEURT",
"MONSIEUR£",
"MONSIEYR",
"Monsigur",
"MONSIIEUR",
"MONSIUER",
"MONSIZEUR",
"MOPNSIEUR",
"MOSIEUR",
"MR",
"Mr  Mme",
"Mr - MME",
"MR BLANC",
"MR ET MME",
"mr mm",
"MR OU MME",
"Mr.",
"MR/MME",
"MRME",
"MRR",
"Mrs",
"Mademoiselle",
"MADAOME",
"madamme",
"MADAME",
"M0NSIEUR",
"M.et Madame",
"M. ET MR",
"M.",
"M%",
"M MME",
"M ET MME",
"M",
"M CROCE",
"M DIEVART",
);
/*
* Main
*/
@set_time_limit(0);
print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
dol_syslog($script_file . " launched with arg " . implode(',', $argv));
$table = $argv[1];
if (empty($argv[1])) {
print "Error: Quelle table ?\n";
print "\n";
exit(-1);
}
$ret = $user->fetch('', 'admin');
if (!$ret > 0) {
print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
exit;
}
$sql = "SELECT * FROM `$table` WHERE 1 "; //ORDER BY REMISE DESC,`LCIVIL` DESC";
$resql = $db->query($sql);
//$db->begin();
if ($resql) {
while ($fields = $db->fetch_array($resql)) {
$i++;
$errorrecord = 0;
if ($startlinenb && $i < $startlinenb) {
continue;
}
if ($endlinenb && $i > $endlinenb) {
continue;
}
$nboflines++;
$object = new Societe($db);
$object->import_key = $fields['CODE'];
$object->state = 1;
$object->client = 3;
$object->fournisseur = 0;
$object->name = $fields['FCIVIL'] . ' ' . $fields['FNOM'];
//$object->name_alias = $fields[0] != $fields[13] ? trim($fields[0]) : '';
$date = $fields['DATCREA'] ? $fields['DATCREA'] : ($fields['DATMOD'] ? $fields['DATMOD'] : '20200101');
$object->code_client = 'CU' . substr($date, 2, 2) . substr($date, 4, 2) . '-' . str_pad(substr($fields['CODE'], 0, 5), 5, "0", STR_PAD_LEFT);
$object->address = trim($fields['FADR1']);
if ($fields['FADR2']) {
$object->address .= "\n" . trim($fields['FADR2']);
}
if ($fields['FADR3']) {
$object->address .= "\n" . trim($fields['FADR3']);
}
$object->zip = trim($fields['FPOSTE']);
$object->town = trim($fields['FVILLE']);
if ($fields['FPAYS']) {
$object->country_id = dol_getIdFromCode($db, trim(ucwords(strtolower($fields['FPAYS']))), 'c_country', 'label', 'rowid');
} else {
$object->country_id = 1;
}
$object->phone = trim($fields['FTEL']) ? trim($fields['FTEL']) : trim($fields['FCONTACT']);
$object->phone = substr($object->phone, 0, 20);
$object->fax = trim($fields['FFAX']) ? trim($fields['FFAX']) : trim($fields['FCONTACT']);
$object->fax = substr($object->fax, 0, 20);
$object->email = trim($fields['FMAIL']);
// $object->idprof2 = trim($fields[29]);
$object->tva_intra = str_replace(['.', ' '], '', $fields['TVAINTRA']);
$object->tva_intra = substr($object->tva_intra, 0, 20);
$object->default_lang = 'fr_FR';
$object->cond_reglement_id = dol_getIdFromCode($db, 'PT_ORDER', 'c_payment_term', 'code', 'rowid', 1);
$object->multicurrency_code = 'EUR';
if ($fields['REMISE'] != '0.00') {
$object->remise_percent = abs($fields['REMISE']);
}
// $object->code_client = $fields[9];
// $object->code_fournisseur = $fields[10];
if ($fields['FCIVIL']) {
$labeltype = in_array($fields['FCIVIL'], $civilPrivate) ? 'TE_PRIVATE' : 'TE_SMALL';
$object->typent_id = dol_getIdFromCode($db, $labeltype, 'c_typent', 'code');
}
// Set price level
$object->price_level = $fields['TARIF'] + 1;
// if ($labeltype == 'Revendeur')
// $object->price_level = 2;
print "Process line nb " . $i . ", code " . $fields['CODE'] . ", name " . $object->name;
// Extrafields
$object->array_options['options_banque'] = $fields['BANQUE'];
$object->array_options['options_banque2'] = $fields['BANQUE2'];
$object->array_options['options_banquevalid'] = $fields['VALID'];
if (!$errorrecord) {
$ret = $object->create($user);
if ($ret < 0) {
print " - Error in create result code = " . $ret . " - " . $object->errorsToString();
$errorrecord++;
var_dump($object->code_client, $db);
die();
} else {
print " - Creation OK with name " . $object->name . " - id = " . $ret;
}
}
if (!$errorrecord) {
dol_syslog("Set price level");
$object->set_price_level($object->price_level, $user);
}
if (!$errorrecord && @$object->remise_percent) {
dol_syslog("Set remise client");
$object->set_remise_client($object->remise_percent, 'Importé', $user);
}
dol_syslog("Add contact");
// Insert an invoice contact if there is an invoice email != standard email
if (!$errorrecord && ($fields['LCIVIL'] || $fields['LNOM'])) {
$madame = array("MADAME",
"MADEMOISELLE",
"MELLE",
"MLLE",
"MM",
"Mme",
"MNE",
);
$monsieur = array("M",
"M ET MME",
"M MME",
"M.",
"M. MME",
"M. OU Mme",
"M.ou Madame",
"MONSEUR",
"MONSIER",
"MONSIEU",
"MONSIEUR",
"monsieur:mme",
"MONSIEUR¨",
"MONSIEZUR",
"MONSIUER",
"MONSKIEUR",
"MR",
);
$ret1 = $ret2 = 0;
$contact = new Contact($db);
if (in_array($fields['LCIVIL'], $madame)) {
// une dame
$contact->civility_id = 'MME';
$contact->lastname = $fields['LNOM'];
} elseif (in_array($fields['LCIVIL'], $monsieur)) {
// un monsieur
$contact->civility_id = 'MR';
$contact->lastname = $fields['LNOM'];
} elseif (in_array($fields['LCIVIL'], ['DOCTEUR'])) {
// un monsieur
$contact->civility_id = 'DR';
$contact->lastname = $fields['LNOM'];
} else {
// un a rattraper
$contact->lastname = $fields['LCIVIL'] . " " . $fields['LNOM'];
}
$contact->address = trim($fields['LADR1']);
if ($fields['LADR2']) {
$contact->address .= "\n" . trim($fields['LADR2']);
}
if ($fields['LADR3']) {
$contact->address .= "\n" . trim($fields['LADR3']);
}
$contact->zip = trim($fields['LPOSTE']);
$contact->town = trim($fields['LVILLE']);
if ($fields['FPAYS']) {
$contact->country_id = dol_getIdFromCode($db, trim(ucwords(strtolower($fields['LPAYS']))), 'c_country', 'label', 'rowid');
} else {
$contact->country_id = 1;
}
$contact->email = $fields['LMAIL'];
$contact->phone = trim($fields['LTEL']) ? trim($fields['LTEL']) : trim($fields['LCONTACT']);
$contact->fax = trim($fields['LFAX']) ? trim($fields['LFAX']) : trim($fields['LCONTACT']);
$contact->socid = $object->id;
$ret1 = $contact->create($user);
if ($ret1 > 0) {
//$ret2=$contact->add_contact($object->id, 'BILLING');
}
if ($ret1 < 0 || $ret2 < 0) {
print " - Error in create contact result code = " . $ret1 . " " . $ret2 . " - " . $contact->errorsToString();
$errorrecord++;
} else {
print " - create contact OK";
}
}
//update date créa
if (!$errorrecord) {
$datec = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2);
$retd = $db->query("UPDATE `llx_societe` SET `datec` = '$datec 00:00:00' WHERE `rowid` = $object->id");
if ($retd < 1) {
print " - Error in update date créa result " . $object->errorsToString();
$errorrecord++;
} else {
print " - update date créa OK";
}
}
print "\n";
if ($errorrecord) {
print( 'Error on record nb ' . $i . " - " . $object->errorsToString() . "\n");
var_dump($db, $object, $contact);
// $db->rollback();
die();
$error++; // $errorrecord will be reset
}
$j++;
}
} else {
die("error : $sql");
}
$db->commit();
// commit or rollback
print "Nb of lines qualified: " . $nboflines . "\n";
print "Nb of errors: " . $error . "\n";
$db->close();
exit($error);

View File

@ -1,599 +0,0 @@
<?php
/**
* \file dev/initdata/dbf/includes/dbase.class.php
* \ingroup dev
* \brief Class to manage DBF databases
*/
// source : https://github.com/donfbecker/php-dbase
define('DBASE_RDONLY', 0);
define('DBASE_WRONLY', 1);
define('DBASE_RDWR', 2);
define('DBASE_TYPE_DBASE', 0);
define('DBASE_TYPE_FOXPRO', 1);
/**
* Class for DBase
*/
class DBase
{
private $fd;
private $headerLength = 0;
private $fields = array();
private $fieldCount = 0;
private $recordLength = 0;
private $recordCount = 0;
/**
* resource dbase_open
* @param string $filename filename
* @param int $mode mode
* @return DBase
*/
public static function open($filename, $mode)
{
if (!file_exists($filename)) {
return false;
}
$modes = array('r', 'w', 'r+');
$mode = $modes[$mode];
$fd = fopen($filename, $mode);
if (!$fd) {
return false;
}
return new DBase($fd);
}
/**
* resource dbase_create
* @param string $filename filename
* @param array $fields fields
* @param int $type DBASE_TYPE_DBASE
* @return DBase
*/
public static function create($filename, $fields, $type = DBASE_TYPE_DBASE)
{
if (file_exists($filename)) {
return false;
}
$fd = fopen($filename, 'c+');
if (!$fd) {
return false;
}
// Byte 0 (1 byte): Valid dBASE for DOS file; bits 0-2 indicate version number, bit 3
// indicates the presence of a dBASE for DOS memo file, bits 4-6 indicate the
// presence of a SQL table, bit 7 indicates the presence of any memo file
// (either dBASE m PLUS or dBASE for DOS)
self::putChar8($fd, 5);
// Byte 1-3 (3 bytes): Date of last update; formatted as YYMMDD
self::putChar8($fd, date('Y') - 1900);
self::putChar8($fd, date('m'));
self::putChar8($fd, date('d'));
// Byte 4-7 (32-bit number): Number of records in the database file. Currently 0
self::putInt32($fd, 0);
// Byte 8-9 (16-bit number): Number of bytes in the header.
self::putInt16($fd, 32 + (32 * count($fields)) + 1);
// Byte 10-11 (16-bit number): Number of bytes in record.
// Make sure the include the byte for deleted flag
$len = 1;
foreach ($fields as &$field) {
$len += self::length($field);
}
self::putInt16($fd, $len);
// Byte 12-13 (2 bytes): Reserved, 0 filled.
self::putInt16($fd, 0);
// Byte 14 (1 byte): Flag indicating incomplete transaction
// The ISMARKEDO function checks this flag. BEGIN TRANSACTION sets it to 1, END TRANSACTION and ROLLBACK reset it to 0.
self::putChar8($fd, 0);
// Byte 15 (1 byte): Encryption flag. If this flag is set to 1, the message Database encrypted appears. Changing this flag to 0 removes the message, but does not decrypt the file.
self::putChar8($fd, 0);
// Byte 16-27 (12 bytes): Reserved for dBASE for DOS in a multi-user environment
self::putInt32($fd, 0);
self::putInt32($fd, 0);
self::putInt32($fd, 0);
// Byte 28 (1 byte): Production .mdx file flag; 0x01 if there is a production .mdx file, 0x00 if not
self::putChar8($fd, 0);
// Byte 29 (1 byte): Language driver ID
// (no clue what this is)
self::putChar8($fd, 0);
// Byte 30-31 (2 bytes): Reserved, 0 filled.
self::putInt16($fd, 0);
// Byte 32 - n (32 bytes each): Field descriptor array
foreach ($fields as &$field) {
self::putString($fd, $field[0], 11); // Byte 0 - 10 (11 bytes): Field name in ASCII (zero-filled)
self::putString($fd, $field[1], 1); // Byte 11 (1 byte): Field type in ASCII (C, D, F, L, M, or N)
self::putInt32($fd, 0); // Byte 12 - 15 (4 bytes): Reserved
self::putChar8($fd, self::length($field)); // Byte 16 (1 byte): Field length in binary. The maximum length of a field is 254 (0xFE).
self::putChar8($fd, $field[3]); // Byte 17 (1 byte): Field decimal count in binary
self::putInt16($fd, 0); // Byte 18 - 19 (2 bytes): Work area ID
self::putChar8($fd, 0); // Byte 20 (1 byte): Example (??)
self::putInt32($fd, 0); // Byte 21 - 30 (10 bytes): Reserved
self::putInt32($fd, 0);
self::putInt16($fd, 0);
self::putChar8($fd, 0); // Byte 31 (1 byte): Production MDX field flag; 1 if field has an index tag in the production MDX file, 0 if not
}
// Byte n + 1 (1 byte): 0x0D as the field descriptor array terminator
self::putChar8($fd, 0x0D);
return new DBase($fd);
}
/**
* Create DBase instance
* @param mixed $fd file descriptor
* @return void
*/
private function __construct($fd)
{
$this->fd = $fd;
// Byte 4-7 (32-bit number): Number of records in the database file. Currently 0
fseek($this->fd, 4, SEEK_SET);
$this->recordCount = self::getInt32($fd);
// Byte 8-9 (16-bit number): Number of bytes in the header.
fseek($this->fd, 8, SEEK_SET);
$this->headerLength = self::getInt16($fd);
// Number of fields is (headerLength - 33) / 32)
$this->fieldCount = ($this->headerLength - 33) / 32;
// Byte 10-11 (16-bit number): Number of bytes in record.
fseek($this->fd, 10, SEEK_SET);
$this->recordLength = self::getInt16($fd);
// Byte 32 - n (32 bytes each): Field descriptor array
fseek($fd, 32, SEEK_SET);
for ($i = 0; $i < $this->fieldCount; $i++) {
$data = fread($this->fd, 32);
$field = array_map('trim', unpack('a11name/a1type/c4/c1length/c1precision/s1workid/c1example/c10/c1production', $data));
$this->fields[] = $field;
}
}
/**
* dbase_close
* @return void
*/
public function close()
{
fclose($this->fd);
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_get_header_info
* @return array
*/
public function get_header_info()
{
// phpcs:disable
return $this->fields;
}
/**
* dbase_numfields
* @return int
*/
public function numfields()
{
return $this->fieldCount;
}
/**
* dbase_numrecords
* @return int
*/
public function numrecords()
{
return $this->recordCount;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_add_record
* @param array $record record
* @return bool
*/
public function add_record($record)
{
// phpcs:enable
if (count($record) != $this->fieldCount) {
return false;
}
// Seek to end of file, minus the end of file marker
fseek($this->fd, 0, SEEK_END);
// Put the deleted flag
self::putChar8($this->fd, 0x20);
// Put the record
if (!$this->putRecord($record)) {
return false;
}
// Update the record count
fseek($this->fd, 4);
self::putInt32($this->fd, ++$this->recordCount);
return true;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_replace_record
* @param array $record record
* @param int $record_number record number
* @return bool
*/
public function replace_record($record, $record_number)
{
// phpcs:enable
if (count($record) != $this->fieldCount) {
return false;
}
if ($record_number < 1 || $record_number > $this->recordCount) {
return false;
}
// Skip to the record location, plus the 1 byte for the deleted flag
fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)) + 1);
return $this->putRecord($record);
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_delete_record
* @param int $record_number record number
* @return bool
*/
public function delete_record($record_number)
{
// phpcs:enable
if ($record_number < 1 || $record_number > $this->recordCount) {
return false;
}
fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)));
self::putChar8($this->fd, 0x2A);
return true;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_get_record
* @param int $record_number record number
* @return array
*/
public function get_record($record_number)
{
// phpcs:enable
if ($record_number < 1 || $record_number > $this->recordCount) {
return false;
}
fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)));
$record = array(
'deleted' => self::getChar8($this->fd) == 0x2A ? 1 : 0
);
foreach ($this->fields as $i => &$field) {
$value = trim(fread($this->fd, $field['length']));
if ($field['type'] == 'L') {
$value = strtolower($value);
if ($value == 't' || $value == 'y') {
$value = true;
} elseif ($value == 'f' || $value == 'n') {
$value = false;
} else {
$value = null;
}
}
$record[$i] = $value;
}
return $record;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* dbase_get_record_with_names
* @param int $record_number record number
* @return array
*/
public function get_record_with_names($record_number)
{
// phpcs:enable
if ($record_number < 1 || $record_number > $this->recordCount) {
return false;
}
$record = $this->get_record($record_number);
foreach ($this->fields as $i => &$field) {
$record[$field['name']] = $record[$i];
unset($record[$i]);
}
return $record;
}
/**
* dbase_pack
* @return void
*/
public function pack()
{
$in_offset = $out_offset = $this->headerLength;
$new_count = 0;
$rec_count = $this->recordCount;
while ($rec_count > 0) {
fseek($this->fd, $in_offset, SEEK_SET);
$record = fread($this->fd, $this->recordLength);
$deleted = substr($record, 0, 1);
if ($deleted != '*') {
fseek($this->fd, $out_offset, SEEK_SET);
fwrite($this->fd, $record);
$out_offset += $this->recordLength;
$new_count++;
}
$in_offset += $this->recordLength;
$rec_count--;
}
ftruncate($this->fd, $out_offset);
// Update the record count
fseek($this->fd, 4);
self::putInt32($this->fd, $new_count);
}
/*
* A few utilitiy functions
*/
/**
* @param string $field field
* @return int
*/
private static function length($field)
{
switch ($field[1]) {
case 'D': // Date: Numbers and a character to separate month, day, and year (stored internally as 8 digits in YYYYMMDD format)
return 8;
case 'T': // DateTime (YYYYMMDDhhmmss.uuu) (FoxPro)
return 18;
case 'M': // Memo (ignored): All ASCII characters (stored internally as 10 digits representing a .dbt block number, right justified, padded with whitespaces)
case 'N': // Number: -.0123456789 (right justified, padded with whitespaces)
case 'F': // Float: -.0123456789 (right justified, padded with whitespaces)
case 'C': // String: All ASCII characters (padded with whitespaces up to the field's length)
return $field[2];
case 'L': // Boolean: YyNnTtFf? (? when not initialized)
return 1;
}
return 0;
}
/*
* Functions for reading and writing bytes
*/
/**
* getChar8
* @param mixed $fd file descriptor
* @return int
*/
private static function getChar8($fd)
{
return ord(fread($fd, 1));
}
/**
* putChar8
* @param mixed $fd file descriptor
* @param mixed $value value
* @return bool
*/
private static function putChar8($fd, $value)
{
return fwrite($fd, chr($value));
}
/**
* getInt16
* @param mixed $fd file descriptor
* @param int $n n
* @return bool
*/
private static function getInt16($fd, $n = 1)
{
$data = fread($fd, 2 * $n);
$i = unpack("S$n", $data);
if ($n == 1) {
return (int) $i[1];
} else {
return array_merge($i);
}
}
/**
* putInt16
* @param mixed $fd file descriptor
* @param mixed $value value
* @return bool
*/
private static function putInt16($fd, $value)
{
return fwrite($fd, pack('S', $value));
}
/**
* getInt32
* @param mixed $fd file descriptor
* @param int $n n
* @return bool
*/
private static function getInt32($fd, $n = 1)
{
$data = fread($fd, 4 * $n);
$i = unpack("L$n", $data);
if ($n == 1) {
return (int) $i[1];
} else {
return array_merge($i);
}
}
/**
* putint32
* @param mixed $fd file descriptor
* @param mixed $value value
* @return bool
*/
private static function putInt32($fd, $value)
{
return fwrite($fd, pack('L', $value));
}
/**
* putString
* @param mixed $fd file descriptor
* @param mixed $value value
* @param int $length length
* @return bool
*/
private static function putString($fd, $value, $length = 254)
{
$ret = fwrite($fd, pack('A' . $length, $value));
}
/**
* putRecord
* @param mixed $record record
* @return bool
*/
private function putRecord($record)
{
foreach ($this->fields as $i => &$field) {
$value = $record[$i];
// Number types are right aligned with spaces
if ($field['type'] == 'N' || $field['type'] == 'F' && strlen($value) < $field['length']) {
$value = str_repeat(' ', $field['length'] - strlen($value)) . $value;
}
self::putString($this->fd, $value, $field['length']);
}
return true;
}
}
if (!function_exists('dbase_open')) {
/**
* dbase_open
* @param string $filename filename
* @param int $mode mode
* @return DBase
*/
function dbase_open($filename, $mode)
{
return DBase::open($filename, $mode);
}
/**
* dbase_create
* @param string $filename filename
* @param array $fields fields
* @param int $type type
* @return DBase
*/
function dbase_create($filename, $fields, $type = DBASE_TYPE_DBASE)
{
return DBase::create($filename, $fields, $type);
}
/**
* dbase_close
* @param Resource $dbase_identifier dbase identifier
* @return bool
*/
function dbase_close($dbase_identifier)
{
return $dbase_identifier->close();
}
/**
* dbase_get_header_info
* @param Resource $dbase_identifier dbase identifier
* @return string
*/
function dbase_get_header_info($dbase_identifier)
{
return $dbase_identifier->get_header_info();
}
/**
* dbase_numfields
* @param Resource $dbase_identifier dbase identifier
* @return int
*/
function dbase_numfields($dbase_identifier)
{
$dbase_identifier->numfields();
}
/**
* dbase_numrecords
* @param Resource $dbase_identifier dbase identifier
* @return int
*/
function dbase_numrecords($dbase_identifier)
{
return $dbase_identifier->numrecords();
}
/**
* dbase_add_record
* @param Resource $dbase_identifier dbase identifier
* @param array $record record
* @return bool
*/
function dbase_add_record($dbase_identifier, $record)
{
return $dbase_identifier->add_record($record);
}
/**
* dbase_delete_record
* @param Resource $dbase_identifier dbase identifier
* @param int $record_number record number
* @return bool
*/
function dbase_delete_record($dbase_identifier, $record_number)
{
return $dbase_identifier->delete_record($record_number);
}
/**
* dbase_replace_record
* @param Resource $dbase_identifier dbase identifier
* @param array $record record
* @param int $record_number record number
* @return bool
*/
function dbase_replace_record($dbase_identifier, $record, $record_number)
{
return $dbase_identifier->replace_record($record, $record_number);
}
/**
* dbase_get_record
* @param Resource $dbase_identifier dbase identifier
* @param int $record_number record number
* @return bool
*/
function dbase_get_record($dbase_identifier, $record_number)
{
return $dbase_identifier->get_record($record_number);
}
/**
* dbase_get_record_with_names
* @param Resource $dbase_identifier dbase identifier
* @param int $record_number record number
* @return bool
*/
function dbase_get_record_with_names($dbase_identifier, $record_number)
{
return $dbase_identifier->get_record_with_names($record_number);
}
/**
* dbase_pack
* @param Resource $dbase_identifier dbase identifier
* @return bool
*/
function dbase_pack($dbase_identifier)
{
return $dbase_identifier->pack();
}
}

1
dev/initdemo/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/initdemopostsql.sql

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -232,6 +232,10 @@ else
fi
if [ -s "$mydir/initdemopostsql.sql" ]; then
mysql -P$port $base < "$mydir/initdemopostsql.sql"
fi
if [ "x$res" = "x0" ]
then

View File

@ -32,12 +32,14 @@ base=$2;
port=$3;
demologin=$4;
demopass=$5;
demopasshash=$6;
# ----------------------------- check params
if [ "x$confirm" != "xconfirm" ]
then
echo "----- $0 -----"
echo "Usage: initdemopassword.sh confirm [base port login pass]"
echo "Usage: initdemopassword.sh confirm [base port login pass password_hash_algo]"
echo "password_hash_algo can be md5 or password_hash"
exit
fi
@ -147,8 +149,20 @@ then
fi
#echo "mysql -P$port -u$admin $passwd $base < $mydir/$dumpfile"
#mysql -P$port -u$admin $passwd $base < $mydir/$dumpfile
echo "echo \"UPDATE llx_user SET pass_crypted = MD5('$demopass') WHERE login = '$demologin';\" | mysql -P$port $base"
echo "UPDATE llx_user SET pass_crypted = MD5('$demopass') WHERE login = '$demologin';" | mysql -P$port $base
if [ "x${demopasshash}" != "xpassword_hash" ]
then
echo '<?php echo MD5("$demopass"); ?>' > /tmp/tmp.php
newpass=`php -f /tmp/tmp.php`
rm /tmp/tmp.php
else
echo '<?php echo password_hash("'$demopass'", PASSWORD_DEFAULT); ?>' > /tmp/tmp.php
newpass=`php -f /tmp/tmp.php`
rm /tmp/tmp.php
fi
echo "echo \"UPDATE llx_user SET pass_crypted = '$newpass' WHERE login = '$demologin';\" | mysql -P$port $base"
echo "UPDATE llx_user SET pass_crypted = '$newpass' WHERE login = '$demologin';" | mysql -P$port $base
export res=$?
if [ $res -ne 0 ]; then
@ -156,6 +170,10 @@ if [ $res -ne 0 ]; then
exit
fi
if [ -s "$mydir/initdemopostsql.sql" ]; then
mysql -P$port $base < "$mydir/initdemopostsql.sql"
fi
if [ "x$res" = "x0" ]
then

File diff suppressed because one or more lines are too long

View File

@ -5503,7 +5503,7 @@ CREATE TABLE `llx_product` (
LOCK TABLES `llx_product` WRITE;
/*!40000 ALTER TABLE `llx_product` DISABLE KEYS */;
INSERT INTO `llx_product` VALUES (1,'2010-07-08 14:33:17','2013-03-12 09:30:24',0,0,'PIDRESS',1,NULL,'Pink dress','A beatifull pink dress','',NULL,NULL,100.00000000,112.50000000,90.00000000,101.25000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',20,NULL,0,'','',NULL,100,0,NULL,0,NULL,0,NULL,0,2,0.00000000,NULL,1,0,NULL,0),(2,'2010-07-09 00:30:01','2013-01-19 17:31:58',0,0,'Product_P1',1,NULL,'Product P1','','','',32,0.00000000,0.00000000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,998,0.00000000,NULL,0,0,NULL,0),(3,'2010-07-09 00:30:25','2012-12-08 13:11:14',0,0,'Service_S1',1,NULL,'Service S1','','',NULL,NULL,0.00000000,0.00000000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,1,'1m',NULL,NULL,0,'','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.00000000,NULL,0,0,NULL,0),(4,'2010-07-10 14:44:06','2013-01-19 17:22:48',0,0,'DECAP',1,NULL,'Decapsuleur','','',NULL,NULL,5.00000000,5.62500000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,2,-3,NULL,0,NULL,0,NULL,0,1001,10.00000000,NULL,1,0,NULL,0),(5,'2011-07-20 23:11:38','2011-07-27 17:02:59',0,0,'aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(6,'2011-07-29 22:16:44','2011-07-29 20:16:44',0,0,'Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(7,'2011-07-29 22:31:21','2011-07-29 20:31:21',0,0,'Copy_of_Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,0,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(8,'2011-07-29 22:46:54','2011-07-29 20:46:54',0,0,'Copy_of_Copy_of_Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,0,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(10,'2008-12-31 00:00:00','2012-12-08 13:11:14',0,0,'PR123456',1,NULL,'My product','This is a description example for record','Some note',NULL,NULL,100.00000000,110.00000000,0.00000000,0.00000000,'HT',10.000,0,0.000,0.000,NULL,0,0,0,'1y',0,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.00000000,NULL,NULL,0,'20110729232310',0),(11,'2013-01-13 20:24:42','2013-01-19 17:22:48',0,0,'gh',1,NULL,'hfghf','','','',NULL,0.00000000,0.00000000,0.00000000,0.00000000,'HT',0.000,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,-1,0.00000000,'',1,0,NULL,0);
INSERT INTO `llx_product` VALUES (1,'2010-07-08 14:33:17','2013-03-12 09:30:24',0,0,'PINKDRESS',1,NULL,'Pink dress','A beatifull pink dress','',NULL,NULL,100.00000000,112.50000000,90.00000000,101.25000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',20,NULL,0,'','',NULL,100,0,NULL,0,NULL,0,NULL,0,2,0.00000000,NULL,1,0,NULL,0),(2,'2010-07-09 00:30:01','2013-01-19 17:31:58',0,0,'Product_P1',1,NULL,'Product P1','','','',32,0.00000000,0.00000000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,998,0.00000000,NULL,0,0,NULL,0),(3,'2010-07-09 00:30:25','2012-12-08 13:11:14',0,0,'Service_S1',1,NULL,'Service S1','','',NULL,NULL,0.00000000,0.00000000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,1,'1m',NULL,NULL,0,'','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.00000000,NULL,0,0,NULL,0),(4,'2010-07-10 14:44:06','2013-01-19 17:22:48',0,0,'DECAP',1,NULL,'Decapsuleur','','',NULL,NULL,5.00000000,5.62500000,0.00000000,0.00000000,'HT',12.500,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,2,-3,NULL,0,NULL,0,NULL,0,1001,10.00000000,NULL,1,0,NULL,0),(5,'2011-07-20 23:11:38','2011-07-27 17:02:59',0,0,'aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(6,'2011-07-29 22:16:44','2011-07-29 20:16:44',0,0,'Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(7,'2011-07-29 22:31:21','2011-07-29 20:31:21',0,0,'Copy_of_Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,0,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(8,'2011-07-29 22:46:54','2011-07-29 20:46:54',0,0,'Copy_of_Copy_of_Copy_of_aaaa',1,NULL,'aaaa','cccc','bbbb','',NULL,10.00000000,11.96000000,0.00000000,0.00000000,'HT',19.600,0,0.000,0.000,1,0,0,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,NULL,0.00000000,'',1,0,NULL,0),(10,'2008-12-31 00:00:00','2012-12-08 13:11:14',0,0,'PR123456',1,NULL,'My product','This is a description example for record','Some note',NULL,NULL,100.00000000,110.00000000,0.00000000,0.00000000,'HT',10.000,0,0.000,0.000,NULL,0,0,0,'1y',0,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0.00000000,NULL,NULL,0,'20110729232310',0),(11,'2013-01-13 20:24:42','2013-01-19 17:22:48',0,0,'gh',1,NULL,'hfghf','','','',NULL,0.00000000,0.00000000,0.00000000,0.00000000,'HT',0.000,0,0.000,0.000,1,1,1,0,'',NULL,NULL,0,'','',NULL,NULL,0,NULL,0,NULL,0,NULL,0,-1,0.00000000,'',1,0,NULL,0);
/*!40000 ALTER TABLE `llx_product` ENABLE KEYS */;
UNLOCK TABLES;

View File

@ -259,6 +259,7 @@ export list="
--ignore-table=$base.llx_dolireport_plot
--ignore-table=$base.llx_dolireport_report
--ignore-table=$base.llx_domain
--ignore-table=$base.llx_ecommerce_category
--ignore-table=$base.llx_ecommerce_commande
--ignore-table=$base.llx_ecommerce_facture
--ignore-table=$base.llx_ecommerce_product

View File

@ -0,0 +1,6 @@
EORI
https://en.wikipedia.org/wiki/EORI_number
in Dolibarr avaiable since v13
- it is set to field 'profid5'

View File

@ -1 +1,4 @@
http://bitboost.com/ref/international-address-formats.html#Formats
https://bitboost.com/ref/international-address-formats.html#Formats
https://www.upu.int/en/Postal-Solutions/Programmes-Services/Addressing-Solutions

View File

@ -1 +1,5 @@
http://ec.europa.eu/eurostat/ramon/nomenclatures/index.cfm?TargetUrl=LST_CLS_DLD&StrNom=NACE_REV2&StrLanguageCode=FR&StrLayoutCode=#
NACE
https://ec.europa.eu/eurostat/ramon/nomenclatures/index.cfm?TargetUrl=LST_CLS_DLD&StrNom=NACE_REV2&StrLanguageCode=EN&StrLayoutCode=
https://en.wikipedia.org/wiki/Statistical_Classification_of_Economic_Activities_in_the_European_Community

View File

@ -3,11 +3,12 @@
# The list is updated whenever a change to the official code list in ISO 3166-1 is effected by the ISO 3166/MA.
# It lists 240 official short names and code elements. One line of text contains one entry.
# A country name and its code element are separated by a semicolon (;).
# http://www.iso.org/iso/fr/iso3166_en_code_lists.txt
# https://www.iso.org/iso-3166-country-codes.html
# ISO-3166: http://en.wikipedia.org/wiki/ISO_3166-1
# ISO-3166 alpha 2: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
# ISO-3166 alpha 3: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
# https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
# ISO-3166: https://en.wikipedia.org/wiki/ISO_3166-1
# ISO-3166 alpha 2: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
# ISO-3166 alpha 3: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
AFGHANISTAN;AF
ÅLAND ISLANDS;AX
@ -254,4 +255,4 @@ WALLIS AND FUTUNA;WF
WESTERN SAHARA;EH
YEMEN;YE
ZAMBIA;ZM
ZIMBABWE;ZW
ZIMBABWE;ZW

View File

@ -3,11 +3,12 @@
# The list is updated whenever a change to the official code list in ISO 3166-1 is effected by the ISO 3166/MA.
# It lists 240 official short names and code elements. One line of text contains one entry.
# A country name and its code element are separated by a semicolon (;).
# http://www.iso.org/iso/fr/iso3166_fr_code_lists.txt
# https://www.iso.org/fr/iso-3166-country-codes.html
# ISO-3166: http://en.wikipedia.org/wiki/ISO_3166-1
# ISO-3166 alpha 2: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
# ISO-3166 alpha 3: http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
# https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
# ISO-3166: https://fr.wikipedia.org/wiki/ISO_3166-1
# ISO-3166 alpha 2: https://fr.wikipedia.org/wiki/ISO_3166-1_alpha-2
# ISO-3166 alpha 3: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
AFGHANISTAN;AF
AFRIQUE DU SUD;ZA
@ -254,4 +255,4 @@ VIET NAM;VN
WALLIS ET FUTUNA;WF
YÉMEN;YE
ZAMBIE;ZM
ZIMBABWE;ZW
ZIMBABWE;ZW

View File

@ -1,9 +1,9 @@
For languages:
http://demo.icu-project.org/icu-bin/locexp?d_=fr
https://icu4c-demos.unicode.org/icu-bin/icudemos - Locale Explorer -> Error 404
For format number:
http://en.wikipedia.org/wiki/Decimal_mark
https://en.wikipedia.org/wiki/Decimal_mark
For date format:
http://en.wikipedia.org/wiki/Date_format_by_country
https://en.wikipedia.org/wiki/Date_format_by_country

View File

@ -1 +1,7 @@
http://en.wikipedia.org/wiki/VAT_identification_number
https://en.wikipedia.org/wiki/VAT_identification_number
terms
(en) VAT = Value Added Tax
(fr) TVA = Taxe sur la Valeur Ajouté
(es) NIF / CIF
(de) USt / MwSt

View File

@ -1,4 +1,5 @@
http://www.taxrates.cc/index.html
https://en.wikipedia.org/wiki/List_of_countries_by_tax_rates
For India: VAT=IGST/CGST=Localtax1/SGST=Localtax2: https://cleartax.in/s/what-is-sgst-cgst-igst

View File

@ -1,3 +1,7 @@
https://en.wikipedia.org/wiki/Single_Euro_Payments_Area
https://www.ecb.europa.eu/paym/integration/retail/sepa/html/index.en.html
https://www.europeanpaymentscouncil.eu/about-sepa
Spec for credit transfer:
https://docs.oracle.com/cd/E39124_01/doc.91/e60210/fields_sepa_pay_file_appx.htm#EOAEL00515

View File

@ -10,6 +10,11 @@ To run phpcs:
> cd dolibarrgitrepo
> phpcs --standard=dev/setup/codesniffer/ruleset.xml --extensions=php --parallel=8 .
To fix with phpcbf:
> cd dolibarrgitrepo
> phpcbf --standard=dev/setup/codesniffer/ruleset.xml --extensions=php --parallel=8 .
Note with Eclipse: You must setup the PTI plugin of Eclipse into PHPCodeSniffer menu with:
* tab value to 4
* path of code sniffer standard to dev/codesniffer

View File

@ -16,7 +16,7 @@
<exclude-pattern type="relative">htdocs/conf.php</exclude-pattern>
<exclude-pattern type="relative">*/nltechno*</exclude-pattern>
<exclude-pattern type="relative">*/htdocs/includes</exclude-pattern>
<exclude-pattern type="relative">*/htdocs/includes</exclude-pattern>
<exclude-pattern type="relative">source</exclude-pattern>
<exclude-pattern type="relative">.git</exclude-pattern>
<!-- List of all tests -->

View File

@ -0,0 +1,20 @@
# Fail2Ban configuration file
#
# Regexp to catch known spambots and software alike. Please verify
# that it is your intent to block IPs which were driven by
# above mentioned bots.
[Definition]
# To test, you can inject this example into log
# echo `date +'%Y-%m-%d %H:%M:%S'`" INFO 1.2.3.4 functions_dolibarr::check_user_password_abcd Authentication KO" >> /mypath/documents/dolibarr.log
#
# then
# fail2ban-client status web-dol-bruteforce
#
# To test rule file on a existing log file
# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf
failregex = ^ [A-Z\s]+ <HOST>\s+functions_dolibarr::check_user_password_.* Authentication KO
ignoreregex =

View File

@ -0,0 +1,20 @@
# Fail2Ban configuration file
#
# Regexp to catch known spambots and software alike. Please verify
# that it is your intent to block IPs which were driven by
# above mentioned bots.
[Definition]
# To test, you can inject this example into log
# echo `date +'%Y-%m-%d %H:%M:%S'`" INFO 1.2.3.4 --- Access to GET /passwordforgotten.php - action=buildnewpassword, massaction=" >> /mypath/documents/dolibarr.log
#
# then
# fail2ban-client status web-dol-passforgotten
#
# To test rule file on a existing log file
# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf
failregex = ^ [A-Z\s]+ <HOST>\s+--- Access to .*/passwordforgotten.php - action=buildnewpassword
ignoreregex =

View File

@ -0,0 +1,28 @@
#
# Examle of rule you can add to fail2ban to restrict bruteforce attacks.
#
[web-dol-passforgotten]
; rule against call of passwordforgottenpage
enabled = true
port = http,https
filter = web-dolibarr-rulespassforgotten
logpath = >> /mypath/documents/documents/dolibarr.log
action = %(action_mw)s
bantime = 4320000 ; 50 days
findtime = 86400 ; 1 day
maxretry = 10
[web-dol-bruteforce]
; rule against bruteforce hacking (login + api)
enabled = true
port = http,https
filter = web-dolibarr-rulesbruteforce
logpath = >> /mypath/documents/documents/dolibarr.log
action = %(action_mw)s
bantime = 86400 ; 1 day
findtime = 3600 ; 1 hour
maxretry = 10

View File

@ -17,3 +17,7 @@ for Linux OS
to install or to update transifex client:
sudo pip install --upgrade transifex-client
Comparison of Terms between ERPs
---------------------------------
https://wiki.dolibarr.org/index.php?title=Comparison_of_Terms_between_ERPs

View File

@ -10,17 +10,16 @@
https://github.com/Dolibarr/foundation
* Few icons are / were from website led24.de
* Attention: This website is no longer available!
# LICENCE OF IMAGE RESOURCES
--------------------------------
This is original README file for this source:
-------------------------------------------------------
* All image resources (except dolihelp.ico and doliadmin.ico) in this directory are distributed under licence CC BY-SA
List of icons from http://led24.de/iconset/ are:
- doliadmin.ico
- dolihelp.ico
This is original README file for the package with this 2 images:
You can do whatever you want with these icons (use on web or in desktop applications) as long as you dont pass them off as your own and remove this readme file. A credit statement and a link back to
http://led24.de/iconset/ or http://led24.de/ would be appreciated.
Follow us on twitter http://twitter.com/gasyoun or email leds24@gmail.com
512 icons 20/05/2009
-------------------------------------------------------
List of icons from http://led24.de/iconset/ are:
- dolihelp.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
doc/images/appicon_32.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -19,7 +19,7 @@ Download
Install
--------------------------------
* For a Quick guide, take a look at README file into root directory.
* For a Quick guide, take a look at README.md file into root directory.
* More complete documentations are also available on line on the Dolibarr Wiki:
https://wiki.dolibarr.org

View File

@ -23,7 +23,7 @@ Download / Herunterladen
Installation / Hilfe
------------------------------------
* Für eine kurze Einleitung schau in die README Datei im Hauptverzeichnis.
* Für eine kurze Einleitung schau in die README.md Datei im Hauptverzeichnis.
* Umfangreiche Dokumentationen sind im Dolibarr Wiki zu finden:
https://wiki.dolibarr.org/index.php/Hauptseite

View File

@ -20,9 +20,7 @@ https://www.dolistore.com
Documentation utilisateur
--------------------------------
* Pour une prise en main et installation rapide, consultez le fichier
README-FR à la racine.
* Pour une prise en main et installation rapide, consultez le fichier README-FR.md à la racine.
* Une documentation utilisateur francophone plus consistante est disponible en
ligne sur le wiki de Dolibarr à l'adresse:
https://wiki.dolibarr.org/index.php/Accueil
* Une documentation utilisateur francophone plus consistante est disponible en ligne sur le wiki de Dolibarr à l'adresse:
https://wiki.dolibarr.org

View File

@ -4,4 +4,5 @@ User guide
--------------------------------
* All Dolibarr guides are available, on line, on the Dolibarr Web site:
https://www.dolibarr.org

View File

@ -7,9 +7,7 @@ Benutzeranleitung
Alle Dolibarr-Informationen sind online verfuegbar ueber die Webseiten:
https://www.dolibarr.de (de) oder https://www.dolibarr.org (intl)
https://wiki.dolibarr.org/index.php/Hauptseite (de)

View File

@ -3,9 +3,6 @@ README (french)
Documentation utilisateur
--------------------------------
* Pour une prise en main et installation rapide, consultez le fichier
README-FR à la racine.
La documentation utilisateur francophone est disponible en ligne sur le site Web de Dolibarr à l'adresse:
* Une documentation utilisateur francophone plus consistante est disponible en
ligne sur le site Web de Dolibarr à l'adresse:
https://www.dolibarr.fr

View File

@ -45,9 +45,15 @@ $search_label = GETPOST('search_label', 'alpha');
$search_labelshort = GETPOST('search_labelshort', 'alpha');
$search_accountparent = GETPOST('search_accountparent', 'alpha');
$search_pcgtype = GETPOST('search_pcgtype', 'alpha');
$toselect = GETPOST('toselect', 'array');
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
$confirm = GETPOST('confirm', 'alpha');
$chartofaccounts = GETPOST('chartofaccounts', 'int');
$permissiontoadd = $user->rights->accounting->chartofaccount;
$permissiontodelete = $user->rights->accounting->chartofaccount;
// Security check
if ($user->socid > 0) {
accessforbidden();
@ -91,7 +97,6 @@ if ($conf->global->MAIN_FEATURES_LEVEL < 2) {
$accounting = new AccountingAccount($db);
/*
* Actions
*/
@ -104,7 +109,7 @@ if (!GETPOST('confirmmassaction', 'alpha')) {
}
$parameters = array();
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been monowraponalldified by some hooks
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
@ -114,6 +119,13 @@ if (empty($reshook)) {
$action = '';
}
$objectclass = 'AccountingAccount';
$uploaddir = $conf->accounting->multidir_output[$conf->entity];
include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
if ($action == "delete") {
$action = "";
}
include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers
@ -126,7 +138,7 @@ if (empty($reshook)) {
}
if ((GETPOST('valid_change_chart', 'alpha') && GETPOST('chartofaccounts', 'int') > 0) // explicit click on button 'Change and load' with js on
|| (GETPOST('chartofaccounts', 'int') > 0 && GETPOST('chartofaccounts', 'int') != $conf->global->CHARTOFACCOUNTS)) { // a submit of form is done and chartofaccounts combo has been modified
if ($chartofaccounts > 0) {
if ($chartofaccounts > 0 && $permissiontoadd) {
// Get language code for this $chartofaccounts
$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'c_country as c, '.MAIN_DB_PREFIX.'accounting_system as a';
$sql .= ' WHERE c.rowid = a.fk_country AND a.rowid = '.(int) $chartofaccounts;
@ -170,7 +182,7 @@ if (empty($reshook)) {
}
}
if ($action == 'disable') {
if ($action == 'disable' && $permissiontoadd) {
if ($accounting->fetch($id)) {
$mode = GETPOST('mode', 'int');
$result = $accounting->accountDeactivate($id, $mode);
@ -180,7 +192,7 @@ if (empty($reshook)) {
if ($result < 0) {
setEventMessages($accounting->error, $accounting->errors, 'errors');
}
} elseif ($action == 'enable') {
} elseif ($action == 'enable' && $permissiontoadd) {
if ($accounting->fetch($id)) {
$mode = GETPOST('mode', 'int');
$result = $accounting->account_activate($id, $mode);
@ -267,6 +279,7 @@ if (strlen(trim($search_pcgtype))) {
$sql .= natural_search("aa.pcg_type", $search_pcgtype);
}
$sql .= $db->order($sortfield, $sortorder);
//print $sql;
// Count total nb of records
$nbtotalofrecords = '';
@ -279,6 +292,16 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
}
}
// List of mass actions available
if ($user->rights->accounting->chartofaccount) {
$arrayofmassactions['predelete'] = '<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
}
if (in_array($massaction, array('presend', 'predelete', 'closed'))) {
$arrayofmassactions = array();
}
$massactionbutton = $form->selectMassAction('', $arrayofmassactions);
$arrayofselected = is_array($toselect) ? $toselect : array();
$sql .= $db->plimit($limit + 1, $offset);
dol_syslog('accountancy/admin/account.php:: $sql='.$sql);
@ -338,8 +361,8 @@ if ($resql) {
print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
$newcardbutton .= dolGetButtonTitle($langs->trans("New"), $langs->trans("Addanaccount"), 'fa fa-plus-circle', './card.php?action=create');
print_barre_liste($langs->trans('ListAccounts'), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
print_barre_liste($langs->trans('ListAccounts'), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
// Box to select active chart of account
print $langs->trans("Selectchartofaccounts")." : ";
@ -376,9 +399,9 @@ if ($resql) {
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
$moreforfilter = '';
$massactionbutton = '';
print '<div class="div-table-responsive">';
print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
@ -411,34 +434,41 @@ if ($resql) {
print '<td class="liste_titre">&nbsp;</td>';
}
print '<td class="liste_titre maxwidthsearch">';
$searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
$searchpicto = $form->showFilterButtons();
print $searchpicto;
print '</td>';
print '</tr>';
$totalarray = array();
print '<tr class="liste_titre">';
if (!empty($arrayfields['aa.account_number']['checked'])) {
print_liste_field_titre($arrayfields['aa.account_number']['label'], $_SERVER["PHP_SELF"], "aa.account_number", "", $param, '', $sortfield, $sortorder);
$totalarray['nbfield']++;
}
if (!empty($arrayfields['aa.label']['checked'])) {
print_liste_field_titre($arrayfields['aa.label']['label'], $_SERVER["PHP_SELF"], "aa.label", "", $param, '', $sortfield, $sortorder);
$totalarray['nbfield']++;
}
if (!empty($arrayfields['aa.labelshort']['checked'])) {
print_liste_field_titre($arrayfields['aa.labelshort']['label'], $_SERVER["PHP_SELF"], "aa.labelshort", "", $param, '', $sortfield, $sortorder);
$totalarray['nbfield']++;
}
if (!empty($arrayfields['aa.account_parent']['checked'])) {
print_liste_field_titre($arrayfields['aa.account_parent']['label'], $_SERVER["PHP_SELF"], "aa.account_parent", "", $param, '', $sortfield, $sortorder, 'left ');
$totalarray['nbfield']++;
}
if (!empty($arrayfields['aa.pcg_type']['checked'])) {
print_liste_field_titre($arrayfields['aa.pcg_type']['label'], $_SERVER["PHP_SELF"], 'aa.pcg_type', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.pcg_type']['help'], 1);
print_liste_field_titre($arrayfields['aa.pcg_type']['label'], $_SERVER["PHP_SELF"], 'aa.pcg_type,aa.account_number', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.pcg_type']['help'], 1);
$totalarray['nbfield']++;
}
if ($conf->global->MAIN_FEATURES_LEVEL >= 2) {
if (!empty($arrayfields['aa.reconcilable']['checked'])) {
print_liste_field_titre($arrayfields['aa.reconcilable']['label'], $_SERVER["PHP_SELF"], 'aa.reconcilable', '', $param, '', $sortfield, $sortorder);
$totalarray['nbfield']++;
}
}
if (!empty($arrayfields['aa.active']['checked'])) {
print_liste_field_titre($arrayfields['aa.active']['label'], $_SERVER["PHP_SELF"], 'aa.active', '', $param, '', $sortfield, $sortorder);
$totalarray['nbfield']++;
}
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
print "</tr>\n";
@ -446,7 +476,6 @@ if ($resql) {
$accountstatic = new AccountingAccount($db);
$accountparent = new AccountingAccount($db);
$totalarray = array();
$i = 0;
while ($i < min($num, $limit)) {
$obj = $db->fetch_object($resql);
@ -563,7 +592,7 @@ if ($resql) {
}
// Action
print '<td class="center">';
print '<td class="center nowraponall">';
if ($user->rights->accounting->chartofaccount) {
print '<a class="editfielda" href="./card.php?action=update&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'">';
print img_edit();
@ -572,6 +601,14 @@ if ($resql) {
print '<a class="marginleftonly" href="./card.php?action=delete&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'">';
print img_delete();
print '</a>';
print '&nbsp;';
if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
$selected = 0;
if (in_array($obj->rowid, $arrayofselected)) {
$selected = 1;
}
print '<input id="cb'.$obj->rowid.'" class="flat checkforselect marginleftonly" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
}
}
print '</td>'."\n";
if (!$i) {
@ -583,6 +620,7 @@ if ($resql) {
}
if ($num == 0) {
$totalarray['nbfield']++;
print '<tr><td colspan="'.$totalarray['nbfield'].'"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
}

View File

@ -54,8 +54,8 @@ $code = GETPOST('code', 'alpha');
$acts[0] = "activate";
$acts[1] = "disable";
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on');
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off', 'class="size15x"');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on', 'class="size15x"');
$listoffset = GETPOST('listoffset', 'alpha');
$listlimit = GETPOST('listlimit', 'int') > 0 ?GETPOST('listlimit', 'int') : 1000;
@ -442,7 +442,7 @@ if ($id) {
} else {
$sql .= " WHERE ";
}
$sql .= " c.rowid = ".$search_country_id;
$sql .= " c.rowid = ".((int) $search_country_id);
}
// If sort order is "country", we use country_code instead
@ -609,10 +609,12 @@ if ($id) {
print '</tr>';
if ($num) {
$i = 0;
// Lines with values
while ($i < $num) {
$obj = $db->fetch_object($resql);
//print_r($obj);
print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
if ($action == 'edit' && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">';
@ -708,6 +710,7 @@ if ($id) {
print "</tr>\n";
}
$i++;
}
}

View File

@ -34,7 +34,6 @@ $error = 0;
// Load translation files required by the page
$langs->loadLangs(array("bills", "accountancy", "compta"));
$mesg = '';
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
$id = GETPOST('id', 'int');
@ -139,7 +138,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
} else {
$result = $object->fetch($id);
$sql = 'SELECT pcg_version FROM ' . MAIN_DB_PREFIX . 'accounting_system WHERE rowid=' . $conf->global->CHARTOFACCOUNTS;
$sql = 'SELECT pcg_version FROM '.MAIN_DB_PREFIX.'accounting_system WHERE rowid='.((int) $conf->global->CHARTOFACCOUNTS);
dol_syslog('accountancy/admin/card.php:: $sql=' . $sql);
$result2 = $db->query($sql);
@ -148,7 +147,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
// Clean code
// To manage zero or not at the end of the accounting account
if ($conf->global->ACCOUNTING_MANAGE_ZERO == 1) {
if (isset($conf->global->ACCOUNTING_MANAGE_ZERO) && $conf->global->ACCOUNTING_MANAGE_ZERO == 1) {
$account_number = $account_number;
} else {
$account_number = clean_account($account_number);
@ -169,13 +168,12 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
$object->labelshort = GETPOST('labelshort', 'alpha');
$result = $object->update($user);
if ($result > 0) {
$urltogo = $backtopage ? $backtopage : ($_SERVER["PHP_SELF"] . "?id=" . $id);
header("Location: " . $urltogo);
exit();
} else {
$mesg = $object->error;
setEventMessages($object->error, null, 'errors');
}
}
} else {
@ -255,13 +253,17 @@ if ($action == 'create') {
print '</td></tr>';
// Chart of accounts type
print '<tr><td>'.$langs->trans("Pcgtype").'</td>';
print '<tr><td>';
print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
print '</td>';
print '<td>';
print '<input type="text" name="pcg_type" value="'.dol_escape_htmltag(GETPOSTISSET('pcg_type') ? GETPOST('pcg_type', 'alpha') : $object->pcg_type).'">';
print '</td></tr>';
// Category
print '<tr><td>'.$langs->trans("AccountingCategory").'</td>';
print '<tr><td>';
print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
print '</td>';
print '<td>';
$formaccounting->select_accounting_category($object->account_category, 'account_category', 1, 0, 1);
print '</td></tr>';
@ -281,8 +283,6 @@ if ($action == 'create') {
$result = $object->fetch($id, $ref, 1);
if ($result > 0) {
dol_htmloutput_mesg($mesg);
$head = accounting_prepare_head($object);
// Edit mode
@ -316,13 +316,17 @@ if ($action == 'create') {
print '</td></tr>';
// Chart of accounts type
print '<tr><td>'.$langs->trans("Pcgtype").'</td>';
print '<tr><td>';
print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
print '</td>';
print '<td>';
print '<input type="text" name="pcg_type" value="'.dol_escape_htmltag(GETPOSTISSET('pcg_type') ? GETPOST('pcg_type', 'alpha') : $object->pcg_type).'">';
print '</td></tr>';
// Category
print '<tr><td>'.$langs->trans("AccountingCategory").'</td>';
print '<tr><td>';
print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
print '</td>';
print '<td>';
$formaccounting->select_accounting_category($object->account_category, 'account_category', 1);
print '</td></tr>';
@ -368,13 +372,17 @@ if ($action == 'create') {
print '<tr><td>'.$langs->trans("Accountparent").'</td>';
print '<td colspan="2">'.$accp->account_number.' - '.$accp->label.'</td></tr>';
// Category
print "<tr><td>".$langs->trans("AccountingCategory")."</td><td colspan='2'>".$object->account_category_label."</td>";
// Chart of accounts type
print '<tr><td>'.$langs->trans("Pcgtype").'</td>';
// Group of accounting account
print '<tr><td>';
print $form->textwithpicto($langs->trans("Pcgtype"), $langs->transnoentitiesnoconv("PcgtypeDesc"));
print '</td>';
print '<td colspan="2">'.$object->pcg_type.'</td></tr>';
// Custom group of accounting account
print "<tr><td>";
print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
print "</td><td colspan='2'>".$object->account_category_label."</td>";
print '</table>';
print '</div>';

View File

@ -32,9 +32,7 @@ $error = 0;
// Load translation files required by the page
$langs->loadLangs(array("bills", "accountancy"));
$mesg = '';
$id = GETPOST('id', 'int');
$rowid = GETPOST('rowid', 'int');
$cancel = GETPOST('cancel', 'alpha');
$action = GETPOST('action', 'aZ09');
$cat_id = GETPOST('account_category', 'int');
@ -57,7 +55,7 @@ $accountingcategory = new AccountancyCategory($db);
* Actions
*/
// si ajout de comptes
// If we add account
if (!empty($selectcpt)) {
$cpts = array();
foreach ($selectcpt as $selectedoption) {
@ -74,6 +72,7 @@ if (!empty($selectcpt)) {
setEventMessages($langs->trans('RecordModifiedSuccessfully'), null, 'mesgs');
}
}
if ($action == 'delete') {
if ($cpt_id) {
if ($accountingcategory->deleteCptCat($cpt_id)) {
@ -95,8 +94,9 @@ $formaccounting = new FormAccounting($db);
llxheader('', $langs->trans('AccountingCategory'));
$linkback = '<a href="'.DOL_URL_ROOT.'/accountancy/admin/categories_list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
$titlepicto = 'setup';
print load_fiche_titre($langs->trans('AccountingCategory'), $linkback);
print load_fiche_titre($langs->trans('AccountingCategory'), $linkback, $titlepicto);
print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
print '<input type="hidden" name="token" value="'.newToken().'">';

View File

@ -1,6 +1,6 @@
<?php
/* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2011-2017 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2011-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,6 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancycategory.class.php';
// Load translation files required by the page
$langs->loadLangs(array("errors", "admin", "companies", "resource", "holiday", "accountancy", "hrm"));
@ -47,12 +48,11 @@ if (empty($user->rights->accounting->chartofaccount)) {
$acts[0] = "activate";
$acts[1] = "disable";
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on');
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off', 'class="size15x"');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on', 'class="size15x"');
$listoffset = GETPOST('listoffset', 'alpha');
$listlimit = GETPOST('listlimit', 'int') > 0 ?GETPOST('listlimit', 'int') : 1000;
$active = 1;
$sortfield = GETPOST("sortfield", 'aZ09comma');
$sortorder = GETPOST("sortorder", 'aZ09comma');
@ -91,19 +91,19 @@ $tabsql[32] = "SELECT a.rowid as rowid, a.code as code, a.label, a.range_account
$tabsqlsort = array();
$tabsqlsort[32] = "position ASC";
// Nom des champs en resultat de select pour affichage du dictionnaire
// Name of the fields in the result of select to display the dictionary
$tabfield = array();
$tabfield[32] = "code,label,range_account,category_type,formula,position,country";
// Nom des champs d'edition pour modification d'un enregistrement
// Name of editing fields for record modification
$tabfieldvalue = array();
$tabfieldvalue[32] = "code,label,range_account,category_type,formula,position,country_id";
// Nom des champs dans la table pour insertion d'un enregistrement
// Name of the fields in the table for inserting a record
$tabfieldinsert = array();
$tabfieldinsert[32] = "code,label,range_account,category_type,formula,position,fk_country";
// Nom du rowid si le champ n'est pas de type autoincrement
// Name of the rowid if the field is not of type autoincrement
// Example: "" if id field is "rowid" and has autoincrement on
// "nameoffield" if id field is not "rowid" or has not autoincrement on
$tabrowid = array();
@ -124,11 +124,7 @@ $tabfieldcheck[32] = array();
// Complete all arrays with entries found into modules
complete_dictionary_with_modules($taborder, $tabname, $tablib, $tabsql, $tabsqlsort, $tabfield, $tabfieldvalue, $tabfieldinsert, $tabrowid, $tabcond, $tabhelp, $tabfieldcheck);
// Define elementList and sourceList (used for dictionary type of contacts "llx_c_type_contact")
$elementList = array();
$sourceList = array();
$accountingcategory = new AccountancyCategory($db);
/*
@ -155,7 +151,7 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
if ($value == 'range_account' && empty($_POST['range_account'])) {
continue;
}
if ($value == 'country' || $value == 'country_id') {
if (($value == 'country' || $value == 'country_id') && (!empty($_POST['country_id']))) {
continue;
}
if (!GETPOSTISSET($value) || GETPOST($value) == '') {
@ -180,6 +176,9 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
if ($fieldnamekey == 'category_type') {
$fieldnamekey = 'Calculated';
}
if ($fieldnamekey == 'country') {
$fieldnamekey = 'Country';
}
setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->transnoentities($fieldnamekey)), null, 'errors');
}
@ -247,7 +246,7 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
if ($_POST[$listfieldvalue[$i]] == '' && !$listfieldvalue[$i] == 'formula') {
$sql .= "null"; // For vat, we want/accept code = ''
} else {
$sql .= "'".$db->escape($_POST[$listfieldvalue[$i]])."'";
$sql .= "'".$db->escape(GETPOST($listfieldvalue[$i]))."'";
}
$i++;
}
@ -267,7 +266,7 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
}
}
// Si verif ok et action modify, on modifie la ligne
// If check ok and action modify, we modify the line
if ($ok && GETPOST('actionmodify', 'alpha')) {
if ($tabrowid[$id]) {
$rowidcol = $tabrowid[$id];
@ -428,437 +427,442 @@ llxHeader('', $langs->trans('DictionaryAccountancyCategory'));
$titre = $langs->trans($tablib[$id]);
$linkback = '';
$titlepicto = 'title_accountancy';
$titlepicto = 'setup';
print load_fiche_titre($titre, $linkback, $titlepicto);
print '<span class="opacitymedium">'.$langs->trans("AccountingAccountGroupsDesc", $langs->transnoentitiesnoconv("ByPersonalizedAccountGroups")).'</span><br><br>';
// Confirmation de la suppression de la ligne
// Confirmation of the deletion of the line
if ($action == 'delete') {
print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.$rowid.'&code='.$code.'&id='.$id.($search_country_id > 0 ? '&search_country_id='.$search_country_id : ''), $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete', '', 0, 1);
}
//var_dump($elementList);
/*
* Show a dictionary
*/
if ($id) {
// Complete requete recherche valeurs avec critere de tri
$sql = $tabsql[$id];
// Complete search query with sorting criteria
$sql = $tabsql[$id];
if ($search_country_id > 0) {
if (preg_match('/ WHERE /', $sql)) {
$sql .= " AND ";
} else {
$sql .= " WHERE ";
}
$sql .= " (a.fk_country = ".$search_country_id." OR a.fk_country = 0)";
if ($search_country_id > 0) {
if (preg_match('/ WHERE /', $sql)) {
$sql .= " AND ";
} else {
$sql .= " WHERE ";
}
$sql .= " (a.fk_country = ".((int) $search_country_id)." OR a.fk_country = 0)";
}
// If sort order is "country", we use country_code instead
if ($sortfield == 'country') {
$sortfield = 'country_code';
}
$sql .= $db->order($sortfield, $sortorder);
$sql .= $db->plimit($listlimit + 1, $offset);
//print $sql;
// If sort order is "country", we use country_code instead
if ($sortfield == 'country') {
$sortfield = 'country_code';
}
$sql .= $db->order($sortfield, $sortorder);
$sql .= $db->plimit($listlimit + 1, $offset);
//print $sql;
$fieldlist = explode(',', $tabfield[$id]);
print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="from" value="'.dol_escape_htmltag(GETPOST('from', 'alpha')).'">';
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
// Form to add a new line
if ($tabname[$id]) {
$fieldlist = explode(',', $tabfield[$id]);
print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="from" value="'.dol_escape_htmltag(GETPOST('from', 'alpha')).'">';
// Line for title
print '<tr class="liste_titre">';
foreach ($fieldlist as $field => $value) {
// Determine le nom du champ par rapport aux noms possibles
// dans les dictionnaires de donnees
$valuetoshow = ucfirst($fieldlist[$field]); // Par defaut
$valuetoshow = $langs->trans($valuetoshow); // try to translate
$class = "left";
if ($fieldlist[$field] == 'type') {
if ($tabname[$id] == MAIN_DB_PREFIX."c_paiement") {
$valuetoshow = $form->textwithtooltip($langs->trans("Type"), $langs->trans("TypePaymentDesc"), 2, 1, img_help(1, ''));
} else {
$valuetoshow = $langs->trans("Type");
}
}
if ($fieldlist[$field] == 'code') {
$valuetoshow = $langs->trans("Code");
}
if ($fieldlist[$field] == 'libelle' || $fieldlist[$field] == 'label') {
$valuetoshow = $langs->trans("Label");
}
if ($fieldlist[$field] == 'libelle_facture') {
$valuetoshow = $langs->trans("LabelOnDocuments");
}
if ($fieldlist[$field] == 'country') {
$valuetoshow = $langs->trans("Country");
}
if ($fieldlist[$field] == 'accountancy_code') {
$valuetoshow = $langs->trans("AccountancyCode");
}
if ($fieldlist[$field] == 'accountancy_code_sell') {
$valuetoshow = $langs->trans("AccountancyCodeSell");
}
if ($fieldlist[$field] == 'accountancy_code_buy') {
$valuetoshow = $langs->trans("AccountancyCodeBuy");
}
if ($fieldlist[$field] == 'pcg_version' || $fieldlist[$field] == 'fk_pcg_version') {
$valuetoshow = $langs->trans("Pcg_version");
}
if ($fieldlist[$field] == 'range_account') {
$valuetoshow = $langs->trans("Comment");
}
if ($fieldlist[$field] == 'category_type') {
$valuetoshow = $langs->trans("Calculated");
}
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
if ($valuetoshow != '') {
print '<td class="'.$class.'">';
if (!empty($tabhelp[$id][$value]) && preg_match('/^http(s*):/i', $tabhelp[$id][$value])) {
print '<a href="'.$tabhelp[$id][$value].'" target="_blank">'.$valuetoshow.' '.img_help(1, $valuetoshow).'</a>';
} elseif (!empty($tabhelp[$id][$value])) {
print $form->textwithpicto($valuetoshow, $tabhelp[$id][$value]);
} else {
print $valuetoshow;
}
print '</td>';
}
}
// Form to add a new line
if ($tabname[$id]) {
$fieldlist = explode(',', $tabfield[$id]);
print '<td>';
print '<input type="hidden" name="id" value="'.$id.'">';
print '</td>';
print '<td style="min-width: 26px;"></td>';
print '<td style="min-width: 26px;"></td>';
print '<td style="min-width: 26px;"></td>';
print '</tr>';
// Line for title
print '<tr class="liste_titre">';
foreach ($fieldlist as $field => $value) {
// Determine le nom du champ par rapport aux noms possibles
// dans les dictionnaires de donnees
$valuetoshow = ucfirst($fieldlist[$field]); // Par defaut
$valuetoshow = $langs->trans($valuetoshow); // try to translate
$class = "left";
if ($fieldlist[$field] == 'type') {
if ($tabname[$id] == MAIN_DB_PREFIX."c_paiement") {
$valuetoshow = $form->textwithtooltip($langs->trans("Type"), $langs->trans("TypePaymentDesc"), 2, 1, img_help(1, ''));
} else {
$valuetoshow = $langs->trans("Type");
// Line to enter new values
print '<tr class="oddeven nodrag nodrop nohover">';
$obj = new stdClass();
// If data was already input, we define them in obj to populate input fields.
if (GETPOST('actionadd', 'alpha')) {
foreach ($fieldlist as $key => $val) {
if (GETPOST($val) != '') {
$obj->$val = GETPOST($val);
}
}
}
$tmpaction = 'create';
$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('createDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
if (empty($reshook)) {
fieldListAccountingCategories($fieldlist, $obj, $tabname[$id], 'add');
}
print '<td colspan="4" class="right">';
print '<input type="submit" class="button" name="actionadd" value="'.$langs->trans("Add").'">';
print '</td>';
print "</tr>";
$colspan = count($fieldlist) + 3;
if ($id == 32) {
$colspan++;
}
print '<tr><td colspan="'.$colspan.'">&nbsp;</td></tr>'; // Keep &nbsp; to have a line with enough height
}
// List of available record in database
dol_syslog("htdocs/accountancy/admin/categories_list.php", LOG_DEBUG);
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
$i = 0;
$param = '&id='.$id;
if ($search_country_id > 0) {
$param .= '&search_country_id='.$search_country_id;
}
$paramwithsearch = $param;
if ($sortorder) {
$paramwithsearch .= '&sortorder='.$sortorder;
}
if ($sortfield) {
$paramwithsearch .= '&sortfield='.$sortfield;
}
if (GETPOST('from', 'alpha')) {
$paramwithsearch .= '&from='.GETPOST('from', 'alpha');
}
// There is several pages
if ($num > $listlimit) {
print '<tr class="none"><td class="right" colspan="'.(3 + count($fieldlist)).'">';
print_fleche_navigation($page, $_SERVER["PHP_SELF"], $paramwithsearch, ($num > $listlimit), '<li class="pagination"><span>'.$langs->trans("Page").' '.($page + 1).'</span></li>');
print '</td></tr>';
}
// Title line with search boxes
print '<tr class="liste_titre liste_titre_add liste_titre_filter">';
$filterfound = 0;
foreach ($fieldlist as $field => $value) {
$showfield = 1; // By defaut
if ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
if ($showfield) {
if ($value == 'country') {
print '<td class="liste_titre">';
print $form->select_country($search_country_id, 'search_country_id', '', 28, 'maxwidth200 maxwidthonsmartphone');
print '</td>';
$filterfound++;
} else {
print '<td class="liste_titre"></td>';
}
}
}
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre center">';
if ($filterfound) {
$searchpicto = $form->showFilterAndCheckAddButtons(0);
print $searchpicto;
}
print '</td>';
print '</tr>';
// Title of lines
print '<tr class="liste_titre">';
foreach ($fieldlist as $field => $value) {
// Determines the name of the field in relation to the possible names
// in data dictionaries
$showfield = 1; // By default
$class = "left";
$sortable = 1;
$valuetoshow = '';
$valuetoshow = ucfirst($fieldlist[$field]); // By default
$valuetoshow = $langs->trans($valuetoshow); // try to translate
if ($fieldlist[$field] == 'source') {
$valuetoshow = $langs->trans("Contact");
}
if ($fieldlist[$field] == 'price') {
$valuetoshow = $langs->trans("PriceUHT");
}
if ($fieldlist[$field] == 'taux') {
if ($tabname[$id] != MAIN_DB_PREFIX."c_revenuestamp") {
$valuetoshow = $langs->trans("Rate");
} else {
$valuetoshow = $langs->trans("Amount");
}
$class = 'center';
}
if ($fieldlist[$field] == 'type') {
$valuetoshow = $langs->trans("Type");
}
if ($fieldlist[$field] == 'code') {
$valuetoshow = $langs->trans("Code");
}
if ($fieldlist[$field] == 'libelle' || $fieldlist[$field] == 'label') {
$valuetoshow = $langs->trans("Label");
}
if ($fieldlist[$field] == 'country') {
$valuetoshow = $langs->trans("Country");
}
if ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
if ($fieldlist[$field] == 'accountancy_code') {
$valuetoshow = $langs->trans("AccountancyCode");
}
if ($fieldlist[$field] == 'accountancy_code_sell') {
$valuetoshow = $langs->trans("AccountancyCodeSell");
$sortable = 0;
}
if ($fieldlist[$field] == 'accountancy_code_buy') {
$valuetoshow = $langs->trans("AccountancyCodeBuy");
$sortable = 0;
}
if ($fieldlist[$field] == 'fk_pcg_version') {
$valuetoshow = $langs->trans("Pcg_version");
}
if ($fieldlist[$field] == 'account_parent') {
$valuetoshow = $langs->trans("Accountsparent");
}
if ($fieldlist[$field] == 'pcg_type') {
$valuetoshow = $langs->trans("Pcg_type");
}
if ($fieldlist[$field] == 'type_template') {
$valuetoshow = $langs->trans("TypeOfTemplate");
}
if ($fieldlist[$field] == 'range_account') {
$valuetoshow = $langs->trans("Comment");
}
if ($fieldlist[$field] == 'category_type') {
$valuetoshow = $langs->trans("Calculated");
}
// Affiche nom du champ
if ($showfield) {
print getTitleFieldOfList($valuetoshow, 0, $_SERVER["PHP_SELF"], ($sortable ? $fieldlist[$field] : ''), ($page ? 'page='.$page.'&' : ''), $param, "", $sortfield, $sortorder, $class.' ');
}
}
print getTitleFieldOfList($langs->trans("Status"), 0, $_SERVER["PHP_SELF"], "active", ($page ? 'page='.$page.'&' : ''), $param, '', $sortfield, $sortorder, 'center ');
print getTitleFieldOfList('');
print getTitleFieldOfList('');
print getTitleFieldOfList('');
print '</tr>';
if ($num) {
// Lines with values
while ($i < $num) {
$obj = $db->fetch_object($resql);
//print_r($obj);
print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
if ($action == 'edit' && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
$tmpaction = 'edit';
$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('editDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
// Show fields
if (empty($reshook)) {
fieldListAccountingCategories($fieldlist, $obj, $tabname[$id], 'edit');
}
}
if ($fieldlist[$field] == 'code') {
$valuetoshow = $langs->trans("Code");
}
if ($fieldlist[$field] == 'libelle' || $fieldlist[$field] == 'label') {
$valuetoshow = $langs->trans("Label");
}
if ($fieldlist[$field] == 'libelle_facture') {
$valuetoshow = $langs->trans("LabelOnDocuments");
}
if ($fieldlist[$field] == 'country') {
$valuetoshow = $langs->trans("Country");
}
if ($fieldlist[$field] == 'accountancy_code') {
$valuetoshow = $langs->trans("AccountancyCode");
}
if ($fieldlist[$field] == 'accountancy_code_sell') {
$valuetoshow = $langs->trans("AccountancyCodeSell");
}
if ($fieldlist[$field] == 'accountancy_code_buy') {
$valuetoshow = $langs->trans("AccountancyCodeBuy");
}
if ($fieldlist[$field] == 'pcg_version' || $fieldlist[$field] == 'fk_pcg_version') {
$valuetoshow = $langs->trans("Pcg_version");
}
if ($fieldlist[$field] == 'range_account') {
$valuetoshow = $langs->trans("Comment");
}
if ($fieldlist[$field] == 'category_type') {
$valuetoshow = $langs->trans("Calculated");
}
if ($valuetoshow != '') {
print '<td class="'.$class.'">';
if (!empty($tabhelp[$id][$value]) && preg_match('/^http(s*):/i', $tabhelp[$id][$value])) {
print '<a href="'.$tabhelp[$id][$value].'" target="_blank">'.$valuetoshow.' '.img_help(1, $valuetoshow).'</a>';
} elseif (!empty($tabhelp[$id][$value])) {
print $form->textwithpicto($valuetoshow, $tabhelp[$id][$value]);
print '<td></td>';
print '<td></td>';
print '<td class="center">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">';
print '<input type="submit" class="button" name="actionmodify" value="'.$langs->trans("Modify").'">';
print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
print '<input type="submit" class="button button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</td>';
print '<td></td>';
} else {
$tmpaction = 'view';
$parameters = array('var'=>$var, 'fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('viewDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
if (empty($reshook)) {
foreach ($fieldlist as $field => $value) {
$showfield = 1;
$class = "left";
$valuetoshow = $obj->{$fieldlist[$field]};
if ($value == 'category_type') {
$valuetoshow = yn($valuetoshow);
} elseif ($valuetoshow == 'all') {
$valuetoshow = $langs->trans('All');
} elseif ($fieldlist[$field] == 'country') {
if (empty($obj->country_code)) {
$valuetoshow = '-';
} else {
$key = $langs->trans("Country".strtoupper($obj->country_code));
$valuetoshow = ($key != "Country".strtoupper($obj->country_code) ? $obj->country_code." - ".$key : $obj->country);
}
} elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_country') {
$key = $langs->trans("Country".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "Country".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_availability') {
$langs->loadLangs(array("propal"));
$key = $langs->trans("AvailabilityType".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "AvailabilityType".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'libelle' && $tabname[$id] == MAIN_DB_PREFIX.'c_actioncomm') {
$key = $langs->trans("Action".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "Action".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
$class = 'tddict';
// Show value for field
if ($showfield) {
print '<!-- '.$fieldlist[$field].' --><td class="'.$class.'">'.dol_escape_htmltag($valuetoshow).'</td>';
}
}
}
// Can an entry be erased or disabled ?
$iserasable = 1; $canbedisabled = 1; $canbemodified = 1; // true by default
if (isset($obj->code)) {
if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) {
$iserasable = 0; $canbedisabled = 0;
}
}
$canbemodified = $iserasable;
$url = $_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.(!empty($obj->rowid) ? $obj->rowid : (!empty($obj->code) ? $obj->code : '')).'&code='.(!empty($obj->code) ?urlencode($obj->code) : '');
if ($param) {
$url .= '&'.$param;
}
$url .= '&';
// Active
print '<td class="center" class="nowrap">';
if ($canbedisabled) {
print '<a href="'.$url.'action='.$acts[$obj->active].'">'.$actl[$obj->active].'</a>';
} else {
print $valuetoshow;
print $langs->trans("AlwaysActive");
}
print "</td>";
// Modify link
if ($canbemodified) {
print '<td class="center"><a class="reposition editfielda" href="'.$url.'action=edit">'.img_edit().'</a></td>';
} else {
print '<td>&nbsp;</td>';
}
// Delete link
if ($iserasable) {
print '<td class="center">';
if ($user->admin) {
print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
}
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
} else {
print '<td>&nbsp;</td>';
}
// Link to setup the group
print '<td class="center">';
if (empty($obj->formula)) {
print '<a href="'.DOL_URL_ROOT.'/accountancy/admin/categories.php?action=display&save_lastsearch_values=1&account_category='.$obj->rowid.'">';
print $langs->trans("ListOfAccounts");
print '</a>';
// Count number of accounts into group
$nbofaccountintogroup = 0;
$listofaccountintogroup = $accountingcategory->getCptsCat($obj->rowid);
$nbofaccountintogroup = count($listofaccountintogroup);
//if ($nbofaccountintogroup > 0) {
print ' <span class="opacitymedium">('.$langs->trans("NAccounts", $nbofaccountintogroup).')</span>';
//} else {
// print ' <span class="opacitymedium">(0)</span>';
//}
}
print '</td>';
}
print "</tr>\n";
$i++;
}
print '<td>';
print '<input type="hidden" name="id" value="'.$id.'">';
print '</td>';
print '<td style="min-width: 26px;"></td>';
print '<td style="min-width: 26px;"></td>';
print '<td style="min-width: 26px;"></td>';
print '</tr>';
// Line to enter new values
print '<tr class="oddeven nodrag nodrop nohover">';
$obj = new stdClass();
// If data was already input, we define them in obj to populate input fields.
if (GETPOST('actionadd', 'alpha')) {
foreach ($fieldlist as $key => $val) {
if (GETPOST($val) != '') {
$obj->$val = GETPOST($val);
}
}
}
$tmpaction = 'create';
$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('createDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
if (empty($reshook)) {
fieldListAccountingCategories($fieldlist, $obj, $tabname[$id], 'add');
}
print '<td colspan="4" class="right">';
print '<input type="submit" class="button" name="actionadd" value="'.$langs->trans("Add").'">';
print '</td>';
print "</tr>";
$colspan = count($fieldlist) + 3;
if ($id == 32) {
$colspan++;
}
print '<tr><td colspan="'.$colspan.'">&nbsp;</td></tr>'; // Keep &nbsp; to have a line with enough height
}
// List of available record in database
dol_syslog("htdocs/admin/dict", LOG_DEBUG);
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
$i = 0;
$param = '&id='.$id;
if ($search_country_id > 0) {
$param .= '&search_country_id='.$search_country_id;
}
$paramwithsearch = $param;
if ($sortorder) {
$paramwithsearch .= '&sortorder='.$sortorder;
}
if ($sortfield) {
$paramwithsearch .= '&sortfield='.$sortfield;
}
if (GETPOST('from', 'alpha')) {
$paramwithsearch .= '&from='.GETPOST('from', 'alpha');
}
// There is several pages
if ($num > $listlimit) {
print '<tr class="none"><td class="right" colspan="'.(3 + count($fieldlist)).'">';
print_fleche_navigation($page, $_SERVER["PHP_SELF"], $paramwithsearch, ($num > $listlimit), '<li class="pagination"><span>'.$langs->trans("Page").' '.($page + 1).'</span></li>');
print '</td></tr>';
}
// Title line with search boxes
print '<tr class="liste_titre liste_titre_add liste_titre_filter">';
$filterfound = 0;
foreach ($fieldlist as $field => $value) {
$showfield = 1; // By defaut
if ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
if ($showfield) {
if ($value == 'country') {
print '<td class="liste_titre">';
print $form->select_country($search_country_id, 'search_country_id', '', 28, 'maxwidth200 maxwidthonsmartphone');
print '</td>';
$filterfound++;
} else {
print '<td class="liste_titre"></td>';
}
}
}
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>';
print '<td class="liste_titre center">';
if ($filterfound) {
$searchpicto = $form->showFilterAndCheckAddButtons(0);
print $searchpicto;
}
print '</td>';
print '</tr>';
// Title of lines
print '<tr class="liste_titre">';
foreach ($fieldlist as $field => $value) {
// Determine le nom du champ par rapport aux noms possibles
// dans les dictionnaires de donnees
$showfield = 1; // By defaut
$class = "left";
$sortable = 1;
$valuetoshow = '';
$valuetoshow = ucfirst($fieldlist[$field]); // By defaut
$valuetoshow = $langs->trans($valuetoshow); // try to translate
if ($fieldlist[$field] == 'source') {
$valuetoshow = $langs->trans("Contact");
}
if ($fieldlist[$field] == 'price') {
$valuetoshow = $langs->trans("PriceUHT");
}
if ($fieldlist[$field] == 'taux') {
if ($tabname[$id] != MAIN_DB_PREFIX."c_revenuestamp") {
$valuetoshow = $langs->trans("Rate");
} else {
$valuetoshow = $langs->trans("Amount");
}
$class = 'center';
}
if ($fieldlist[$field] == 'type') {
$valuetoshow = $langs->trans("Type");
}
if ($fieldlist[$field] == 'code') {
$valuetoshow = $langs->trans("Code");
}
if ($fieldlist[$field] == 'libelle' || $fieldlist[$field] == 'label') {
$valuetoshow = $langs->trans("Label");
}
if ($fieldlist[$field] == 'country') {
$valuetoshow = $langs->trans("Country");
}
if ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
if ($fieldlist[$field] == 'accountancy_code') {
$valuetoshow = $langs->trans("AccountancyCode");
}
if ($fieldlist[$field] == 'accountancy_code_sell') {
$valuetoshow = $langs->trans("AccountancyCodeSell");
$sortable = 0;
}
if ($fieldlist[$field] == 'accountancy_code_buy') {
$valuetoshow = $langs->trans("AccountancyCodeBuy");
$sortable = 0;
}
if ($fieldlist[$field] == 'fk_pcg_version') {
$valuetoshow = $langs->trans("Pcg_version");
}
if ($fieldlist[$field] == 'account_parent') {
$valuetoshow = $langs->trans("Accountsparent");
}
if ($fieldlist[$field] == 'pcg_type') {
$valuetoshow = $langs->trans("Pcg_type");
}
if ($fieldlist[$field] == 'type_template') {
$valuetoshow = $langs->trans("TypeOfTemplate");
}
if ($fieldlist[$field] == 'range_account') {
$valuetoshow = $langs->trans("Comment");
}
if ($fieldlist[$field] == 'category_type') {
$valuetoshow = $langs->trans("Calculated");
}
// Affiche nom du champ
if ($showfield) {
print getTitleFieldOfList($valuetoshow, 0, $_SERVER["PHP_SELF"], ($sortable ? $fieldlist[$field] : ''), ($page ? 'page='.$page.'&' : ''), $param, "", $sortfield, $sortorder, $class.' ');
}
}
print getTitleFieldOfList($langs->trans("Status"), 0, $_SERVER["PHP_SELF"], "active", ($page ? 'page='.$page.'&' : ''), $param, '', $sortfield, $sortorder, 'center ');
print getTitleFieldOfList('');
print getTitleFieldOfList('');
print getTitleFieldOfList('');
print '</tr>';
if ($num) {
// Lines with values
while ($i < $num) {
$obj = $db->fetch_object($resql);
//print_r($obj);
print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
if ($action == 'edit' && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
$tmpaction = 'edit';
$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('editDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
// Show fields
if (empty($reshook)) {
fieldListAccountingCategories($fieldlist, $obj, $tabname[$id], 'edit');
}
print '<td></td>';
print '<td></td>';
print '<td class="center">';
print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">';
print '<input type="submit" class="button" name="actionmodify" value="'.$langs->trans("Modify").'">';
print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
print '<input type="submit" class="button button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</td>';
print '<td></td>';
} else {
$tmpaction = 'view';
$parameters = array('var'=>$var, 'fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
$reshook = $hookmanager->executeHooks('viewDictionaryFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
$error = $hookmanager->error; $errors = $hookmanager->errors;
if (empty($reshook)) {
foreach ($fieldlist as $field => $value) {
$showfield = 1;
$class = "left";
$valuetoshow = $obj->{$fieldlist[$field]};
if ($value == 'category_type') {
$valuetoshow = yn($valuetoshow);
} elseif ($valuetoshow == 'all') {
$valuetoshow = $langs->trans('All');
} elseif ($fieldlist[$field] == 'country') {
if (empty($obj->country_code)) {
$valuetoshow = '-';
} else {
$key = $langs->trans("Country".strtoupper($obj->country_code));
$valuetoshow = ($key != "Country".strtoupper($obj->country_code) ? $obj->country_code." - ".$key : $obj->country);
}
} elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_country') {
$key = $langs->trans("Country".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "Country".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'label' && $tabname[$id] == MAIN_DB_PREFIX.'c_availability') {
$langs->loadLangs(array("propal"));
$key = $langs->trans("AvailabilityType".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "AvailabilityType".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'libelle' && $tabname[$id] == MAIN_DB_PREFIX.'c_actioncomm') {
$key = $langs->trans("Action".strtoupper($obj->code));
$valuetoshow = ($obj->code && $key != "Action".strtoupper($obj->code) ? $key : $obj->{$fieldlist[$field]});
} elseif ($fieldlist[$field] == 'region_id' || $fieldlist[$field] == 'country_id') {
$showfield = 0;
}
$class = 'tddict';
// Show value for field
if ($showfield) {
print '<!-- '.$fieldlist[$field].' --><td class="'.$class.'">'.$valuetoshow.'</td>';
}
}
}
// Can an entry be erased or disabled ?
$iserasable = 1; $canbedisabled = 1; $canbemodified = 1; // true by default
if (isset($obj->code)) {
if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) {
$iserasable = 0; $canbedisabled = 0;
}
}
$canbemodified = $iserasable;
$url = $_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.(!empty($obj->rowid) ? $obj->rowid : (!empty($obj->code) ? $obj->code : '')).'&code='.(!empty($obj->code) ?urlencode($obj->code) : '');
if ($param) {
$url .= '&'.$param;
}
$url .= '&';
// Active
print '<td class="center" class="nowrap">';
if ($canbedisabled) {
print '<a href="'.$url.'action='.$acts[$obj->active].'">'.$actl[$obj->active].'</a>';
} else {
print $langs->trans("AlwaysActive");
}
print "</td>";
// Modify link
if ($canbemodified) {
print '<td class="center"><a class="reposition editfielda" href="'.$url.'action=edit">'.img_edit().'</a></td>';
} else {
print '<td>&nbsp;</td>';
}
// Delete link
if ($iserasable) {
print '<td class="center">';
if ($user->admin) {
print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
}
//else print '<a href="#">'.img_delete().'</a>'; // Some dictionary can be edited by other profile than admin
print '</td>';
} else {
print '<td>&nbsp;</td>';
}
// Link to setup the group
print '<td class="center">';
if (empty($obj->formula)) {
print '<a href="'.DOL_URL_ROOT.'/accountancy/admin/categories.php?action=display&save_lastsearch_values=1&account_category='.$obj->rowid.'">';
print $langs->trans("ListOfAccounts");
print '</a>';
}
print '</td>';
}
print "</tr>\n";
$i++;
}
}
} else {
dol_print_error($db);
}
print '</table>';
print '</div>';
print '</form>';
} else {
dol_print_error($db);
}
print '</table>';
print '</div>';
print '</form>';
print '<br>';
// End of page
@ -879,9 +883,6 @@ function fieldListAccountingCategories($fieldlist, $obj = '', $tabname = '', $co
{
global $conf, $langs, $db;
global $form, $mysoc;
global $region_id;
global $elementList, $sourceList, $localtax_typeList;
global $bc;
$formadmin = new FormAdmin($db);
$formcompany = new FormCompany($db);

View File

@ -169,7 +169,7 @@ foreach ($list_account_main as $key) {
print '</td>';
// Value
print '<td>'; // Do not force class=right, or it align also the content of the select box
print $formaccounting->select_account($conf->global->$key, $key, 1, '', 1, 1);
print $formaccounting->select_account($conf->global->$key, $key, 1, '', 1, 1, 'minwidth100 maxwidth300 maxwidthonsmartphone', 'accountsmain');
print '</td>';
print '</tr>';
}
@ -186,7 +186,7 @@ foreach ($list_account as $key) {
print '<td width="50%">'.$label.'</td>';
// Value
print '<td>'; // Do not force class=right, or it align also the content of the select box
print $formaccounting->select_account($conf->global->$key, $key, 1, '', 1, 1);
print $formaccounting->select_account($conf->global->$key, $key, 1, '', 1, 1, 'minwidth100 maxwidth300 maxwidthonsmartphone', 'accounts');
print '</td>';
print '</tr>';
}

View File

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2013-2014 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2019 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2014-2015 Ari Elbaz (elarifr) <github@accedinfo.com>
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es>
@ -58,17 +58,39 @@ $list_binding = array(
'ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER'
);
$error = 0;
/*
* Actions
*/
if (in_array($action, array(
'setBANK_DISABLE_DIRECT_INPUT',
'setACCOUNTANCY_COMBO_FOR_AUX',
'setACCOUNTING_MANAGE_ZERO',
'setACCOUNTING_LIST_SORT_VENTILATION_TODO',
'setACCOUNTING_LIST_SORT_VENTILATION_DONE'))) {
$constname = preg_replace('/^set/', '', $action);
$constvalue = GETPOST('value', 'int');
$res = dolibarr_set_const($db, $constname, $constvalue, 'yesno', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'mesgs');
}
}
if ($action == 'update') {
$error = 0;
if (!$error) {
foreach ($list as $constname) {
$constvalue = GETPOST($constname, 'alpha');
if (!dolibarr_set_const($db, $constname, $constvalue, 'chaine', 0, '', $conf->entity)) {
$error++;
}
@ -236,7 +258,23 @@ llxHeader('', $title);
$linkback = '';
//$linkback = '<a href="' . DOL_URL_ROOT . '/admin/modules.php?restore_lastsearch_values=1">' . $langs->trans("BackToModuleList") . '</a>';
print load_fiche_titre($langs->trans('ConfigAccountingExpert'), $linkback, 'accountancy');
print load_fiche_titre($title, $linkback, 'accountancy');
// Show message if accountancy hidden options are activated to help to resolve some problems
if (!$user->admin) {
if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
print '<div class="info">' . $langs->trans("ConstantIsOn", "FACTURE_DEPOSITS_ARE_JUST_PAYMENTS") . '</div>';
}
if (!empty($conf->global->ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY)) {
print '<div class="info">' . $langs->trans("ConstantIsOn", "ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY") . '</div>';
}
if (!empty($conf->global->MAIN_COMPANY_PERENTITY_SHARED)) {
print '<div class="info">' . $langs->trans("ConstantIsOn", "MAIN_COMPANY_PERENTITY_SHARED") . '</div>';
}
if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
print '<div class="info">' . $langs->trans("ConstantIsOn", "MAIN_PRODUCT_PERENTITY_SHARED") . '</div>';
}
}
print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
print '<input type="hidden" name="token" value="'.newToken().'">';
@ -268,25 +306,27 @@ print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("BANK_DISABLE_DIRECT_INPUT").'</td>';
if (!empty($conf->global->BANK_DISABLE_DIRECT_INPUT)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&disabledirectinput&value=0">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setBANK_DISABLE_DIRECT_INPUT&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&disabledirectinput&value=1">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setBANK_DISABLE_DIRECT_INPUT&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTANCY_COMBO_FOR_AUX").'</td>';
print '<td>'.$langs->trans("ACCOUNTANCY_COMBO_FOR_AUX");
print ' - <span class="opacitymedium">'.$langs->trans("NotRecommended").'</span>';
print '</td>';
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&enablesubsidiarylist&value=0">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTANCY_COMBO_FOR_AUX&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&enablesubsidiarylist&value=1">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTANCY_COMBO_FOR_AUX&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
@ -295,11 +335,11 @@ print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_MANAGE_ZERO").'</td>';
if (!empty($conf->global->ACCOUNTING_MANAGE_ZERO)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&managezero&value=0">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_MANAGE_ZERO&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&managezero&value=1">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_MANAGE_ZERO&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
@ -336,11 +376,11 @@ print "</tr>\n";
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_LIST_SORT_VENTILATION_TODO").'</td>';
if (!empty($conf->global->ACCOUNTING_LIST_SORT_VENTILATION_TODO)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&listsorttodo&value=0">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_LIST_SORT_VENTILATION_TODO&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&listsorttodo&value=1">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_LIST_SORT_VENTILATION_TODO&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
@ -349,11 +389,11 @@ print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_LIST_SORT_VENTILATION_DONE").'</td>';
if (!empty($conf->global->ACCOUNTING_LIST_SORT_VENTILATION_DONE)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&listsortdone&value=0">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_LIST_SORT_VENTILATION_DONE&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&listsortdone&value=1">';
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setACCOUNTING_LIST_SORT_VENTILATION_DONE&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
@ -385,7 +425,7 @@ print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_DISABLE_BINDING_ON_SALES").'</td>';
if (!empty($conf->global->ACCOUNTING_DISABLE_BINDING_ON_SALES)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonsales&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print img_picto($langs->trans("Activated"), 'switch_on', '', false, 0, 0, '', 'warning');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonsales&value=1">';
@ -398,7 +438,7 @@ print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_DISABLE_BINDING_ON_PURCHASES").'</td>';
if (!empty($conf->global->ACCOUNTING_DISABLE_BINDING_ON_PURCHASES)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonpurchases&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print img_picto($langs->trans("Activated"), 'switch_on', '', false, 0, 0, '', 'warning');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonpurchases&value=1">';
@ -411,7 +451,7 @@ print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_DISABLE_BINDING_ON_EXPENSEREPORTS").'</td>';
if (!empty($conf->global->ACCOUNTING_DISABLE_BINDING_ON_EXPENSEREPORTS)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonexpensereports&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print img_picto($langs->trans("Activated"), 'switch_on', '', false, 0, 0, '', 'warning');
print '</a></td>';
} else {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setdisablebindingonexpensereports&value=1">';

View File

@ -51,8 +51,8 @@ if (empty($user->rights->accounting->chartofaccount)) {
$acts[0] = "activate";
$acts[1] = "disable";
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on');
$actl[0] = img_picto($langs->trans("Disabled"), 'switch_off', 'class="size15x"');
$actl[1] = img_picto($langs->trans("Activated"), 'switch_on', 'class="size15x"');
$listoffset = GETPOST('listoffset', 'alpha');
$listlimit = GETPOST('listlimit', 'int') > 0 ?GETPOST('listlimit', 'int') : 1000;

View File

@ -183,21 +183,38 @@ if ($action == 'update') {
}
if ($result <= 0) {
// setEventMessages(null, $accounting->errors, 'errors');
$msg .= '<div><span style="color:red">'.$langs->trans("ErrorDB").' : '.$langs->trans("Product").' '.$productid.' '.$langs->trans("NotVentilatedinAccount").' : id='.$accounting_account_id.'<br/> <pre>'.$sql.'</pre></span></div>';
$msg .= '<div><span style="color:red">'.$langs->trans("ErrorDB").' : '.$langs->trans("Product").' '.$productid.' '.$langs->trans("NotVentilatedinAccount").' : id='.$accounting_account_id.'<br> <pre>'.$sql.'</pre></span></div>';
$ko++;
} else {
$db->begin();
$sql = '';
if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_perentity (fk_product, entity, '".$db->escape($accountancy_field_name)."')";
$sql .= " VALUES (".((int) $productid).", ".((int) $conf->entity).", '".$db->escape($accounting->account_number)."')";
$sql .= " ON DUPLICATE KEY UPDATE ".$accountancy_field_name." = '".$db->escape($accounting->account_number)."'";
$sql_exists = "SELECT rowid FROM " . MAIN_DB_PREFIX . "product_perentity";
$sql_exists .= " WHERE fk_product = " . ((int) $productid) . " AND entity = " . ((int) $conf->entity);
$resql_exists = $db->query($sql_exists);
if (!$resql_exists) {
$msg .= '<div><span style="color:red">'.$langs->trans("ErrorDB").' : '.$langs->trans("Product").' '.$productid.' '.$langs->trans("NotVentilatedinAccount").' : id='.$accounting_account_id.'<br> <pre>'.$resql_exists.'</pre></span></div>';
$ko++;
} else {
$nb_exists = $db->num_rows($resql_exists);
if ($nb_exists <= 0) {
// insert
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "product_perentity (fk_product, entity, " . $db->escape($accountancy_field_name) . ")";
$sql .= " VALUES (" . ((int) $productid) . ", " . ((int) $conf->entity) . ", '" . $db->escape($accounting->account_number) . "')";
} else {
$obj_exists = $db->fetch_object($resql_exists);
// update
$sql = "UPDATE " . MAIN_DB_PREFIX . "product_perentity";
$sql .= " SET " . $accountancy_field_name . " = '" . $db->escape($accounting->account_number) . "'";
$sql .= " WHERE rowid = " . ((int) $obj_exists->rowid);
}
}
} else {
$sql = " UPDATE ".MAIN_DB_PREFIX."product";
$sql .= " SET ".$accountancy_field_name." = '".$db->escape($accounting->account_number)."'";
$sql .= " WHERE rowid = ".((int) $productid);
}
$db->begin();
dol_syslog("/accountancy/admin/productaccount.php sql=".$sql, LOG_DEBUG);
if ($db->query($sql)) {
$ok++;
@ -270,8 +287,8 @@ if (empty($pcgvercode)) {
$sql = "SELECT p.rowid, p.ref, p.label, p.description, p.tosell, p.tobuy, p.tva_tx,";
if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
$sql .= " pa.accountancy_code_sell, pa.accountancy_code_sell_intra, pa.accountancy_code_sell_export,";
$sql .= " pa.accountancy_code_buy, pa.accountancy_code_buy_intra, pa.accountancy_code_buy_export,";
$sql .= " ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export,";
$sql .= " ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export,";
} else {
$sql .= " p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export,";
$sql .= " p.accountancy_code_buy, p.accountancy_code_buy_intra, p.accountancy_code_buy_export,";
@ -280,14 +297,14 @@ $sql .= " p.tms, p.fk_product_type as product_type,";
$sql .= " aa.rowid as aaid";
$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
if (!empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED)) {
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as pa ON pa.fk_product = p.rowid AND pa.entity = " . ((int) $conf->entity);
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = pa." . $accountancy_field_name . " AND aa.fk_pcg_version = '" . $db->escape($pcgvercode) . "'";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product_perentity as ppe ON ppe.fk_product = p.rowid AND ppe.entity = " . ((int) $conf->entity);
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = ppe." . $accountancy_field_name . " AND aa.fk_pcg_version = '" . $db->escape($pcgvercode) . "'";
} else {
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.account_number = p." . $accountancy_field_name . " AND aa.fk_pcg_version = '" . $db->escape($pcgvercode) . "'";
}
$sql .= ' WHERE p.entity IN ('.getEntity('product').')';
if (strlen(trim($search_current_account))) {
$sql .= natural_search((empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED) ? "p." : "pa.") . $accountancy_field_name, $search_current_account);
$sql .= natural_search((empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED) ? "p." : "ppe.") . $accountancy_field_name, $search_current_account);
}
if ($search_current_account_valid == 'withoutvalidaccount') {
$sql .= " AND aa.account_number IS NULL";
@ -466,7 +483,7 @@ if ($result) {
} else {
print_liste_field_titre("OnBuy", $_SERVER["PHP_SELF"], "p.tobuy", "", $param, '', $sortfield, $sortorder, 'center ');
}
print_liste_field_titre("CurrentDedicatedAccountingAccount", $_SERVER["PHP_SELF"], (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED) ? "p." : "pa.") . $accountancy_field_name, "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("CurrentDedicatedAccountingAccount", $_SERVER["PHP_SELF"], (empty($conf->global->MAIN_PRODUCT_PERENTITY_SHARED) ? "p." : "ppe.") . $accountancy_field_name, "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("AssignDedicatedAccountingAccount");
$clickpitco = $form->showCheckAddButtons('checkforselect', 1);
print_liste_field_titre($clickpitco, '', '', '', '', '', '', '', 'center ');

View File

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2016 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2016-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2016-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
*
* This program is free software; you can redistribute it and/or modify
@ -30,6 +30,7 @@ require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
@ -38,9 +39,6 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
// Load translation files required by the page
$langs->loadLangs(array("accountancy", "compta"));
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
$sortorder = GETPOST("sortorder", 'alpha');
$sortfield = GETPOST("sortfield", 'alpha');
$action = GETPOST('action', 'aZ09');
// Load variable for pagination
@ -60,7 +58,7 @@ $pagenext = $page + 1;
$show_subgroup = GETPOST('show_subgroup', 'alpha');
$search_date_start = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int'));
$search_date_end = dol_mktime(23, 59, 59, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
$search_ledger_code = GETPOST('search_ledger_code', 'array');
$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
if ($search_accountancy_code_start == - 1) {
$search_accountancy_code_start = '';
@ -70,7 +68,9 @@ if ($search_accountancy_code_end == - 1) {
$search_accountancy_code_end = '';
}
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$object = new BookKeeping($db);
$hookmanager->initHooks(array('balancelist')); // Note that conf->hooks_modules contains array
$formaccounting = new FormAccounting($db);
$formother = new FormOther($db);
@ -134,6 +134,12 @@ if (!empty($search_accountancy_code_end)) {
$filter['t.numero_compte<='] = $search_accountancy_code_end;
$param .= '&amp;search_accountancy_code_end='.$search_accountancy_code_end;
}
if (!empty($search_ledger_code)) {
$filter['t.code_journal'] = $search_ledger_code;
foreach ($search_ledger_code as $code) {
$param .= '&search_ledger_code[]='.urlencode($code);
}
}
if (empty($conf->accounting->enabled)) {
accessforbidden();
@ -151,15 +157,23 @@ if (empty($user->rights->accounting->mouvements->lire)) {
* Action
*/
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
$show_subgroup = '';
$search_date_start = '';
$search_date_end = '';
$search_accountancy_code_start = '';
$search_accountancy_code_end = '';
$filter = array();
$parameters = array('socid'=>$socid);
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if (empty($reshook)) {
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All tests are required to be compatible with all browsers
$show_subgroup = '';
$search_date_start = '';
$search_date_end = '';
$search_accountancy_code_start = '';
$search_accountancy_code_end = '';
$search_ledger_code = array();
$filter = array();
}
}
/*
* View
@ -178,11 +192,11 @@ if ($action == 'export_csv') {
}
foreach ($object->lines as $line) {
print length_accountg($line->numero_compte).$sep;
print $object->get_compte_desc($line->numero_compte).$sep;
print price($line->debit).$sep;
print price($line->credit).$sep;
print price($line->debit - $line->credit).$sep;
print '"'.length_accountg($line->numero_compte).'"'.$sep;
print '"'.$object->get_compte_desc($line->numero_compte).'"'.$sep;
print '"'.price($line->debit).'"'.$sep;
print '"'.price($line->credit).'"'.$sep;
print '"'.price($line->debit - $line->credit).'"'.$sep;
print "\n";
}
@ -221,22 +235,28 @@ if ($action != 'export_csv') {
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<input type="hidden" name="page" value="'.$page.'">';
$button = '<input type="button" id="exportcsvbutton" name="exportcsvbutton" class="butAction" value="'.$langs->trans("Export").' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />';
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$button = '<input type="button" id="exportcsvbutton" name="exportcsvbutton" class="butAction" value="'.$langs->trans("Export").' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />';
print '<script type="text/javascript" language="javascript">
jQuery(document).ready(function() {
jQuery("#exportcsvbutton").click(function() {
event.preventDefault();
console.log("Set action to export_csv");
jQuery("#action").val("export_csv");
jQuery("#searchFormList").submit();
jQuery("#action").val("list");
print '<script type="text/javascript" language="javascript">
jQuery(document).ready(function() {
jQuery("#exportcsvbutton").click(function() {
event.preventDefault();
console.log("Set action to export_csv");
jQuery("#action").val("export_csv");
jQuery("#searchFormList").submit();
jQuery("#action").val("list");
});
});
});
</script>';
</script>';
}
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit);
$selectedfields = '';
$moreforfilter = '';
$moreforfilter .= '<div class="divsearchfield">';
@ -249,6 +269,12 @@ if ($action != 'export_csv') {
$moreforfilter .= '<label for="show_subgroup">'.$langs->trans('ShowSubtotalByGroup').'</label>: ';
$moreforfilter .= '<input type="checkbox" name="show_subgroup" id="show_subgroup" value="show_subgroup"'.($show_subgroup == 'show_subgroup' ? ' checked' : '').'>';
$moreforfilter .= '</div>';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans("Journal");
$moreforfilter .= $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1);
$moreforfilter .= '</div>';
@ -261,24 +287,29 @@ if ($action != 'export_csv') {
print '</div>';
}
$colspan = (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE) ? 5 : 4);
print '<table class="liste '.($moreforfilter ? "listwithfilterbefore" : "").'">';
print '<tr class="liste_titre_filter">';
print '<td class="liste_titre" colspan="'.$colspan.'">';
print $langs->trans('From');
print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', 1, array(), 1, 1, '');
print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, '', 'accounts');
print ' ';
print $langs->trans('to');
print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', 1, array(), 1, 1, '');
print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, '', 'accounts');
print '</td>';
print '<td class="liste_titre center">';
// Fields from hook
$parameters = array('arrayfields'=>$arrayfields);
$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
// Action column
print '<td class="liste_titre maxwidthsearch">';
$searchpicto = $form->showFilterButtons();
print $searchpicto;
print '</td>';
print '</tr>';
print '</tr>'."\n";
print '<tr class="liste_titre">';
print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder);
@ -288,8 +319,14 @@ if ($action != 'export_csv') {
print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $param, 'class="right"', $sortfield, $sortorder);
print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $param, 'class="right"', $sortfield, $sortorder);
print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $param, "", 'class="right"', $sortfield, $sortorder);
print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $param, "", 'width="60" class="center"', $sortfield, $sortorder);
print "</tr>\n";
// Hook fields
$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
// Action column
print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
print '</tr>'."\n";
$total_debit = 0;
$total_credit = 0;
@ -351,7 +388,7 @@ if ($action != 'export_csv') {
} elseif (empty($tmparrayforrootaccount['label'])) {
// $tmparrayforrootaccount['label'] not defined = the account has not parent with a parent.
// This is useless, we should not create a new account when an account has no parent, we must edit it to fix its parent.
// BUG 1: Accounts on level root or level 1 must not have a parent 2 level higher, so shoule not show a link to create another account.
// BUG 1: Accounts on level root or level 1 must not have a parent 2 level higher, so should not show a link to create another account.
// BUG 2: Adding a link to create a new accounting account here is useless because it is not add as parent of the orphelin.
//$link = '<a href="' . DOL_URL_ROOT . '/accountancy/admin/card.php?action=create&token=' . newToken() . '&accountingaccount=' . length_accountg($line->numero_compte) . '">' . img_edit_add() . '</a>';
}
@ -364,14 +401,14 @@ if ($action != 'export_csv') {
print '<tr class="liste_total">';
print '<td class="right">'.$langs->trans("SubTotal").':</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">'.price($sous_total_opening_balance).'</td>';
print '<td class="right nowraponall amount">'.price($sous_total_opening_balance).'</td>';
}
print '<td class="nowrap right">'.price($sous_total_debit).'</td>';
print '<td class="nowrap right">'.price($sous_total_credit).'</td>';
print '<td class="right nowraponall amount">'.price($sous_total_debit).'</td>';
print '<td class="right nowraponall amount">'.price($sous_total_credit).'</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">'.price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit)).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit)).'</td>';
} else {
print '<td class="nowrap right">'.price(price2num($sous_total_debit - $sous_total_credit)).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($sous_total_debit - $sous_total_credit)).'</td>';
}
print "<td></td>\n";
print '</tr>';
@ -392,7 +429,7 @@ if ($action != 'export_csv') {
print '<tr class="oddeven">';
print '<td>'.$accounting_account.'</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowraponall right">'.price($opening_balance).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($opening_balance, 'MT')).'</td>';
}
$urlzoom = '';
@ -406,16 +443,17 @@ if ($action != 'export_csv') {
}
}
// Debit
print '<td class="nowraponall right"><a href="'.$urlzoom.'">'.price($line->debit).'</a></td>';
print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->debit, 'MT')).'</a></td>';
// Credit
print '<td class="nowraponall right"><a href="'.$urlzoom.'">'.price($line->credit).'</a></td>';
print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->credit, 'MT')).'</a></td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowraponall right">'.price(price2num($opening_balance + $line->debit - $line->credit, 'MT')).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($opening_balance + $line->debit - $line->credit, 'MT')).'</td>';
} else {
print '<td class="nowraponall right">'.price(price2num($line->debit - $line->credit, 'MT')).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($line->debit - $line->credit, 'MT')).'</td>';
}
print '<td class="center">'.$link;
print '<td class="center">';
print $link;
print '</td>';
print "</tr>\n";
@ -428,14 +466,14 @@ if ($action != 'export_csv') {
if (!empty($show_subgroup)) {
print '<tr class="liste_total"><td class="right">'.$langs->trans("SubTotal").':</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">'.price($sous_total_opening_balance).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($sous_total_opening_balance, 'MT')).'</td>';
}
print '<td class="nowrap right">'.price($sous_total_debit).'</td>';
print '<td class="nowrap right">'.price($sous_total_credit).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($sous_total_debit, 'MT')).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($sous_total_credit, 'MT')).'</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">' . price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
print '<td class="right nowraponall amount">' . price(price2num($sous_total_opening_balance + $sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
} else {
print '<td class="nowrap right">' . price(price2num($sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
print '<td class="right nowraponall amount">' . price(price2num($sous_total_debit - $sous_total_credit, 'MT')) . '</td>';
}
print "<td></td>\n";
print '</tr>';
@ -443,14 +481,14 @@ if ($action != 'export_csv') {
print '<tr class="liste_total"><td class="right">'.$langs->trans("AccountBalance").':</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">'.price($total_opening_balance).'</td>';
print '<td class="nowrap right">'.price(price2num($total_opening_balance, 'MT')).'</td>';
}
print '<td class="nowrap right">'.price($total_debit).'</td>';
print '<td class="nowrap right">'.price($total_credit).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($total_debit, 'MT')).'</td>';
print '<td class="right nowraponall amount">'.price(price2num($total_credit, 'MT')).'</td>';
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="nowrap right">' . price(price2num($total_opening_balance + $total_debit - $total_credit, 'MT')) . '</td>';
print '<td class="right nowraponall amount">' . price(price2num($total_opening_balance + $total_debit - $total_credit, 'MT')) . '</td>';
} else {
print '<td class="nowrap right">' . price(price2num($total_debit - $total_credit, 'MT')) . '</td>';
print '<td class="right nowraponall amount">' . price(price2num($total_debit - $total_credit, 'MT')) . '</td>';
}
print "<td></td>\n";
print '</tr>';

View File

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2013-2017 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2017 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2018 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
*
@ -260,7 +260,7 @@ if ($action == "confirm_update") {
if ($mode != '_tmp') {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
}
$action = 'update';
$action = '';
$id = $object->id;
$piece_num = $object->piece_num;
}
@ -537,6 +537,22 @@ if ($action == 'create') {
print '</td>';
print '</tr>';
// Date document creation
print '<tr>';
print '<td class="titlefield">'.$langs->trans("DateExport").'</td>';
print '<td>';
print $object->date_export ? dol_print_date($object->date_export, 'dayhour') : '&nbsp;';
print '</td>';
print '</tr>';
// Date document creation
print '<tr>';
print '<td class="titlefield">'.$langs->trans("DateValidation").'</td>';
print '<td>';
print $object->date_validation ? dol_print_date($object->date_validation, 'dayhour') : '&nbsp;';
print '</td>';
print '</tr>';
// Validate
/*
print '<tr>';
@ -563,7 +579,7 @@ if ($action == 'create') {
{
$sqlmid = 'SELECT rowid as ref';
$sqlmid .= " FROM ".MAIN_DB_PREFIX."facture as fac";
$sqlmid .= " WHERE fac.rowid=" . $object->fk_doc;
$sqlmid .= " WHERE fac.rowid=" . ((int) $object->fk_doc);
dol_syslog("accountancy/bookkeeping/card.php::sqlmid=" . $sqlmid, LOG_DEBUG);
$resultmid = $db->query($sqlmid);
if ($resultmid) {
@ -619,10 +635,20 @@ if ($action == 'create') {
print_liste_field_titre("LabelOperation");
print_liste_field_titre("Debit", "", "", "", "", 'class="right"');
print_liste_field_titre("Credit", "", "", "", "", 'class="right"');
print_liste_field_titre("Action", "", "", "", "", 'width="60" class="center"');
if (empty($object->date_validation)) {
print_liste_field_titre("Action", "", "", "", "", 'width="60" class="center"');
} else {
print_liste_field_titre("");
}
print "</tr>\n";
// Empty line is the first line of $object->linesmvt
// So we must get the first line (the empty one) and pu it at the end of the array
// in order to display it correctly to the user
$empty_line = array_shift($object->linesmvt);
$object->linesmvt[]= $empty_line;
foreach ($object->linesmvt as $line) {
print '<tr class="oddeven">';
$total_debit += $line->debit;
@ -653,7 +679,33 @@ if ($action == 'create') {
print '<input type="hidden" name="id" value="'.$line->id.'">'."\n";
print '<input type="submit" class="button" name="update" value="'.$langs->trans("Update").'">';
print '</td>';
} elseif (empty($line->numero_compte) || (empty($line->debit) && empty($line->credit))) {
if ($action == "" || $action == 'add') {
print '<!-- td columns in add mode -->';
print '<td>';
print $formaccounting->select_account('', 'accountingaccount_number', 1, array(), 1, 1, '');
print '</td>';
print '<td>';
// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because:
// It does not use the setup of "key pressed" to select a thirdparty and this hang browser on large databases.
// Also, it is not possible to use a value that is not in the list.
// Also, the label is not automatically filled when a value is selected.
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $formaccounting->select_auxaccount('', 'subledger_account', 1, 'maxwidth250', '', 'subledger_label');
} else {
print '<input type="text" class="maxwidth150" name="subledger_account" value="" placeholder="' . dol_escape_htmltag($langs->trans("SubledgerAccount")) . '">';
}
print '<br><input type="text" class="maxwidth150" name="subledger_label" value="" placeholder="' . dol_escape_htmltag($langs->trans("SubledgerAccountLabel")) . '">';
print '</td>';
print '<td><input type="text" class="minwidth200" name="label_operation" value="' . $label_operation . '"/></td>';
print '<td class="right"><input type="text" size="6" class="right" name="debit" value=""/></td>';
print '<td class="right"><input type="text" size="6" class="right" name="credit" value=""/></td>';
print '<td>';
print '<input type="submit" class="button" name="save" value="' . $langs->trans("Add") . '">';
print '</td>';
}
} else {
print '<!-- td columns in display mode -->';
$accountingaccount->fetch(null, $line->numero_compte, true);
print '<td>'.$accountingaccount->getNomUrl(0, 1, 1, '', 0).'</td>';
print '<td>'.length_accounta($line->subledger_account);
@ -662,21 +714,25 @@ if ($action == 'create') {
}
print '</td>';
print '<td>'.$line->label_operation.'</td>';
print '<td class="nowrap right">'.price($line->debit).'</td>';
print '<td class="nowrap right">'.price($line->credit).'</td>';
print '<td class="right nowraponall amount">'.price($line->debit).'</td>';
print '<td class="right nowraponall amount">'.price($line->credit).'</td>';
print '<td class="center">';
print '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=update&id='.$line->id.'&piece_num='.urlencode($line->piece_num).'&mode='.urlencode($mode).'&token='.urlencode(newToken()).'">';
print img_edit('', 0, 'class="marginrightonly"');
print '</a> &nbsp;';
$actiontodelete = 'delete';
if ($mode == '_tmp' || $action != 'delmouv') {
$actiontodelete = 'confirm_delete';
if (empty($line->date_export) && empty($line->date_validation)) {
print '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=update&id=' . $line->id . '&piece_num=' . urlencode($line->piece_num) . '&mode=' . urlencode($mode) . '&token=' . urlencode(newToken()) . '">';
print img_edit('', 0, 'class="marginrightonly"');
print '</a> &nbsp;';
}
print '<a href="'.$_SERVER["PHP_SELF"].'?action='.$actiontodelete.'&id='.$line->id.'&piece_num='.urlencode($line->piece_num).'&mode='.urlencode($mode).'&token='.urlencode(newToken()).'">';
print img_delete();
if (empty($line->date_validation)) {
$actiontodelete = 'delete';
if ($mode == '_tmp' || $action != 'delmouv') {
$actiontodelete = 'confirm_delete';
}
print '<a href="' . $_SERVER["PHP_SELF"] . '?action=' . $actiontodelete . '&id=' . $line->id . '&piece_num=' . urlencode($line->piece_num) . '&mode=' . urlencode($mode) . '&token=' . urlencode(newToken()) . '">';
print img_delete();
}
print '</a>';
print '</td>';
@ -691,32 +747,8 @@ if ($action == 'create') {
setEventMessages(null, array($langs->trans('MvtNotCorrectlyBalanced', $total_debit, $total_credit)), 'warnings');
}
if ($action == "" || $action == 'add') {
print '<tr class="oddeven">';
print '<!-- td columns in add mode -->';
print '<td>';
print $formaccounting->select_account('', 'accountingaccount_number', 1, array(), 1, 1, '');
print '</td>';
print '<td>';
// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because:
// It does not use the setup of "key pressed" to select a thirdparty and this hang browser on large databases.
// Also, it is not possible to use a value that is not in the list.
// Also, the label is not automatically filled when a value is selected.
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $formaccounting->select_auxaccount('', 'subledger_account', 1);
} else {
print '<input type="text" class="maxwidth150" name="subledger_account" value="" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'">';
}
print '<br><input type="text" class="maxwidth150" name="subledger_label" value="" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccountLabel")).'">';
print '</td>';
print '<td><input type="text" class="minwidth200" name="label_operation" value="'.$label_operation.'"/></td>';
print '<td class="right"><input type="text" size="6" class="right" name="debit" value=""/></td>';
print '<td class="right"><input type="text" size="6" class="right" name="credit" value=""/></td>';
print '<td><input type="submit" class="button" name="save" value="'.$langs->trans("Add").'"></td>';
print '</tr>';
}
print '</table>';
print '</div>';
if ($mode == '_tmp' && $action == '') {
print '<br>';

View File

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2016-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
*
@ -44,15 +44,47 @@ $action = GETPOST('action', 'aZ09');
$search_mvt_num = GETPOST('search_mvt_num', 'int');
$search_doc_type = GETPOST("search_doc_type", 'alpha');
$search_doc_ref = GETPOST("search_doc_ref", 'alpha');
$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
$search_date_end = dol_mktime(23, 59, 59, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
$search_date_startyear = GETPOST('search_date_startyear', 'int');
$search_date_startmonth = GETPOST('search_date_startmonth', 'int');
$search_date_startday = GETPOST('search_date_startday', 'int');
$search_date_endyear = GETPOST('search_date_endyear', 'int');
$search_date_endmonth = GETPOST('search_date_endmonth', 'int');
$search_date_endday = GETPOST('search_date_endday', 'int');
$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);
$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
$search_doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$search_date_creation_start = dol_mktime(0, 0, 0, GETPOST('date_creation_startmonth', 'int'), GETPOST('date_creation_startday', 'int'), GETPOST('date_creation_startyear', 'int'));
$search_date_creation_end = dol_mktime(23, 59, 59, GETPOST('date_creation_endmonth', 'int'), GETPOST('date_creation_endday', 'int'), GETPOST('date_creation_endyear', 'int'));
$search_date_modification_start = dol_mktime(0, 0, 0, GETPOST('date_modification_startmonth', 'int'), GETPOST('date_modification_startday', 'int'), GETPOST('date_modification_startyear', 'int'));
$search_date_modification_end = dol_mktime(23, 59, 59, GETPOST('date_modification_endmonth', 'int'), GETPOST('date_modification_endday', 'int'), GETPOST('date_modification_endyear', 'int'));
$search_date_export_start = dol_mktime(0, 0, 0, GETPOST('date_export_startmonth', 'int'), GETPOST('date_export_startday', 'int'), GETPOST('date_export_startyear', 'int'));
$search_date_export_end = dol_mktime(23, 59, 59, GETPOST('date_export_endmonth', 'int'), GETPOST('date_export_endday', 'int'), GETPOST('date_export_endyear', 'int'));
$search_date_creation_startyear = GETPOST('search_date_creation_startyear', 'int');
$search_date_creation_startmonth = GETPOST('search_date_creation_startmonth', 'int');
$search_date_creation_startday = GETPOST('search_date_creation_startday', 'int');
$search_date_creation_endyear = GETPOST('search_date_creation_endyear', 'int');
$search_date_creation_endmonth = GETPOST('search_date_creation_endmonth', 'int');
$search_date_creation_endday = GETPOST('search_date_creation_endday', 'int');
$search_date_creation_start = dol_mktime(0, 0, 0, $search_date_creation_startmonth, $search_date_creation_startday, $search_date_creation_startyear);
$search_date_creation_end = dol_mktime(23, 59, 59, $search_date_creation_endmonth, $search_date_creation_endday, $search_date_creation_endyear);
$search_date_modification_startyear = GETPOST('search_date_modification_startyear', 'int');
$search_date_modification_startmonth = GETPOST('search_date_modification_startmonth', 'int');
$search_date_modification_startday = GETPOST('search_date_modification_startday', 'int');
$search_date_modification_endyear = GETPOST('search_date_modification_endyear', 'int');
$search_date_modification_endmonth = GETPOST('search_date_modification_endmonth', 'int');
$search_date_modification_endday = GETPOST('search_date_modification_endday', 'int');
$search_date_modification_start = dol_mktime(0, 0, 0, $search_date_modification_startmonth, $search_date_modification_startday, $search_date_modification_startyear);
$search_date_modification_end = dol_mktime(23, 59, 59, $search_date_modification_endmonth, $search_date_modification_endday, $search_date_modification_endyear);
$search_date_export_startyear = GETPOST('search_date_export_startyear', 'int');
$search_date_export_startmonth = GETPOST('search_date_export_startmonth', 'int');
$search_date_export_startday = GETPOST('search_date_export_startday', 'int');
$search_date_export_endyear = GETPOST('search_date_export_endyear', 'int');
$search_date_export_endmonth = GETPOST('search_date_export_endmonth', 'int');
$search_date_export_endday = GETPOST('search_date_export_endday', 'int');
$search_date_export_start = dol_mktime(0, 0, 0, $search_date_export_startmonth, $search_date_export_startday, $search_date_export_startyear);
$search_date_export_end = dol_mktime(23, 59, 59, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear);
$search_date_validation_startyear = GETPOST('search_date_validation_startyear', 'int');
$search_date_validation_startmonth = GETPOST('search_date_validation_startmonth', 'int');
$search_date_validation_startday = GETPOST('search_date_validation_startday', 'int');
$search_date_validation_endyear = GETPOST('search_date_validation_endyear', 'int');
$search_date_validation_endmonth = GETPOST('search_date_validation_endmonth', 'int');
$search_date_validation_endday = GETPOST('search_date_validation_endday', 'int');
$search_date_validation_start = dol_mktime(0, 0, 0, $search_date_validation_startmonth, $search_date_validation_startday, $search_date_validation_startyear);
$search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear);
//var_dump($search_date_start);exit;
if (GETPOST("button_delmvt_x") || GETPOST("button_delmvt.x") || GETPOST("button_delmvt")) {
@ -72,7 +104,7 @@ if ($search_accountancy_code_end == - 1) {
$search_accountancy_code_end = '';
}
$search_accountancy_aux_code = GETPOST("search_accountancy_aux_code");
$search_accountancy_aux_code = GETPOST("search_accountancy_aux_code", 'alpha');
$search_accountancy_aux_code_start = GETPOST('search_accountancy_aux_code_start', 'alpha');
if ($search_accountancy_aux_code_start == - 1) {
$search_accountancy_aux_code_start = '';
@ -157,6 +189,7 @@ $arrayfields = array(
't.date_creation'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0),
't.tms'=>array('label'=>$langs->trans("DateModification"), 'checked'=>0),
't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1),
't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1),
);
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) {
@ -216,14 +249,46 @@ if (empty($reshook)) {
$search_mvt_label = '';
$search_direction = '';
$search_ledger_code = array();
$search_date_startyear = '';
$search_date_startmonth = '';
$search_date_startday = '';
$search_date_endyear = '';
$search_date_endmonth = '';
$search_date_endday = '';
$search_date_start = '';
$search_date_end = '';
$search_date_creation_startyear = '';
$search_date_creation_startmonth = '';
$search_date_creation_startday = '';
$search_date_creation_endyear = '';
$search_date_creation_endmonth = '';
$search_date_creation_endday = '';
$search_date_creation_start = '';
$search_date_creation_end = '';
$search_date_modification_startyear = '';
$search_date_modification_startmonth = '';
$search_date_modification_startday = '';
$search_date_modification_endyear = '';
$search_date_modification_endmonth = '';
$search_date_modification_endday = '';
$search_date_modification_start = '';
$search_date_modification_end = '';
$search_date_export_startyear = '';
$search_date_export_startmonth = '';
$search_date_export_startday = '';
$search_date_export_endyear = '';
$search_date_export_endmonth = '';
$search_date_export_endday = '';
$search_date_export_start = '';
$search_date_export_end = '';
$search_date_validation_startyear = '';
$search_date_validation_startmonth = '';
$search_date_validation_startday = '';
$search_date_validation_endyear = '';
$search_date_validation_endmonth = '';
$search_date_validation_endday = '';
$search_date_validation_start = '';
$search_date_validation_end = '';
$search_debit = '';
$search_credit = '';
$search_lettering_code = '';
@ -268,10 +333,6 @@ if (empty($reshook)) {
$filter['t.numero_compte<='] = $search_accountancy_code_end;
$param .= '&search_accountancy_code_end='.urlencode($search_accountancy_code_end);
}
if (!empty($search_accountancy_aux_code)) {
$filter['t.subledger_account'] = $search_accountancy_aux_code;
$param .= '&search_accountancy_aux_code='.urlencode($search_accountancy_aux_code);
}
if (!empty($search_accountancy_aux_code_start)) {
$filter['t.subledger_account>='] = $search_accountancy_aux_code_start;
$param .= '&search_accountancy_aux_code_start='.urlencode($search_accountancy_aux_code_start);
@ -301,32 +362,42 @@ if (empty($reshook)) {
if (!empty($search_date_creation_start)) {
$filter['t.date_creation>='] = $search_date_creation_start;
$tmp = dol_getdate($search_date_creation_start);
$param .= '&date_creation_startmonth='.urlencode($tmp['mon']).'&date_creation_startday='.urlencode($tmp['mday']).'&date_creation_startyear='.urlencode($tmp['year']);
$param .= '&search_date_creation_startmonth='.urlencode($tmp['mon']).'&search_date_creation_startday='.urlencode($tmp['mday']).'&search_date_creation_startyear='.urlencode($tmp['year']);
}
if (!empty($search_date_creation_end)) {
$filter['t.date_creation<='] = $search_date_creation_end;
$tmp = dol_getdate($search_date_creation_end);
$param .= '&date_creation_endmonth='.urlencode($tmp['mon']).'&date_creation_endday='.urlencode($tmp['mday']).'&date_creation_endyear='.urlencode($tmp['year']);
$param .= '&search_date_creation_endmonth='.urlencode($tmp['mon']).'&search_date_creation_endday='.urlencode($tmp['mday']).'&search_date_creation_endyear='.urlencode($tmp['year']);
}
if (!empty($search_date_modification_start)) {
$filter['t.tms>='] = $search_date_modification_start;
$tmp = dol_getdate($search_date_modification_start);
$param .= '&date_modification_startmonth='.urlencode($tmp['mon']).'&date_modification_startday='.urlencode($tmp['mday']).'&date_modification_startyear='.urlencode($tmp['year']);
$param .= '&search_date_modification_startmonth='.urlencode($tmp['mon']).'&search_date_modification_startday='.urlencode($tmp['mday']).'&search_date_modification_startyear='.urlencode($tmp['year']);
}
if (!empty($search_date_modification_end)) {
$filter['t.tms<='] = $search_date_modification_end;
$tmp = dol_getdate($search_date_modification_end);
$param .= '&date_modification_endmonth='.urlencode($tmp['mon']).'&date_modification_endday='.urlencode($tmp['mday']).'&date_modification_endyear='.urlencode($tmp['year']);
$param .= '&search_date_modification_endmonth='.urlencode($tmp['mon']).'&search_date_modification_endday='.urlencode($tmp['mday']).'&search_date_modification_endyear='.urlencode($tmp['year']);
}
if (!empty($search_date_export_start)) {
$filter['t.date_export>='] = $search_date_export_start;
$tmp = dol_getdate($search_date_export_start);
$param .= '&date_export_startmonth='.urlencode($tmp['mon']).'&date_export_startday='.urlencode($tmp['mday']).'&date_export_startyear='.urlencode($tmp['year']);
$param .= '&search_date_export_startmonth='.urlencode($tmp['mon']).'&search_date_export_startday='.urlencode($tmp['mday']).'&search_date_export_startyear='.urlencode($tmp['year']);
}
if (!empty($search_date_export_end)) {
$filter['t.date_export<='] = $search_date_export_end;
$tmp = dol_getdate($search_date_export_end);
$param .= '&date_export_endmonth='.urlencode($tmp['mon']).'&date_export_endday='.urlencode($tmp['mday']).'&date_export_endyear='.urlencode($tmp['year']);
$param .= '&search_date_export_endmonth='.urlencode($tmp['mon']).'&search_date_export_endday='.urlencode($tmp['mday']).'&search_date_export_endyear='.urlencode($tmp['year']);
}
if (!empty($search_date_validation_start)) {
$filter['t.date_validated>='] = $search_date_validation_start;
$tmp = dol_getdate($search_date_validation_start);
$param .= '&search_date_validation_startmonth='.urlencode($tmp['mon']).'&search_date_validation_startday='.urlencode($tmp['mday']).'&search_date_validation_startyear='.urlencode($tmp['year']);
}
if (!empty($search_date_validation_end)) {
$filter['t.date_validated<='] = $search_date_validation_end;
$tmp = dol_getdate($search_date_validation_end);
$param .= '&search_date_validation_endmonth='.urlencode($tmp['mon']).'&search_date_validation_endday='.urlencode($tmp['mday']).'&search_date_validation_endyear='.urlencode($tmp['year']);
}
if (!empty($search_debit)) {
$filter['t.debit'] = $search_debit;
@ -447,7 +518,8 @@ $sql .= " t.journal_label,";
$sql .= " t.piece_num,";
$sql .= " t.date_creation,";
$sql .= " t.tms as date_modification,";
$sql .= " t.date_export";
$sql .= " t.date_export,";
$sql .= " t.date_validated as date_validation";
$sql .= ' FROM '.MAIN_DB_PREFIX.$object->table_element.' as t';
// Manage filter
$sqlwhere = array();
@ -469,6 +541,8 @@ if (count($filter) > 0) {
$sqlwhere[] = $key.'\''.$db->idate($value).'\'';
} elseif ($key == 't.date_export>=' || $key == 't.date_export<=') {
$sqlwhere[] = $key.'\''.$db->idate($value).'\'';
} elseif ($key == 't.date_validated>=' || $key == 't.date_validated<=') {
$sqlwhere[] = $key.'\''.$db->idate($value).'\'';
} elseif ($key == 't.credit' || $key == 't.debit') {
$sqlwhere[] = natural_search($key, $value, 1, 1);
} elseif ($key == 't.reconciled_option') {
@ -496,7 +570,7 @@ if (!empty($sortfield)) {
// Export into a file with format defined into setup (FEC, CSV, ...)
// Must be after definition of $sql
if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->export) {
// TODO Replace the fetchAll + ->export later that consume too much memory on large export with the query($sql) and loop on each line to export them.
// TODO Replace the fetchAll to get all ->line followed by call to ->export(). It consumew too much memory on large export. Replace this with the query($sql) and loop on each line to export them.
$result = $object->fetchAll($sortorder, $sortfield, 0, 0, $filter, 'AND', (empty($conf->global->ACCOUNTING_REEXPORT) ? 0 : 1));
if ($result < 0) {
@ -506,10 +580,13 @@ if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->ex
$accountancyexport = new AccountancyExport($db);
$accountancyexport->export($object->lines, $formatexportset);
$notifiedexportdate = GETPOST('notifiedexportdate', 'alpha');
$notifiedvalidationdate = GETPOST('notifiedvalidationdate', 'alpha');
if (!empty($accountancyexport->errors)) {
setEventMessages('', $accountancyexport->errors, 'errors');
} else {
// Specify as export : update field date_export
} elseif (!empty($notifiedexportdate) || !empty($notifiedvalidationdate)) {
// Specify as export : update field date_export or date_validated
$error = 0;
$db->begin();
@ -518,11 +595,18 @@ if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->ex
$now = dol_now();
$sql = " UPDATE ".MAIN_DB_PREFIX."accounting_bookkeeping";
$sql .= " SET date_export = '".$db->idate($now)."'";
$sql .= " , date_validated = '".$db->idate($now)."'";
$sql .= " SET";
if (!empty($notifiedexportdate) && !empty($notifiedvalidationdate)) {
$sql .= " date_export = '".$db->idate($now)."'";
$sql .= ", date_validated = '".$db->idate($now)."'";
} elseif (!empty($notifiedexportdate)) {
$sql .= " date_export = '".$db->idate($now)."'";
} elseif (!empty($notifiedvalidationdate)) {
$sql .= " date_validated = '".$db->idate($now)."'";
}
$sql .= " WHERE rowid = ".((int) $movement->id);
dol_syslog("/accountancy/bookeeping/list.php Function export_file Specify movements as exported sql=".$sql, LOG_DEBUG);
dol_syslog("/accountancy/bookkeeping/list.php Function export_file Specify movements as exported sql=".$sql, LOG_DEBUG);
$result = $db->query($sql);
if (!$result) {
$error++;
@ -533,11 +617,11 @@ if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->ex
if (!$error) {
$db->commit();
// setEventMessages($langs->trans("AllExportedMovementsWereRecordedAsExported"), null, 'mesgs');
// setEventMessages($langs->trans("AllExportedMovementsWereRecordedAsExportedOrValidated"), null, 'mesgs');
} else {
$error++;
$db->rollback();
setEventMessages($langs->trans("NotAllExportedMovementsCouldBeRecordedAsExported"), null, 'errors');
setEventMessages($langs->trans("NotAllExportedMovementsCouldBeRecordedAsExportedOrValidated"), null, 'errors');
}
}
exit;
@ -585,6 +669,8 @@ if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords) {
llxHeader('', $title_page);
$formconfirm = '';
if ($action == 'export_file') {
$form_question = array();
@ -596,17 +682,15 @@ if ($action == 'export_file') {
);
$form_question['notifiedvalidationdate'] = array(
'name' => 'notifiedvalidationdate',
'type' => 'checkbox', // We don't use select here, the journal_array is already a select html component
'type' => 'checkbox',
'label' => $langs->trans('NotifiedValidationDate'),
'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_VALIDATION_DATE) ? 'false' : 'true'),
);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300);
print $formconfirm;
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300, 600);
}
if ($action == 'delmouv') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?mvt_num='.GETPOST('mvt_num').$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvtPartial'), 'delmouvconfirm', '', 0, 1);
print $formconfirm;
}
if ($action == 'delbookkeepingyear') {
$form_question = array();
@ -646,9 +730,11 @@ if ($action == 'delbookkeepingyear') {
);
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans('DeleteMvt'), $langs->trans('ConfirmDeleteMvt', $langs->transnoentitiesnoconv("RegistrationInAccounting")), 'delbookkeepingyearconfirm', $form_question, '', 1, 300);
print $formconfirm;
}
// Print form confirm
print $formconfirm;
//$param=''; param started before
if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
$param .= '&contextpage='.urlencode($contextpage);
@ -667,6 +753,8 @@ print '<input type="hidden" name="formfilteraction" id="formfilteraction" value=
print '<input type="hidden" name="sortfield" value="'.urlencode($sortfield).'">';
print '<input type="hidden" name="sortorder" value="'.urlencode($sortorder).'">';
$massactionbutton = '';
if (count($filter)) {
$buttonLabel = $langs->trans("ExportFilteredList");
} else {
@ -699,7 +787,7 @@ if (empty($reshook)) {
$newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', $url, '', $user->rights->accounting->mouvements->creer);
}
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
@ -728,7 +816,7 @@ if (!empty($arrayfields['t.piece_num']['checked'])) {
// Code journal
if (!empty($arrayfields['t.code_journal']['checked'])) {
print '<td class="liste_titre center">';
print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1);
print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1, 'maxwidth150');
print '</td>';
}
// Date document
@ -750,36 +838,29 @@ if (!empty($arrayfields['t.doc_ref']['checked'])) {
if (!empty($arrayfields['t.numero_compte']['checked'])) {
print '<td class="liste_titre">';
print '<div class="nowrap">';
print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth200', 1);
print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth200', 'account');
print '</div>';
print '<div class="nowrap">';
print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth200', 1);
print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth200', 'account');
print '</div>';
print '</td>';
}
// Subledger account
if (!empty($arrayfields['t.subledger_account']['checked'])) {
print '<td class="liste_titre">';
print '<div class="nowrap">';
// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not
// use setup of keypress to select thirdparty and this hang browser on large database.
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $langs->trans('From').' ';
print $formaccounting->select_auxaccount($search_accountancy_aux_code_start, 'search_accountancy_aux_code_start', 1);
print '<div class="nowrap">';
//print $langs->trans('From').' ';
print $formaccounting->select_auxaccount($search_accountancy_aux_code_start, 'search_accountancy_aux_code_start', $langs->trans('From'), 'maxwidth250', 'subledgeraccount');
print '</div>';
print '<div class="nowrap">';
print $formaccounting->select_auxaccount($search_accountancy_aux_code_end, 'search_accountancy_aux_code_end', $langs->trans('to'), 'maxwidth250', 'subledgeraccount');
print '</div>';
} else {
print '<input type="text" class="maxwidth100" name="search_accountancy_aux_code_start" value="'.$search_accountancy_aux_code_start.'" placeholder="'.$langs->trans("From").'">';
print '<input type="text" class="maxwidth75" name="search_accountancy_aux_code" value="'.$search_accountancy_aux_code.'">';
}
print '</div>';
print '<div class="nowrap">';
// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not
// use setup of keypress to select thirdparty and this hang browser on large database.
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $langs->trans('to').' ';
print $formaccounting->select_auxaccount($search_accountancy_aux_code_end, 'search_accountancy_aux_code_end', 1);
} else {
print '<input type="text" class="maxwidth100" name="search_accountancy_aux_code_end" value="'.$search_accountancy_aux_code_end.'" placeholder="'.$langs->trans("to").'">';
}
print '</div>';
print '</td>';
}
// Label operation
@ -817,10 +898,10 @@ print $hookmanager->resPrint;
if (!empty($arrayfields['t.date_creation']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_creation_start, 'date_creation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print $form->selectDate($search_date_creation_start, 'search_date_creation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_creation_end, 'date_creation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print $form->selectDate($search_date_creation_end, 'search_date_creation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print '</div>';
print '</td>';
}
@ -828,10 +909,10 @@ if (!empty($arrayfields['t.date_creation']['checked'])) {
if (!empty($arrayfields['t.tms']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_modification_start, 'date_modification_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print $form->selectDate($search_date_modification_start, 'search_date_modification_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_modification_end, 'date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print $form->selectDate($search_date_modification_end, 'search_date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '</td>';
}
@ -839,10 +920,21 @@ if (!empty($arrayfields['t.tms']['checked'])) {
if (!empty($arrayfields['t.date_export']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_export_start, 'date_export_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print $form->selectDate($search_date_export_start, 'search_date_export_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_export_end, 'date_export_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print $form->selectDate($search_date_export_end, 'search_date_export_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print '</div>';
print '</td>';
}
// Date validation
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_start, 'search_date_validation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_end, 'search_date_validation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print '</div>';
print '</td>';
}
@ -897,6 +989,9 @@ if (!empty($arrayfields['t.tms']['checked'])) {
if (!empty($arrayfields['t.date_export']['checked'])) {
print_liste_field_titre($arrayfields['t.date_export']['label'], $_SERVER['PHP_SELF'], "t.date_export", "", $param, '', $sortfield, $sortorder, 'center ');
}
if (!empty($arrayfields['t.date_validated']['checked'])) {
print_liste_field_titre($arrayfields['t.date_validated']['label'], $_SERVER['PHP_SELF'], "t.date_validated", "", $param, '', $sortfield, $sortorder, 'center ');
}
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
print "</tr>\n";
@ -939,6 +1034,7 @@ while ($i < min($num, $limit)) {
$line->date_creation = $db->jdate($obj->date_creation);
$line->date_modification = $db->jdate($obj->date_modification);
$line->date_export = $db->jdate($obj->date_export);
$line->date_validation = $db->jdate($obj->date_validation);
$total_debit += $line->debit;
$total_credit += $line->credit;
@ -1072,7 +1168,7 @@ while ($i < min($num, $limit)) {
// Amount debit
if (!empty($arrayfields['t.debit']['checked'])) {
print '<td class="nowrap right">'.($line->debit != 0 ? price($line->debit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->debit != 0 ? price($line->debit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -1084,7 +1180,7 @@ while ($i < min($num, $limit)) {
// Amount credit
if (!empty($arrayfields['t.credit']['checked'])) {
print '<td class="nowrap right">'.($line->credit != 0 ? price($line->credit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->credit != 0 ? price($line->credit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -1131,12 +1227,22 @@ while ($i < min($num, $limit)) {
}
}
// Validated operation date
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="center">'.dol_print_date($line->date_validation, 'dayhour').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
}
// Action column
print '<td class="nowraponall center">';
if (empty($line->date_export)) {
if (empty($line->date_export) && empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->creer) {
print '<a class="editfielda paddingleft marginrightonly" href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_edit().'</a>';
print '<a class="editfielda paddingleft marginrightonly" href="' . DOL_URL_ROOT . '/accountancy/bookkeeping/card.php?piece_num=' . $line->piece_num . $param . '&page=' . $page . ($sortfield ? '&sortfield=' . $sortfield : '') . ($sortorder ? '&sortorder=' . $sortorder : '') . '">' . img_edit() . '</a>';
}
}
if (empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->supprimer) {
print '<a class="reposition paddingleft marginrightonly" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>';
}

View File

@ -2,7 +2,7 @@
/* Copyright (C) 2016 Neil Orley <neil.orley@oeris.fr>
* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2020 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
*
* This program is free software; you can redistribute it and/or modify
@ -55,7 +55,15 @@ $search_date_export_endyear = GETPOST('search_date_export_endyear', 'int');
$search_date_export_endmonth = GETPOST('search_date_export_endmonth', 'int');
$search_date_export_endday = GETPOST('search_date_export_endday', 'int');
$search_date_export_start = dol_mktime(0, 0, 0, $search_date_export_startmonth, $search_date_export_startday, $search_date_export_startyear);
$search_date_export_end = dol_mktime(0, 0, 0, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear);
$search_date_export_end = dol_mktime(23, 59, 59, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear);
$search_date_validation_startyear = GETPOST('search_date_validation_startyear', 'int');
$search_date_validation_startmonth = GETPOST('search_date_validation_startmonth', 'int');
$search_date_validation_startday = GETPOST('search_date_validation_startday', 'int');
$search_date_validation_endyear = GETPOST('search_date_validation_endyear', 'int');
$search_date_validation_endmonth = GETPOST('search_date_validation_endmonth', 'int');
$search_date_validation_endday = GETPOST('search_date_validation_endday', 'int');
$search_date_validation_start = dol_mktime(0, 0, 0, $search_date_validation_startmonth, $search_date_validation_startday, $search_date_validation_startyear);
$search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear);
$search_accountancy_code = GETPOST("search_accountancy_code");
$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
@ -81,7 +89,7 @@ if (GETPOST("button_delmvt_x") || GETPOST("button_delmvt.x") || GETPOST("button_
}
// Load variable for pagination
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION);
$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION);
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
@ -144,6 +152,7 @@ $arrayfields = array(
't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1),
't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1),
't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1),
't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1),
);
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) {
@ -221,6 +230,14 @@ if (empty($reshook)) {
$search_date_export_endyear = '';
$search_date_export_endmonth = '';
$search_date_export_endday = '';
$search_date_validation_start = '';
$search_date_validation_end = '';
$search_date_validation_startyear = '';
$search_date_validation_startmonth = '';
$search_date_validation_startday = '';
$search_date_validation_endyear = '';
$search_date_validation_endmonth = '';
$search_date_validation_endday = '';
$search_debit = '';
$search_credit = '';
$search_lettering_code = '';
@ -301,6 +318,14 @@ if (empty($reshook)) {
$filter['t.date_export<='] = $search_date_export_end;
$param .= '&search_date_export_endmonth='.$search_date_export_endmonth.'&search_date_export_endday='.$search_date_export_endday.'&search_date_export_endyear='.$search_date_export_endyear;
}
if (!empty($search_date_validation_start)) {
$filter['t.date_validated>='] = $search_date_validation_start;
$param .= '&search_date_validation_startmonth='.$search_date_validation_startmonth.'&search_date_validation_startday='.$search_date_validation_startday.'&search_date_validation_startyear='.$search_date_validation_startyear;
}
if (!empty($search_date_validation_end)) {
$filter['t.date_validated<='] = $search_date_validation_end;
$param .= '&search_date_validation_endmonth='.$search_date_validation_endmonth.'&search_date_validation_endday='.$search_date_validation_endday.'&search_date_validation_endyear='.$search_date_validation_endyear;
}
}
if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->supprimer) {
@ -484,10 +509,9 @@ $moreforfilter = '';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans('AccountAccounting').': ';
$moreforfilter .= '<div class="nowrap inline-block">';
$moreforfilter .= $langs->trans('From').' ';
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', 1, array(), 1, 1, 'maxwidth200');
$moreforfilter .= ' '.$langs->trans('to').' ';
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', 1, array(), 1, 1, 'maxwidth200');
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth200');
$moreforfilter .= ' ';
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth200');
$moreforfilter .= '</div>';
$moreforfilter .= '</div>';
@ -564,6 +588,17 @@ if (!empty($arrayfields['t.date_export']['checked'])) {
print '</div>';
print '</td>';
}
// Date validation
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_start, 'search_date_validation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_end, 'search_date_validation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print '</div>';
print '</td>';
}
// Fields from hook
$parameters = array('arrayfields'=>$arrayfields);
@ -605,6 +640,9 @@ if (!empty($arrayfields['t.lettering_code']['checked'])) {
if (!empty($arrayfields['t.date_export']['checked'])) {
print_liste_field_titre($arrayfields['t.date_export']['label'], $_SERVER['PHP_SELF'], "t.date_export", "", $param, '', $sortfield, $sortorder, 'center ');
}
if (!empty($arrayfields['t.date_validated']['checked'])) {
print_liste_field_titre($arrayfields['t.date_validated']['label'], $_SERVER['PHP_SELF'], "t.date_validated", "", $param, '', $sortfield, $sortorder, 'center ');
}
// Hook fields
$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
@ -632,20 +670,19 @@ while ($i < min($num, $limit)) {
$accountg = length_accountg($line->numero_compte);
//if (empty($accountg)) $accountg = '-';
$colspan = 0; // colspan before field 'label of operation'
$colspanend = 3; // colspan after debit/credit
if (!empty($arrayfields['t.piece_num']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.code_journal']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.doc_date']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.doc_ref']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.label_operation']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.date_export']['checked'])) { $colspanend++; }
if (!empty($arrayfields['t.date_validating']['checked'])) { $colspanend++; }
if (!empty($arrayfields['t.lettering_code']['checked'])) { $colspanend++; }
// Is it a break ?
if ($accountg != $displayed_account_number || !isset($displayed_account_number)) {
$colnumber = 5;
$colnumberend = 7;
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING) || empty($arrayfields['t.lettering_code']['checked'])) {
$colnumber--;
}
if (empty($arrayfields['t.date_export']['checked'])) {
$colnumber--;
}
$colspan = $totalarray['nbfield'] - $colnumber;
$colspanend = $totalarray['nbfield'] - $colnumberend;
// Show a subtotal by accounting account
if (isset($displayed_account_number)) {
print '<tr class="liste_total">';
@ -807,7 +844,7 @@ while ($i < min($num, $limit)) {
// Amount debit
if (!empty($arrayfields['t.debit']['checked'])) {
print '<td class="nowrap right">'.($line->debit ? price($line->debit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->debit ? price($line->debit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -819,7 +856,7 @@ while ($i < min($num, $limit)) {
// Amount credit
if (!empty($arrayfields['t.credit']['checked'])) {
print '<td class="nowrap right">'.($line->credit ? price($line->credit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->credit ? price($line->credit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -845,6 +882,14 @@ while ($i < min($num, $limit)) {
}
}
// Validated operation date
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="center">'.dol_print_date($line->date_validation, 'dayhour').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
}
// Fields from hook
$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj);
$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
@ -852,12 +897,14 @@ while ($i < min($num, $limit)) {
// Action column
print '<td class="nowraponall center">';
if (empty($line->date_export)) {
if (empty($line->date_export) && empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->creer) {
print '<a class="editfielda" href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_edit().'</a>';
print '<a class="editfielda paddingleft marginrightonly" href="' . DOL_URL_ROOT . '/accountancy/bookkeeping/card.php?piece_num=' . $line->piece_num . $param . '&page=' . $page . ($sortfield ? '&sortfield=' . $sortfield : '') . ($sortorder ? '&sortorder=' . $sortorder : '') . '">' . img_edit() . '</a>';
}
}
if (empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->supprimer) {
print ' &nbsp; <a class="paddingleft" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>';
print '<a class="reposition paddingleft marginrightonly" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>';
}
}
print '</td>';
@ -874,9 +921,7 @@ while ($i < min($num, $limit)) {
$i++;
}
if ($num > 0) {
$colspan = $totalarray['nbfield'] - $colnumber;
$colspanend = $totalarray['nbfield'] - $colnumberend;
if ($num > 0 && $colspan > 0) {
print '<tr class="liste_total">';
print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.$accountg.':</td>';
print '<td class="nowrap right">'.price($sous_total_debit).'</td>';

View File

@ -2,8 +2,8 @@
/* Copyright (C) 2016 Neil Orley <neil.orley@oeris.fr>
* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2020 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -46,7 +46,7 @@ $search_date_endyear = GETPOST('search_date_endyear', 'int');
$search_date_endmonth = GETPOST('search_date_endmonth', 'int');
$search_date_endday = GETPOST('search_date_endday', 'int');
$search_date_start = dol_mktime(0, 0, 0, $search_date_startmonth, $search_date_startday, $search_date_startyear);
$search_date_end = dol_mktime(0, 0, 0, $search_date_endmonth, $search_date_endday, $search_date_endyear);
$search_date_end = dol_mktime(23, 59, 59, $search_date_endmonth, $search_date_endday, $search_date_endyear);
$search_doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$search_date_export_startyear = GETPOST('search_date_export_startyear', 'int');
$search_date_export_startmonth = GETPOST('search_date_export_startmonth', 'int');
@ -55,7 +55,15 @@ $search_date_export_endyear = GETPOST('search_date_export_endyear', 'int');
$search_date_export_endmonth = GETPOST('search_date_export_endmonth', 'int');
$search_date_export_endday = GETPOST('search_date_export_endday', 'int');
$search_date_export_start = dol_mktime(0, 0, 0, $search_date_export_startmonth, $search_date_export_startday, $search_date_export_startyear);
$search_date_export_end = dol_mktime(0, 0, 0, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear);
$search_date_export_end = dol_mktime(23, 59, 59, $search_date_export_endmonth, $search_date_export_endday, $search_date_export_endyear);
$search_date_validation_startyear = GETPOST('search_date_validation_startyear', 'int');
$search_date_validation_startmonth = GETPOST('search_date_validation_startmonth', 'int');
$search_date_validation_startday = GETPOST('search_date_validation_startday', 'int');
$search_date_validation_endyear = GETPOST('search_date_validation_endyear', 'int');
$search_date_validation_endmonth = GETPOST('search_date_validation_endmonth', 'int');
$search_date_validation_endday = GETPOST('search_date_validation_endday', 'int');
$search_date_validation_start = dol_mktime(0, 0, 0, $search_date_validation_startmonth, $search_date_validation_startday, $search_date_validation_startyear);
$search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear);
$search_accountancy_code = GETPOST("search_accountancy_code");
$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
@ -144,6 +152,7 @@ $arrayfields = array(
't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1),
't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1),
't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1),
't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1),
);
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) {
@ -221,6 +230,14 @@ if (empty($reshook)) {
$search_date_export_endyear = '';
$search_date_export_endmonth = '';
$search_date_export_endday = '';
$search_date_validation_start = '';
$search_date_validation_end = '';
$search_date_validation_startyear = '';
$search_date_validation_startmonth = '';
$search_date_validation_startday = '';
$search_date_validation_endyear = '';
$search_date_validation_endmonth = '';
$search_date_validation_endday = '';
$search_debit = '';
$search_credit = '';
$search_lettering_code = '';
@ -301,6 +318,14 @@ if (empty($reshook)) {
$filter['t.date_export<='] = $search_date_export_end;
$param .= '&search_date_export_endmonth='.$search_date_export_endmonth.'&search_date_export_endday='.$search_date_export_endday.'&search_date_export_endyear='.$search_date_export_endyear;
}
if (!empty($search_date_validation_start)) {
$filter['t.date_validated>='] = $search_date_validation_start;
$param .= '&search_date_validation_startmonth='.$search_date_validation_startmonth.'&search_date_validation_startday='.$search_date_validation_startday.'&search_date_validation_startyear='.$search_date_validation_startyear;
}
if (!empty($search_date_validation_end)) {
$filter['t.date_validated<='] = $search_date_validation_end;
$param .= '&search_date_validation_endmonth='.$search_date_validation_endmonth.'&search_date_validation_endday='.$search_date_validation_endday.'&search_date_validation_endyear='.$search_date_validation_endyear;
}
}
if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->supprimer) {
@ -373,7 +398,6 @@ $title_page = $langs->trans("Operations").' - '.$langs->trans("VueByAccountAccou
llxHeader('', $title_page);
// List
$nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
@ -448,7 +472,6 @@ print '<input type="hidden" name="formfilteraction" id="formfilteraction" value=
print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
@ -488,10 +511,9 @@ $moreforfilter = '';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans('AccountAccounting').': ';
$moreforfilter .= '<div class="nowrap inline-block">';
$moreforfilter .= $langs->trans('From').' ';
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_start, 'search_accountancy_code_start', 1, 'maxwidth200');
$moreforfilter .= ' '.$langs->trans('to').' ';
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_end, 'search_accountancy_code_end', 1, 'maxwidth200');
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), 'maxwidth200');
$moreforfilter .= ' ';
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), 'maxwidth200');
$moreforfilter .= '</div>';
$moreforfilter .= '</div>';
@ -568,6 +590,17 @@ if (!empty($arrayfields['t.date_export']['checked'])) {
print '</div>';
print '</td>';
}
// Date validation
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="liste_titre center">';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_start, 'search_date_validation_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
print '</div>';
print '<div class="nowrap">';
print $form->selectDate($search_date_validation_end, 'search_date_validation_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
print '</div>';
print '</td>';
}
// Fields from hook
$parameters = array('arrayfields'=>$arrayfields);
@ -609,6 +642,9 @@ if (!empty($arrayfields['t.lettering_code']['checked'])) {
if (!empty($arrayfields['t.date_export']['checked'])) {
print_liste_field_titre($arrayfields['t.date_export']['label'], $_SERVER['PHP_SELF'], "t.date_export", "", $param, '', $sortfield, $sortorder, 'center ');
}
if (!empty($arrayfields['t.date_validated']['checked'])) {
print_liste_field_titre($arrayfields['t.date_validated']['label'], $_SERVER['PHP_SELF'], "t.date_validated", "", $param, '', $sortfield, $sortorder, 'center ');
}
// Hook fields
$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
@ -636,21 +672,19 @@ while ($i < min($num, $limit)) {
$accountg = length_accounta($line->subledger_account);
//if (empty($accountg)) $accountg = '-';
$colspan = 0; // colspan before field 'label of operation'
$colspanend = 3; // colspan after debit/credit
if (!empty($arrayfields['t.piece_num']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.code_journal']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.doc_date']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.doc_ref']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.label_operation']['checked'])) { $colspan++; }
if (!empty($arrayfields['t.date_export']['checked'])) { $colspanend++; }
if (!empty($arrayfields['t.date_validating']['checked'])) { $colspanend++; }
if (!empty($arrayfields['t.lettering_code']['checked'])) { $colspanend++; }
// Is it a break ?
if ($accountg != $displayed_account_number || !isset($displayed_account_number)) {
$colnumber = 5;
$colnumberend = 7;
if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING) || empty($arrayfields['t.lettering_code']['checked'])) {
$colnumber--;
}
if (empty($arrayfields['t.date_export']['checked'])) {
$colnumber--;
}
$colspan = $totalarray['nbfield'] - $colnumber;
$colspanend = $totalarray['nbfield'] - $colnumberend;
// Show a subtotal by accounting account
if (isset($displayed_account_number)) {
print '<tr class="liste_total">';
@ -682,7 +716,7 @@ while ($i < min($num, $limit)) {
print "<tr>";
print '<td colspan="'.($totalarray['nbfield'] ? $totalarray['nbfield'] : 10).'" style="font-weight:bold; border-bottom: 1pt solid black;">';
if ($line->subledger_account != "" && $line->subledger_account != '-1') {
print $object->get_compte_desc($line->numero_compte).' : '.length_accounta($line->subledger_account);
print $line->subledger_label.' : '.length_accounta($line->subledger_account);
} else {
// Should not happen: subledger account must be null or a non empty value
print '<span class="error">'.$langs->trans("Unknown");
@ -821,7 +855,7 @@ while ($i < min($num, $limit)) {
// Amount debit
if (!empty($arrayfields['t.debit']['checked'])) {
print '<td class="nowrap right">'.($line->debit ? price($line->debit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->debit ? price($line->debit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -833,7 +867,7 @@ while ($i < min($num, $limit)) {
// Amount credit
if (!empty($arrayfields['t.credit']['checked'])) {
print '<td class="nowrap right">'.($line->credit ? price($line->credit) : '').'</td>';
print '<td class="right nowraponall amount">'.($line->credit ? price($line->credit) : '').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
@ -859,6 +893,14 @@ while ($i < min($num, $limit)) {
}
}
// Validated operation date
if (!empty($arrayfields['t.date_validated']['checked'])) {
print '<td class="center">'.dol_print_date($line->date_validation, 'dayhour').'</td>';
if (!$i) {
$totalarray['nbfield']++;
}
}
// Fields from hook
$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj);
$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
@ -866,12 +908,14 @@ while ($i < min($num, $limit)) {
// Action column
print '<td class="nowraponall center">';
if (empty($line->date_export)) {
if (empty($line->date_export) && empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->creer) {
print '<a class="editfielda" href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_edit().'</a>';
print '<a class="editfielda paddingleft marginrightonly" href="' . DOL_URL_ROOT . '/accountancy/bookkeeping/card.php?piece_num=' . $line->piece_num . $param . '&page=' . $page . ($sortfield ? '&sortfield=' . $sortfield : '') . ($sortorder ? '&sortorder=' . $sortorder : '') . '">' . img_edit() . '</a>';
}
}
if (empty($line->date_validation)) {
if ($user->rights->accounting->mouvements->supprimer) {
print ' &nbsp; <a class="paddingleft" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>';
print '<a class="reposition paddingleft marginrightonly" href="'.$_SERVER['PHP_SELF'].'?action=delmouv&mvt_num='.$line->piece_num.$param.'&page='.$page.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'.img_delete().'</a>';
}
}
print '</td>';
@ -888,9 +932,7 @@ while ($i < min($num, $limit)) {
$i++;
}
if ($num > 0) {
$colspan = $totalarray['nbfield'] - $colnumber;
$colspanend = $totalarray['nbfield'] - $colnumberend;
if ($num > 0 && $colspan > 0) {
print '<tr class="liste_total">';
print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.$accountg.':</td>';
print '<td class="nowrap right">'.price($sous_total_debit).'</td>';

View File

@ -281,7 +281,7 @@ if ($resql) {
$journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $obj->code_journal);
print '<td class="center">'.$journaltoshow.'</td>';
if (empty($obj->lettering_code)) {
if (empty($obj->lettering_code) && empty($obj->date_validated)) {
print '<td class="nowrap center"><input type="checkbox" class="flat checkforselect" name="toselect[]" id="toselect[]" value="'.$obj->rowid.'" /></td>';
print '<td><a href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num='.$obj->piece_num.'">';
print img_edit();
@ -296,15 +296,15 @@ if ($resql) {
print '<tr class="oddeven">';
print '<td class="right" colspan="3">'.$langs->trans("Total").':</td>'."\n";
print '<td class="nowrap right"><strong>'.price($debit).'</strong></td>';
print '<td class="nowrap right"><strong>'.price($credit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($debit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($credit).'</strong></td>';
print '<td colspan="4"></td>';
print "</tr>\n";
print '<tr class="oddeven">';
print '<td class="right" colspan="3">'.$langs->trans("Balancing").':</td>'."\n";
print '<td colspan="2">&nbsp;</td>';
print '<td class="nowrap right"><strong>'.price($credit - $debit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($credit - $debit).'</strong></td>';
print '<td colspan="6"></td>';
print "</tr>\n";

View File

@ -293,15 +293,15 @@ if ($resql) {
print '<tr class="oddeven">';
print '<td class="right" colspan="3">'.$langs->trans("Total").':</td>'."\n";
print '<td class="nowrap right"><strong>'.price($debit).'</strong></td>';
print '<td class="nowrap right"><strong>'.price($credit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($debit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($credit).'</strong></td>';
print '<td colspan="6"></td>';
print "</tr>\n";
print '<tr class="oddeven">';
print '<td class="right" colspan="3">'.$langs->trans("Balancing").':</td>'."\n";
print '<td colspan="2">&nbsp;</td>';
print '<td class="nowrap right"><strong>'.price($credit - $debit).'</strong></td>';
print '<td class="right nowraponall amount"><strong>'.price($credit - $debit).'</strong></td>';
print '<td colspan="4"></td>';
print "</tr>\n";

View File

@ -201,7 +201,7 @@ class AccountancyCategory // extends CommonObject
$sql .= "entity";
$sql .= ") VALUES (";
if ($this->rowid > 0) {
$sql .= " ".$this->rowid.",";
$sql .= " ".((int) $this->rowid).",";
}
$sql .= " ".(!isset($this->code) ? 'NULL' : "'".$this->db->escape($this->code)."'").",";
$sql .= " ".(!isset($this->label) ? 'NULL' : "'".$this->db->escape($this->label)."'").",";
@ -209,9 +209,9 @@ class AccountancyCategory // extends CommonObject
$sql .= " ".(!isset($this->sens) ? 'NULL' : "'".$this->db->escape($this->sens)."'").",";
$sql .= " ".(!isset($this->category_type) ? 'NULL' : "'".$this->db->escape($this->category_type)."'").",";
$sql .= " ".(!isset($this->formula) ? 'NULL' : "'".$this->db->escape($this->formula)."'").",";
$sql .= " ".(!isset($this->position) ? 'NULL' : $this->db->escape($this->position)).",";
$sql .= " ".(!isset($this->fk_country) ? 'NULL' : $this->db->escape($this->fk_country)).",";
$sql .= " ".(!isset($this->active) ? 'NULL' : $this->db->escape($this->active));
$sql .= " ".(!isset($this->position) ? 'NULL' : ((int) $this->position)).",";
$sql .= " ".(!isset($this->fk_country) ? 'NULL' : ((int) $this->fk_country)).",";
$sql .= " ".(!isset($this->active) ? 'NULL' : ((int) $this->active));
$sql .= ", ".$conf->entity;
$sql .= ")";
@ -263,7 +263,7 @@ class AccountancyCategory // extends CommonObject
if ($id) {
$sql .= " WHERE t.rowid = ".((int) $id);
} else {
$sql .= " WHERE t.entity IN (".getEntity('c_accounting_category').")"; // Dont't use entity if you use rowid
$sql .= " WHERE t.entity IN (".getEntity('c_accounting_category').")"; // Don't use entity if you use rowid
if ($code) {
$sql .= " AND t.code = '".$this->db->escape($code)."'";
} elseif ($label) {
@ -418,10 +418,10 @@ class AccountancyCategory // extends CommonObject
/**
* Function to select all accounting accounts from an accounting category
* Function to select into ->lines_display all accounting accounts for a given custom accounting group
*
* @param int $id Id
* @return int <0 if KO, 0 if not found, >0 if OK
* @param int $id Id
* @return int <0 if KO, 0 if not found, >0 if OK
*/
public function display($id)
{
@ -453,33 +453,33 @@ class AccountancyCategory // extends CommonObject
}
/**
* Function to select accounting category of an accounting account present in chart of accounts
* Function to fill ->lines_cptbk with accounting account used (into bookkeeping) and not yet into a custom group
*
* @param int $id Id category
*
* @return int <0 if KO, 0 if not found, >0 if OK
* @param int $id Id of custom group
* @return int <0 if KO, 0 if not found, >0 if OK
*/
/*
public function getCptBK($id)
{
global $conf;
$sql = "SELECT t.numero_compte, t.label_operation, t.doc_ref";
$sql = "SELECT DISTINCT t.numero_compte, t.label_operation, t.doc_ref";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as t";
$sql .= " WHERE t.numero_compte NOT IN (";
$sql .= " WHERE t.numero_compte NOT IN ("; // account not into a custom group
$sql .= " SELECT t.account_number";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as t";
$sql .= " WHERE t.fk_accounting_category = ".$id." AND t.entity = ".$conf->entity.")";
$sql .= " AND t.numero_compte IN (";
$sql .= " WHERE t.fk_accounting_category = ".((int) $id)." AND t.entity = ".$conf->entity.")";
$sql .= " AND t.numero_compte IN ("; // account into current chart of account
$sql .= " SELECT DISTINCT aa.account_number";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
$sql .= " AND asy.rowid = ".$conf->global->CHARTOFACCOUNTS;
$sql .= " AND asy.rowid = ".((int) $conf->global->CHARTOFACCOUNTS);
$sql .= " AND aa.active = 1";
$sql .= " AND aa.entity = ".$conf->entity.")";
$sql .= " GROUP BY t.numero_compte, t.label_operation, t.doc_ref";
$sql .= " ORDER BY t.numero_compte";
$this->lines_CptBk = array();
$this->lines_cptbk = array();
dol_syslog(__METHOD__, LOG_DEBUG);
$resql = $this->db->query($sql);
@ -500,13 +500,13 @@ class AccountancyCategory // extends CommonObject
return -1;
}
}
*/
/**
* Function to select accounting category of an accounting account present in chart of accounts
* Function to fill ->lines_cptbk with accounting account (defined in chart of account) and not yet into a custom group
*
* @param int $id Id of category to know which account to exclude
*
* @return int <0 if KO, 0 if not found, >0 if OK
* @param int $id Id of category to know which account to exclude
* @return int <0 if KO, 0 if not found, >0 if OK
*/
public function getAccountsWithNoCategory($id)
{
@ -515,14 +515,14 @@ class AccountancyCategory // extends CommonObject
$sql = "SELECT aa.account_number as numero_compte, aa.label as label_compte";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
$sql .= " WHERE (aa.fk_accounting_category != ".$id." OR aa.fk_accounting_category IS NULL)";
$sql .= " AND asy.rowid = ".$conf->global->CHARTOFACCOUNTS;
$sql .= " WHERE (aa.fk_accounting_category <> ".((int) $id)." OR aa.fk_accounting_category IS NULL)";
$sql .= " AND asy.rowid = ".((int) $conf->global->CHARTOFACCOUNTS);
$sql .= " AND aa.active = 1";
$sql .= " AND aa.entity = ".$conf->entity;
$sql .= " GROUP BY aa.account_number, aa.label";
$sql .= " ORDER BY aa.account_number, aa.label";
$this->lines_CptBk = array();
$this->lines_cptbk = array();
dol_syslog(__METHOD__, LOG_DEBUG);
$resql = $this->db->query($sql);
@ -562,7 +562,7 @@ class AccountancyCategory // extends CommonObject
$sql = "SELECT aa.rowid, aa.account_number";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
$sql .= " AND asy.rowid = ".$conf->global->CHARTOFACCOUNTS;
$sql .= " AND asy.rowid = ".((int) $conf->global->CHARTOFACCOUNTS);
$sql .= " AND aa.active = 1";
$sql .= " AND aa.entity = ".$conf->entity;
$sql .= " ORDER BY LENGTH(aa.account_number) DESC;"; // LENGTH is ok with mysql and postgresql
@ -589,8 +589,8 @@ class AccountancyCategory // extends CommonObject
$accountincptsadded[$account_number_formated] = 1;
// We found an account number that is in list $cpts of account to add
$sql = "UPDATE ".MAIN_DB_PREFIX."accounting_account";
$sql .= " SET fk_accounting_category=".$id_cat;
$sql .= " WHERE rowid=".$obj->rowid;
$sql .= " SET fk_accounting_category=".((int) $id_cat);
$sql .= " WHERE rowid=".((int) $obj->rowid);
dol_syslog(__METHOD__, LOG_DEBUG);
$resqlupdate = $this->db->query($sql);
if (!$resqlupdate) {
@ -629,7 +629,7 @@ class AccountancyCategory // extends CommonObject
$sql = "UPDATE ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " SET fk_accounting_category= 0";
$sql .= " WHERE aa.rowid= ".$cpt_id;
$sql .= " WHERE aa.rowid = ".((int) $cpt_id);
$this->db->begin();
dol_syslog(__METHOD__." sql=".$sql, LOG_DEBUG);
@ -656,7 +656,7 @@ class AccountancyCategory // extends CommonObject
}
/**
* Function to know all category from accounting account
* Function to know all custom groupd from an accounting account
*
* @return array|integer Result in table (array), -1 if KO
*/
@ -675,7 +675,7 @@ class AccountancyCategory // extends CommonObject
$sql .= " FROM ".MAIN_DB_PREFIX."c_accounting_category as c";
$sql .= " WHERE c.active = 1";
$sql .= " AND c.entity = ".$conf->entity;
$sql .= " AND (c.fk_country = ".$mysoc->country_id." OR c.fk_country = 0)";
$sql .= " AND (c.fk_country = ".((int) $mysoc->country_id)." OR c.fk_country = 0)";
$sql .= " AND cat.rowid = t.fk_accounting_category";
$sql .= " AND t.entity = ".$conf->entity;
$sql .= " ORDER BY cat.position ASC";
@ -785,7 +785,7 @@ class AccountancyCategory // extends CommonObject
}
/**
* Return list of personalized groups that are active
* Return list of custom groups that are active
*
* @param int $categorytype -1=All, 0=Only non computed groups, 1=Only computed groups
* @return array|int Array of groups or -1 if error
@ -806,7 +806,7 @@ class AccountancyCategory // extends CommonObject
if ($categorytype >= 0) {
$sql .= " AND c.category_type = 1";
}
$sql .= " AND (c.fk_country = ".$mysoc->country_id." OR c.fk_country = 0)";
$sql .= " AND (c.fk_country = ".((int) $mysoc->country_id)." OR c.fk_country = 0)";
$sql .= " ORDER BY c.position ASC";
$resql = $this->db->query($sql);
@ -843,11 +843,11 @@ class AccountancyCategory // extends CommonObject
/**
* Get all accounting account of a group.
* Get all accounting account of a custom group (or a list of custom groups).
* You must choose between first parameter (personalized group) or the second (free criteria filter)
*
* @param int $cat_id Id if personalized accounting group/category
* @param string $predefinedgroupwhere Sql criteria filter to select accounting accounts
* @param string $predefinedgroupwhere Sql criteria filter to select accounting accounts. This value must not come from an input of a user.
* @return array|int Array of accounting accounts or -1 if error
*/
public function getCptsCat($cat_id, $predefinedgroupwhere = '')

View File

@ -5,7 +5,7 @@
* Copyright (C) 2015 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2016 Pierre-Henry Favre <phf@atm-consulting.fr>
* Copyright (C) 2016-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2016-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2013-2017 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2017 Elarifr. Ari Elbaz <github@accedinfo.com>
* Copyright (C) 2017-2019 Frédéric France <frederic.france@netlogic.fr>
@ -119,8 +119,8 @@ class AccountancyExport
self::$EXPORT_TYPE_CHARLEMAGNE => $langs->trans('Modelcsv_charlemagne'),
self::$EXPORT_TYPE_LDCOMPTA => $langs->trans('Modelcsv_LDCompta'),
self::$EXPORT_TYPE_LDCOMPTA10 => $langs->trans('Modelcsv_LDCompta10'),
self::$EXPORT_TYPE_GESTIMUMV3 => $langs->trans('Modelcsv_Gestinum_v3'),
self::$EXPORT_TYPE_GESTIMUMV5 => $langs->trans('Modelcsv_Gestinum_v5'),
self::$EXPORT_TYPE_GESTIMUMV3 => $langs->trans('Modelcsv_Gestinumv3'),
self::$EXPORT_TYPE_GESTIMUMV5 => $langs->trans('Modelcsv_Gestinumv5'),
self::$EXPORT_TYPE_FEC => $langs->trans('Modelcsv_FEC'),
self::$EXPORT_TYPE_FEC2 => $langs->trans('Modelcsv_FEC2'),
);
@ -466,38 +466,47 @@ class AccountancyExport
}
/**
* Export format : CIEL
* Export format : CIEL (Format XIMPORT)
* Format since 2003 compatible CIEL version > 2002 / Sage50
* Last review for this format : 2021-09-13 Alexandre Spangaro (aspangaro@open-dsi.fr)
*
* Help : https://sage50c.online-help.sage.fr/aide-technique/
* In sage software | Use menu : "Exchange" > "Importing entries..."
*
* If you want to force filename to "XIMPORT.TXT" for automatically import file present in a directory :
* use constant ACCOUNTING_EXPORT_XIMPORT_FORCE_FILENAME
*
* @param array $TData data
* @return void
*/
public function exportCiel(&$TData)
{
global $conf;
$end_line = "\r\n";
$i = 1;
$date_ecriture = dol_print_date(dol_now(), $conf->global->ACCOUNTING_EXPORT_DATE); // format must be yyyymmdd
foreach ($TData as $data) {
$code_compta = $data->numero_compte;
$code_compta = length_accountg($data->numero_compte);
if (!empty($data->subledger_account)) {
$code_compta = $data->subledger_account;
$code_compta = length_accounta($data->subledger_account);
}
$date_document = dol_print_date($data->doc_date, '%Y%m%d');
$date_echeance = dol_print_date($data->date_lim_reglement, '%Y%m%d');
$Tab = array();
$Tab['num_ecriture'] = str_pad($i, 5);
$Tab['code_journal'] = str_pad($data->code_journal, 2);
$Tab['date_ecriture'] = $date_ecriture;
$Tab['date_ope'] = dol_print_date($data->doc_date, $conf->global->ACCOUNTING_EXPORT_DATE);
$Tab['num_piece'] = str_pad(self::trunc($data->piece_num, 12), 12);
$Tab['num_ecriture'] = str_pad($data->piece_num, 5);
$Tab['code_journal'] = str_pad(self::trunc($data->code_journal, 2), 2);
$Tab['date_ecriture'] = str_pad($date_document, 8, ' ', STR_PAD_LEFT);
$Tab['date_echeance'] = str_pad($date_echeance, 8, ' ', STR_PAD_LEFT);
$Tab['num_piece'] = str_pad(self::trunc($data->doc_ref, 12), 12);
$Tab['num_compte'] = str_pad(self::trunc($code_compta, 11), 11);
$Tab['libelle_ecriture'] = str_pad(self::trunc(dol_string_unaccent($data->doc_ref).dol_string_unaccent($data->label_operation), 25), 25);
$Tab['montant'] = str_pad(abs($data->debit - $data->credit), 13, ' ', STR_PAD_LEFT);
$Tab['montant'] = str_pad(price2fec(abs($data->debit - $data->credit)), 13, ' ', STR_PAD_LEFT);
$Tab['type_montant'] = str_pad($data->sens, 1);
$Tab['vide'] = str_repeat(' ', 18);
$Tab['vide'] = str_repeat(' ', 18); // Analytical accounting - Not managed in Dolibarr
$Tab['intitule_compte'] = str_pad(self::trunc(dol_string_unaccent($data->label_operation), 34), 34);
$Tab['end'] = 'O2003';
$Tab['end'] = 'O2003'; // 0 = EUR | 2003 = Format Ciel
$Tab['end_line'] = $end_line;
@ -507,14 +516,19 @@ class AccountancyExport
}
/**
* Export format : Quadratus
* Export format : Quadratus (Format ASCII)
* Format since 2015 compatible QuadraCOMPTA
* Last review for this format : 2021/09/13 Alexandre Spangaro (aspangaro@open-dsi.fr)
*
* Help : https://docplayer.fr/20769649-Fichier-d-entree-ascii-dans-quadracompta.html
* In QuadraCompta | Use menu : "Outils" > "Suivi des dossiers" > "Import ASCII(Compta)"
*
* @param array $TData data
* @return void
*/
public function exportQuadratus(&$TData)
{
global $conf;
global $conf, $db;
$end_line = "\r\n";
@ -527,6 +541,44 @@ class AccountancyExport
$code_compta = $data->subledger_account;
}
$Tab = array();
if (!empty($data->subledger_account)) {
$Tab['type_ligne'] = 'C';
$Tab['num_compte'] = str_pad(self::trunc($data->subledger_account, 8), 8);
$Tab['lib_compte'] = str_pad(self::trunc($data->subledger_label, 30), 30);
if ($data->doc_type == 'customer_invoice') {
$Tab['lib_alpha'] = strtoupper(str_pad('C'.self::trunc($data->subledger_label, 6), 6));
$Tab['filler'] = str_repeat(' ', 52);
$Tab['coll_compte'] = str_pad(self::trunc($conf->global->ACCOUNTING_ACCOUNT_CUSTOMER, 8), 8);
} elseif ($data->doc_type == 'supplier_invoice') {
$Tab['lib_alpha'] = strtoupper(str_pad('F'.self::trunc($data->subledger_label, 6), 6));
$Tab['filler'] = str_repeat(' ', 52);
$Tab['coll_compte'] = str_pad(self::trunc($conf->global->ACCOUNTING_ACCOUNT_SUPPLIER, 8), 8);
} else {
$Tab['filler'] = str_repeat(' ', 59);
$Tab['coll_compte'] = str_pad(' ', 8);
}
$Tab['filler2'] = str_repeat(' ', 110);
$Tab['Maj'] = 2; // Partial update (alpha key, label, address, collectif, RIB)
if ($data->doc_type == 'customer_invoice') {
$Tab['type_compte'] = 'C';
} elseif ($data->doc_type == 'supplier_invoice') {
$Tab['coll_compte'] = 'F';
} else {
$Tab['coll_compte'] = 'G';
}
$Tab['filler3'] = str_repeat(' ', 235);
$Tab['end_line'] = $end_line;
print implode($Tab);
}
$Tab = array();
$Tab['type_ligne'] = 'M';
$Tab['num_compte'] = str_pad(self::trunc($code_compta, 8), 8);
@ -557,13 +609,13 @@ class AccountancyExport
$Tab['signe_montant'] = '+';
// The amount must be in centimes without decimal points.
$Tab['montant'] = str_pad(abs(($data->debit - $abs->credit) * 100), 12, '0', STR_PAD_LEFT);
$Tab['montant'] = str_pad(abs(($data->debit - $data->credit) * 100), 12, '0', STR_PAD_LEFT);
$Tab['contrepartie'] = str_repeat(' ', 8);
// Force date format : %d%m%y
if (!empty($data->date_echeance)) {
//$Tab['date_echeance'] = dol_print_date($data->date_echeance, $conf->global->ACCOUNTING_EXPORT_DATE);
$Tab['date_echeance'] = dol_print_date($data->date_echeance, '%d%m%y'); // Format must be ddmmyy
if (!empty($data->date_lim_reglement)) {
//$Tab['date_echeance'] = dol_print_date($data->date_lim_reglement, $conf->global->ACCOUNTING_EXPORT_DATE);
$Tab['date_echeance'] = dol_print_date($data->date_lim_reglement, '%d%m%y'); // Format must be ddmmyy
} else {
$Tab['date_echeance'] = '000000';
}
@ -660,9 +712,9 @@ class AccountancyExport
$Tab['code_stat'] = str_repeat(' ', 4);
if (!empty($data->date_echeance)) {
//$Tab['date_echeance'] = dol_print_date($data->date_echeance, $conf->global->ACCOUNTING_EXPORT_DATE);
$Tab['date_echeance'] = dol_print_date($data->date_echeance, '%d%m%Y');
if (!empty($data->date_lim_reglement)) {
//$Tab['date_echeance'] = dol_print_date($data->date_lim_reglement, $conf->global->ACCOUNTING_EXPORT_DATE);
$Tab['date_echeance'] = dol_print_date($data->date_lim_reglement, '%d%m%Y');
} else {
$Tab['date_echeance'] = dol_print_date($data->doc_date, '%d%m%Y');
}
@ -1287,7 +1339,9 @@ class AccountancyExport
/**
* Export format : LD Compta version 10 & higher
* http://www.ldsysteme.fr/fileadmin/telechargement/np/ldcompta/Documentation/IntCptW10.pdf
* Last review for this format : 08-15-2021 Alexandre Spangaro (aspangaro@open-dsi.fr)
*
* Help : http://www.ldsysteme.fr/fileadmin/telechargement/np/ldcompta/Documentation/IntCptW10.pdf
*
* @param array $objectLines data
*
@ -1450,14 +1504,14 @@ class AccountancyExport
print $date_lim_reglement.$separator;
// CNPI
if ($line->doc_type == 'supplier_invoice') {
if (($line->debit - $line->credit) > 0) {
if (($line->amount) < 0) { // Currently, only the sign of amount allows to know the type of invoice (standard or credit note). Other solution is to analyse debit/credit/role of account. TODO Add column doc_type_long or make amount mandatory with rule on sign.
$nature_piece = 'AF';
} else {
$nature_piece = 'FF';
}
} elseif ($line->doc_type == 'customer_invoice') {
if (($line->debit - $line->credit) < 0) {
$nature_piece = 'AC';
if (($line->amount) < 0) {
$nature_piece = 'AC'; // Currently, only the sign of amount allows to know the type of invoice (standard or credit note). Other solution is to analyse debit/credit/role of account. TODO Add column doc_type_long or make amount mandatory with rule on sign.
} else {
$nature_piece = 'FC';
}

Some files were not shown because too many files have changed in this diff Show More