Merge branch 'develop' into fix_multicompany_compatibility2

This commit is contained in:
Laurent Destailleur 2023-03-02 13:42:40 +01:00 committed by GitHub
commit 9fd9b0cfa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5058 changed files with 320014 additions and 88693 deletions

25
.github/workflows/code_quality.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Qodana
on:
schedule:
- cron: "0 20 * * *"
workflow_dispatch:
branches:
- develop
# push:
# branches:
# - develop
jobs:
qodana:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 1
#php-version: '7.1'
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2022.3.4
#with:
# php-version: '7.1'
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

View File

@ -0,0 +1,38 @@
# See syntax file on https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions
name: Doxygen
on:
schedule:
- cron: "0 15 * * *"
workflow_dispatch:
branches:
- develop
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Build
uses: DenverCoder1/doxygen-github-pages-action@v1.2.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
folder: build/html
config_file: build/doxygen/dolibarr-doxygen.doxyfile
# - name: Deploy
# uses: JamesIves/github-pages-deploy-action@v4
# with:
# branch: gh-pages
# folder: build/html # The folder the action should deploy.
# target-folder: docs/html2
#jobs:
# doxygen:
# runs-on: ubuntu-latest
# steps:
# - name: 'Doxygen'
# uses: mattnotmitt/doxygen-action@1.9.5
# with:
# doxyfile-path: build/doxygen

View File

@ -4,6 +4,9 @@ name: "Exakat analysis"
on: on:
schedule: schedule:
- cron: "0 20 * * *" - cron: "0 20 * * *"
workflow_dispatch:
branches:
- develop
permissions: permissions:
contents: read contents: read
@ -13,6 +16,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with:
fetch-depth: 1
- name: Exakat - name: Exakat
uses: docker://exakat/exakat-ga uses: docker://exakat/exakat-ga
with: with:

View File

@ -6,9 +6,14 @@ on:
- cron: "0 21 * * *" - cron: "0 21 * * *"
issue_comment: issue_comment:
types: [created] types: [created]
workflow_dispatch:
permissions: {} # none
jobs: jobs:
stale: stale:
permissions:
issues: write
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: Dolibarr/stale@staleunstale - uses: Dolibarr/stale@staleunstale

2
.gitignore vendored
View File

@ -14,11 +14,11 @@ default.properties
/.pydevproject /.pydevproject
/.vscode /.vscode
.DS_Store .DS_Store
.idea
*.iml *.iml
*.orig *.orig
Thumbs.db Thumbs.db
/dolibarr_genesis.mp4 /dolibarr_genesis.mp4
.phpunit.result.cache
# Log files # Log files
dolibarr_install.log dolibarr_install.log
upgrade.log upgrade.log

5
.idea/php.xml Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="7.0">
<component name="PhpProjectSharedConfiguration" php_language_level="7.0" />
</project>

View File

@ -6,22 +6,26 @@ build:
analysis: analysis:
tests: tests:
override: override:
- php-scrutinizer-run - command: php-scrutinizer-run
idle_timeout: 8000
#- php-scrutinizer-run --sub-project-dir=htdocs/admin
imports: imports:
- javascript
- php - php
filter: filter:
excluded_paths: excluded_paths:
- build/* - build/
- dev/* - dev/
- doc/* - doc/
- documents/* - documents/
- node_modules/* - node_modules/
- test/* - test/
dependency_paths: - htdocs/custom/
- htdocs/includes/* - htdocs/includes/
- htdocs/install/doctemplates/
#dependency_paths:
# - htdocs/includes/
paths: paths:
- htdocs/* - htdocs/*
- scripts/* - scripts/*
@ -32,19 +36,23 @@ tools:
enabled: true enabled: true
extensions: extensions:
- php - php
dependency_paths: #dependency_paths:
- htdocs/includes/ # - htdocs/includes/
filter: filter:
excluded_paths: excluded_paths:
- build/* - build/
- dev/* - dev/
- doc/* - doc/
- test/* - documents/
- htdocs/includes/* - htdocs/custom/
- htdocs/includes/
- htdocs/install/doctemplates/
- htdocs/core/class/lessc.class.php - htdocs/core/class/lessc.class.php
- node_modules/
- test/
paths: paths:
- htdocs/ - htdocs/*
- scripts/ - scripts/*
config: config:
parameter_reference_check: parameter_reference_check:
enabled: true enabled: true
@ -153,67 +161,73 @@ tools:
# To use specific config for a specific path, use path_configs: (see example on page https://scrutinizer-ci.com/docs/configuration/tool_config_structure) # To use specific config for a specific path, use path_configs: (see example on page https://scrutinizer-ci.com/docs/configuration/tool_config_structure)
# php_depend # php_depend
php_pdepend: #php_pdepend:
enabled: false # enabled: false
configuration_file: null # configuration_file: null
suffixes: # suffixes:
- php # - php
excluded_dirs: { } # excluded_dirs: { }
filter: # filter:
excluded_paths: # excluded_paths:
- 'build/*' # - 'build/*'
- 'dev/*' # - 'dev/*'
- 'doc/*' # - 'doc/*'
- 'test/*' # - 'test/*'
- 'htdocs/includes/*' # - 'htdocs/includes/*'
paths: { } # paths: { }
# change tracking # change tracking
php_changetracking: #php_changetracking:
enabled: false # enabled: false
bug_patterns: # bug_patterns:
- '\bfix(?:es|ed)?\b' # - '\bfix(?:es|ed)?\b'
feature_patterns: # feature_patterns:
- '\badd(?:s|ed)?\b' # - '\badd(?:s|ed)?\b'
- '\bimplement(?:s|ed)?\b' # - '\bimplement(?:s|ed)?\b'
filter: # filter:
excluded_paths: # excluded_paths:
- 'build/*' # - 'build/*'
- 'dev/*' # - 'dev/*'
- 'doc/*' # - 'doc/*'
- 'test/*' # - 'documents/*'
- 'htdocs/includes/*' # - 'htdocs/includes/*'
paths: { } # - 'node_modules/*'
# - 'test/*'
# paths: { }
# Similar code detection # Similar code detection
php_sim: #php_sim:
enabled: false # enabled: false
min_mass: 30 # min_mass: 30
filter: # filter:
excluded_paths: # excluded_paths:
- 'build/*' # - 'build/*'
- 'dev/*' # - 'dev/*'
- 'doc/*' # - 'doc/*'
- 'test/*' # - 'documents/*'
- 'htdocs/includes/*' # - 'htdocs/includes/*'
paths: { } # - 'node_modules/*'
# - 'test/*'
# paths: { }
# Coding-Style / Bug Detection # Coding-Style / Bug Detection
js_hint: #js_hint:
enabled: false # enabled: false
use_native_config: true # use_native_config: true
extensions: # extensions:
- js # - js
filter: # filter:
excluded_paths: # excluded_paths:
- 'build/*' # - 'build/*'
- 'dev/*' # - 'dev/*'
- 'doc/*' # - 'doc/*'
- 'test/*' # - 'documents/*'
- 'htdocs/includes/*' # - 'htdocs/includes/*'
paths: { } # - 'node_modules/*'
config: { } # - 'test/*'
path_configs: { } # paths: { }
# config: { }
# path_configs: { }
before_commands: { } before_commands: { }

View File

@ -2,10 +2,9 @@
# from Dolibarr GitHub repository. # from Dolibarr GitHub repository.
# For syntax, see https://docs.travis-ci.com/user/languages/php/ # For syntax, see https://docs.travis-ci.com/user/languages/php/
# We use dist: xenial to have php 5.6+ available # We use dist: bionic = 18.04
os: linux os: linux
dist: xenial dist: bionic
#dist: bionic
language: php language: php
@ -18,21 +17,42 @@ services:
- mysql - mysql
- postgresql - postgresql
before_install:
- |
echo "Add ondrej PPA"
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get update
echo "Disabling Xdebug for composer"
export PHP_VERSION_NAME=$(phpenv version-name)
echo $PHP_VERSION_NAME
ls ~/.phpenv/versions/$PHP_VERSION_NAME/etc/conf.d/
cp ~/.phpenv/versions/$PHP_VERSION_NAME/etc/conf.d/xdebug.ini /tmp/xdebug.ini
phpenv config-rm xdebug.ini
phpenv rehash
echo
addons: addons:
# Force postgresql to 9.4 (the oldest availablable on xenial) # Force postgresql version
postgresql: '9.4' postgresql: '10'
apt: apt:
sources: sources:
# To use the last version of pgloader, we add repo of postgresql with a name available in http://apt.postgresql.org/pub/repos/apt/ - sourceline: 'ppa:ondrej/php'
- pgdg-xenial
packages: packages:
# We need a webserver to test the webservices # We need a webserver to test the webservices
# Let's install Apache with. # Let's install Apache with.
- apache2 - apache2
# mod_php is not supported by Travis. Add fcgi. We install FPM later on.
- libapache2-mod-fastcgi
# We need pgloader for import mysql database into pgsql # We need pgloader for import mysql database into pgsql
- pgloader - pgloader
- php
- php7.1-pgsql
- php7.1-mysqli
- php7.1-xml
- php7.1-intl
- php8.1-pgsql
- php8.1-mysqli
- php8.1-xml
- php8.1-intl
env: env:
global: global:
@ -44,20 +64,20 @@ jobs:
#allow_failures: #allow_failures:
#- php: nightly #- php: nightly
include: include:
- stage: PHP 5.6-7.4 - stage: PHP 7.0-8.1
if: type = push if: type = push
php: '5.6' php: '7.1'
env: DB=postgresql env: DB=postgresql
- stage: PHP 5.6-7.4 - stage: PHP 7.0-8.1
if: type = pull_request OR type = push if: type = pull_request OR type = push
php: '7.4.22' php: '8.1'
env: DB=mysql env: DB=mysql
- stage: PHP Dev - stage: PHP Dev
if: type = push AND branch = develop if: type = push AND branch = develop
php: nightly php: nightly
env: DB=mysql env: DB=mysql
- stage: PHP Dev - stage: PHP Dev
if: type = push AND branch = 15.0 if: type = push AND branch = 17.0
php: nightly php: nightly
env: DB=mysql env: DB=mysql
@ -72,43 +92,31 @@ notifications:
on_failure: always on_failure: always
use_notice: true use_notice: true
before_install:
- |
echo "Disabling Xdebug for composer"
export PHP_VERSION_NAME=$(phpenv version-name)
cp ~/.phpenv/versions/$PHP_VERSION_NAME/etc/conf.d/xdebug.ini /tmp/xdebug.ini
phpenv config-rm xdebug.ini
echo
install: install:
- | - |
echo "Updating Composer (version 2.5 is bugged and generate phpunit error Exception: Serialization of 'Closure' is not allowed)" echo "Updating Composer config"
composer -V
#rm $TRAVIS_BUILD_DIR/composer.json #rm $TRAVIS_BUILD_DIR/composer.json
#rm $TRAVIS_BUILD_DIR/composer.lock #rm $TRAVIS_BUILD_DIR/composer.lock
composer -V
composer self-update 2.4.4
#composer -n init #composer -n init
#composer -n config vendor-dir htdocs/includes #composer -n config vendor-dir htdocs/includes
composer -n config -g vendor-dir htdocs/includes composer -n config -g vendor-dir htdocs/includes
echo echo
- | - |
echo "Installing Composer dependencies - PHP Unit, Parallel Lint, PHP CodeSniffer, PHP Vardump check - for $TRAVIS_PHP_VERSION" echo "Update Composer version and Install tools - PHP Unit, Parallel Lint, PHP CodeSniffer, PHP Vardump check - for $TRAVIS_PHP_VERSION"
if [ "$TRAVIS_PHP_VERSION" = '5.6' ]; then echo "(version 2.5 is bugged and generate phpunit error Exception: Serialization of 'Closure' is not allowed)"
composer -n require phpunit/phpunit ^5 \
php-parallel-lint/php-parallel-lint ^1 \
php-parallel-lint/php-console-highlighter ^0 \
php-parallel-lint/php-var-dump-check ~0.4 \
squizlabs/php_codesniffer ^3
fi
if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ]; then if [ "$TRAVIS_PHP_VERSION" = '7.0' ] || [ "$TRAVIS_PHP_VERSION" = '7.1' ] || [ "$TRAVIS_PHP_VERSION" = '7.2' ]; then
composer self-update 2.2.18
composer -n require phpunit/phpunit ^6 \ composer -n require phpunit/phpunit ^6 \
php-parallel-lint/php-parallel-lint ^1 \ php-parallel-lint/php-parallel-lint ^1 \
php-parallel-lint/php-console-highlighter ^0 \ php-parallel-lint/php-console-highlighter ^0 \
php-parallel-lint/php-var-dump-check ~0.4 \ php-parallel-lint/php-var-dump-check ~0.4 \
squizlabs/php_codesniffer ^3 squizlabs/php_codesniffer ^3
fi fi
if [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ] || [ "$TRAVIS_PHP_VERSION" = '7.4.22' ]; then if [ "$TRAVIS_PHP_VERSION" = '7.3' ] || [ "$TRAVIS_PHP_VERSION" = '7.4' ]; then
composer self-update 2.2.18
composer -n require phpunit/phpunit ^7 \ composer -n require phpunit/phpunit ^7 \
php-parallel-lint/php-parallel-lint ^1.2 \ php-parallel-lint/php-parallel-lint ^1.2 \
php-parallel-lint/php-console-highlighter ^0 \ php-parallel-lint/php-console-highlighter ^0 \
@ -116,13 +124,16 @@ install:
squizlabs/php_codesniffer ^3 squizlabs/php_codesniffer ^3
fi fi
# phpunit 9 is required for php 8 # phpunit 9 is required for php 8
if [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then if [ "$TRAVIS_PHP_VERSION" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then
composer -n require --ignore-platform-reqs phpunit/phpunit ^7 \ composer self-update 2.4.4
composer -n require --ignore-platform-reqs phpunit/phpunit ^8 \
php-parallel-lint/php-parallel-lint ^1.2 \ php-parallel-lint/php-parallel-lint ^1.2 \
php-parallel-lint/php-console-highlighter ^0 \ php-parallel-lint/php-console-highlighter ^0 \
php-parallel-lint/php-var-dump-check ~0.4 \ php-parallel-lint/php-var-dump-check ~0.4 \
squizlabs/php_codesniffer ^3 squizlabs/php_codesniffer ^3
fi fi
# Remove non expected files
rm -fr /home/travis/build/Dolibarr/dolibarr/htdocs/includes/phpunit/php-code-coverage/src/Report/Html/Renderer/Template/js
echo echo
- | - |
@ -246,17 +257,22 @@ before_script:
- echo "Setting up Apache + FPM" - echo "Setting up Apache + FPM"
# setup link for php legacy
- sudo ln -s ~/.phpenv/versions/$(phpenv version-name)/bin/php /bin/php
# install apache web server
- sudo apt-get install apache2 php-fpm php-mysql php-pgsql php-gd php-ldap php-xml php-mbstring libapache2-mod-php
# enable php-fpm # enable php-fpm
- sudo cp ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf.default ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf - 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" = '7.4.22' ] || [ "$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" = '8.0' ] || [ "$TRAVIS_PHP_VERSION" = '8.1' ] || [ "$TRAVIS_PHP_VERSION" = 'nightly' ]; then
# Copy the included pool # 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 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 fi
- sudo a2enmod rewrite actions fastcgi alias - sudo a2enmod proxy_fcgi rewrite setenvif cgi alias
- echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini - echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- sudo sed -i -e "s,www-data,travis,g" /etc/apache2/envvars - sudo sed -i -e "s,www-data,travis,g" /etc/apache2/envvars
- sudo chown -R travis:travis /var/lib/apache2/fastcgi #- sudo chown -R travis:travis /var/lib/apache2/fastcgi
# start php-fpm
- ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
# configure apache virtual hosts # configure apache virtual hosts
- sudo cp -f build/travis-ci/apache.conf /etc/apache2/sites-available/000-default.conf - sudo cp -f build/travis-ci/apache.conf /etc/apache2/sites-available/000-default.conf
@ -284,12 +300,12 @@ script:
set -e set -e
#parallel-lint --exclude htdocs/includes --blame . #parallel-lint --exclude htdocs/includes --blame .
# Exclusions are defined in the ruleset.xml file # Exclusions are defined in the ruleset.xml file
if [ "$TRAVIS_PHP_VERSION" = "7.4.22" ]; then if [ "$TRAVIS_PHP_VERSION" = "8.1" ]; 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 \ 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/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/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/mike42/escpos-php/example --exclude htdocs/includes/maximebf \
--exclude htdocs/includes/phpunit/ --exclude htdocs/includes/tecnickcom/tcpdf/include/barcodes --exclude htdocs/includes/webmozart --blame . --exclude htdocs/includes/phpunit/ --exclude htdocs/includes/tecnickcom/tcpdf/include/barcodes --exclude htdocs/includes/webmozart --exclude htdocs/includes/webklex --blame .
fi fi
set +e set +e
echo echo
@ -299,7 +315,7 @@ script:
# Ensure we catch errors # Ensure we catch errors
set -e set -e
# Exclusions are defined in the ruleset.xml file # Exclusions are defined in the ruleset.xml file
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "7.4.22" ]; then if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "8.1" ]; 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 .; 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 fi
set +e set +e
@ -310,7 +326,7 @@ script:
# Ensure we catch errors # Ensure we catch errors
set -e set -e
# Exclusions are defined in the ruleset.xml file # Exclusions are defined in the ruleset.xml file
if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "7.4.22" ]; then if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_PHP_VERSION" = "8.1" ]; then
var-dump-check --extensions php --tracy --exclude htdocs/includes --exclude test/ --exclude htdocs/public/test/ --exclude htdocs/core/lib/functions.lib.php . var-dump-check --extensions php --tracy --exclude htdocs/includes --exclude test/ --exclude htdocs/public/test/ --exclude htdocs/core/lib/functions.lib.php .
fi fi
set +e set +e
@ -436,6 +452,12 @@ script:
php upgrade.php 15.0.0 16.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade15001600.log php upgrade.php 15.0.0 16.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade15001600.log
php upgrade2.php 15.0.0 16.0.0 > $TRAVIS_BUILD_DIR/upgrade15001600-2.log php upgrade2.php 15.0.0 16.0.0 > $TRAVIS_BUILD_DIR/upgrade15001600-2.log
php step5.php 15.0.0 16.0.0 > $TRAVIS_BUILD_DIR/upgrade15001600-3.log php step5.php 15.0.0 16.0.0 > $TRAVIS_BUILD_DIR/upgrade15001600-3.log
php upgrade.php 16.0.0 17.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade16001700.log
php upgrade2.php 16.0.0 17.0.0 > $TRAVIS_BUILD_DIR/upgrade16001700-2.log
php step5.php 16.0.0 17.0.0 > $TRAVIS_BUILD_DIR/upgrade16001700-3.log
php upgrade.php 17.0.0 18.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade17001800.log
php upgrade2.php 17.0.0 18.0.0 > $TRAVIS_BUILD_DIR/upgrade17001800-2.log
php step5.php 17.0.0 18.0.0 > $TRAVIS_BUILD_DIR/upgrade17001800-3.log
ls -alrt $TRAVIS_BUILD_DIR/ ls -alrt $TRAVIS_BUILD_DIR/
- | - |
@ -468,6 +490,9 @@ after_script:
ls $TRAVIS_BUILD_DIR/documents ls $TRAVIS_BUILD_DIR/documents
#cat $TRAVIS_BUILD_DIR/documents/dolibarr.log #cat $TRAVIS_BUILD_DIR/documents/dolibarr.log
sudo tail -n 50 $TRAVIS_BUILD_DIR/documents/dolibarr.log sudo tail -n 50 $TRAVIS_BUILD_DIR/documents/dolibarr.log
echo "After script - Output last lines of apache error.log"
sudo ls /var/log/apache2
sudo tail -n 50 /var/log/apache2/travis_error_log
after_success: after_success:
- | - |
@ -476,16 +501,16 @@ after_success:
after_failure: after_failure:
- | - |
echo Failure detected, so we show samples of log to help diagnose echo Failure detected, so we show samples of log to help diagnose
# This part of code is executed only if previous command that fails are enclosed with set +e # This part of code is executed only if the command that fails are enclosed with set +e
# Upgrade log files # Show upgrade log files
for ficlog in `ls $TRAVIS_BUILD_DIR/*.log` for ficlog in `ls $TRAVIS_BUILD_DIR/*.log`
do do
echo "Debugging informations for file $ficlog" echo "Debugging informations for file $ficlog"
#cat $ficlog #cat $ficlog
done done
# Apache log file # Show Apache log file
echo "Debugging informations for file apache error.log" echo "Debugging informations for file apache error.log"
sudo cat /var/log/apache2/travis_error_log sudo tail -n 50 /var/log/apache2/travis_error_log
if [ "$DEBUG" = true ]; then if [ "$DEBUG" = true ]; then
# Dolibarr log file # Dolibarr log file
echo "Debugging informations for file dolibarr.log (latest 50 lines)" echo "Debugging informations for file dolibarr.log (latest 50 lines)"

View File

@ -2,433 +2,439 @@
host = https://www.transifex.com host = https://www.transifex.com
lang_map = uz: uz_UZ, sw: sw_SW, sr@latin: sr_RS lang_map = uz: uz_UZ, sw: sw_SW, sr@latin: sr_RS
[dolibarr.accountancy] [o:dolibarr-association:p:dolibarr:r:accountancy]
file_filter = htdocs/langs/<lang>/accountancy.lang file_filter = htdocs/langs/<lang>/accountancy.lang
source_file = htdocs/langs/en_US/accountancy.lang source_file = htdocs/langs/en_US/accountancy.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.admin] [o:dolibarr-association:p:dolibarr:r:admin]
file_filter = htdocs/langs/<lang>/admin.lang file_filter = htdocs/langs/<lang>/admin.lang
source_file = htdocs/langs/en_US/admin.lang source_file = htdocs/langs/en_US/admin.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.agenda] [o:dolibarr-association:p:dolibarr:r:agenda]
file_filter = htdocs/langs/<lang>/agenda.lang file_filter = htdocs/langs/<lang>/agenda.lang
source_file = htdocs/langs/en_US/agenda.lang source_file = htdocs/langs/en_US/agenda.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.assets] [o:dolibarr-association:p:dolibarr:r:assets]
file_filter = htdocs/langs/<lang>/assets.lang file_filter = htdocs/langs/<lang>/assets.lang
source_file = htdocs/langs/en_US/assets.lang source_file = htdocs/langs/en_US/assets.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.banks] [o:dolibarr-association:p:dolibarr:r:banks]
file_filter = htdocs/langs/<lang>/banks.lang file_filter = htdocs/langs/<lang>/banks.lang
source_file = htdocs/langs/en_US/banks.lang source_file = htdocs/langs/en_US/banks.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.bills] [o:dolibarr-association:p:dolibarr:r:bills]
file_filter = htdocs/langs/<lang>/bills.lang file_filter = htdocs/langs/<lang>/bills.lang
source_file = htdocs/langs/en_US/bills.lang source_file = htdocs/langs/en_US/bills.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.blockedlog] [o:dolibarr-association:p:dolibarr:r:blockedlog]
file_filter = htdocs/langs/<lang>/blockedlog.lang file_filter = htdocs/langs/<lang>/blockedlog.lang
source_file = htdocs/langs/en_US/blockedlog.lang source_file = htdocs/langs/en_US/blockedlog.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.bookmarks] [o:dolibarr-association:p:dolibarr:r:bookmarks]
file_filter = htdocs/langs/<lang>/bookmarks.lang file_filter = htdocs/langs/<lang>/bookmarks.lang
source_file = htdocs/langs/en_US/bookmarks.lang source_file = htdocs/langs/en_US/bookmarks.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.boxes] [o:dolibarr-association:p:dolibarr:r:boxes]
file_filter = htdocs/langs/<lang>/boxes.lang file_filter = htdocs/langs/<lang>/boxes.lang
source_file = htdocs/langs/en_US/boxes.lang source_file = htdocs/langs/en_US/boxes.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.cashdesk] [o:dolibarr-association:p:dolibarr:r:cashdesk]
file_filter = htdocs/langs/<lang>/cashdesk.lang file_filter = htdocs/langs/<lang>/cashdesk.lang
source_file = htdocs/langs/en_US/cashdesk.lang source_file = htdocs/langs/en_US/cashdesk.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.categories] [o:dolibarr-association:p:dolibarr:r:categories]
file_filter = htdocs/langs/<lang>/categories.lang file_filter = htdocs/langs/<lang>/categories.lang
source_file = htdocs/langs/en_US/categories.lang source_file = htdocs/langs/en_US/categories.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.commercial] [o:dolibarr-association:p:dolibarr:r:commercial]
file_filter = htdocs/langs/<lang>/commercial.lang file_filter = htdocs/langs/<lang>/commercial.lang
source_file = htdocs/langs/en_US/commercial.lang source_file = htdocs/langs/en_US/commercial.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.companies] [o:dolibarr-association:p:dolibarr:r:companies]
file_filter = htdocs/langs/<lang>/companies.lang file_filter = htdocs/langs/<lang>/companies.lang
source_file = htdocs/langs/en_US/companies.lang source_file = htdocs/langs/en_US/companies.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.compta] [o:dolibarr-association:p:dolibarr:r:compta]
file_filter = htdocs/langs/<lang>/compta.lang file_filter = htdocs/langs/<lang>/compta.lang
source_file = htdocs/langs/en_US/compta.lang source_file = htdocs/langs/en_US/compta.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.contracts] [o:dolibarr-association:p:dolibarr:r:contracts]
file_filter = htdocs/langs/<lang>/contracts.lang file_filter = htdocs/langs/<lang>/contracts.lang
source_file = htdocs/langs/en_US/contracts.lang source_file = htdocs/langs/en_US/contracts.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.cron] [o:dolibarr-association:p:dolibarr:r:cron]
file_filter = htdocs/langs/<lang>/cron.lang file_filter = htdocs/langs/<lang>/cron.lang
source_file = htdocs/langs/en_US/cron.lang source_file = htdocs/langs/en_US/cron.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.deliveries] [o:dolibarr-association:p:dolibarr:r:datapolicy]
file_filter = htdocs/langs/<lang>/datapolicy.lang
source_file = htdocs/langs/en_US/datapolicy.lang
source_lang = en_US
type = MOZILLAPROPERTIES
[o:dolibarr-association:p:dolibarr:r:deliveries]
file_filter = htdocs/langs/<lang>/deliveries.lang file_filter = htdocs/langs/<lang>/deliveries.lang
source_file = htdocs/langs/en_US/deliveries.lang source_file = htdocs/langs/en_US/deliveries.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.dict] [o:dolibarr-association:p:dolibarr:r:dict]
file_filter = htdocs/langs/<lang>/dict.lang file_filter = htdocs/langs/<lang>/dict.lang
source_file = htdocs/langs/en_US/dict.lang source_file = htdocs/langs/en_US/dict.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.donations] [o:dolibarr-association:p:dolibarr:r:donations]
file_filter = htdocs/langs/<lang>/donations.lang file_filter = htdocs/langs/<lang>/donations.lang
source_file = htdocs/langs/en_US/donations.lang source_file = htdocs/langs/en_US/donations.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.ecm] [o:dolibarr-association:p:dolibarr:r:ecm]
file_filter = htdocs/langs/<lang>/ecm.lang file_filter = htdocs/langs/<lang>/ecm.lang
source_file = htdocs/langs/en_US/ecm.lang source_file = htdocs/langs/en_US/ecm.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.errors] [o:dolibarr-association:p:dolibarr:r:errors]
file_filter = htdocs/langs/<lang>/errors.lang file_filter = htdocs/langs/<lang>/errors.lang
source_file = htdocs/langs/en_US/errors.lang source_file = htdocs/langs/en_US/errors.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.eventorganization] [o:dolibarr-association:p:dolibarr:r:eventorganization]
file_filter = htdocs/langs/<lang>/eventorganization.lang file_filter = htdocs/langs/<lang>/eventorganization.lang
source_file = htdocs/langs/en_US/eventorganization.lang source_file = htdocs/langs/en_US/eventorganization.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.exports] [o:dolibarr-association:p:dolibarr:r:exports]
file_filter = htdocs/langs/<lang>/exports.lang file_filter = htdocs/langs/<lang>/exports.lang
source_file = htdocs/langs/en_US/exports.lang source_file = htdocs/langs/en_US/exports.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.help] [o:dolibarr-association:p:dolibarr:r:help]
file_filter = htdocs/langs/<lang>/help.lang file_filter = htdocs/langs/<lang>/help.lang
source_file = htdocs/langs/en_US/help.lang source_file = htdocs/langs/en_US/help.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.holiday] [o:dolibarr-association:p:dolibarr:r:holiday]
file_filter = htdocs/langs/<lang>/holiday.lang file_filter = htdocs/langs/<lang>/holiday.lang
source_file = htdocs/langs/en_US/holiday.lang source_file = htdocs/langs/en_US/holiday.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.hrm] [o:dolibarr-association:p:dolibarr:r:hrm]
file_filter = htdocs/langs/<lang>/hrm.lang file_filter = htdocs/langs/<lang>/hrm.lang
source_file = htdocs/langs/en_US/hrm.lang source_file = htdocs/langs/en_US/hrm.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.install] [o:dolibarr-association:p:dolibarr:r:install]
file_filter = htdocs/langs/<lang>/install.lang file_filter = htdocs/langs/<lang>/install.lang
source_file = htdocs/langs/en_US/install.lang source_file = htdocs/langs/en_US/install.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.interventions] [o:dolibarr-association:p:dolibarr:r:interventions]
file_filter = htdocs/langs/<lang>/interventions.lang file_filter = htdocs/langs/<lang>/interventions.lang
source_file = htdocs/langs/en_US/interventions.lang source_file = htdocs/langs/en_US/interventions.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.intracommreport] [o:dolibarr-association:p:dolibarr:r:intracommreport]
file_filter = htdocs/langs/<lang>/intracommreport.lang file_filter = htdocs/langs/<lang>/intracommreport.lang
source_file = htdocs/langs/en_US/intracommreport.lang source_file = htdocs/langs/en_US/intracommreport.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.knowledgemanagement] [o:dolibarr-association:p:dolibarr:r:knowledgemanagement]
file_filter = htdocs/langs/<lang>/knowledgemanagement.lang file_filter = htdocs/langs/<lang>/knowledgemanagement.lang
source_file = htdocs/langs/en_US/knowledgemanagement.lang source_file = htdocs/langs/en_US/knowledgemanagement.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.languages-not-res] [o:dolibarr-association:p:dolibarr:r:languages-not-res]
file_filter = htdocs/langs/<lang>/languages.lang file_filter = htdocs/langs/<lang>/languages.lang
source_file = htdocs/langs/en_US/languages.lang source_file = htdocs/langs/en_US/languages.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.ldap] [o:dolibarr-association:p:dolibarr:r:ldap]
file_filter = htdocs/langs/<lang>/ldap.lang file_filter = htdocs/langs/<lang>/ldap.lang
source_file = htdocs/langs/en_US/ldap.lang source_file = htdocs/langs/en_US/ldap.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.link] [o:dolibarr-association:p:dolibarr:r:link]
file_filter = htdocs/langs/<lang>/link.lang file_filter = htdocs/langs/<lang>/link.lang
source_file = htdocs/langs/en_US/link.lang source_file = htdocs/langs/en_US/link.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.loan] [o:dolibarr-association:p:dolibarr:r:loan]
file_filter = htdocs/langs/<lang>/loan.lang file_filter = htdocs/langs/<lang>/loan.lang
source_file = htdocs/langs/en_US/loan.lang source_file = htdocs/langs/en_US/loan.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.mailmanspip] [o:dolibarr-association:p:dolibarr:r:mailmanspip]
file_filter = htdocs/langs/<lang>/mailmanspip.lang file_filter = htdocs/langs/<lang>/mailmanspip.lang
source_file = htdocs/langs/en_US/mailmanspip.lang source_file = htdocs/langs/en_US/mailmanspip.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.mails] [o:dolibarr-association:p:dolibarr:r:mails]
file_filter = htdocs/langs/<lang>/mails.lang file_filter = htdocs/langs/<lang>/mails.lang
source_file = htdocs/langs/en_US/mails.lang source_file = htdocs/langs/en_US/mails.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.main] [o:dolibarr-association:p:dolibarr:r:main]
file_filter = htdocs/langs/<lang>/main.lang file_filter = htdocs/langs/<lang>/main.lang
source_file = htdocs/langs/en_US/main.lang source_file = htdocs/langs/en_US/main.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.margins] [o:dolibarr-association:p:dolibarr:r:margins]
file_filter = htdocs/langs/<lang>/margins.lang file_filter = htdocs/langs/<lang>/margins.lang
source_file = htdocs/langs/en_US/margins.lang source_file = htdocs/langs/en_US/margins.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.members] [o:dolibarr-association:p:dolibarr:r:members]
file_filter = htdocs/langs/<lang>/members.lang file_filter = htdocs/langs/<lang>/members.lang
source_file = htdocs/langs/en_US/members.lang source_file = htdocs/langs/en_US/members.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.modulebuilder] [o:dolibarr-association:p:dolibarr:r:modulebuilder]
file_filter = htdocs/langs/<lang>/modulebuilder.lang file_filter = htdocs/langs/<lang>/modulebuilder.lang
source_file = htdocs/langs/en_US/modulebuilder.lang source_file = htdocs/langs/en_US/modulebuilder.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.mrp] [o:dolibarr-association:p:dolibarr:r:mrp]
file_filter = htdocs/langs/<lang>/mrp.lang file_filter = htdocs/langs/<lang>/mrp.lang
source_file = htdocs/langs/en_US/mrp.lang source_file = htdocs/langs/en_US/mrp.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.multicurrency] [o:dolibarr-association:p:dolibarr:r:multicurrency]
file_filter = htdocs/langs/<lang>/multicurrency.lang file_filter = htdocs/langs/<lang>/multicurrency.lang
source_file = htdocs/langs/en_US/multicurrency.lang source_file = htdocs/langs/en_US/multicurrency.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.oauth] [o:dolibarr-association:p:dolibarr:r:oauth]
file_filter = htdocs/langs/<lang>/oauth.lang file_filter = htdocs/langs/<lang>/oauth.lang
source_file = htdocs/langs/en_US/oauth.lang source_file = htdocs/langs/en_US/oauth.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.opensurvey] [o:dolibarr-association:p:dolibarr:r:opensurvey]
file_filter = htdocs/langs/<lang>/opensurvey.lang file_filter = htdocs/langs/<lang>/opensurvey.lang
source_file = htdocs/langs/en_US/opensurvey.lang source_file = htdocs/langs/en_US/opensurvey.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.orders] [o:dolibarr-association:p:dolibarr:r:orders]
file_filter = htdocs/langs/<lang>/orders.lang file_filter = htdocs/langs/<lang>/orders.lang
source_file = htdocs/langs/en_US/orders.lang source_file = htdocs/langs/en_US/orders.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.other] [o:dolibarr-association:p:dolibarr:r:other]
file_filter = htdocs/langs/<lang>/other.lang file_filter = htdocs/langs/<lang>/other.lang
source_file = htdocs/langs/en_US/other.lang source_file = htdocs/langs/en_US/other.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.partnership] [o:dolibarr-association:p:dolibarr:r:partnership]
file_filter = htdocs/langs/<lang>/partnership.lang file_filter = htdocs/langs/<lang>/partnership.lang
source_file = htdocs/langs/en_US/partnership.lang source_file = htdocs/langs/en_US/partnership.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.paybox] [o:dolibarr-association:p:dolibarr:r:paybox]
file_filter = htdocs/langs/<lang>/paybox.lang file_filter = htdocs/langs/<lang>/paybox.lang
source_file = htdocs/langs/en_US/paybox.lang source_file = htdocs/langs/en_US/paybox.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.paypal] [o:dolibarr-association:p:dolibarr:r:paypal]
file_filter = htdocs/langs/<lang>/paypal.lang file_filter = htdocs/langs/<lang>/paypal.lang
source_file = htdocs/langs/en_US/paypal.lang source_file = htdocs/langs/en_US/paypal.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.printing] [o:dolibarr-association:p:dolibarr:r:printing]
file_filter = htdocs/langs/<lang>/printing.lang file_filter = htdocs/langs/<lang>/printing.lang
source_file = htdocs/langs/en_US/printing.lang source_file = htdocs/langs/en_US/printing.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.productbatch] [o:dolibarr-association:p:dolibarr:r:productbatch]
file_filter = htdocs/langs/<lang>/productbatch.lang file_filter = htdocs/langs/<lang>/productbatch.lang
source_file = htdocs/langs/en_US/productbatch.lang source_file = htdocs/langs/en_US/productbatch.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.products] [o:dolibarr-association:p:dolibarr:r:products]
file_filter = htdocs/langs/<lang>/products.lang file_filter = htdocs/langs/<lang>/products.lang
source_file = htdocs/langs/en_US/products.lang source_file = htdocs/langs/en_US/products.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.projects] [o:dolibarr-association:p:dolibarr:r:projects]
file_filter = htdocs/langs/<lang>/projects.lang file_filter = htdocs/langs/<lang>/projects.lang
source_file = htdocs/langs/en_US/projects.lang source_file = htdocs/langs/en_US/projects.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.propal] [o:dolibarr-association:p:dolibarr:r:propal]
file_filter = htdocs/langs/<lang>/propal.lang file_filter = htdocs/langs/<lang>/propal.lang
source_file = htdocs/langs/en_US/propal.lang source_file = htdocs/langs/en_US/propal.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.receiptprinter] [o:dolibarr-association:p:dolibarr:r:receiptprinter]
file_filter = htdocs/langs/<lang>/receiptprinter.lang file_filter = htdocs/langs/<lang>/receiptprinter.lang
source_file = htdocs/langs/en_US/receiptprinter.lang source_file = htdocs/langs/en_US/receiptprinter.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.receptions] [o:dolibarr-association:p:dolibarr:r:receptions]
file_filter = htdocs/langs/<lang>/receptions.lang file_filter = htdocs/langs/<lang>/receptions.lang
source_file = htdocs/langs/en_US/receptions.lang source_file = htdocs/langs/en_US/receptions.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.recruitment] [o:dolibarr-association:p:dolibarr:r:recruitment]
file_filter = htdocs/langs/<lang>/recruitment.lang file_filter = htdocs/langs/<lang>/recruitment.lang
source_file = htdocs/langs/en_US/recruitment.lang source_file = htdocs/langs/en_US/recruitment.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.resource] [o:dolibarr-association:p:dolibarr:r:resource]
file_filter = htdocs/langs/<lang>/resource.lang file_filter = htdocs/langs/<lang>/resource.lang
source_file = htdocs/langs/en_US/resource.lang source_file = htdocs/langs/en_US/resource.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.salaries] [o:dolibarr-association:p:dolibarr:r:salaries]
file_filter = htdocs/langs/<lang>/salaries.lang file_filter = htdocs/langs/<lang>/salaries.lang
source_file = htdocs/langs/en_US/salaries.lang source_file = htdocs/langs/en_US/salaries.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.sendings] [o:dolibarr-association:p:dolibarr:r:sendings]
file_filter = htdocs/langs/<lang>/sendings.lang file_filter = htdocs/langs/<lang>/sendings.lang
source_file = htdocs/langs/en_US/sendings.lang source_file = htdocs/langs/en_US/sendings.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.sms] [o:dolibarr-association:p:dolibarr:r:sms]
file_filter = htdocs/langs/<lang>/sms.lang file_filter = htdocs/langs/<lang>/sms.lang
source_file = htdocs/langs/en_US/sms.lang source_file = htdocs/langs/en_US/sms.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.stocks] [o:dolibarr-association:p:dolibarr:r:stocks]
file_filter = htdocs/langs/<lang>/stocks.lang file_filter = htdocs/langs/<lang>/stocks.lang
source_file = htdocs/langs/en_US/stocks.lang source_file = htdocs/langs/en_US/stocks.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.stripe] [o:dolibarr-association:p:dolibarr:r:stripe]
file_filter = htdocs/langs/<lang>/stripe.lang file_filter = htdocs/langs/<lang>/stripe.lang
source_file = htdocs/langs/en_US/stripe.lang source_file = htdocs/langs/en_US/stripe.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.supplier_proposal] [o:dolibarr-association:p:dolibarr:r:supplier_proposal]
file_filter = htdocs/langs/<lang>/supplier_proposal.lang file_filter = htdocs/langs/<lang>/supplier_proposal.lang
source_file = htdocs/langs/en_US/supplier_proposal.lang source_file = htdocs/langs/en_US/supplier_proposal.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.suppliers] [o:dolibarr-association:p:dolibarr:r:suppliers]
file_filter = htdocs/langs/<lang>/suppliers.lang file_filter = htdocs/langs/<lang>/suppliers.lang
source_file = htdocs/langs/en_US/suppliers.lang source_file = htdocs/langs/en_US/suppliers.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.ticket] [o:dolibarr-association:p:dolibarr:r:ticket]
file_filter = htdocs/langs/<lang>/ticket.lang file_filter = htdocs/langs/<lang>/ticket.lang
source_file = htdocs/langs/en_US/ticket.lang source_file = htdocs/langs/en_US/ticket.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.trips] [o:dolibarr-association:p:dolibarr:r:trips]
file_filter = htdocs/langs/<lang>/trips.lang file_filter = htdocs/langs/<lang>/trips.lang
source_file = htdocs/langs/en_US/trips.lang source_file = htdocs/langs/en_US/trips.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.users] [o:dolibarr-association:p:dolibarr:r:users]
file_filter = htdocs/langs/<lang>/users.lang file_filter = htdocs/langs/<lang>/users.lang
source_file = htdocs/langs/en_US/users.lang source_file = htdocs/langs/en_US/users.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.website] [o:dolibarr-association:p:dolibarr:r:website]
file_filter = htdocs/langs/<lang>/website.lang file_filter = htdocs/langs/<lang>/website.lang
source_file = htdocs/langs/en_US/website.lang source_file = htdocs/langs/en_US/website.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.withdrawals] [o:dolibarr-association:p:dolibarr:r:withdrawals]
file_filter = htdocs/langs/<lang>/withdrawals.lang file_filter = htdocs/langs/<lang>/withdrawals.lang
source_file = htdocs/langs/en_US/withdrawals.lang source_file = htdocs/langs/en_US/withdrawals.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.workflow] [o:dolibarr-association:p:dolibarr:r:workflow]
file_filter = htdocs/langs/<lang>/workflow.lang file_filter = htdocs/langs/<lang>/workflow.lang
source_file = htdocs/langs/en_US/workflow.lang source_file = htdocs/langs/en_US/workflow.lang
source_lang = en_US source_lang = en_US
type = MOZILLAPROPERTIES type = MOZILLAPROPERTIES
[dolibarr.zapier] [o:dolibarr-association:p:dolibarr:r:zapier]
file_filter = htdocs/langs/<lang>/zapier.lang file_filter = htdocs/langs/<lang>/zapier.lang
source_file = htdocs/langs/en_US/zapier.lang source_file = htdocs/langs/en_US/zapier.lang
source_lang = en_US source_lang = en_US

View File

@ -23,7 +23,6 @@ Licence of dependencies of third-party components used by Dolibarr (all compatib
Component Version License GPL Compatible Usage Component Version License GPL Compatible Usage
------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------
PHP libraries: PHP libraries:
ADOdb-Date 0.36 Modified BSD License Yes Date convertion (not into rpm package)
EvalMath 1.0 BSD Yes Safe math expressions evaluation 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 Escpos-php 2.2 MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers
GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert
@ -33,8 +32,9 @@ PEAR Mail_MIME 1.8.9 BSD Yes
ParseDown 1.6 MIT License Yes Markdown parser ParseDown 1.6 MIT License Yes Markdown parser
PCLZip 2.8.4 LGPL-3+ Yes Library to zip/unzip files 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 PHPDebugBar 1.15.1 MIT License Yes Used only by the module "debugbar" for developers
PHP-Imap 2.7.2 MIT License Yes Library to use IMAP with OAuth
PHPSpreadSheet 1.8.2 LGPL-2.1+ Yes Read/Write XLS files, read ODS files PHPSpreadSheet 1.8.2 LGPL-2.1+ Yes Read/Write XLS files, read ODS files
php-iban 4.1 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP php-iban 4.1.1 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 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 PHPPrintIPP 1.3 GPL-2+ Yes Library to send print IPP requests
PSR/Logs 1.0 MIT License Yes Library for logs (used by DebugBar) PSR/Logs 1.0 MIT License Yes Library for logs (used by DebugBar)
@ -52,7 +52,7 @@ Ace 1.4.14 BSD Yes
ChartJS 3.7.1 MIT License Yes JS library for graph ChartJS 3.7.1 MIT License Yes JS library for graph
CKEditor 4.18 LGPL-2.1+ Yes Editor WYSIWYG CKEditor 4.18 LGPL-2.1+ Yes Editor WYSIWYG
jQuery 3.6.0 MIT License Yes JS library jQuery 3.6.0 MIT License Yes JS library
jQuery UI 1.13.1 GPL and MIT License Yes JS library plugin UI jQuery UI 1.13.2 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 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 Colorpicker 1.1 MIT License Yes JS library for color picker for a defined list of colors

426
ChangeLog
View File

@ -3,26 +3,274 @@ English Dolibarr ChangeLog
-------------------------------------------------------------- --------------------------------------------------------------
***** ChangeLog for 18.0.0 compared to 17.0.0 *****
NEW: PHP 8.2 compatibility:
WARNING:
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
* The deprecated method "escapeunderscore()" of database handlers has been removed. You must use "escapeforlike()" instead.
* The method "nb_expedition()" has been renamed into "countNbOfShipments()"
* Revert default type of hooks. Default is now 'addreplace' hooks (and exception become 'output' hooks, that become deprecated).
* Deprecated property libelle removed from entrepot class.
* The type 'text' in ->fields property dos not accept html content anymore. Use the type 'html' for that.
***** ChangeLog for 17.0.0 compared to 16.0.0 *****
For users:
---------------
NEW: Minimal PHP version is now PHP 7.0 instead of PHP 5.6
NEW: #19680 Add option PRODUCT_ALLOW_EXTERNAL_DOWNLOAD to automatically have uploaded files shared publicly by a link
NEW: #20650 can move the checkbox column on left (experimental option MAIN_CHECKBOX_LEFT_COLUMN)
NEW: #21000 Added columns 'alias_name' on project, supplier invoice, supplier order, supplier proposals and task list
NEW: #21780 Add pid field to Cronjob class and store PID on job execution
NEW: #21395 Added option for dark theme mode in display - color and theme
NEW: #21397 added option to auto define barcode numbers for third-parties in barcode module setup
NEW: #21399 add image for event_array
NEW: #21442 Enhancement of module builder init
NEW: #21654 add bank account number used on invoices for debit
NEW: #22048 added notes to productlot module
NEW: #22298 Bank - Add salaries & vat in the tab of planned entries of a bank account
NEW: #22328 OAuth admin
NEW: #22424 online signature for contracts
NEW: #22500 member module set up made easier
NEW: #22527 projects and thirdparties can be viewed as conversation ("Message" view), like events/agenda.
NEW: #22546 can now set user supervisors using mass action in htdocs/user
NEW: #22594 can chose if VAT ID is unique or not for third parties
NEW: #22622 all partnerships displayed on tab partnership of a thirdparty and member
NEW: #22676 massaction for updating product prices
NEW: #22735 massaction to affect users on projects
NEW: #25594 can chose if VAT ID is unique or not for third parties
NEW: #4482 adding js to hide/show advanced option on the export data page
NEW: Add a constant to disallow modification of the product reference.
NEW: add attached file in presend email form of thirdparty card
NEW: Add a way to enter LICENSE file content in property of website
NEW: Add employment anniversary in birthday box
NEW: Add hidden option MAIN_EMAIL_SUPPORT_ACK to restore Email ack checkbox (feature abandonned by mailers)
NEW: Add link to create an element from the category page
NEW: Add max size send for "backup and link to mail" option
NEW: Add method httponly_accessforbidden()
NEW: Add more advices into the Setup security page
NEW: Add new global variable for keeping the previous signature information on proposale (case of reopen a proposale)
NEW: Add option --force on CLI cron_run_jobs.php
NEW: Add option "Show price on the generated documents for receptions"
NEW: Manage VAT on all lines on purchases cycle
NEW: parent company column and filter in invoice and order list
NEW: private and public note columns on user, thirdparty and contact lists
NEW: Public counters feature
NEW: Save one click to select on delivery ack, on emails.
NEW: scheduled job to send unpaid invoice reminder can now use the cc and bcc from email template
NEW: can substitue project title in mail template
NEW: The purge of files can purge only if older than a number of seconds
NEW: Update ActionComm type_code on email message ticket
NEW: Add the target to select attendees of event for emailings
NEW: add redirect on action confirm addconsumedline and addproduceline
NEW: Add the referrer-policy to "same-origin" by default on all public pages.
NEW: Add trigger to record the event of sending an email from a project #20912
NEW: Allow download link option in module configuration (propal, order, invoice, supplier proposal)
NEW: Can enter the unit price including the VAT
NEW: Can invoice task time per different services
NEW: Can set a commercial discount by entering amount including VAT
NEW: Can set start and end dates and comment on button "Activate all services"
NEW: show date delivery planned on orders linked to company and product
NEW: filter on reception dates (from / to) in cheque paiement card
NEW: Accountancy - add a graphic option to enable lettering function - FPC21
NEW: Accountancy - add a way to clean some words when you generate thirdparty accounting account
NEW: Accountancy - added an option during export to export or not the lettering FPC21
NEW: Accountancy - Invoice export : add accounting affectation
NEW: Accountancy - Manage supplier deposit with specific account
NEW: Accountancy - Model Digitaria - Add a way to clean some words when you generate thirdparty accounting account FPC22
NEW: Agenda - start a simple support of recurrent events on agenda
NEW: Bank - add salaries & VAT in tab planned entries
NEW: Bank - on a bank reconciled line, we can modify the bank receipt
NEW: Contracts - add a method doAutoRenewContracts that can be used as a cron task
NEW: Contracts - default template of contract is not mandatory
NEW: Contracts - Manage Position (Rank) on Contract Lines
NEW: EMail - can copy/paste images into emails sent
NEW: EMail - can edit label of an emailing even once sent
NEW: EMail - can join several files by default on email form
NEW: EMail - can send an email on scheduled job error
NEW: EMail - on a form to send an email, we show all emails of all contacts of object
NEW: EMail - add the SMTP header References on ticket email created by email
NEW: EMail - add substitution key __SENDEREMAIL_SIGNATURE__
NEW: EMail - experimental SMTP using PhpImap allowing OAuth2 authentication (need to add option MAIN_IMAP_USE_PHPIMAP)
NEW: EMail-Collector - add IMAP port setting
NEW: EMail-Collector - add a button "Test collect"
NEW: Event-Organization - add date event (!= date project) and location on event organization
NEW: Expedition - add objectLink on expedition
NEW: Export - Add " as enclosure by default for CSV export. Keep removing CR/LF.
NEW: Extrafields - add badge in admin extrafields setup
NEW: Extrafields - can edit property css, cssview, csslist on extrafields
NEW: Extrafields - default values in extrafields are not more limited to 255 char.
NEW: Extrafields - field price with currency
NEW: Extrafields - support IP type to store IP addresses
NEW: Finance - VAT - Admin - Add information on deadline day for submission of VAT declaration
NEW: Interventions - enable online signature for interventions
NEW: Invoice - add french mention on PDF when VAT debit option is on
NEW: Members - default_lang for members
NEW: Members - table of membership types
NEW: Members - add free membership amounts at the membership type level
NEW: OAuth - possibility to select scopes with checkbox for OAuth tokens
NEW: OAuth - saved token of OAUTH module are now encrypted into llx_oauth_token
NEW: Orders - resize parent company column in order list
NEW: Products - Categories - label on products categories filter
NEW: Products - Supplier price - autofill default supplier VAT
NEW: Products - Supplier price - can sort and preselected best supplier price
NEW: Projects - add author on list
NEW: Projects - add thirdparty column to the time list (projet/tasks/time.php)
NEW: Proposals - show delivery mode on PDF for proposals
NEW: Proposals - skip accept/refuse process for proposals (option PROPAL_SKIP_ACCEPT_REFUSE)
NEW: Reception - add a from/to on search on date field
NEW: Stock - page for mass stock transfer can be used with no source stock
NEW: Stock - product categories filter on inventory list
NEW: Stock - show product label on inventory
NEW: Stock - manage virtual stock at a future date
NEW: Stock Inventory - add filter "Product subject to lot/Serial" in stock per lot/serial
NEW: Stock Inventory - can use products categories to make inventory
NEW: Supplier Order List - add column private and public note
NEW: TakePOS - add margin infos to TakePOS invoice lines
NEW: TakePOS - add price to product box in TakePOS
NEW: TakePOS - add setup parameters, can setup terminal name
NEW: TakePOS - different product list on smartphone
NEW: TakePOS - display currency in TakePOS menu
NEW: TakePOS - Header Scroll in TakePOS
NEW: TakePOS - Receipt preview in TakePOS setup
NEW: TakePOS - support of Stripe Terminal with TakePOS
NEW: Thirdparty - manage no email with thirdparties (better for GDPR)
NEW: Thirdparty - set thirdparty type with company modify trigger
NEW: Tickets - change filter type on tickets list into a multiselect combo
NEW: Tickets - add oldcopy to Ticket so triggers intercepting TICKET_MODIFY have access to old values of the updated properties
NEW: Website - can delete a whole website if disabled
NEW: Website - can remove a website template
NEW: Website - can set header "Strict-Transport-Security" in web sites.
NEW: Website - can switch status of website and page from the website toolbar
NEW: Website - Templates of websites are now directories and not zip into core repo
NEW: Website - add 4 other templates in website module
General:
NEW: Actions: Bulk action to remove a category in list/search website pages
NEW: Cronjobs: can set a monthly frequency (or multiple) in cron tasks
NEW: Database: Encrypt all sensitive constants in llx_const
NEW: Database: Add performance index (name for company and contact) and llx_bank_url(url_id)
NEW: Database: Introduce dolEncrypt and dolDecrypt to be able to encrypt data in db
NEW: GUI: If we select another view list mode, we keep it
NEW: GUI: the link "add to bookmark" is always on top in the bookmark popup
NEW: GUI: Picto for shared link is clickable
NEW: GUI: add picto property on sub-module for password generation
NEW: GUI: show also scheduled task never finished in scheduled task widget
NEW: GUI: show badge with number of extrafields in setup
NEW: GUI: show category tree in sellist and chkbxlst for common object
NEW: GUI: show picto and color into combo for selection of tags
NEW: GUI: show sell-by and eat-by dates only if not empty
NEW: GUI: show SellBy/EatBy dates for each batch product in shipment card
NEW: GUI/Permissions: expand/collapse permissions on user permission page
NEW: Permissions: add a new advanced permission "read price"
NEW: Print: add show "Sales rep" option for PDF
NEW: Security: add fail2ban rules examples to limit access to /public pages
Option / Const for System:
NEW: FICHINTER_ALLOW_EXTERNAL_DOWNLOAD
NEW: MAIN_CHECKBOX_LEFT_COLUMN
NEW: MAIN_EMAIL_SUPPORT_ACK
NEW: MAIN_IMAP_USE_PHPIMAP
NEW: MAIN_SEARCH_CATEGORY_PRODUCT_ON_LISTS - const to show category customer filter
NEW: PRODUCT_ALLOW_EXTERNAL_DOWNLOAD
NEW: PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT - showing warehouse on PDF
NEW: PRODUIT_DESC_IN_FORM accept - desktop only or +smartphone
NEW: PROPAL_BYPASS_VALIDATED_STATUS
NEW: PROPAL_NEW_AS_SIGNED
NEW: PROPAL_SKIP_ACCEPT_REFUSE
NEW: TIMESPENT_ALWAYS_UPDATE_THM - when it's on we always check current thm of user to update it in task time line
Localisation:
NEW: adding JAPAN Chart-of-Account and regions/departments
NEW: adding NIF verification for Algeria
Modules
NEW: Experimental module Asset
NEW: Init module bookcal
NEW: Make module WebservicesClient deprecated. Use module WebHook instead.
For developers or integrators:
------------------------------
NEW: ModuleBuilder can generate code of class from an existing SQL table
NEW: #20912 Add trigger to record the event of sending an email from a project
NEW: #21750 Added "Get lines and Post lines from BOM" at the REST Service
NEW: #22370 Modulebuilder supports 'alwayseditable' (like extrafields)
NEW: conf->global->SYSLOG_FILE_ONEPERSESSION accept a string
NEW: All ajax pages have now a top_httphead()
API:
NEW: Add API for the partnership module
NEW: Add "Get lines and Post lines from BOM" in the API
NEW: translate for contact type API, setup/ticket API, shipping method API
NEW: support multilang in Civilities API
Hooks:
NEW: Actioncomm - add new hooks for actioncomm
NEW: Actioncomm - hook formConfirm on actioncomm card
NEW: Agenda - hook on agenda pages
NEW: Help - hook "changeHelpURL" to modify target of the help button
NEW: Product - add hook to show virtual stock details on product stock card
NEW: Product - add hook to modify supplier product html select
NEW: TakePOS - add hook to complete payment in TakePOS
NEW: Removed completely the need for the library adodbtime
NEW: Replace fk_categories_product with categories_product in inventory
NEW: Rewrite of SQL request. Removed the join on category (for filter on categ), replaced with a EXISTS/NOT
WARNING:
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
* Minimal PHP version is now PHP 7.0 instead of PHP 5.6
* The signature of method getNomUrl() of class ProductFournisseur has been modified to match the signature of method Product
* Trigger ORDER_SUPPLIER_DISPATCH is removed, use ORDER_SUPPLIER_RECEIVE and/or LINEORDER_SUPPLIER_DISPATCH instead.
* All functions fetch_all() have been set to deprecated for naming consitency, use fetchAll() instead.
* Code standardization: '$user->rights->propale' is now '$user->rights->propal' everywhere.
* Deprecated method set_billed() on shipment and reception class has been removed. Use setBilled() instead.
* Tables llx_prelevement_facture and llx_prelevement_facture_demande have been renamed into llx_prelevement and llx_prelevement_demande.
* Rename MAIN_LIST_ALLOW_NOTES into MAIN_LIST_HIDE_NOTES and rename MAIN_LIST_ALLOW_PRIVATE_NOTES into MAIN_LIST_HIDE_PRIVATE_NOTES
* Rename the substitution for "project label" instead of "project title" in substitution variables
* You must use "$objectoffield" to manipulate the current object inside the formulare of computed custom extrafields instead of $obj/$object.
* Making a global search is sending the parameter using always the name search_all (instead of sometimes sall and search_all)
* The property $url_last_version must be public if defined into module descriptor files;
***** ChangeLog for 16.0.4 compared to 16.0.3 ***** ***** ChangeLog for 16.0.4 compared to 16.0.3 *****
FIX: Amount of localtax1 and 2 not correctly save on purchase order (the rate was saved instead) FIX: Amount of localtax1 and 2 not correctly save on purchase order (the rate was saved instead)
FIX: #20415 FIX: #20415
FIX: #21280 FIX: #23008 FIX: #21280
FIX: #22271 FIX: #22271
FIX: #22524 FIX: #22524
FIX: #22837 FIX: #22837
FIX: #22964 FIX: #22964
FIX: #23008
FIX: #23012 FIX: #23012
FIX: #23019 Impossible to add task times to an existing draft invoice FIX: #23019 Impossible to add task times to an existing draft invoice
FIX: #23072 FIX: #23072
FIX: #23075
FIX: #23087 FIX: #23087
FIX: #23115 FIX: #23116 FIX: #23115
FIX: #23116
FIX: #23117
FIX: #23281 FIX: #23281
FIX: #23420 : wrong check on $search_categ value causing FATAL ERROR FIX: #23420 : wrong check on $search_categ value causing FATAL ERROR
FIX: Accountancy - Quadra export FIX: Accountancy - Quadra export
FIX: add border left on image product when conf activated FIX: add border left on image product when conf activated
FIX: Add missing token when deleting template inn order_supplier admin menu FIX: Add missing token when deleting template inn order_supplier admin menu
FIX: Amount of localtax1 and 2 not correctly save on purchase order (the
FIX: API access for deactivated users FIX: API access for deactivated users
FIX: bad selection of barcode numbering module FIX: bad selection of barcode numbering module
FIX: Can't see all time spent by all user FIX: Can't see all time spent by all user
@ -33,8 +281,6 @@ FIX: Empty FormSetup emailTemplate type IF empty fieldvalue
FIX: Errors Handling for CreateFrom Hooks FIX: Errors Handling for CreateFrom Hooks
FIX: error with dol_banner_tab, ref is needed FIX: error with dol_banner_tab, ref is needed
FIX: ExpenseReport card was not reloaded after addline FIX: ExpenseReport card was not reloaded after addline
FIX: #23075
FIX: #23117
FIX: get multicurrency infos of propal when create order from propal with "WORKFLOW_PROPAL_AUTOCREATE_ORDER" conf FIX: get multicurrency infos of propal when create order from propal with "WORKFLOW_PROPAL_AUTOCREATE_ORDER" conf
FIX: Give predictable order to inventory lines FIX: Give predictable order to inventory lines
FIX: include class multicurrency FIX: include class multicurrency
@ -42,7 +288,6 @@ FIX: methods declaration (backport fix 67b9a7dc07d708231d12b5e58800334d4a01ef98)
FIX: multicurrency_tx and not currency_tx FIX: multicurrency_tx and not currency_tx
FIX: on public ticket list, only the page 1 was accessible. Other pages were 404 error. FIX: on public ticket list, only the page 1 was accessible. Other pages were 404 error.
FIX: PGSQL Integer type does not have a free lenght FIX: PGSQL Integer type does not have a free lenght
FIX: PGSQL Int type does not have a free lenght
FIX: Product list in setup.php in new Module FIX: Product list in setup.php in new Module
FIX: propal and order stats broken on Tag+User(retricted customer list) FIX: propal and order stats broken on Tag+User(retricted customer list)
FIX: saving of numbering module for jobs FIX: saving of numbering module for jobs
@ -51,7 +296,6 @@ FIX: travis
FIX: wrong check on $search_categ value causing fatal error FIX: wrong check on $search_categ value causing fatal error
FIX: wrong stock list with multicompany and without stock sharing FIX: wrong stock list with multicompany and without stock sharing
***** ChangeLog for 16.0.3 compared to 16.0.2 ***** ***** ChangeLog for 16.0.3 compared to 16.0.2 *****
FIX: $sign is useless FIX: $sign is useless
@ -208,118 +452,115 @@ NEW: PHP 8.0 and 8.1 compatibility:
log files (depending on your PHP setup). Removal of all PHP warnings on server side is planned for v17. log files (depending on your PHP setup). Removal of all PHP warnings on server side is planned for v17.
NEW: Support for recurring purchase invoices. NEW: Support for recurring purchase invoices.
NEW: #20292 Include German public holidays NEW: #20292 Include German public holidays
NEW: Can show ZATCA QRCode on PDFs NEW: Can show ZATCA QR-Code on PDFs
NEW: Can show Swiss QR Code on PDFs NEW: Can show Swiss QR-Code on PDFs
NEW: #17123 added ExtraFields for Stock Mouvement NEW: #17123 added ExtraFields for Stock Mouvement
NEW: #20609 : new massaction to assign a sale representatives on a selection of thirdparties NEW: #20609 new massaction to assign a sale representatives on a selection of thirdparties
NEW: #20653 edit discount pourcentage for all lines in one shot NEW: #20653 edit discount pourcentage for all lines in one shot
NEW: Accept 'auto' for ref of object on import of purchase order/proposal NEW: Accept 'auto' for ref of object on import of purchase order/proposal
NEW: Accountancy - Add more filters and info on page to bind accounting accounts NEW: Accountancy - Add more filters and info on page to bind accounting accounts
NEW: Accountancy - Add subledger account when we generate a transaction with a deposit invoice NEW: Accountancy - Add subledger account when generate a transaction with a deposit invoice
NEW: Accountancy - Add a massaction to preselect an account (customer and supplier list) NEW: Accountancy - Add a massaction to preselect an account (customer and supplier list)
NEW: Accountancy - Add hidden feature for accounting reconciliation
NEW: ACE Editor is restored at same cursor position after a save. NEW: ACE Editor is restored at same cursor position after a save.
NEW: Add "addMoreActionsButtons" hook to subscription form NEW: Add "addMoreActionsButtons" hook to subscription form
NEW: Add an option in GUI to show a Quick add button into top menu bar NEW: Add an option in GUI to show a Quick add button into top menu bar
NEW: Module Recruitment - Add a public page with all list of open job positions.
NEW: Module Recruitment - Add a tab with list of application on the jobposition file.
NEW: Add a workflow to auto link contract on a ticket NEW: Add a workflow to auto link contract on a ticket
NEW: Add column date of Signature on proposal list
NEW: Add column template invoice in invoice list NEW: Add column template invoice in invoice list
NEW: Add column "Total HT" to products array on document creation card NEW: Add column "Total HT" to products array on document creation card
NEW: ADD configuration for text color of button action NEW: Add configuration for text color of button action
NEW: Add constant to hide categories in TakePos
NEW: Add constant to show category description in TakePos
NEW: Add constant to show only the products in stock in TakePos
NEW: Add entity filter in exports
NEW: Show the event block on recurring invoices #20870 NEW: Show the event block on recurring invoices #20870
NEW: Add filter "opportunity status" on statistics of projects.
NEW: Add firstname, lastname and max number of attendees for module "Event Organization" NEW: Add firstname, lastname and max number of attendees for module "Event Organization"
NEW: add margin info in proposal and order list NEW: Add margin info in proposal and order list
NEW: Add massaction "Edit Extrafield" for Product
NEW: Add more fields to detect duplicate during import of thirdparties NEW: Add more fields to detect duplicate during import of thirdparties
NEW: Add option to foce delivery on email for purchase order receipt to yes NEW: Add option to foce delivery on email for purchase order receipt to yes
NEW: Add param boder table for md theme
NEW: Add param color button action
NEW: Add possibility to create contract from invoice NEW: Add possibility to create contract from invoice
NEW: Add possibility with constant MAIN_LOGIN_BADCHARUNAUTHORIZED to define bad character unauthorized into login name NEW: Add possibility with constant MAIN_LOGIN_BADCHARUNAUTHORIZED to define bad character unauthorized into login name
NEW: Add private and public notes on tax files. NEW: Add private and public notes on tax files
NEW: Add status "Obsolete" to KM articles
NEW: Add substitutions "user numbers" NEW: Add substitutions "user numbers"
NEW: Add the possibility to add sub-BOMs to BOM
NEW: allow a ticket to be automatically marked as read when created from backend.
NEW: allow cut&paste as real numeric value to excel NEW: allow cut&paste as real numeric value to excel
NEW: A public form to send a message and create a lead is available NEW: A public form to send a message and create a lead is available
NEW: automatically set totally received status in reception NEW: automatically set totally received status in reception
NEW: Auto set invoice paid when adding credit not and remain to pay is 0 NEW: Auto set invoice paid when adding credit not and remain to pay is 0
NEW: Availibility dictionnary has a new column unit and number NEW: Backup tool has an "lowmemory" option for mysqldump on large database
NEW: barcode rule to insert product in takepos
NEW: Can change value of AWP during the inventory
NEW: Can enter price with tax for predefined products on purchase objects NEW: Can enter price with tax for predefined products on purchase objects
NEW: Can filter on a thirdparty on product statistics
NEW: Can removed doc templates from setup page of thirdparty NEW: Can removed doc templates from setup page of thirdparty
NEW: Can set the parent company during the creation of thirdparty (action=add of societe/card.php)
NEW: Can use ! to make a search that exclude a string NEW: Can use ! to make a search that exclude a string
NEW: Change in theme colors does not need to use the refresh button
NEW: clean values and amount in FEC import NEW: clean values and amount in FEC import
NEW: const MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND for mailing mass action NEW: const MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND for mailing mass action
NEW: Contact filter project list NEW: Contact filter project list
NEW: Create contract from invoice NEW: Create contract from invoice
NEW: create third-party with contact if not found on public ticket NEW: Database: Can store the session into database (instead of beeing managed by PHP)
NEW: Database: Some core tables are created only at module activation
NEW: Default value for MAIN_SECURITY_CSRF_WITH_TOKEN is now 2 (GET are also protected agains CSRF attacks) NEW: Default value for MAIN_SECURITY_CSRF_WITH_TOKEN is now 2 (GET are also protected agains CSRF attacks)
NEW: deposit payment terms: add field into dictionary admin page to define default percentage of deposit. NEW: deposit payment terms: add field into dictionary admin page to define default percentage of deposit.
NEW: Dictionaries - add possibility to manage countries in EEC NEW: Dictionaries - add possibility to manage countries in EEC
NEW: display errors in a message box after generating documents NEW: Dictionaries - Availibility dictionnary has a new column unit and number
NEW: Display physical and virtual stock of the products when creating OF from a BOM NEW: Display errors in a message box after generating documents
NEW: Display product ref in "Object link" product tab for BOM
NEW: Enhance the import. Can use 'auto' for the ref (import of orders) NEW: Enhance the import. Can use 'auto' for the ref (import of orders)
NEW: Events on Proposal to Return to Draft NEW: Events on Proposal to Return to Draft
NEW: Exports - add entity filter in exports
NEW: Page to list expense report payments NEW: Page to list expense report payments
NEW: JS inventory autocalc input NEW: JS inventory autocalc input
NEW: language support for more emailing target selectors NEW: language support for more emailing target selectors
NEW: leave requests: add field into type dictionary to block request if balance is negative NEW: leave requests: add field into type dictionary to block request if balance is negative
NEW: MAIN_MAIL_AUTOCOPY_TO can accept several email and special keys
NEW: MAIN_SEARCH_CAT_OR_BY_DEFAULT const for search by category
NEW: Mass action "Close shipments" NEW: Mass action "Close shipments"
NEW: Module website now supports the multicompany module NEW: Module BOM - add tabs for nets BOM
NEW: More mode for THEME_TOPMENU_DISABLE_IMAGE (2, 3, ...) NEW: Module BOM - add the possibility to add sub-BOMs to BOM
NEW: Module Recruitment - Add a public page with list of all open job positions.
NEW: Module Recruitment - Add a tab with list of application on the jobposition file.
NEW: Add option to move checkbox column as first column on Thirdparty list (only few screens) NEW: Add option to move checkbox column as first column on Thirdparty list (only few screens)
NEW: Add tabs for nets Bom
NEW: on redirect of page in website module, GET parameters are kept.
NEW: optional display warning icons on ticket list
NEW: option to default check "notify tier at creation" in ticket module
NEW: option update prices on proposal cloning
NEW: payment conditions enabling semi-automatic deposit creation (Issue #18439) NEW: payment conditions enabling semi-automatic deposit creation (Issue #18439)
NEW: possibility to consume multiple batch NEW: possibility to consume multiple batch
NEW: Reverse movement product consumption NEW: Reverse movement product consumption
NEW: Send email to the supplier order contact NEW: Send email to the supplier order contact
NEW: New permission to report time on timesheet. NEW: add permission to report time on timesheet
NEW: Knowledge Management - add status "Obsolete" to KM articles
NEW: MRP - split consumption line on MO
NEW: MRP - display physical and virtual stock of the products when creating OF from a BOM
NEW: MRP - display product ref in "Object link" product tab for BOM
NEW: Orders - support user_modif in order
NEW: Products - add massaction "Edit Extrafield" for Product
NEW: Products - List - add thumbnail field in product list
NEW: Products - Statistics - can filter on a thirdparty
NEW: Projects - add filter "opportunity status" on statistics of projects.
NEW: Proposals - option update prices on proposal cloning
NEW: Proposals - List - add column date of Signature on proposal list
NEW: SEPA XML - option to place payment Type Info at Credit transfer Transaction level NEW: SEPA XML - option to place payment Type Info at Credit transfer Transaction level
NEW: Show number of votes into the label of tab "Results" of a survey NEW: Stocks - stock filter in reassort lists
NEW: Show product reference in Takepos NEW: Stocks - stock limit in stock export CSV
NEW: Some core tables are created only at module activation NEW: Stocks - Inventory - can change value of AWP during the inventory
NEW: split consumption line on MO
NEW: stock filter in reassort lists
NEW: stock limit in stock export CSV
NEW: Sub-bom are availables
NEW: Supplier order - Show ref supplier of reception in linked object block NEW: Supplier order - Show ref supplier of reception in linked object block
NEW: support user_modif in order NEW: Surveys - Show number of votes into the label of tab "Results" of a survey
NEW: TakePos - pagination on search results NEW: TakePOS - barcode rule to insert product in TakePOS
NEW: The backup tools has an "lowmemory" option for mysqldump on large database NEW: TakePOS - pagination on search results
NEW: TakePOS - show product reference
NEW: TakePOS - add constant to hide categories
NEW: TakePOS - add constant to show category description
NEW: TakePOS - add constant to show only the products in stock
NEW: Themes - add param color button action
NEW: Themes - Change in theme colors does not need to use the refresh button
NEW: Themes - more modes for THEME_TOPMENU_DISABLE_IMAGE (2, 3, ...)
NEW: Themes - MD - add param border table for md theme
NEW: Third-Parties - add rules "customer accountancy code" is mandatory to validate invoice
NEW: Third-Parties - can set the parent company during the creation of thirdparty (action=add of societe/card.php)
NEW: Tickets - allow a Ticket to be automatically marked as read when created from backend
NEW: Tickets - create Third-party with contact if not found on public ticket
NEW: Tickets - option to default check "notify tier at creation"
NEW: Tickets - Trigger: allow to automatically send messages on new tickets
NEW: Tickets - optional display warning icons on ticket list
NEW: Websites Module - supports now the multicompany module
NEW: Websites Module - on redirect of page in website module, GET parameters are kept.
NEW: The 'reposition' class works on ajax constantonoff that make redirects NEW: The 'reposition' class works on ajax constantonoff that make redirects
NEW: Thirdparty - Add rules "customer accountancy code" is mandatory to validate invoice
NEW: thumbnail field in product list
NEW: total mark rate in list NEW: total mark rate in list
NEW: uncheck "send message" by default on a ticket when private messages has been checked NEW: uncheck "send message" by default on a ticket when private messages has been checked
NEW: VAT Report by month - Show detail by rate and also by code NEW: VAT Report by month - Show detail by rate and also by code
NEW: Ticket triggers: allow to automatically send messages on new tickets
NEW: Accountancy - Add hidden feature for accounting reconciliation
NEW: Can store the session into database (instead of beeing managed by PHP)
NEW: Added MMK currency (Myanmar Kyat) NEW: Added MMK currency (Myanmar Kyat)
NEW: On a form to send an email, we show all emails of contacts of object NEW: On a form to send an email, we show all emails of contacts of object
Modules Modules state
NEW: Module Partnership Management NEW: Module Partnership Management - stable
NEW: Module Event Organization Management NEW: Module Event Organization Management - stable
For developers or integrators: For developers or integrators:
@ -327,48 +568,46 @@ For developers or integrators:
NEW: dol_uncompress() supports more extensions (.gz, .bz2, .zstd). Only .zip was supported before. NEW: dol_uncompress() supports more extensions (.gz, .bz2, .zstd). Only .zip was supported before.
NEW: Implement a generic method for Kaban views NEW: Implement a generic method for Kaban views
NEW: Upgrade chartjs library to 3.7.1 NEW: Upgrade chartjs library to 3.7.1
NEW: update rank line is possible on API for customer invoices, sales orders and supplier invoice
NEW: stripe element with more gateways NEW: stripe element with more gateways
NEW: solde() function evolution to be able to get solde until a chosen date NEW: solde() function evolution to be able to get solde until a chosen date
NEW: Suggest a way to run upgrade per entities. NEW: Suggest a way to run upgrade per entities.
NEW: Support html content for multiselect component. NEW: Support html content for multiselect component.
NEW: ModuleBuilder - Add tabs view in module builder NEW: ModuleBuilder - Add tabs view in module builder
NEW: ModuleBuilder - More feature that can be modifed after module generation NEW: ModuleBuilder - More feature that can be modifed after module generation
NEW: Hook getNomUrl available everywhere in tooltip of ref links
NEW: Identification of tr is possible with by attribute data-id on some pages NEW: Identification of tr is possible with by attribute data-id on some pages
NEW: Import with select boxes V2 NEW: Import with select boxes V2
NEW: Can update rank of invoice, proposal and order lines with API update
NEW: Can use current entity filter on 'chkbxlst' NEW: Can use current entity filter on 'chkbxlst'
NEW: Creation of the function select_bom() used to display bom select list NEW: Creation of the function select_bom() used to display bom select list
NEW: add printFieldListWhere hook in product reassort card
NEW: Add trigger and event on completely received status change NEW: Add trigger and event on completely received status change
NEW: Add utility function send backup by mail NEW: Add utility function send backup by mail
NEW: add WordPress OAuth to save a token (not SSO) NEW: add WordPress OAuth to save a token (not SSO)
NEW: A module can embed a sql script run at each Dolibarr upgrade NEW: A module can embed a SQL script run at each Dolibarr upgrade
NEW: API Proposals - Add POST lines
NEW: API REST filter states by country
NEW: Add option INVOICEREC_SET_AUTOFILL_DATE_START/END
NEW: Add option MAIN_API_DEBUG to save API logs into a file
NEW: Add param to keep the robot=index meta tag on public pages NEW: Add param to keep the robot=index meta tag on public pages
NEW: Add method hintindex() in database handlers. NEW: Add method hintindex() in database handlers.
NEW: add modifications for new function "$db->prefix()" NEW: add modifications for new function "$db->prefix()"
NEW: addMoreActionsButtonsList hook for button in list NEW: addMoreActionsButtonsList hook for button in list
NEW: Add API to get a template invoice
NEW: Standardize a lot of code. NEW: Standardize a lot of code.
NEW: #20736 Allow extrafields SQL filters on REST API product lookup
NEW: #19294 implement detailed timespent in task of project API
NEW: Add a protection into PHPunit to avoid to forget a var_dump NEW: Add a protection into PHPunit to avoid to forget a var_dump
API:
NEW: API Proposals - Add POST lines
NEW: API REST filter states by country
NEW: Add API to get a template invoice
NEW: Add datem and type parameters to API to create movements NEW: Add datem and type parameters to API to create movements
NEW: Add hidden option on contract PDF line to hide qty and price NEW: #19294 implement detailed timespent in task of project API
NEW: Option MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND to send last document in mass mailing action NEW: #20736 Allow extrafields SQL filters on REST API product lookup
NEW: Can update rank of invoice, proposal and order lines with API update
NEW: update rank line is possible on API for customer invoices, sales orders and supplier invoice
NEW: Add option MAIN_API_DEBUG to save API logs into a file
Hooks:
NEW: Hook getNomUrl available everywhere in tooltip of ref links
NEW: Add hooks: selectContactListWhere hook, selectThirdpartyListWhere hook NEW: Add hooks: selectContactListWhere hook, selectThirdpartyListWhere hook
NEW: TakePos - add hooks complete product display
NEW: TakePos - add hooks for cart display
NEW: TakePos - add hooks to complete ajax return array
NEW: Add hook before the public ticket list NEW: Add hook before the public ticket list
NEW: Add hook doaction in takepos invoice NEW: Add hook for Notif
NEW: Add Hook for Notif
NEW: Add hook for more buttons NEW: Add hook for more buttons
NEW: add hook printFieldListWhere in product ressort card
NEW: Add hook printFieldListWhere in "show_contacts" function NEW: Add hook printFieldListWhere in "show_contacts" function
NEW: Add hook printFieldWhere in load_state_board function NEW: Add hook printFieldWhere in load_state_board function
NEW: Add hooks contact tab badge and hooks parameter for avoid conflicts NEW: Add hooks contact tab badge and hooks parameter for avoid conflicts
@ -380,7 +619,20 @@ NEW: Add hooks on project task time page
NEW: Add hooks on salaries and sociales card NEW: Add hooks on salaries and sociales card
NEW: Add hooks select product list and select thirdparty list function NEW: Add hooks select product list and select thirdparty list function
NEW: Add hook to getSellPrice function NEW: Add hook to getSellPrice function
NEW: TakePos - add hooks complete product display
NEW: TakePos - add hooks for cart display
NEW: TakePos - add hooks to complete ajax return array
NEW: TakePOS - add hook doaction in TakePOS invoice
Config Options:
NEW: Add hidden option on contract PDF line to hide qty and price
NEW: Option MAIL_MASS_ACTION_ADD_LAST_IF_MAIN_DOC_NOT_FOUND to send last document in mass mailing action
NEW: Option MAIN_API_DEBUG to save API logs into a file
NEW: Option MAIN_MAIL_AUTOCOPY_TO can accept several email and special keys
NEW: Option MAIN_SEARCH_CAT_OR_BY_DEFAULT const for search by category
NEW: Option INVOICEREC_SET_AUTOFILL_DATE_START/END
WARNING:
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
* There is a new specific permission to be allowed to enter timesheets. If you use timesheet, don't forget to give the new permission (disable and * There is a new specific permission to be allowed to enter timesheets. If you use timesheet, don't forget to give the new permission (disable and
@ -408,10 +660,8 @@ FIX: #18704
FIX: #20444 FIX: #20444
FIX: #20448 missing preg_replace for vat rate when adding a free line FIX: #20448 missing preg_replace for vat rate when adding a free line
FIX: #20476 migration postgresql 13.0.x to 14.0.x packaging type FIX: #20476 migration postgresql 13.0.x to 14.0.x packaging type
FIX: #20487 missing letter D in constant THIRDPARTIES_DISABLE_RELATED_…
FIX: #20487 missing letter D in constant THIRDPARTIES_DISABLE_RELATED_OBJECT_TAB FIX: #20487 missing letter D in constant THIRDPARTIES_DISABLE_RELATED_OBJECT_TAB
FIX: #20527 Accountancy - Unbalanced entry proposed when an employee are declared on a social contribution FIX: #20527 Accountancy - Unbalanced entry proposed when an employee are declared on a social contribution
FIX: #20527 Accountancy Unbalanced entry proposed when an employee are declared on social contribution
FIX: #20621 signature online with proposal with n page. FIX: #20621 signature online with proposal with n page.
FIX: #20696 FIX: #20696
FIX: #20828 FIX: #20828
@ -756,6 +1006,8 @@ NEW: make it easier to set the `keyword`, `keywords` and `description` attribute
NEW: Experimental feature to manage user sessions in database NEW: Experimental feature to manage user sessions in database
WARNING:
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
* ALL EXTERNAL MODULES THAT WERE NOT CORRECTLY DEVELOPPED WILL NOT WORK ON V15 (All modules that forgot to manage the security token field * ALL EXTERNAL MODULES THAT WERE NOT CORRECTLY DEVELOPPED WILL NOT WORK ON V15 (All modules that forgot to manage the security token field
into forms will be broken. The security token field is expected since Dolibarr v9 but a lot of external modules did not implement it). into forms will be broken. The security token field is expected since Dolibarr v9 but a lot of external modules did not implement it).

View File

@ -56,6 +56,10 @@ Vous pouvez aussi utiliser un serveur Web et une base de données prise en charg
Pour mettre à jour Dolibarr depuis une vieille version vers celle ci: Pour mettre à jour Dolibarr depuis une vieille version vers celle ci:
- Faites une sauvegarde de votre instance [voir ce tutorial](https://wiki.dolibarr.org/index.php/Installation_-_Upgrade#Upgrade_Dolibarr)
- Vérifiez que la nouvelle version est compatible avec la version PHP de votre serveur [voir PHP support](https://wiki.dolibarr.org/index.php/Releases).
- Ecrasez les vieux fichiers dans le vieux répertoire 'dolibarr' par les fichiers - Ecrasez les vieux fichiers dans le vieux répertoire 'dolibarr' par les fichiers
fournis dans ce nouveau package. fournis dans ce nouveau package.

View File

@ -6,9 +6,8 @@ This file contains some policies about the security reports on Dolibarr ERP CRM
| Version | Supported | | Version | Supported |
| ---------- | ---------------------- | | ---------- | ---------------------- |
| <= 15.0.0 | :x: | | <= 16.0.2 | :x: |
| >= 15.0.1+ | :white_check_mark: except CSRF attacks| | >= 16.0.3 | :white_check_mark: |
| >= 16.0.0 | :white_check_mark: |
| >= develop | :white_check_mark: | | >= develop | :white_check_mark: |
## Reporting a Vulnerability ## Reporting a Vulnerability
@ -54,16 +53,17 @@ ONLY vulnerabilities discovered, when the following setup on test platform is us
* $dolibarr_nocsrfcheck must be kept to the value 0 into conf.php (this is the default value) * $dolibarr_nocsrfcheck must be kept to the value 0 into conf.php (this is the default value)
* $dolibarr_main_force_https must be set to something else than 0. * $dolibarr_main_force_https must be set to something else than 0.
* The constant MAIN_SECURITY_CSRF_WITH_TOKEN must be set to 3 into backoffice menu Home - Setup - Other (this protection should be set to 3 soon by default) * The constant MAIN_SECURITY_CSRF_WITH_TOKEN must be set to 3 into backoffice menu Home - Setup - Other (this protection should be set to 3 soon by default)
* The module DebugBar and ModuleBuilder must NOT be enabled (by default, these modules are not enabled. They are developer tools)
* ONLY security reports on modules provided by default and with the "stable" status are valid (troubles into "experimental", "developement" or external modules are not valid vulnerabilities). * ONLY security reports on modules provided by default and with the "stable" status are valid (troubles into "experimental", "developement" or external modules are not valid vulnerabilities).
* The root of web server must link to htdocs and the documents directory must be outside of the web server root (this is the default when using the default installer but may differs with external installer). * The root of web server must link to htdocs and the documents directory must be outside of the web server root (this is the default when using the default installer but may differs with external installer).
* The web server setup must be done so that only the documents directory is in write mode. The root directory called htdocs must be read-only. * The web server setup must be done so that only the documents directory is in write mode. The root directory called htdocs must be read-only.
* CSRF attacks are accepted but double check that you have set MAIN_SECURITY_CSRF_WITH_TOKEN to value 3. * CSRF attacks are accepted but double check that you have set MAIN_SECURITY_CSRF_WITH_TOKEN to value 3.
* The module DebugBar and ModuleBuilder must NOT be enabled (by default, these modules are not enabled. They are developer tools)
* Ability for a high level user to edit web site pages into the CMS by including HTML or Javascript is an expected feature. Vulnerabilities into the website module are validated only if HTML or Javascript injection can be done by a non allowed user. * Ability for a high level user to edit web site pages into the CMS by including HTML or Javascript is an expected feature. Vulnerabilities into the website module are validated only if HTML or Javascript injection can be done by a non allowed user.
* Fail2ban rules for rate limit on the login page,password forgotten page and all public pages (/public/*) must be installed as recommendend into the section "About - Admin tools - Section Access limits and mitigation".
Scope is the web application (back office) and the APIs. Scope is the web application (back office) and the APIs.
## Qualifying vulnerabilities for reporting ## Example of vulnerabilities Qualified for reporting.
* Remote code execution (RCE) * Remote code execution (RCE)
* Local files access and manipulation (LFI, RFI, XXE, SSRF, XSPA) * Local files access and manipulation (LFI, RFI, XXE, SSRF, XSPA)
@ -79,7 +79,7 @@ Scope is the web application (back office) and the APIs.
* Software version disclosure (for non admin users only) * Software version disclosure (for non admin users only)
* Stack traces or path disclosure (for non admin users only) * Stack traces or path disclosure (for non admin users only)
## Non-qualifying vulnerabilities for reporting ## Example of vulnerabilities non Non-qualified for reporting.
* "Self" XSS * "Self" XSS
* SSL/TLS best practices * SSL/TLS best practices
@ -96,3 +96,4 @@ Scope is the web application (back office) and the APIs.
* Software version or private IP disclosure when logged user is admin * Software version or private IP disclosure when logged user is admin
* Stack traces or path disclosure when logged user is admin * Stack traces or path disclosure when logged user is admin
* Any vulnerabilities due to a configuration different than the one defined into chapter "Scope for qualified vulnerabilities". * Any vulnerabilities due to a configuration different than the one defined into chapter "Scope for qualified vulnerabilities".
* Brute force attacks on login page, password forgotten page or any public pages (/public/*) are not qualified if the fail2ban recommended fail2ban rules were not installed.

View File

@ -1 +1 @@
7 10

View File

@ -19,7 +19,6 @@ Depends: libapache2-mod-php5 | libapache2-mod-php5filter | php5-cgi | php5-fpm |
php-pear, php-mail-mime, php-pear, php-mail-mime,
# php-tcpdf, # php-tcpdf,
# libfpdf-tpl-php, php-fpdf, # libfpdf-tpl-php, php-fpdf,
# libphp-adodb,
# libnusoap-php, # libnusoap-php,
# libphp-pclzip, # libphp-pclzip,
# Required javascript libraries # Required javascript libraries

View File

@ -61,31 +61,6 @@ License: GPL-3+
------------------------------------------------------------ ------------------------------------------------------------
Files: htdocs/includes/adodbtime/*
Copyright: 2003-2005, John Lim
unknown, jackbbs
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
.
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
Neither the name of the John Lim nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
Comment:
Those files are not shipped in the binary package since we use
the library as packaged in "libphp-adodb".
------------------------------------------------------------
Files: htdocs/includes/ckeditor/* Files: htdocs/includes/ckeditor/*
Copyright: 2003-2012 CKSource - Frederico Knabben Copyright: 2003-2012 CKSource - Frederico Knabben
License: GPL-2+ License: GPL-2+

View File

@ -146,7 +146,6 @@ case "$1" in
#else #else
# File already exist. We add params not found. # File already exist. We add params not found.
#echo Add new params to overwrite path to use shared libraries/fonts #echo Add new params to overwrite path to use shared libraries/fonts
#grep -q -c "dolibarr_lib_ADODB_PATH" $config || [ ! -d "/usr/share/php/adodb" ] || echo "<?php \$dolibarr_lib_ADODB_PATH='/usr/share/php/adodb'; ?>" >> $config
##grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config ##grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config
#grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config #grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config
#grep -q -c "dolibarr_lib_ODTPHP_PATHTOPCLZIP" $config || [ ! -d "/usr/share/php/libphp-pclzip" ] || echo "<?php \$dolibarr_lib_ODTPHP_PATHTOPCLZIP='/usr/share/php/libphp-pclzip'; ?>" >> $config #grep -q -c "dolibarr_lib_ODTPHP_PATHTOPCLZIP" $config || [ ! -d "/usr/share/php/libphp-pclzip" ] || echo "<?php \$dolibarr_lib_ODTPHP_PATHTOPCLZIP='/usr/share/php/libphp-pclzip'; ?>" >> $config

View File

@ -31,7 +31,6 @@ $force_install_distrib='debian';
// - not removed from package (see rm in rules file), // - not removed from package (see rm in rules file),
// - declared into dependencies (see Depends in control file) // - declared into dependencies (see Depends in control file)
//$force_dolibarr_lib_TCPDF_PATH=''; //$force_dolibarr_lib_TCPDF_PATH='';
//$force_dolibarr_lib_ADODB_PATH='/usr/share/php/adodb';
//$force_dolibarr_lib_GEOIP_PATH=''; //$force_dolibarr_lib_GEOIP_PATH='';
//$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; //$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap';
//$force_dolibarr_lib_ODTPHP_PATHTOPCLZIP='/usr/share/php/libphp-pclzip'; //$force_dolibarr_lib_ODTPHP_PATHTOPCLZIP='/usr/share/php/libphp-pclzip';

View File

@ -89,7 +89,6 @@ override_dh_install:
rm -fr build/zip rm -fr build/zip
# clean from all PHP embedded libraries (we use package dependencies instead) # clean from all PHP embedded libraries (we use package dependencies instead)
# rm -fr htdocs/includes/adodbtime
# rm -fr htdocs/includes/geoip # rm -fr htdocs/includes/geoip
# rm -fr htdocs/includes/nusoap # rm -fr htdocs/includes/nusoap
# rm -fr htdocs/includes/odtphp/zip/pclzip # rm -fr htdocs/includes/odtphp/zip/pclzip

View File

@ -1,2 +0,0 @@
htdocs/install/doctemplates/websites/website_template-corporate.zip
htdocs/install/doctemplates/websites/website_template-stellar.zip

View File

@ -1,4 +1,4 @@
FROM php:7.3-apache FROM php:8.1-apache-bullseye
ENV PHP_INI_DATE_TIMEZONE 'UTC' ENV PHP_INI_DATE_TIMEZONE 'UTC'
ENV PHP_INI_MEMORY_LIMIT 256M ENV PHP_INI_MEMORY_LIMIT 256M
@ -25,7 +25,7 @@ RUN apt-get update -y \
mailutils \ mailutils \
&& apt-get autoremove -y \ && apt-get autoremove -y \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \ && docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) calendar intl mysqli pdo_mysql gd soap zip \ && docker-php-ext-install -j$(nproc) calendar intl mysqli pdo_mysql gd soap zip \
&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \ && docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
&& docker-php-ext-install -j$(nproc) ldap && \ && docker-php-ext-install -j$(nproc) ldap && \

View File

@ -34,6 +34,8 @@ services:
build: . build: .
environment: environment:
HOST_USER_ID: $HOST_USER_ID HOST_USER_ID: $HOST_USER_ID
PHP_INI_DATE_TIMEZONE: $PHP_INI_DATE_TIMEZONE
PHP_INI_MEMORY_LIMIT: $PHP_INI_MEMORY_LIMIT
volumes: volumes:
- ../../htdocs:/var/www/html/ - ../../htdocs:/var/www/html/
- ../../documents:/var/documents - ../../documents:/var/documents

View File

@ -15,10 +15,10 @@ fi
echo "[docker-run] => Set Permission to www-data for /var/documents" echo "[docker-run] => Set Permission to www-data for /var/documents"
chown -R www-data:www-data /var/documents chown -R www-data:www-data /var/documents
if [ ! -f /usr/local/etc/php/php.ini ]; then echo "[docker-run] => update ${PHP_INI_DIR}/conf.d/dolibarr-php.ini"
cat <<EOF > /usr/local/etc/php/php.ini cat <<EOF > ${PHP_INI_DIR}/conf.d/dolibarr-php.ini
date.timezone = $PHP_INI_DATE_TIMEZONE date.timezone = ${PHP_INI_DATE_TIMEZONE:-UTC}
memory_limit = ${PHP_INI_MEMORY_LIMIT:-256M}
EOF EOF
fi
exec apache2-foreground exec apache2-foreground

View File

@ -11,24 +11,24 @@ LaunchProgram=Launch %1
AssocFileExtension=&Associate %1 with the %2 file extension AssocFileExtension=&Associate %1 with the %2 file extension
AssocingFileExtension=Associating %1 with the %2 file extension... AssocingFileExtension=Associating %1 with the %2 file extension...
YouWillInstallDoliWamp=You will install DoliWamp (so Dolibarr + all required third party software like Apache, Mysql and PHP) on your computer. YouWillInstallDoliWamp=You will install DoliWamp (so Dolibarr plus all required third-party software like Apache, MySQL and PHP) on your computer.
ThisAssistantInstallOrUpgrade=WARNING: Using an ERP CRM installed on a local computer can be dangerous: if your computer break down, you can lose all your data. Do this if you are ready to manage backup yourself seriously. If not, use an installation in Saas instead (see https://saas.dolibarr.org). ThisAssistantInstallOrUpgrade=WARNING: Using an ERP CRM installed on a local computer can be dangerous: if your computer breaks down, you can lose all your data. Do this if you are ready to manage backups yourself seriously. If not, use an installation in SaaS instead (see https://saas.dolibarr.org).
IfYouHaveTechnicalKnowledge=Moreover, if you have technical knowledges and want to manage your Apache, Mysql and PHP yourself, you should not use this assistant and make a manual installation of Dolibarr on your existing server with Apache, Mysql and PHP. IfYouHaveTechnicalKnowledge=Moreover, if you have technical knowledge and want to manage Apache, MySQL and PHP yourself, you should not use this assistant and instead make a manual installation of Dolibarr on your existing server with Apache, MySQL and PHP.
ButIfYouLook=But if you look for an automatic setup on your local computer, you''re on the good way... ButIfYouLook=But if you are looking for an automatic setup on your local computer, you're on the right path...
DoYouWantToStart=Do you want to start installation process ? DoYouWantToStart=Do you want to start the installation process?
TechnicalParameters=Technical parameters TechnicalParameters=Technical parameters
IfFirstInstall=If first install, please specify some technical parameters. If you don't understand, are not sure, or are doing an upgrade, just leave the default values. IfFirstInstall=If this is the first install, please specify some technical parameters. If you don't understand, are not sure, or are doing an upgrade, just keep the default values.
; WARNING !!! STRINGS HERE MUST BE LOWER THAN 60 CHARACTERS ; WARNING !!! STRINGS HERE MUST BE LOWER THAN 60 CHARACTERS
SMTPServer=SMTP server (your own or ISP SMTP server, first install only): SMTPServer=SMTP server (your own or ISP SMTP server, first install only):
ApachePort=Apache port (first install only, common choice is 80): ApachePort=Apache port (first install only, common choice is 80):
MySqlPort=MySql port (first install only, common choice is 3306) : MySqlPort=MySQL port (first install only, common choice is 3306):
MySqlPassword=MySql server and database password you want for root (first install only): MySqlPassword=MySQL server and database password you want for root (first install only):
FailedToDeleteLock=Failed to delete the file %1/www/dolibarr/install.lock. You can ignore warning but you may have to remove it manually later when asked. Click OK to continue... FailedToDeleteLock=Failed to delete the file %1/www/dolibarr/install.lock. You can ignore this warning but you may have to remove the file manually later when asked. Click OK to continue...
PortAlreadyInUse=Port %1 seems to be already in use. You should cancel to go back and choose another value for %2 port. Cancel choice and choose another value ? PortAlreadyInUse=Port %1 seems to already be in use. You should cancel to go back and choose another value for %2 port. Cancel choice and choose another value?
FirefoxDetected=Firefox has been detected on your computer. Would you like to use it as the default browser for Dolibarr? FirefoxDetected=Firefox has been detected on your computer. Would you like to use it as the default browser for Dolibarr?
ChromeDetected=Chrome has been detected on your computer. Would you like to use it as the default browser for Dolibarr? ChromeDetected=Chrome has been detected on your computer. Would you like to use it as the default browser for Dolibarr?
@ -37,12 +37,12 @@ ChooseDefaultBrowser=Please choose your default browser (iexplore.exe, firefox.e
LaunchNow=Launch Dolibarr now LaunchNow=Launch Dolibarr now
ProgramHasBeenRemoved=Dolibarr program files have been removed. However, all your data files are still in directory %1. You must remove this directory manually for a complete uninstall. ProgramHasBeenRemoved=Dolibarr's program files have been removed. However, all your data files are still in directory %1. You must remove this directory manually for a complete uninstall.
DoliWampWillStartApacheMysql=DoliWamp installer will now start or restart Apache and Mysql, this may last from several seconds to one minute after this confirmation. Start to install or upgrade the web and database server required by Dolibarr ? DoliWampWillStartApacheMysql=DoliWamp installer will now start or restart Apache and MySQL. This may take from several seconds to one minute. Start to install or upgrade the web and database server required by Dolibarr?
OldVersionFoundAndMoveInNew=An old database version has been found and moved to be used by new Dolibarr version OldVersionFoundAndMoveInNew=An old database version has been found and moved to be used by the new Dolibarr version
OldVersionFoundButFailedToMoveInNew=An old database version has been found but could not be moved to be used with new Dolibarr version OldVersionFoundButFailedToMoveInNew=An old database version has been found but could not be moved to be used with the new Dolibarr version
DLLMissing=Your Windows installation is missing The "Micrsoft Visual C++ Redistributable for Visual Studio 2012" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://www.microsoft.com/en-us/download/) and restart DoliWamp installation/upgrade after. DLLMissing=Your Windows installation is missing the "Microsoft Visual C++ Redistributable for Visual Studio 2012" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://www.microsoft.com/en-us/download/) and restart DoliWamp installation/upgrade after.
ContinueAnyway=Continue anyway (install process may fails without this prerequisite) ContinueAnyway=Continue anyway (install process may fail without this prerequisite)

View File

@ -9,3 +9,5 @@ The build of .exe files need to have some windows executable files already insta
If you have technical knowledge in web administration and plan to share your server instance (Apache, Mysql or PHP) with other projects than Dolibarr or want to use Dolibarr other components (PostgreSQL), you should not use this assistant and make a manual installation of Dolibarr on your existing server by downloading the standard package (.tgz or .zip file). If you have technical knowledge in web administration and plan to share your server instance (Apache, Mysql or PHP) with other projects than Dolibarr or want to use Dolibarr other components (PostgreSQL), you should not use this assistant and make a manual installation of Dolibarr on your existing server by downloading the standard package (.tgz or .zip file).
!!! See file ../makepack-howto.txt

View File

@ -1,5 +1,4 @@
<?php <?php
/* !!! DO NOT EDIT THIS FILE, EDIT config.inc.php INSTEAD !!! */ /* !!! DO NOT EDIT THIS FILE, EDIT config.inc.php INSTEAD !!! */
// vim: expandtab sw=4 ts=4 sts=4: // vim: expandtab sw=4 ts=4 sts=4:

View File

@ -46,6 +46,7 @@ require_once DOL_DOCUMENT_ROOT."/core/lib/files.lib.php";
$includecustom=0; $includecustom=0;
$includeconstants=array(); $includeconstants=array();
$buildzip=0;
if (empty($argv[1])) { if (empty($argv[1])) {
print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value] [buildzip=1]\n"; print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value] [buildzip=1]\n";
@ -55,14 +56,27 @@ if (empty($argv[1])) {
$i=0; $i=0;
$result=array();
while ($i < $argc) { while ($i < $argc) {
if (!empty($argv[$i])) { if (!empty($argv[$i])) {
parse_str($argv[$i]); // set all params $release, $includecustom, $includeconstant, $buildzip ... parse_str($argv[$i], $result); // set all params $release, $includecustom, $includeconstant, $buildzip ...
} }
if (preg_match('/includeconstant=/', $argv[$i])) { if (!empty($result["release"])) {
$tmp=explode(':', $includeconstant, 3); // $includeconstant has been set with previous parse_str() $release = $result["release"];
}
if (!empty($result["includecustom"])) {
$includecustom = $result["includecustom"];
}
if (!empty($result["includeconstant"])) {
$includeconstants[$i] = $result["includeconstant"];
}
if (!empty($result["buildzip"])) {
$buildzip=1;
}
if (preg_match('/includeconstant=/', strval($argv[$i]))) {
$tmp=explode(':', $result['includeconstant'], 3); // $includeconstant has been set with previous parse_str()
if (count($tmp) != 3) { if (count($tmp) != 3) {
print "Error: Bad parameter includeconstant=".$includeconstant."\n"; print "Error: Bad parameter includeconstant=".$result['includeconstant'] ."\n";
exit -1; exit -1;
} }
$includeconstants[$tmp[0]][$tmp[1]] = $tmp[2]; $includeconstants[$tmp[0]][$tmp[1]] = $tmp[2];
@ -71,7 +85,7 @@ while ($i < $argc) {
} }
if (empty($release)) { if (empty($release)) {
print "Error: Missing release paramater\n"; print "Error: Missing release parameter\n";
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]\n";
exit -1; exit -1;
} }

View File

@ -524,12 +524,13 @@ if ($nboftargetok) {
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/ansible`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/ansible`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/codesniffer`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/codesniffer`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/codetemplates`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/codetemplates`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/dbmodel`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/examples/ldap`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/examples/zapier`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdata`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdata`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdemo`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdemo`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/iso-normes`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/resources/dbmodel`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/ldap`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/resources/iso-normes`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/licence`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/resources/licence`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/mail`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/mail`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/multitail`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/multitail`;
$ret=`rm -fr $BUILDROOT/$PROJECT/dev/phpcheckstyle`; $ret=`rm -fr $BUILDROOT/$PROJECT/dev/phpcheckstyle`;

View File

@ -293,6 +293,7 @@ foreach my $PROJECT (@PROJECTLIST) {
} }
print "Clean $BUILDROOT\n"; print "Clean $BUILDROOT\n";
$ret=`rm -fr $BUILDROOT/$PROJECTLC/.cache`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/.cache`;
$ret=`rm -fr $BUILDROOT/$PROJECTLC/.git`;
$ret=`rm -fr $BUILDROOT/$PROJECTLC/.project`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/.project`;
$ret=`rm -fr $BUILDROOT/$PROJECTLC/.settings`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/.settings`;
$ret=`rm -fr $BUILDROOT/$PROJECTLC/index.php`; $ret=`rm -fr $BUILDROOT/$PROJECTLC/index.php`;

View File

@ -8,13 +8,13 @@ of Dolibarr. There is a chapter for BETA version and a chapter for RELEASE versi
Prerequisites to build tgz, debian and rpm packages: Prerequisites to build tgz, debian and rpm packages:
> apt-get install perl tar dpkg dpatch p7zip-full rpm zip php-cli > apt-get install perl tar dpkg dpatch p7zip-full rpm zip php-cli
Prerequisites to build autoexe DoliWamp package: Prerequisites to build autoexe DoliWamp package from Linux (solution seems broken since Ubuntu 20.04):
> apt-get install wine q4wine > apt-get install wine q4wine
> Launch "wine cmd" to check a drive Z: pointing to / exists. > Launch "wine cmd" to check a drive Z: pointing to / exists.
> Install InnoSetup > Install InnoSetup
For example by running isetup-5.5.8.exe (https://www.jrsoftware.org) https://files.jrsoftware.org/is/5/ For example by running isetup-5.5.8.exe (https://www.jrsoftware.org) https://files.jrsoftware.org/is/5/
> Install WampServer into "C:\wamp64" to have Apache, PHP and MariaDB > Install WampServer into "C:\wamp64" to have Apache, PHP and MariaDB
For example by running wampserver3.2.0_x64.exe (https://www.wampserver.com). For example by running wampserver3.2.6_x64.exe (https://www.wampserver.com).
See file build/exe/doliwamp.iss to know the doliwamp version currently setup. See file build/exe/doliwamp.iss to know the doliwamp version currently setup.
> Add path to ISCC into PATH windows var: > Add path to ISCC into PATH windows var:
Launch wine cmd, then regedit and add entry int HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment\PATH Launch wine cmd, then regedit and add entry int HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment\PATH
@ -25,9 +25,21 @@ Prerequisites to build autoexe DoliWamp package:
***** Prerequisites For Windows ***** ***** Prerequisites For Windows *****
Install Perl Prerequisites to build autoexe DoliWamp package from Windows:
Install WampServer-3.2.*-64.exe
isetup-5.5.8.exe > Install Perl for Windwos (https://strawberryperl.com/)
> Install isetup-5.5.8.exe (https://www.jrsoftware.org)
> Install WampServer-3.2.*-64.exe (Apache 2.4.51, PHP 7.3.33, MariaDB 10.6.5 for example. Version must match the values found into doliwamp.iss)
> Install GIT for Windows (https://git-scm.com/ => You must choose option "Add Git bash profile", "Git commit as-is")
> Install Dolibarr verions:
git clone https://github.com/dolibarr/dolibarr
> Add the path of PHP (C:\wamp64\bin\php\php7.3.33) and InnoSetup (C:\Program Files (x86)\Inno Setup 5) into the %PATH% of Windows.
> Create a config file c:\dolibarr\dolibarr\htdocs\conf\conf.php with content
<?php
$dolibarr_main_document_root="c:\dolibarr\dolibarr\htdocs";
$dolibarr_main_url_root='http://localhost';
***** Actions to do a BETA ***** ***** Actions to do a BETA *****

View File

@ -25,7 +25,7 @@ BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build
Group: Applications/Productivity Group: Applications/Productivity
Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-adodb, php-nusoap, dejavu-sans-fonts Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-nusoap, dejavu-sans-fonts
Requires: mysql-server, mysql Requires: mysql-server, mysql
#BuildRequires: desktop-file-utils #BuildRequires: desktop-file-utils
@ -104,7 +104,6 @@ cui hai bisogno ed essere facile da usare.
%{__cp} -pr htdocs $RPM_BUILD_ROOT%{_datadir}/%{name} %{__cp} -pr htdocs $RPM_BUILD_ROOT%{_datadir}/%{name}
%{__cp} -pr scripts $RPM_BUILD_ROOT%{_datadir}/%{name} %{__cp} -pr scripts $RPM_BUILD_ROOT%{_datadir}/%{name}
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/ckeditor/_source %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/ckeditor/_source
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/adodbtime
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/nusoap %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/nusoap
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/fonts %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/fonts
@ -165,6 +164,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/barcode %_datadir/dolibarr/htdocs/barcode
%_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/bookcal
%_datadir/dolibarr/htdocs/bom %_datadir/dolibarr/htdocs/bom
%_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/categories
%_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/collab
@ -274,7 +274,6 @@ if [ -s $config ] && grep -q "File generated by" $config
then then
# File already exist. We add params not found. # File already exist. We add params not found.
echo Add new params to overwrite path to use shared libraries/fonts echo Add new params to overwrite path to use shared libraries/fonts
grep -q -c "dolibarr_lib_ADODB_PATH" $config || [ ! -d "/usr/share/php/adodb" ] || echo "<?php \$dolibarr_lib_ADODB_PATH='/usr/share/php/adodb'; ?>" >> $config
grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config
#grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config #grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config
grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config

View File

@ -46,7 +46,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} %if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version}
Group: Applications/Productivity Group: Applications/Productivity
Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-adodb, php-nusoap, dejavu-sans-fonts, php-mbstring, php-xml Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-nusoap, dejavu-sans-fonts, php-mbstring, php-xml
Requires: mysql-server, mysql Requires: mysql-server, mysql
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
%else %else
@ -169,7 +169,6 @@ cui hai bisogno ed essere facile da usare.
%{__cp} -pr scripts $RPM_BUILD_ROOT%{_datadir}/%{name} %{__cp} -pr scripts $RPM_BUILD_ROOT%{_datadir}/%{name}
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/ckeditor/_source %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/ckeditor/_source
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} %if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version}
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/adodbtime
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/nusoap %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/nusoap
%{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/fonts %{__rm} -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/htdocs/includes/fonts
%else %else
@ -246,6 +245,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/barcode %_datadir/dolibarr/htdocs/barcode
%_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/bookcal
%_datadir/dolibarr/htdocs/bom %_datadir/dolibarr/htdocs/bom
%_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/categories
%_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/collab
@ -425,7 +425,6 @@ if [ -s $config ] && grep -q "File generated by" $config
then then
# File already exist. We add params not found. # File already exist. We add params not found.
echo Add new params to overwrite path to use shared libraries/fonts echo Add new params to overwrite path to use shared libraries/fonts
grep -q -c "dolibarr_lib_ADODB_PATH" $config || [ ! -d "/usr/share/php/adodb" ] || echo "<?php \$dolibarr_lib_ADODB_PATH='/usr/share/php/adodb'; ?>" >> $config
grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config
#grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config #grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config
grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config

View File

@ -162,6 +162,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/barcode %_datadir/dolibarr/htdocs/barcode
%_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/bookcal
%_datadir/dolibarr/htdocs/bom %_datadir/dolibarr/htdocs/bom
%_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/categories
%_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/collab
@ -271,7 +272,6 @@ if [ -s $config ] && grep -q "File generated by" $config
then then
# File already exist. We add params not found. # File already exist. We add params not found.
echo Add new params to overwrite path to use shared libraries/fonts echo Add new params to overwrite path to use shared libraries/fonts
grep -q -c "dolibarr_lib_ADODB_PATH" $config || [ ! -d "/usr/share/php/adodb" ] || echo "<?php \$dolibarr_lib_ADODB_PATH='/usr/share/php/adodb'; ?>" >> $config
grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config
#grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config #grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config
grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config

View File

@ -67,7 +67,7 @@ Programmo web, progettato per poter fornire solo ciò di
cui hai bisogno ed essere facile da usare. cui hai bisogno ed essere facile da usare.
#---- prep #---- prepo
%prep %prep
%setup -q %setup -q
%patch0 -p0 -b .patch %patch0 -p0 -b .patch
@ -172,6 +172,7 @@ done >>%{name}.lang
%_datadir/dolibarr/htdocs/barcode %_datadir/dolibarr/htdocs/barcode
%_datadir/dolibarr/htdocs/blockedlog %_datadir/dolibarr/htdocs/blockedlog
%_datadir/dolibarr/htdocs/bookmarks %_datadir/dolibarr/htdocs/bookmarks
%_datadir/dolibarr/htdocs/bookcal
%_datadir/dolibarr/htdocs/bom %_datadir/dolibarr/htdocs/bom
%_datadir/dolibarr/htdocs/categories %_datadir/dolibarr/htdocs/categories
%_datadir/dolibarr/htdocs/collab %_datadir/dolibarr/htdocs/collab
@ -281,7 +282,6 @@ if [ -s $config ] && grep -q "File generated by" $config
then then
# File already exist. We add params not found. # File already exist. We add params not found.
echo Add new params to overwrite path to use shared libraries/fonts echo Add new params to overwrite path to use shared libraries/fonts
grep -q -c "dolibarr_lib_ADODB_PATH" $config || [ ! -d "/usr/share/php/adodb" ] || echo "<?php \$dolibarr_lib_ADODB_PATH='/usr/share/php/adodb'; ?>" >> $config
grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config grep -q -c "dolibarr_lib_FPDI_PATH" $config || [ ! -d "/usr/share/php/fpdi" ] || echo "<?php \$dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; ?>" >> $config
#grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config #grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "<?php \$dolibarr_lib_GEOIP_PATH=''; ?>" >> $config
grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config grep -q -c "dolibarr_lib_NUSOAP_PATH" $config || [ ! -d "/usr/share/php/nusoap" ] || echo "<?php \$dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; ?>" >> $config

View File

@ -20,7 +20,6 @@ $force_install_lockinstall='444';
$force_install_distrib='rpmfedora'; $force_install_distrib='rpmfedora';
// Value to overwrite path to use shared libraries/fonts instead of embedded one // Value to overwrite path to use shared libraries/fonts instead of embedded one
$force_dolibarr_lib_ADODB_PATH='/usr/share/php/adodb';
//$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; //$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi';
//$force_dolibarr_lib_GEOIP_PATH=''; //$force_dolibarr_lib_GEOIP_PATH='';
$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; $force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap';

View File

@ -20,7 +20,6 @@ $force_install_lockinstall='444';
$force_install_distrib='rpmmandriva'; $force_install_distrib='rpmmandriva';
// Value to overwrite path to use shared libraries/fonts instead of embedded one // Value to overwrite path to use shared libraries/fonts instead of embedded one
$force_dolibarr_lib_ADODB_PATH='/usr/share/php/adodb';
//$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; //$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi';
//$force_dolibarr_lib_GEOIP_PATH=''; //$force_dolibarr_lib_GEOIP_PATH='';
$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; $force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap';

View File

@ -20,7 +20,6 @@ $force_install_lockinstall='444';
$force_install_distrib='rpmopensuse'; $force_install_distrib='rpmopensuse';
// Value to overwrite path to use shared libraries/fonts instead of embedded one // Value to overwrite path to use shared libraries/fonts instead of embedded one
//$force_dolibarr_lib_ADODB_PATH='/usr/share/php/adodb';
//$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi'; //$force_dolibarr_lib_FPDI_PATH='/usr/share/php/fpdi';
//$force_dolibarr_lib_GEOIP_PATH=''; //$force_dolibarr_lib_GEOIP_PATH='';
//$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap'; //$force_dolibarr_lib_NUSOAP_PATH='/usr/share/php/nusoap';

View File

@ -1,15 +1,17 @@
*~ *~
.#* .#*
.git
.gitignore
.scrutinizer.yml
Thumbs.db Thumbs.db
build/exe build/exe
build/html build/html
dev/dbmodel dev/examples/zapier
dev/fpdf
dev/initdemo dev/initdemo
dev/initdata dev/initdata
dev/iso-normes dev/resources/dbmodel
dev/licence dev/resources/iso-normes
dev/load dev/resources/licence
htdocs/conf/conf.php htdocs/conf/conf.php
htdocs/conf/conf.php.mysql htdocs/conf/conf.php.mysql
htdocs/conf/conf.php.old htdocs/conf/conf.php.old

View File

@ -209,6 +209,11 @@ with
with with
foreach ($value[1] as $k => $v) { foreach ($value[1] as $k => $v) {
* Fix by replacing
if ($res[0] == PDF_TYPE_OBJECT)
with
if (isset($res[0]) && $res[0] == PDF_TYPE_OBJECT)
JSGANTT: JSGANTT:
@ -283,6 +288,9 @@ RESTLER:
elseif (count($value) && isset($value[0]) && is_numeric($value[0])) elseif (count($value) && isset($value[0]) && is_numeric($value[0]))
* Add CommentParser.php line 406 & 407 to remove a warning on api request in php 8.1
empty($value[0]) ? null :
empty($value[1]) ? null :
+With swagger 2 provided into /explorer: +With swagger 2 provided into /explorer:
---------------------------------------- ----------------------------------------

View File

@ -1,20 +1,21 @@
# ldapsearch_sample1.txt # ldapsearch_sample1.txt
# ldapsearch is into package ldap-utils on debian. # ldapsearch is into package ldap-utils on debian.
# #
# Use this sample to search into a ldap # Use this samples to test a ldap_bind or to make a search into a ldap
# #
# Anonymous access # Anonymous access
# ldapsearch -h hostname -p 389 # ldapsearch -h hostname -p 389
# #
# Login access (using a Bind DN) # Login access (using a Bind DN)
# Such access must succeed to use LDAP as login module.
# ldapsearch -h hostname -p 389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password # 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 -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 -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 # 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) # 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 # 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. # 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 # You must also check that /etc/ldap/ldap.conf contains the line TLS_CACERT /etc/ssl/certs/ca-certificates.crt

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -84,7 +84,7 @@ const getFallbackRealAction = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/actions', // url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/actions',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -76,7 +76,7 @@ const getFallbackRealContact = (z, bundle) => {
// const getModulesChoices = (z/*, bundle*/) => { // const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', // url: bundle.authData.url + '/api/index.php/zapier/getmoduleschoices',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));
@ -94,7 +94,7 @@ const getFallbackRealContact = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, // url: url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/thirparty`,
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -76,7 +76,7 @@ const getFallbackRealMember = (z, bundle) => {
// const getModulesChoices = (z/*, bundle*/) => { // const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', // url: bundle.authData.url + '/api/index.php/zapier/getmoduleschoices',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));
@ -94,7 +94,7 @@ const getFallbackRealMember = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, // url: url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/thirparty`,
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -74,7 +74,7 @@ const getFallbackRealOrder = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/orders', // url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/orders',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -83,7 +83,7 @@ const getFallbackRealThirdparty = (z, bundle) => {
// const getModulesChoices = (z/*, bundle*/) => { // const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', // url: bundle.authData.url + '/api/index.php/zapier/getmoduleschoices',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));
@ -102,7 +102,7 @@ const getFallbackRealThirdparty = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, // url: url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/thirparty`,
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -76,7 +76,7 @@ const getFallbackRealTicket = (z, bundle) => {
// const getModulesChoices = (z/*, bundle*/) => { // const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', // url: bundle.authData.url + '/api/index.php/zapier/getmoduleschoices',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));
@ -97,7 +97,7 @@ const getFallbackRealTicket = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, // url: url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/thirparty`,
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

View File

@ -10,7 +10,7 @@ const subscribeHook = (z, bundle) => {
action: bundle.inputData.action action: bundle.inputData.action
}; };
const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; const url = bundle.authData.url + '/api/index.php/zapier/hook';
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
@ -32,7 +32,7 @@ const unsubscribeHook = (z, bundle) => {
// You can build requests and our client will helpfully inject all the variables // 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. // you need to complete. You can also register middleware to control this.
const options = { const options = {
url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, url: bundle.authData.url + '/api/index.php/zapier/hook/' + bundle.subscribeData.id,
method: 'DELETE', method: 'DELETE',
}; };
@ -73,7 +73,7 @@ const getFallbackRealUser = (z, bundle) => {
// const getModulesChoices = (z/*, bundle*/) => { // const getModulesChoices = (z/*, bundle*/) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const options = { // const options = {
// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', // url: bundle.authData.url + '/api/index.php/zapier/getmoduleschoices',
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));
@ -93,7 +93,7 @@ const getFallbackRealUser = (z, bundle) => {
// // For the test poll, you should get some real data, to aid the setup process. // // For the test poll, you should get some real data, to aid the setup process.
// const module = bundle.inputData.module; // const module = bundle.inputData.module;
// const options = { // const options = {
// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, // url: url: bundle.authData.url + '/api/index.php/zapier/getactionschoices/thirparty`,
// }; // };
// return z.request(options).then((response) => JSON.parse(response.content)); // return z.request(options).then((response) => JSON.parse(response.content));

File diff suppressed because one or more lines are too long

View File

@ -12,3 +12,11 @@ Le client règle rapidement et on lui accorde un escompte de 3% (120 € * 3% =
411xxx 3,60 € TTC 411xxx 3,60 € TTC
Et ça marche à l’inverse avec un fournisseur sauf que l’on est en 775000 au lieu de 665000 pour escompte obtenus. Et ça marche à l’inverse avec un fournisseur sauf que l’on est en 775000 au lieu de 665000 pour escompte obtenus.
Un compte comptable de Tiers vente = Acount Receivable
Un compte comptable de Tiers achat = Acount Payable

Binary file not shown.

View File

@ -22,8 +22,7 @@ https://www.tecklenborgh.com/post/ksa-zatca-publishes-guide-on-how-to-develop-a-
Method to encode/decode ZATCA string is available in test/phpunit/BarcodeTest.php Method to encode/decode ZATCA string is available in test/phpunit/BarcodeTest.php
* FOR QR-Bill in switzerland * FOR QR-Bill in switzerland - Facture-QR
----------------------------
Syntax of QR Code - See file ig-qr-bill-v2.2-fr.pdf (more doc on https://www.swiss-qr-invoice.org/downloads/) Syntax of QR Code - See file ig-qr-bill-v2.2-fr.pdf (more doc on https://www.swiss-qr-invoice.org/downloads/)
Syntax of complentary field named "structured information of invoice S1": https://www.swiss-qr-invoice.org/downloads/qr-bill-s1-syntax-fr.pdf Syntax of complentary field named "structured information of invoice S1": https://www.swiss-qr-invoice.org/downloads/qr-bill-s1-syntax-fr.pdf
To test/validate: https://www.swiss-qr-invoice.org/validator/ To test/validate: https://www.swiss-qr-invoice.org/validator/

View File

@ -10,8 +10,7 @@ Signification des chiffres.
- 1 chiffre pour la somme de controle - 1 chiffre pour la somme de controle
Cette regle subit de nombreuses entorses pour ameliorer l'usage des chiffres disponibles. Cette regle subit de nombreuses entorses pour ameliorer l'usage des chiffres disponibles.
Voici la liste des codes pays ou systeme : Voici la liste des codes pays ou systeme, les préfixes qui ne sont pas explicitement mentionnés sont réservés par GS1 :
EN EN
@ -25,105 +24,139 @@ Meaning of the numbers:
This rule has been twisted many times to improve the use of the available numbers. This rule has been twisted many times to improve the use of the available numbers.
Here is the list of country codes or system: Here is the list of country codes or system, prefixes not explicitly listed are reserved by GS1:
List List (https://www.gs1.org/prefixes)
==== ===================================
00 - 13 UCC (U.S.A / États-Unis & Canada) 0000000 Flag for internal numbering / Codification interne en magasin
20 - 29 Flag for internal numbering / Codification interne en magasin 00001–01999 GS1 US (U.S.A / États-Unis & Canada)
30 - 37 GENCOD-EAN France 020-029 Restricted / Restreint
380 BCCI (Bulgaria) 030-039 GS1 US (U.S.A / États-Unis & Canada)
383 SANA (Slovenia) 040-049 Flag for internal numbering / Codification interne en magasin
385 CRO-EAN (Croatia) 050-059 GS1 US (U.S.A / États-Unis & Canada)
387 EAN-BIH (Bosnia-Herzegovina) 060-139 GS1 US (U.S.A / États-Unis & Canada)
400-440 CCG (DE/Germany/Allemagne) 300-379 GS1 France
45 + 49 Distribution Code Center - DCC (Japan) 380 GS1 Bulgaria
460-469 UNISCAN - EAN Russia (Federation de Russie) 383 GS1 Slovenija
471 CAN Taiwan 385 GS1 Croatia
474 EAN Estonia 387 GS1 BIH (Bosnia-Herzegovina)
475 EAN Latvia 389 GS1 Montenegro
476 EAN Azerbaijan 400-440 GS1 Germany
477 EAN Lithuania 450-459 GS1 Japan
478 EAN Uzbekistan 460-469 GS1 Russia
479 EAN Sri Lanka 470 GS1 Kyrgyzstan
480 PANC Philippines 471 GS1 Chinese Taipei
481 EAN Belarus 474 GS1 Estonia
482 EAN Ukraine 475 GS1 Latvia
484 EAN Moldova 476 GS1 Azerbaijan
485 EAN Armenia 477 GS1 Lithuania
486 EAN Georgia 478 GS1 Uzbekistan
487 EAN Kazakhstan 479 GS1 Sri Lanka
489 HKANA Hong Kong 480 GS1 Philippines
50 E Centre UK - United Kingdom 481 GS1 Belarus
520 HELLCAN-EAN HELLAS - Greece 482 GS1 Ukraine
528 EAN Lebanon 483 GS1 Turkmenistan
529 EAN Cyprus 484 GS1 Moldova
531 EAN-MAC (FYR Macedonia) 485 GS1 Armenia
535 EAN Malta 486 GS1 Georgia
539 EAN Ireland 487 GS1 Kazakstan
54 ICODIF/EAN Belgium & Luxembourg 488 GS1 Tajikistan
560 CODIPOR (Portugal) 489 GS1 Hong Kong, China
569 EAN Iceland/Islande 490-499 GS1 Japan
57 EAN Denmark 500-509 GS1 UK
590 EAN Poland 520-521 GS1 Association Greece
594 EAN Romania 528 GS1 Lebanon
599 H.A.P.M.H. (Hungary) 529 GS1 Cyprus
600-601 EAN South Africa 530 GS1 Albania
609 EAN Mauritius Island 531 GS1 Macedonia
611 EAN Morocco 535 GS1 Malta
613 EAN Algeria 539 GS1 Ireland
619 Tunicode (Tunisia) 540-549 GS1 Belgium & Luxembourg
621 EAN Syria 560 GS1 Portugal
622 EAN Egypt 569 GS1 Iceland
625 EAN Jordan/Jordanie 570-579 GS1 Denmark
626 EAN Iran 590 GS1 Poland
628 EAN Saudi Arabia 594 GS1 Romania
64 EAN Finland 599 GS1 Hungary
690-693 ANCC - Article Numbering Centre of China 600-601 GS1 South Africa
70 EAN Norge (Norvege) 603 GS1 Ghana
729 Israeli Bar Code Association - EAN Israel 604 GS1 Senegal
73 EAN Suede 607 GS1 Oman
740 EAN Guatemala 608 GS1 Bahrain
741 EAN El Salvador 609 GS1 Mauritius
742 ICCC (Honduras) 611 GS1 Morocco
743 EAN Nicaragua 613 GS1 Algeria
744 EAN Costa Rica Panama 615 GS1 Nigeria
746 746 EAN Republique Dominicaine 616 GS1 Kenya
750 AMECE (Mexique) 617 GS1 Cameroon
759 EAN Venezuela 618 GS1 Côte d'Ivoire
76 EAN (Schweiz, Suisse, Svizzera) 619 GS1 Tunisia
770 IAC (Colombie) 620 GS1 Tanzania
773 EAN Uruguay 621 GS1 Syria
775 APC - EAN Peru (Perou) 622 GS1 Egypt
777 EAN Bolivie 624 GS1 Libya
779 CODIGO - EAN Argentine 625 GS1 Jordan
780 EAN Chili 626 GS1 Iran
784 EAN Paraguay 627 GS1 Kuwait
786 ECOP (Equateur) 628 GS1 Saudi Arabia
789 EAN Bresil 629 GS1 Emirates
80 - 83 INDICOD (Italy) 630 GS1 Qatar
84 AECOC (Espagne) 631 GS1 Namibia
850 Camera de Comercio de la Republica de Cuba (Cuba) 640-649 GS1 Finland
858 EAN Slovaquie 690-699 GS1 China
859 EAN Republique Tcheque 700-709 GS1 Norway
860 EAN YU (Yougoslavie) 729 GS1 Israel
867 EAN DPR Korea (Coree du Nord) 730-739 GS1 Sweden
869 Union of Chambers of Commerce of Turkey (Turquie) 740 GS1 Guatemala
87 EAN Nederland (Hollande) 741 GS1 El Salvador
880 EAN Korea (Coree du Sud) 742 GS1 Honduras
885 EAN Thailande 743 GS1 Nicaragua
888 SANC (Singapour) 744 GS1 Costa Rica
890 EAN Inde 745 GS1 Panama
893 EAN Vietnam 746 GS1 Republica Dominicana
899 EAN Indonesie 750 GS1 Mexico
90 - 91 EAN Autriche 754-755 GS1 Canada
93 EAN Australie 759 GS1 Venezuela
94 EAN Nouvelle Zelande 760-769 GS1 Schweiz, Suisse, Svizzera
955 Malaysian Article Numbering Council (MANC) - Malaisie 770-771 GS1 Colombia
977 Publications sirielles (ISSN) 773 GS1 Uruguay
978 - 979 Livres (ISBN) 775 GS1 Peru
980 Refus de remboursement 777 GS1 Bolivia
981 - 982 Coupons (monnaie courante) 778-779 GS1 Argentina
99 Coupons 780 GS1 Chile
784 GS1 Paraguay
786 GS1 Ecuador
789-790 GS1 Brasil
800-839 GS1 Italy
840-849 GS1 Spain
850 GS1 Cuba
858 GS1 Slovakia
859 GS1 Czech
860 GS1 Serbia
865 GS1 Mongolia
867 GS1 North Korea
868-869 GS1 Türkiye
870-879 GS1 Netherlands
880 GS1 South Korea
883 GS1 Myanmar
884 GS1 Cambodia
885 GS1 Thailand
888 GS1 Singapore
890 GS1 India
893 GS1 Vietnam
896 GS1 Pakistan
899 GS1 Indonesia
900-919 GS1 Austria
930-939 GS1 Australia
940-949 GS1 New Zealand
950 GS1 Global Office
955 GS1 Malaysia
958 GS1 Macao, China
960-969 Global Office - GTIN-8
977 Serial publications / Publications en série (ISSN)
978-979 Bookland / Livres (ISBN)
980 Refund receipts / Remboursements
981-983 GS1 Coupons
99 GS1 Coupons

View File

@ -4,4 +4,5 @@ terms
(en) VAT = Value Added Tax (en) VAT = Value Added Tax
(fr) TVA = Taxe sur la Valeur Ajouté (fr) TVA = Taxe sur la Valeur Ajouté
(es) NIF / CIF (es) NIF / CIF
(de) USt / MwSt (de) USt / MwSt = UmsatzSteuer / Mehrwertsteuer
(it) IVA

View File

@ -0,0 +1,10 @@
VAT Rates
---------
https://www.taxrates.cc/index.html
https://en.wikipedia.org/wiki/List_of_countries_by_tax_rates
For India: VAT=IGST / CGST=Localtax1 / SGST=Localtax2
see:
https://cleartax.in/s/what-is-sgst-cgst-igst
https://www.mastersindia.co/blog/what-is-cgst-sgst-igst-and-ugst/

View File

@ -1,8 +0,0 @@
VAT Rates
---------
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,9 +1,18 @@
<VirtualHost *:80> <VirtualHost *:80>
#php_admin_value sendmail_path "/usr/sbin/sendmail -t -i" #php_admin_value sendmail_path "/usr/sbin/sendmail -t -i"
#php_admin_value mail.force_extra_parameters "-f postmaster@mydomain.com" #php_admin_value mail.force_extra_parameters "-f postmaster@mydomain.com"
php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f postmaster@mydomain.com" #php_admin_value sendmail_path "/usr/sbin/sendmail -t -i -f postmaster@mydomain.com"
php_admin_value open_basedir /tmp/:/home/.../htdocs:/home/.../dolibarr_documents: php_admin_value open_basedir /tmp/:/home/.../htdocs:/home/.../dolibarr_documents:
# Add this to use a custom apparmor profile when using apache php handler
<IfModule mod_apparmor.c>
AADefaultHatName sellyoursaas-instances
</IfModule>
# The URLs of the web site
ServerName myvirtualalias ServerName myvirtualalias
ServerAlias myvirtualalias ServerAlias myvirtualalias
@ -15,8 +24,13 @@
AddDefaultCharset UTF-8 AddDefaultCharset UTF-8
DocumentRoot "/home/.../htdocs"
# Detect if we are using DoliDroid
#SetEnvIf User-Agent DoliDroid dolidroid
# The directory and permissions for the web site
DocumentRoot "/home/.../htdocs"
<Directory /home/.../htdocs/> <Directory /home/.../htdocs/>
AllowOverride None AllowOverride None
Options -Indexes -MultiViews +FollowSymLinks -ExecCGI Options -Indexes -MultiViews +FollowSymLinks -ExecCGI
@ -29,42 +43,46 @@
#require valid-user #require valid-user
</Directory> </Directory>
# Leaving /public and /api, /dav, .well_known but also wrappers for document and viewimage accessible to everyone # Leaving /public and /api, /dav, .well_known but also wrappers for document, viewimage and public json/img accessible to everyone
<Directory /home/admin/wwwroot/dolibarr/htdocs/public/> <Directory /home/admin/wwwroot/dolibarr/htdocs/public/>
AuthType None AuthType None
Require all granted
Satisfy any Satisfy any
Require all granted
</Directory> </Directory>
<Directory /home/admin/wwwroot/dolibarr/htdocs/api/> <Directory /home/admin/wwwroot/dolibarr/htdocs/api/>
AuthType None AuthType None
Require all granted
Satisfy any Satisfy any
Require all granted
</Directory> </Directory>
<Directory /home/admin/wwwroot/dolibarr/htdocs/dav/> <Directory /home/admin/wwwroot/dolibarr/htdocs/dav/>
AuthType None AuthType None
Require all granted
Satisfy any Satisfy any
Require all granted
</Directory> </Directory>
<Directory /home/admin/wwwroot/dolibarr/htdocs/.well-known/> <Directory /home/admin/wwwroot/dolibarr/htdocs/.well-known/>
AuthType None AuthType None
Require all granted
Satisfy any Satisfy any
Require all granted
</Directory> </Directory>
<Files ~ "(document\.php|viewimage\.php|\.js\.php|\.json\.php|\.js|\.css\.php|\.css|\.gif|\.png|\.svg|\.woff2|favicon\.ico)$"> <Files ~ "(document\.php|viewimage\.php|\.js\.php|\.json\.php|\.js|\.css\.php|\.css|\.gif|\.png|\.svg|\.woff2|favicon\.ico)$">
AuthType None AuthType None
Require all granted
Satisfy any Satisfy any
Require all granted
</Files> </Files>
# Log directoves
ErrorLog /var/log/apache2/myvirtualalias_error_log ErrorLog /var/log/apache2/myvirtualalias_error_log
TransferLog /var/log/apache2/myvirtualalias_access_log TransferLog /var/log/apache2/myvirtualalias_access_log
# Compress returned resources of type php pages, text file export, css and javascript
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript
# Compress is done on resources of type php pages, text file export, css and javascript
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/x-javascript
AddType text/javascript .jgz AddType text/javascript .jgz
AddEncoding gzip .jgz AddEncoding gzip .jgz
# Add cach performance directives
ExpiresActive On ExpiresActive On
ExpiresByType image/x-icon A2592000 ExpiresByType image/x-icon A2592000
ExpiresByType image/gif A2592000 ExpiresByType image/gif A2592000
@ -75,11 +93,11 @@
ExpiresByType application/x-javascript A2592000 ExpiresByType application/x-javascript A2592000
ExpiresByType application/javascript A2592000 ExpiresByType application/javascript A2592000
# To enable the SSL if the certificate file exists
<IfFile "/etc/letsencrypt/live/www.mydomain.com/cert.pem">
SSLEngine On SSLEngine On
# A self-signed (snakeoil) certificate can be created by installing
# the ssl-cert package. See
# /usr/share/doc/apache2.2-common/README.Debian.gz for more info.
# If both key and certificate are stored in the same file, only the # If both key and certificate are stored in the same file, only the
# SSLCertificateFile directive is needed. # SSLCertificateFile directive is needed.
SSLCertificateFile /etc/letsencrypt/live/www.mydomain.com/cert.pem SSLCertificateFile /etc/letsencrypt/live/www.mydomain.com/cert.pem
@ -89,5 +107,6 @@
#RewriteEngine on #RewriteEngine on
#RewriteCond %{SERVER_PORT} ^80$ #RewriteCond %{SERVER_PORT} ^80$
#RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [L,R] #RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [L,R]
</IfFile>
</VirtualHost> </VirtualHost>

View File

@ -15,9 +15,10 @@
<exclude-pattern type="relative">htdocs/install/doctemplates/websites</exclude-pattern> <exclude-pattern type="relative">htdocs/install/doctemplates/websites</exclude-pattern>
<exclude-pattern type="relative">htdocs/conf.php</exclude-pattern> <exclude-pattern type="relative">htdocs/conf.php</exclude-pattern>
<exclude-pattern type="relative">*/nltechno*</exclude-pattern> <exclude-pattern type="relative">*/nltechno*</exclude-pattern>
<exclude-pattern type="relative">*/htdocs/includes</exclude-pattern>
<exclude-pattern type="relative">source</exclude-pattern> <exclude-pattern type="relative">source</exclude-pattern>
<exclude-pattern type="relative">.git</exclude-pattern> <exclude-pattern type="relative">.git</exclude-pattern>
<exclude-pattern>htdocs/includes</exclude-pattern>
<exclude-pattern>htdocs/install/doctemplates/websites</exclude-pattern>
<!-- List of all tests --> <!-- List of all tests -->
@ -135,7 +136,7 @@
<rule ref="Generic.Metrics.CyclomaticComplexity"> <rule ref="Generic.Metrics.CyclomaticComplexity">
<properties> <properties>
<property name="complexity" value="250" /> <property name="complexity" value="250" />
<property name="absoluteComplexity" value="300" /> <property name="absoluteComplexity" value="400" />
</properties> </properties>
</rule> </rule>
<rule ref="Generic.Metrics.NestingLevel"> <rule ref="Generic.Metrics.NestingLevel">

View File

@ -0,0 +1,19 @@
# Fail2Ban configuration file
#
# Regexp to detect forbidden access on pages (public or not) so we can add mitigation on IP making too much
# access to your a Dolibarr instance.
[Definition]
# To test, you can inject this example into log
# echo `myvirtualhost.com:443 1.2.3.4 - - [15/Dec/2022:09:57:47 +0000] "GET /public/abc" 403 123 "-" "Mozilla" >> /var/log/apache2/access.log
#
# then
# fail2ban-client status web-accesslog-limit403
#
# To test rule file on a existing log file
# fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/web-accesslog-limit403.conf
failregex = <HOST> - - .*HTTP/[0-9]+(.[0-9]+)?" 403
ignoreregex =

View File

@ -0,0 +1,19 @@
# Fail2Ban configuration file
#
# Regexp to detect access on public pages so we can add mitigation on IP making too much
# access to your a Dolibarr instance.
[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 /public/clicktodial/cidlookup.php" >> /mypath/documents/dolibarr.log
#
# then
# fail2ban-client status web-dolibarr-limitpublic
#
# To test rule file on a existing log file
# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-limitpublic.conf
failregex = ^ [A-Z\s]+ <HOST>\s+--- Access to .*/public/
ignoreregex =

View File

@ -1,8 +1,7 @@
# Fail2Ban configuration file # Fail2Ban configuration file
# #
# Regexp to catch known spambots and software alike. Please verify # Regexp to detect try to check a couple login/password so we can add mitigation
# that it is your intent to block IPs which were driven by # on IP making too much tries.
# above mentioned bots.
[Definition] [Definition]
@ -11,7 +10,7 @@
# 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 # 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 # then
# fail2ban-client status web-dol-bruteforce # fail2ban-client status web-dolibarr-rulesbruteforce
# #
# To test rule file on a existing log file # To test rule file on a existing log file
# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf # fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulesbruteforce.conf

View File

@ -1,8 +1,7 @@
# Fail2Ban configuration file # Fail2Ban configuration file
# #
# Regexp to catch known spambots and software alike. Please verify # Regexp to detect access on passwordforgotten.php page so we can add mitigation on IP making too much
# that it is your intent to block IPs which were driven by # access to this Dolibarr page.
# above mentioned bots.
[Definition] [Definition]
@ -11,7 +10,7 @@
# 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 # 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 # then
# fail2ban-client status web-dol-passforgotten # fail2ban-client status web-dolibarr-rulespassforgotten
# #
# To test rule file on a existing log file # To test rule file on a existing log file
# fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf # fail2ban-regex /mypath/documents/dolibarr.log /etc/fail2ban/filter.d/web-dolibarr-rulespassforgotten.conf

View File

@ -8,21 +8,36 @@
enabled = true enabled = true
port = http,https port = http,https
filter = web-dolibarr-rulespassforgotten filter = web-dolibarr-rulespassforgotten
logpath = >> /mypath/documents/documents/dolibarr.log logpath = /mypath/documents/documents/dolibarr.log
action = %(action_mw)s action = %(action_mw)s
bantime = 4320000 ; 50 days bantime = 4320000 ; 50 days
findtime = 86400 ; 1 day findtime = 86400 ; 1 day
maxretry = 10 maxretry = 10
[web-dol-bruteforce] [web-dol-bruteforce]
; rule against bruteforce hacking (login + api) ; rule against bruteforce hacking (login + api)
enabled = true enabled = true
port = http,https port = http,https
filter = web-dolibarr-rulesbruteforce filter = web-dolibarr-rulesbruteforce
logpath = >> /mypath/documents/documents/dolibarr.log logpath = /mypath/documents/documents/dolibarr.log
action = %(action_mw)s action = %(action_mw)s
bantime = 86400 ; 1 day bantime = 86400 ; 1 day
findtime = 3600 ; 1 hour findtime = 3600 ; 1 hour
maxretry = 10 maxretry = 10
[web-dol-limitpublic]
; rule to add rate limit on some public pages
; note you must keep enough for public access like agenda export, emailing trackers, stripe ipn access, ...
enabled = true
port = http,https
filter = web-dolibarr-limitpublic
logpath = /mypath/documents/documents/dolibarr.log
action = %(action_mw)s
bantime = 86400 ; 1 day
findtime = 86400 ; 1 day
maxretry = 1000

View File

@ -0,0 +1,14 @@
QODANA TUTO
-----------
This README explains how to use qodana to generate static analytics reports on the code
Install docker
Install qodana
To run inspection on CLI
cd ~/git/dirtoscan
sudo qodana scan --show-report

View File

@ -1,4 +1,7 @@
#!/bin/sh #!/bin/sh
#
# Count number of different contributors and number of commits for a given year.
#
if [ "x$1" = "x" ]; then if [ "x$1" = "x" ]; then
echo "Usage: $0 YEAR" echo "Usage: $0 YEAR"

View File

@ -1,6 +1,10 @@
#/bin/bash #/bin/bash
Releases=("3.8" "3.9" "4.0" "5.0" "6.0" " 7.0" "develop") #
Dates=("2013-01-01", "2014-01-01", "2015-01-01", "2016-07-01", "2017-02-01", "2017-07-01", "2018-02-01", "2050-01-01") # Count number of commits per user and per versions (using date for version detection)
#
Releases=("16.0" "develop")
Dates=("2022-01-01" "2022-08-31" "2050-01-01")
let "counter = 1" let "counter = 1"
for i in "${Releases[@]}" for i in "${Releases[@]}"

View File

@ -0,0 +1,16 @@
#/bin/bash
#
# Count number of lines modified per user for a given branch
#
if [ "x$2" = "x" ]; then
echo "Usage: $0 tagnamestart|START tagnameend|HEAD"
exit
fi
echo "git log $1..$2 --shortstat | grep ... | perl ... > /tmp/github_lines_perusers.tmp"
git log $1..$2 --shortstat | grep -e 'Author:' -e 'Date:' -e ' changed' -e ' insertion' -e ' deletion' | perl -n -e '/^(.*)$/; $line = $1; if ($line =~ /(changed|insertion|deletion)/) { $line =~ s/[^0-9\s]//g; my @arr=split /\s+/, $line; $tot=0; for (1..@arr) { $tot += $arr[$_]; }; print $tot."\n"; } else { print $line."\n"; };' > /tmp/github_lines_perusers.tmp
cat /tmp/github_lines_perusers.tmp | awk 'BEGIN { FS="\n"; print "user and nb of lines"; lastuser=""; } { if ($1 ~ /Author:/) { lastuser=$1 }; if ($1 ~ /^[0-9]+$/) { aaa[lastuser]+=$1; } } END { for (var in aaa) print var," ",aaa[var]; } '

View File

@ -121,8 +121,10 @@ main()
# Search of all jpg/jpeg/png in $INPUT # Search of all jpg/jpeg/png in $INPUT
# We remove images from $OUTPUT if $OUTPUT is a subdirectory of $INPUT # We remove images from $OUTPUT if $OUTPUT is a subdirectory of $INPUT
echo "Scan $INPUT to find images with find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v $OUTPUT" echo "Scan $INPUT to find images with find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v '/documents/' | grep -v $OUTPUT"
#echo "Scan $INPUT to find images with find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/'"
IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v '/documents/' | grep -v $OUTPUT) IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v '/documents/' | grep -v $OUTPUT)
#IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/')
if [ "$QUIET" == "0" ]; then if [ "$QUIET" == "0" ]; then
echo --- Optimizing $INPUT --- echo --- Optimizing $INPUT ---

View File

@ -1,5 +1,4 @@
<?php <?php
/*spl_autoload_register(function ($class_name) { /*spl_autoload_register(function ($class_name) {
//var_dump('class='.$class_name); //var_dump('class='.$class_name);
require $class_name; require $class_name;

View File

@ -36,7 +36,7 @@ then
echo "tx pull -a" echo "tx pull -a"
tx pull -a tx pull -a
echo "Remove some language directories (not enough translated)" echo "Remove some language directories (not enough translated) like ach, br_FR, en, frp, fy_NL, ..."
rm -fr htdocs/langs/ach rm -fr htdocs/langs/ach
rm -fr htdocs/langs/br_FR rm -fr htdocs/langs/br_FR
rm -fr htdocs/langs/en rm -fr htdocs/langs/en

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -23,6 +23,7 @@
* \brief List accounting account * \brief List accounting account
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
@ -30,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("compta", "bills", "admin", "accountancy", "salaries")); $langs->loadLangs(array('accountancy', 'admin', 'bills', 'compta', 'salaries'));
$mesg = ''; $mesg = '';
$action = GETPOST('action', 'aZ09'); $action = GETPOST('action', 'aZ09');
@ -46,20 +47,21 @@ $search_label = GETPOST('search_label', 'alpha');
$search_labelshort = GETPOST('search_labelshort', 'alpha'); $search_labelshort = GETPOST('search_labelshort', 'alpha');
$search_accountparent = GETPOST('search_accountparent', 'alpha'); $search_accountparent = GETPOST('search_accountparent', 'alpha');
$search_pcgtype = GETPOST('search_pcgtype', 'alpha'); $search_pcgtype = GETPOST('search_pcgtype', 'alpha');
$search_import_key = GETPOST('search_import_key', 'alpha');
$toselect = GETPOST('toselect', 'array'); $toselect = GETPOST('toselect', 'array');
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
$confirm = GETPOST('confirm', 'alpha'); $confirm = GETPOST('confirm', 'alpha');
$chartofaccounts = GETPOST('chartofaccounts', 'int'); $chartofaccounts = GETPOST('chartofaccounts', 'int');
$permissiontoadd = !empty($user->rights->accounting->chartofaccount); $permissiontoadd = $user->hasRight('accounting', 'chartofaccount');
$permissiontodelete = !empty($user->rights->accounting->chartofaccount); $permissiontodelete = $user->hasRight('accounting', 'chartofaccount');
// Security check // Security check
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -82,21 +84,27 @@ if (!$sortorder) {
} }
$arrayfields = array( $arrayfields = array(
'aa.account_number'=>array('label'=>$langs->trans("AccountNumber"), 'checked'=>1), 'aa.account_number'=>array('label'=>"AccountNumber", 'checked'=>1),
'aa.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1), 'aa.label'=>array('label'=>"Label", 'checked'=>1),
'aa.labelshort'=>array('label'=>$langs->trans("LabelToShow"), 'checked'=>1), 'aa.labelshort'=>array('label'=>"LabelToShow", 'checked'=>1),
'aa.account_parent'=>array('label'=>$langs->trans("Accountparent"), 'checked'=>1), 'aa.account_parent'=>array('label'=>"Accountparent", 'checked'=>1),
'aa.pcg_type'=>array('label'=>$langs->trans("Pcgtype"), 'checked'=>1, 'help'=>'PcgtypeDesc'), 'aa.pcg_type'=>array('label'=>"Pcgtype", 'checked'=>1, 'help'=>'PcgtypeDesc'),
'aa.reconcilable'=>array('label'=>$langs->trans("Reconcilable"), 'checked'=>1), 'categories'=>array('label'=>"AccountingCategories", 'checked'=>-1, 'help'=>'AccountingCategoriesDesc'),
'aa.active'=>array('label'=>$langs->trans("Activated"), 'checked'=>1) 'aa.reconcilable'=>array('label'=>"Reconcilable", 'checked'=>1),
'aa.active'=>array('label'=>"Activated", 'checked'=>1),
'aa.import_key'=>array('label'=>"ImportId", 'checked'=>-1)
); );
if ($conf->global->MAIN_FEATURES_LEVEL < 2) { if ($conf->global->MAIN_FEATURES_LEVEL < 2) {
unset($arrayfields['categories']);
unset($arrayfields['aa.reconcilable']); unset($arrayfields['aa.reconcilable']);
} }
$accounting = new AccountingAccount($db); $accounting = new AccountingAccount($db);
// Initialize technical object to manage hooks. Note that conf->hooks_modules contains array
$hookmanager->initHooks(array('accountancyadminaccount'));
/* /*
* Actions * Actions
@ -109,8 +117,8 @@ if (!GETPOST('confirmmassaction', 'alpha')) {
$massaction = ''; $massaction = '';
} }
$parameters = array(); $parameters = array('chartofaccounts' => $chartofaccounts, 'permissiontoadd' => $permissiontoadd, 'permissiontodelete' => $permissiontodelete);
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been monowraponalldified by some hooks $reshook = $hookmanager->executeHooks('doActions', $parameters, $accounting, $action); // Note that $action and $object may have been monowraponalldified by some hooks
if ($reshook < 0) { if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
} }
@ -222,15 +230,12 @@ if ($action == 'delete') {
$pcgver = $conf->global->CHARTOFACCOUNTS; $pcgver = $conf->global->CHARTOFACCOUNTS;
$sql = "SELECT aa.rowid, aa.fk_pcg_version, aa.pcg_type, aa.account_number, aa.account_parent , aa.label, aa.labelshort, aa.reconcilable, aa.active, "; $sql = "SELECT aa.rowid, aa.fk_pcg_version, aa.pcg_type, aa.account_number, aa.account_parent, aa.label, aa.labelshort, aa.fk_accounting_category,";
$sql .= " aa.reconcilable, aa.active, aa.import_key,";
$sql .= " a2.rowid as rowid2, a2.label as label2, a2.account_number as account_number2"; $sql .= " a2.rowid as rowid2, a2.label as label2, a2.account_number as account_number2";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa"; $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version AND aa.entity = ".$conf->entity; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version AND aa.entity = ".((int) $conf->entity);
if ($db->type == 'pgsql') { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = aa.account_parent AND a2.entity = ".((int) $conf->entity);
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = aa.account_parent AND a2.entity = ".$conf->entity;
} else {
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = aa.account_parent AND a2.entity = ".$conf->entity;
}
$sql .= " WHERE asy.rowid = ".((int) $pcgver); $sql .= " WHERE asy.rowid = ".((int) $pcgver);
//print $sql; //print $sql;
if (strlen(trim($search_account))) { if (strlen(trim($search_account))) {
@ -294,7 +299,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
} }
// List of mass actions available // List of mass actions available
if ($user->rights->accounting->chartofaccount) { if ($user->hasRight('accounting', 'chartofaccount')) {
$arrayofmassactions['predelete'] = '<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete"); $arrayofmassactions['predelete'] = '<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
} }
if (in_array($massaction, array('presend', 'predelete', 'closed'))) { if (in_array($massaction, array('presend', 'predelete', 'closed'))) {
@ -333,6 +338,9 @@ if ($resql) {
if ($search_pcgtype) { if ($search_pcgtype) {
$param .= '&search_pcgtype='.urlencode($search_pcgtype); $param .= '&search_pcgtype='.urlencode($search_pcgtype);
} }
if ($optioncss != '') {
$param .= '&search_import_key='.urlencode($search_import_key);
}
if ($optioncss != '') { if ($optioncss != '') {
$param .= '&optioncss='.urlencode($optioncss); $param .= '&optioncss='.urlencode($optioncss);
} }
@ -395,9 +403,14 @@ if ($resql) {
} }
print "</select>"; print "</select>";
print ajax_combobox("chartofaccounts"); print ajax_combobox("chartofaccounts");
print '<input type="'.(empty($conf->use_javascript_ajax) ? 'submit' : 'button').'" class="button button-edit" name="change_chart" id="change_chart" value="'.dol_escape_htmltag($langs->trans("ChangeAndLoad")).'">'; print '<input type="'.(empty($conf->use_javascript_ajax) ? 'submit' : 'button').'" class="button button-edit small" name="change_chart" id="change_chart" value="'.dol_escape_htmltag($langs->trans("ChangeAndLoad")).'">';
print '<br>'; print '<br>';
$parameters = array('chartofaccounts' => $chartofaccounts, 'permissiontoadd' => $permissiontoadd, 'permissiontodelete' => $permissiontodelete);
$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $accounting, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print '<br>'; print '<br>';
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
@ -427,11 +440,20 @@ if ($resql) {
} }
if (!empty($arrayfields['aa.account_parent']['checked'])) { if (!empty($arrayfields['aa.account_parent']['checked'])) {
print '<td class="liste_titre">'; print '<td class="liste_titre">';
print $formaccounting->select_account($search_accountparent, 'search_accountparent', 2); print $formaccounting->select_account($search_accountparent, 'search_accountparent', 2, array(), 0, 0, 'maxwidth150');
print '</td>'; print '</td>';
} }
// Predefined group
if (!empty($arrayfields['aa.pcg_type']['checked'])) { if (!empty($arrayfields['aa.pcg_type']['checked'])) {
print '<td class="liste_titre"><input type="text" class="flat width100" name="search_pcgtype" value="'.$search_pcgtype.'"></td>'; print '<td class="liste_titre"><input type="text" class="flat width75" name="search_pcgtype" value="'.$search_pcgtype.'"></td>';
}
// Custom groups
if (!empty($arrayfields['categories']['checked'])) {
print '<td class="liste_titre"></td>';
}
// Import key
if (!empty($arrayfields['aa.import_key']['checked'])) {
print '<td class="liste_titre"><input type="text" class="flat width75" name="search_import_key" value="'.$search_import_key.'"></td>';
} }
if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { if ($conf->global->MAIN_FEATURES_LEVEL >= 2) {
if (!empty($arrayfields['aa.reconcilable']['checked'])) { if (!empty($arrayfields['aa.reconcilable']['checked'])) {
@ -462,6 +484,12 @@ if ($resql) {
if (!empty($arrayfields['aa.pcg_type']['checked'])) { if (!empty($arrayfields['aa.pcg_type']['checked'])) {
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); 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);
} }
if (!empty($arrayfields['categories']['checked'])) {
print_liste_field_titre($arrayfields['categories']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, '', $arrayfields['categories']['help'], 1);
}
if (!empty($arrayfields['aa.import_key']['checked'])) {
print_liste_field_titre($arrayfields['aa.import_key']['label'], $_SERVER["PHP_SELF"], 'aa.import_key', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.import_key']['help'], 1);
}
if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { if ($conf->global->MAIN_FEATURES_LEVEL >= 2) {
if (!empty($arrayfields['aa.reconcilable']['checked'])) { if (!empty($arrayfields['aa.reconcilable']['checked'])) {
print_liste_field_titre($arrayfields['aa.reconcilable']['label'], $_SERVER["PHP_SELF"], 'aa.reconcilable', '', $param, '', $sortfield, $sortorder); print_liste_field_titre($arrayfields['aa.reconcilable']['label'], $_SERVER["PHP_SELF"], 'aa.reconcilable', '', $param, '', $sortfield, $sortorder);
@ -496,7 +524,7 @@ if ($resql) {
// Account label // Account label
if (!empty($arrayfields['aa.label']['checked'])) { if (!empty($arrayfields['aa.label']['checked'])) {
print "<td>"; print "<td>";
print $obj->label; print dol_escape_htmltag($obj->label);
print "</td>\n"; print "</td>\n";
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
@ -506,7 +534,7 @@ if ($resql) {
// Account label to show (label short) // Account label to show (label short)
if (!empty($arrayfields['aa.labelshort']['checked'])) { if (!empty($arrayfields['aa.labelshort']['checked'])) {
print "<td>"; print "<td>";
print $obj->labelshort; print dol_escape_htmltag($obj->labelshort);
print "</td>\n"; print "</td>\n";
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
@ -540,10 +568,30 @@ if ($resql) {
} }
} }
// Chart of accounts type // Predefined group (deprecated)
if (!empty($arrayfields['aa.pcg_type']['checked'])) { if (!empty($arrayfields['aa.pcg_type']['checked'])) {
print "<td>"; print "<td>";
print $obj->pcg_type; print dol_escape_htmltag($obj->pcg_type);
print "</td>\n";
if (!$i) {
$totalarray['nbfield']++;
}
}
// Custom accounts
if (!empty($arrayfields['categories']['checked'])) {
print "<td>";
// TODO Get all custom groups labels the account is in
print dol_escape_htmltag($obj->fk_accounting_category);
print "</td>\n";
if (!$i) {
$totalarray['nbfield']++;
}
}
// Import id
if (!empty($arrayfields['aa.import_key']['checked'])) {
print "<td>";
print dol_escape_htmltag($obj->import_key);
print "</td>\n"; print "</td>\n";
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
@ -590,7 +638,7 @@ if ($resql) {
// Action // Action
print '<td class="center nowraponall">'; print '<td class="center nowraponall">';
if ($user->rights->accounting->chartofaccount) { if ($user->hasRight('accounting', 'chartofaccount')) {
print '<a class="editfielda" href="./card.php?action=update&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'">'; print '<a class="editfielda" href="./card.php?action=update&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'">';
print img_edit(); print img_edit();
print '</a>'; print '</a>';

View File

@ -32,6 +32,7 @@
* \brief Page to administer model of chart of accounts * \brief Page to administer model of chart of accounts
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
@ -44,7 +45,7 @@ if (isModEnabled('accounting')) {
} }
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("errors", "admin", "companies", "resource", "holiday", "compta", "accountancy", "hrm")); $langs->loadLangs(array('accountancy', 'admin', 'companies', 'compta', 'errors', 'holiday', 'hrm', 'resource'));
$action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; $action = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view';
$confirm = GETPOST('confirm', 'alpha'); $confirm = GETPOST('confirm', 'alpha');
@ -78,7 +79,7 @@ $search_country_id = GETPOST('search_country_id', 'int');
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -503,8 +504,8 @@ if ($id) {
print '<td>'; print '<td>';
print '<input type="hidden" name="id" value="'.$id.'">'; print '<input type="hidden" name="id" value="'.$id.'">';
print '</td>'; print '</td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '</tr>'; print '</tr>';
// Line to enter new values // Line to enter new values
@ -639,7 +640,8 @@ if ($id) {
foreach ($fieldlist as $field => $value) { foreach ($fieldlist as $field => $value) {
$showfield = 1; $showfield = 1;
$class = "left"; $class = "left";
$valuetoshow = $obj->{$fieldlist[$field]}; $tmpvar = $fieldlist[$field];
$valuetoshow = $obj->$tmpvar;
if ($value == 'type_template') { if ($value == 'type_template') {
$valuetoshow = isset($elementList[$valuetoshow]) ? $elementList[$valuetoshow] : $valuetoshow; $valuetoshow = isset($elementList[$valuetoshow]) ? $elementList[$valuetoshow] : $valuetoshow;
} }

View File

@ -23,6 +23,7 @@
* \brief Card of accounting account * \brief Card of accounting account
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
@ -32,7 +33,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
$error = 0; $error = 0;
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("bills", "accountancy", "compta")); $langs->loadLangs(array('accountancy', 'bills', 'compta'));
$action = GETPOST('action', 'aZ09'); $action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha'); $backtopage = GETPOST('backtopage', 'alpha');
@ -48,7 +49,7 @@ $label = GETPOST('label', 'alpha');
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -66,7 +67,7 @@ if (GETPOST('cancel', 'alpha')) {
exit; exit;
} }
if ($action == 'add' && $user->rights->accounting->chartofaccount) { if ($action == 'add' && $user->hasRight('accounting', 'chartofaccount')) {
if (!$cancel) { if (!$cancel) {
if (!$account_number) { if (!$account_number) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors'); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors');
@ -84,7 +85,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
// Clean code // Clean code
// To manage zero or not at the end of the accounting account // To manage zero or not at the end of the accounting account
if ($conf->global->ACCOUNTING_MANAGE_ZERO == 1) { if (!empty($conf->global->ACCOUNTING_MANAGE_ZERO)) {
$account_number = $account_number; $account_number = $account_number;
} else { } else {
$account_number = clean_account($account_number); $account_number = clean_account($account_number);
@ -127,7 +128,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
} }
} }
} }
} elseif ($action == 'edit' && $user->rights->accounting->chartofaccount) { } elseif ($action == 'edit' && $user->hasRight('accounting', 'chartofaccount')) {
if (!$cancel) { if (!$cancel) {
if (!$account_number) { if (!$account_number) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors'); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountNumber")), null, 'errors');
@ -147,7 +148,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
// Clean code // Clean code
// To manage zero or not at the end of the accounting account // To manage zero or not at the end of the accounting account
if (isset($conf->global->ACCOUNTING_MANAGE_ZERO) && $conf->global->ACCOUNTING_MANAGE_ZERO == 1) { if (!empty($conf->global->ACCOUNTING_MANAGE_ZERO)) {
$account_number = $account_number; $account_number = $account_number;
} else { } else {
$account_number = clean_account($account_number); $account_number = clean_account($account_number);
@ -184,7 +185,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount) {
header("Location: ".$urltogo); header("Location: ".$urltogo);
exit(); exit();
} }
} elseif ($action == 'delete' && $user->rights->accounting->chartofaccount) { } elseif ($action == 'delete' && $user->hasRight('accounting', 'chartofaccount')) {
$result = $object->fetch($id); $result = $object->fetch($id);
if (!empty($object->id)) { if (!empty($object->id)) {
@ -281,7 +282,7 @@ if ($action == 'create') {
print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc")); print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
print '</td>'; print '</td>';
print '<td>'; print '<td>';
$formaccounting->select_accounting_category($object->account_category, 'account_category', 1, 0, 1); print $formaccounting->select_accounting_category($object->account_category, 'account_category', 1, 0, 1);
print '</td></tr>'; print '</td></tr>';
print '</table>'; print '</table>';
@ -328,7 +329,8 @@ if ($action == 'create') {
// Account parent // Account parent
print '<tr><td>'.$langs->trans("Accountparent").'</td>'; print '<tr><td>'.$langs->trans("Accountparent").'</td>';
print '<td>'; print '<td>';
print $formaccounting->select_account($object->account_parent, 'account_parent', 1); // Note: We accept disabled account as parent account so we can build a hierarchy and use only childs
print $formaccounting->select_account($object->account_parent, 'account_parent', 1, array(), 0, 0, 'minwidth100 maxwidth300 maxwidthonsmartphone', 1, '');
print '</td></tr>'; print '</td></tr>';
// Chart of accounts type // Chart of accounts type
@ -357,7 +359,7 @@ if ($action == 'create') {
print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc")); print $form->textwithpicto($langs->trans("AccountingCategory"), $langs->transnoentitiesnoconv("AccountingAccountGroupsDesc"));
print '</td>'; print '</td>';
print '<td>'; print '<td>';
$formaccounting->select_accounting_category($object->account_category, 'account_category', 1); print $formaccounting->select_accounting_category($object->account_category, 'account_category', 1);
print '</td></tr>'; print '</td></tr>';
print '</table>'; print '</table>';
@ -419,17 +421,15 @@ if ($action == 'create') {
*/ */
print '<div class="tabsAction">'; print '<div class="tabsAction">';
if (!empty($user->rights->accounting->chartofaccount)) { if ($user->hasRight('accounting', 'chartofaccount')) {
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=update&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Modify').'</a>'; print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=update&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Modify').'</a>';
} else { } else {
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotAllowed")).'">'.$langs->trans('Modify').'</a>'; print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotAllowed")).'">'.$langs->trans('Modify').'</a>';
} }
if (!empty($user->rights->accounting->chartofaccount)) { // Delete
print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id.'">'.$langs->trans('Delete').'</a>'; $permissiontodelete = $user->hasRight('accounting', 'chartofaccount');
} else { print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
print '<a class="butActionRefused classfortooltip" href="#" title="'.dol_escape_htmltag($langs->trans("NotAllowed")).'">'.$langs->trans('Delete').'</a>';
}
print '</div>'; print '</div>';
} }

View File

@ -1,6 +1,7 @@
<?php <?php
/* Copyright (C) 2016 Jamal Elbaz <jamelbaz@gmail.pro> /* Copyright (C) 2016 Jamal Elbaz <jamelbaz@gmail.pro>
* Copyright (C) 2017-2022 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2017-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2022 Laurent Destailleur <eldy@users.sourceforge.net>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -22,6 +23,7 @@
* \brief Page to assign mass categories to accounts * \brief Page to assign mass categories to accounts
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancycategory.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancycategory.class.php';
@ -30,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
$error = 0; $error = 0;
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("bills", "accountancy")); $langs->loadLangs(array("bills", "accountancy", "compta"));
$id = GETPOST('id', 'int'); $id = GETPOST('id', 'int');
$cancel = GETPOST('cancel', 'alpha'); $cancel = GETPOST('cancel', 'alpha');
@ -43,8 +45,28 @@ if ($cat_id == 0) {
$cat_id = null; $cat_id = null;
} }
// Load variable for pagination
$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
// If $page is not defined, or '' or -1 or if we click on clear filters
$page = 0;
}
$offset = $limit * $page;
$pageprev = $page - 1;
$pagenext = $page + 1;
if (empty($sortfield)) {
$sortfield = 'account_number';
}
if (empty($sortorder)) {
$sortorder = 'ASC';
}
// Security check // Security check
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -109,18 +131,22 @@ print '<table class="border centpercent">';
// Select the category // Select the category
print '<tr><td class="titlefield">'.$langs->trans("AccountingCategory").'</td>'; print '<tr><td class="titlefield">'.$langs->trans("AccountingCategory").'</td>';
print '<td>'; print '<td>';
$formaccounting->select_accounting_category($cat_id, 'account_category', 1, 0, 0, 1); print $formaccounting->select_accounting_category($cat_id, 'account_category', 1, 0, 0, 0);
print '<input type="submit" class="button" value="'.$langs->trans("Select").'">'; print '<input type="submit" class="button small" value="'.$langs->trans("Select").'">';
print '</td></tr>'; print '</td></tr>';
print '</table>';
print dol_get_fiche_end();
// Select the accounts // Select the accounts
if (!empty($cat_id)) { if (!empty($cat_id)) {
$return = $accountingcategory->getAccountsWithNoCategory($cat_id); $return = $accountingcategory->getAccountsWithNoCategory($cat_id);
if ($return < 0) { if ($return < 0) {
setEventMessages(null, $accountingcategory->errors, 'errors'); setEventMessages(null, $accountingcategory->errors, 'errors');
} }
print '<tr><td>'.$langs->trans("AddAccountFromBookKeepingWithNoCategories").'</td>'; print '<br>';
print '<td>';
$arraykeyvalue = array(); $arraykeyvalue = array();
foreach ($accountingcategory->lines_cptbk as $key => $val) { foreach ($accountingcategory->lines_cptbk as $key => $val) {
@ -129,33 +155,25 @@ if (!empty($cat_id)) {
} }
if (is_array($accountingcategory->lines_cptbk) && count($accountingcategory->lines_cptbk) > 0) { if (is_array($accountingcategory->lines_cptbk) && count($accountingcategory->lines_cptbk) > 0) {
print $form->multiselectarray('cpt_bk', $arraykeyvalue, GETPOST('cpt_bk', 'array'), null, null, null, null, "90%"); print img_picto($langs->trans("AccountingAccount"), 'accounting_account', 'class="pictofixedwith"');
print '<br>'; print $form->multiselectarray('cpt_bk', $arraykeyvalue, GETPOST('cpt_bk', 'array'), null, null, '', 0, "80%", '', '', $langs->transnoentitiesnoconv("AddAccountFromBookKeepingWithNoCategories"));
/*print '<select class="flat minwidth200" size="8" name="cpt_bk[]" multiple>'; print '<input type="submit" class="button button-add small" id="" class="action-delete" value="'.$langs->trans("Add").'"> ';
foreach ( $accountingcategory->lines_cptbk as $cpt ) {
print '<option value="' . length_accountg($cpt->numero_compte) . '">' . length_accountg($cpt->numero_compte) . ' (' . $cpt->label_compte . ' ' . $cpt->doc_ref . ')</option>';
} }
print '</select><br>';
print ajax_combobox('cpt_bk');
*/
print '<input type="submit" class="button button-add" id="" class="action-delete" value="'.$langs->trans("Add").'"> ';
} }
print '</td></tr>';
}
print '</table>';
print dol_get_fiche_end();
print '</form>'; print '</form>';
if ($action == 'display' || $action == 'delete') { if ((empty($action) || $action == 'display' || $action == 'delete') && $cat_id > 0) {
print "<table class='noborder' width='100%'>\n"; $param = 'account_category='.((int) $cat_id);
print '<br>';
print '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print '<td class="liste_titre">'.$langs->trans("AccountAccounting")."</td>"; print getTitleFieldOfList('AccountAccounting', 0, $_SERVER['PHP_SELF'], 'account_number', '', $param, '', $sortfield, $sortorder, '')."\n";
print '<td class="liste_titre" colspan="2">'.$langs->trans("Label")."</td>"; print getTitleFieldOfList('Label', 0, $_SERVER['PHP_SELF'], 'label', '', $param, '', $sortfield, $sortorder, '')."\n";
print "</tr>\n"; print getTitleFieldOfList('', 0, $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, '')."\n";
print '</tr>'."\n";
if (!empty($cat_id)) { if (!empty($cat_id)) {
$return = $accountingcategory->display($cat_id); // This load ->lines_display $return = $accountingcategory->display($cat_id); // This load ->lines_display
@ -164,6 +182,8 @@ if ($action == 'display' || $action == 'delete') {
} }
if (is_array($accountingcategory->lines_display) && count($accountingcategory->lines_display) > 0) { if (is_array($accountingcategory->lines_display) && count($accountingcategory->lines_display) > 0) {
$accountingcategory->lines_display = dol_sort_array($accountingcategory->lines_display, $sortfield, $sortorder, -1, 0, 1);
foreach ($accountingcategory->lines_display as $cpt) { foreach ($accountingcategory->lines_display as $cpt) {
print '<tr class="oddeven">'; print '<tr class="oddeven">';
print '<td>'.length_accountg($cpt->account_number).'</td>'; print '<td>'.length_accountg($cpt->account_number).'</td>';
@ -176,6 +196,8 @@ if ($action == 'display' || $action == 'delete') {
print "</td>"; print "</td>";
print "</tr>\n"; print "</tr>\n";
} }
} else {
print '<tr><td colspan="3"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
} }
} }

View File

@ -22,6 +22,7 @@
* \brief Page to administer data tables * \brief Page to administer data tables
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
@ -42,7 +43,7 @@ $rowid = GETPOST('rowid', 'alpha');
$code = GETPOST('code', 'alpha'); $code = GETPOST('code', 'alpha');
// Security access // Security access
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -189,7 +190,7 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
setEventMessages($langs->transnoentities('ErrorCodeCantContainZero'), null, 'errors'); setEventMessages($langs->transnoentities('ErrorCodeCantContainZero'), null, 'errors');
} }
} }
if (!is_numeric(GETPOST('position', 'alpha'))) { if (GETPOST('position') && !is_numeric(GETPOST('position', 'alpha'))) {
$langs->loadLangs(array("errors")); $langs->loadLangs(array("errors"));
$ok = 0; $ok = 0;
setEventMessages($langs->transnoentities('ErrorFieldMustBeANumeric', $langs->transnoentities("Position")), null, 'errors'); setEventMessages($langs->transnoentities('ErrorFieldMustBeANumeric', $langs->transnoentities("Position")), null, 'errors');
@ -443,15 +444,37 @@ if ($search_country_id > 0) {
if ($sortfield == 'country') { if ($sortfield == 'country') {
$sortfield = 'country_code'; $sortfield = 'country_code';
} }
if (empty($sortfield)) {
$sortfield = 'position';
}
$sql .= $db->order($sortfield, $sortorder); $sql .= $db->order($sortfield, $sortorder);
$sql .= $db->plimit($listlimit + 1, $offset); $sql .= $db->plimit($listlimit + 1, $offset);
//print $sql; //print $sql;
$fieldlist = explode(',', $tabfield[$id]); $fieldlist = explode(',', $tabfield[$id]);
$param = '&id='.$id;
if ($search_country_id > 0) {
$param .= '&search_country_id='.urlencode($search_country_id);
}
$paramwithsearch = $param;
if ($sortorder) {
$paramwithsearch .= '&sortorder='.urlencode($sortorder);
}
if ($sortfield) {
$paramwithsearch .= '&sortfield='.urlencode($sortfield);
}
if (GETPOST('from', 'alpha')) {
$paramwithsearch .= '&from='.urlencode(GETPOST('from', 'alpha'));
}
print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">'; print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">';
print '<input type="hidden" name="token" value="'.newToken().'">'; print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="from" value="'.dol_escape_htmltag(GETPOST('from', 'alpha')).'">'; print '<input type="hidden" name="from" value="'.dol_escape_htmltag(GETPOST('from', 'alpha')).'">';
print '<input type="hidden" name="sortfield" value="'.dol_escape_htmltag($sortfield).'">';
print '<input type="hidden" name="sortorder" value="'.dol_escape_htmltag($sortorder).'">';
print '<div class="div-table-responsive">'; print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">'; print '<table class="noborder centpercent">';
@ -522,9 +545,9 @@ if ($tabname[$id]) {
print '<td>'; print '<td>';
print '<input type="hidden" name="id" value="'.$id.'">'; print '<input type="hidden" name="id" value="'.$id.'">';
print '</td>'; print '</td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '</tr>'; print '</tr>';
// Line to enter new values // Line to enter new values
@ -570,20 +593,6 @@ if ($resql) {
$num = $db->num_rows($resql); $num = $db->num_rows($resql);
$i = 0; $i = 0;
$param = '&id='.$id;
if ($search_country_id > 0) {
$param .= '&search_country_id='.urlencode($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 // There is several pages
if ($num > $listlimit) { if ($num > $listlimit) {
print '<tr class="none"><td class="right" colspan="'.(3 + count($fieldlist)).'">'; print '<tr class="none"><td class="right" colspan="'.(3 + count($fieldlist)).'">';
@ -604,7 +613,7 @@ if ($resql) {
if ($showfield) { if ($showfield) {
if ($value == 'country') { if ($value == 'country') {
print '<td class="liste_titre">'; print '<td class="liste_titre">';
print $form->select_country($search_country_id, 'search_country_id', '', 28, 'maxwidth200 maxwidthonsmartphone'); print $form->select_country($search_country_id, 'search_country_id', '', 28, 'maxwidth150 maxwidthonsmartphone');
print '</td>'; print '</td>';
$filterfound++; $filterfound++;
} else { } else {
@ -724,11 +733,11 @@ if ($resql) {
print '<td></td>'; print '<td></td>';
print '<td></td>'; print '<td></td>';
print '<td class="center">'; print '<td class="center">';
print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
print '<input type="hidden" name="page" value="'.$page.'">'; print '<input type="hidden" name="page" value="'.$page.'">';
print '<input type="hidden" name="rowid" value="'.$rowid.'">'; print '<input type="hidden" name="rowid" value="'.$rowid.'">';
print '<input type="submit" class="button button-edit" name="actionmodify" value="'.$langs->trans("Modify").'">'; print '<input type="submit" class="button button-edit smallpaddingimp" 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 smallpaddingimp" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '<input type="submit" class="button button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
print '</td>'; print '</td>';
print '<td></td>'; print '<td></td>';
} else { } else {
@ -742,7 +751,8 @@ if ($resql) {
foreach ($fieldlist as $field => $value) { foreach ($fieldlist as $field => $value) {
$showfield = 1; $showfield = 1;
$class = "left"; $class = "left";
$valuetoshow = $obj->{$fieldlist[$field]}; $tmpvar = $fieldlist[$field];
$valuetoshow = $obj->$tmpvar;
if ($value == 'category_type') { if ($value == 'category_type') {
$valuetoshow = yn($valuetoshow); $valuetoshow = yn($valuetoshow);
} elseif ($valuetoshow == 'all') { } elseif ($valuetoshow == 'all') {
@ -821,7 +831,7 @@ if ($resql) {
} }
// Link to setup the group // Link to setup the group
print '<td class="center">'; print '<td>';
if (empty($obj->formula)) { 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 '<a href="'.DOL_URL_ROOT.'/accountancy/admin/categories.php?action=display&save_lastsearch_values=1&account_category='.$obj->rowid.'">';
print $langs->trans("ListOfAccounts"); print $langs->trans("ListOfAccounts");
@ -886,10 +896,10 @@ function fieldListAccountingCategories($fieldlist, $obj = '', $tabname = '', $co
if ($context == 'add') { if ($context == 'add') {
$fieldname = 'country_id'; $fieldname = 'country_id';
$preselectcountrycode = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : $mysoc->country_code; $preselectcountrycode = GETPOSTISSET('country_id') ? GETPOST('country_id', 'int') : $mysoc->country_code;
print $form->select_country($preselectcountrycode, $fieldname, '', 28, 'maxwidth200 maxwidthonsmartphone'); print $form->select_country($preselectcountrycode, $fieldname, '', 28, 'maxwidth150 maxwidthonsmartphone');
} else { } else {
$preselectcountrycode = (empty($obj->country_code) ? (empty($obj->country) ? $mysoc->country_code : $obj->country) : $obj->country_code); $preselectcountrycode = (empty($obj->country_code) ? (empty($obj->country) ? $mysoc->country_code : $obj->country) : $obj->country_code);
print $form->select_country($preselectcountrycode, $fieldname, '', 28, 'maxwidth200 maxwidthonsmartphone'); print $form->select_country($preselectcountrycode, $fieldname, '', 28, 'maxwidth150 maxwidthonsmartphone');
} }
print '</td>'; print '</td>';
} elseif ($fieldlist[$field] == 'country_id') { } elseif ($fieldlist[$field] == 'country_id') {

View File

@ -22,6 +22,7 @@
* \brief Setup page to configure accounting expert module * \brief Setup page to configure accounting expert module
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
@ -31,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
$langs->loadLangs(array("compta", "admin", "accountancy")); $langs->loadLangs(array("compta", "admin", "accountancy"));
// Security check // Security check
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }

View File

@ -38,7 +38,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
$langs->loadLangs(array("compta", "bills", "admin", "accountancy", "salaries", "loan")); $langs->loadLangs(array("compta", "bills", "admin", "accountancy", "salaries", "loan"));
// Security check // Security check
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -84,6 +84,9 @@ $list_account[] = 'ACCOUNTING_VAT_PAY_ACCOUNT';
if (isModEnabled('banque')) { if (isModEnabled('banque')) {
$list_account[] = 'ACCOUNTING_ACCOUNT_TRANSFER_CASH'; $list_account[] = 'ACCOUNTING_ACCOUNT_TRANSFER_CASH';
} }
if (!empty($conf->global->INVOICE_USE_RETAINED_WARRANTY)) {
$list_account[] = 'ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY';
}
if (isModEnabled('don')) { if (isModEnabled('don')) {
$list_account[] = 'DONATION_ACCOUNTINGACCOUNT'; $list_account[] = 'DONATION_ACCOUNTINGACCOUNT';
} }
@ -133,6 +136,12 @@ if ($action == 'update') {
$error++; $error++;
} }
$constname = 'ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT';
$constvalue = GETPOST($constname, 'int');
if (!dolibarr_set_const($db, $constname, $constvalue, 'chaine', 0, '', $conf->entity)) {
$error++;
}
if (!$error) { if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
@ -155,6 +164,20 @@ if ($action == 'setACCOUNTING_ACCOUNT_CUSTOMER_USE_AUXILIARY_ON_DEPOSIT') {
} }
} }
if ($action == 'setACCOUNTING_ACCOUNT_SUPPLIER_USE_AUXILIARY_ON_DEPOSIT') {
$setDisableAuxiliaryAccountOnSupplierDeposit = GETPOST('value', 'int');
$res = dolibarr_set_const($db, "ACCOUNTING_ACCOUNT_SUPPLIER_USE_AUXILIARY_ON_DEPOSIT", $setDisableAuxiliaryAccountOnSupplierDeposit, 'yesno', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'mesgs');
}
}
/* /*
* View * View
@ -281,6 +304,33 @@ if (isModEnabled('societe') && getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_D
print '</tr>'; print '</tr>';
} }
// Supplier deposit account
print '<tr class="oddeven value">';
// Param
print '<td>';
print img_picto('', 'supplier_invoice', 'class="pictofixedwidth"') . $langs->trans('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT');
print '</td>';
// Value
print '<td class="right">'; // Do not force class=right, or it align also the content of the select box
print $formaccounting->select_account(getDolGlobalString('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT'), 'ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT', 1, '', 1, 1, 'minwidth100 maxwidth300 maxwidthonsmartphone', 'accounts');
print '</td>';
print '</tr>';
if (isModEnabled('societe') && getDolGlobalString('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT') && getDolGlobalString('ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT') != '-1') {
print '<tr class="oddeven">';
print '<td>' . img_picto('', 'supplier_invoice', 'class="pictofixedwidth"') . $langs->trans("UseAuxiliaryAccountOnSupplierDeposit") . '</td>';
if (getDolGlobalInt('ACCOUNTING_ACCOUNT_SUPPLIER_USE_AUXILIARY_ON_DEPOSIT')) {
print '<td class="right"><a class="reposition" href="' . $_SERVER['PHP_SELF'] . '?token=' . newToken() . '&action=setACCOUNTING_ACCOUNT_SUPPLIER_USE_AUXILIARY_ON_DEPOSIT&value=0">';
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=setACCOUNTING_ACCOUNT_SUPPLIER_USE_AUXILIARY_ON_DEPOSIT&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
print '</tr>';
}
print "</table>\n"; print "</table>\n";
print "</div>\n"; print "</div>\n";

View File

@ -36,7 +36,7 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php';
$langs->loadLangs(array("compta", "bills", "admin", "accountancy")); $langs->loadLangs(array("compta", "bills", "admin", "accountancy"));
// Security access // Security access
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }

View File

@ -21,6 +21,7 @@
* \brief Setup page to configure fiscal year * \brief Setup page to configure fiscal year
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/fiscalyear.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/fiscalyear.class.php';
@ -52,7 +53,7 @@ $langs->loadLangs(array("admin", "compta"));
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->fiscalyear->write)) { // If we can read accounting records, we should be able to see fiscal year. if (!$user->hasRight('accounting', 'fiscalyear', 'write')) { // If we can read accounting records, we should be able to see fiscal year.
accessforbidden(); accessforbidden();
} }
@ -121,7 +122,7 @@ if ($result) {
$i = 0; $i = 0;
$addbutton .= dolGetButtonTitle($langs->trans('NewFiscalYear'), '', 'fa fa-plus-circle', 'fiscalyear_card.php?action=create', '', $user->rights->accounting->fiscalyear->write); $addbutton .= dolGetButtonTitle($langs->trans('NewFiscalYear'), '', 'fa fa-plus-circle', 'fiscalyear_card.php?action=create', '', $user->hasRight('accounting', 'fiscalyear', 'write'));
$title = $langs->trans('AccountingPeriods'); $title = $langs->trans('AccountingPeriods');

View File

@ -22,6 +22,7 @@
* \brief Page to show a fiscal year * \brief Page to show a fiscal year
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/fiscalyear.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/fiscalyear.lib.php';
@ -34,7 +35,7 @@ $langs->loadLangs(array("admin", "compta"));
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->fiscalyear->write)) { if (!$user->hasRight('accounting', 'fiscalyear', 'write')) {
accessforbidden(); accessforbidden();
} }
@ -299,12 +300,12 @@ if ($action == 'create') {
/* /*
* Action bar * Action bar
*/ */
if (!empty($user->rights->accounting->fiscalyear->write)) { if ($user->hasRight('accounting', 'fiscalyear', 'write')) {
print '<div class="tabsAction">'; print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$id.'">'.$langs->trans('Modify').'</a>'; print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$id.'">'.$langs->trans('Modify').'</a>';
// print '<a class="butActionDelete" href="' . $_SERVER["PHP_SELF"] . '?action=delete&token='.newToken().'&id=' . $id . '">' . $langs->trans('Delete') . '</a>'; //print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
print '</div>'; print '</div>';
} }

View File

@ -21,6 +21,7 @@
* \brief Page to show info of a fiscal year * \brief Page to show info of a fiscal year
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/fiscalyear.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/fiscalyear.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
@ -33,7 +34,7 @@ $langs->loadLangs(array("admin", "compta"));
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->fiscalyear->write)) { if (!$user->hasRight('accounting', 'fiscalyear', 'write')) {
accessforbidden(); accessforbidden();
} }

View File

@ -29,6 +29,7 @@
* \brief Setup page to configure accounting expert module * \brief Setup page to configure accounting expert module
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
@ -38,7 +39,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
$langs->loadLangs(array("compta", "bills", "admin", "accountancy", "other")); $langs->loadLangs(array("compta", "bills", "admin", "accountancy", "other"));
// Security access // Security access
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -246,6 +247,34 @@ if ($action == 'setdisablebindingonexpensereports') {
} }
} }
if ($action == 'setenablelettering') {
$setenablelettering = GETPOST('value', 'int');
$res = dolibarr_set_const($db, "ACCOUNTING_ENABLE_LETTERING", $setenablelettering, '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 == 'setenableautolettering') {
$setenableautolettering = GETPOST('value', 'int');
$res = dolibarr_set_const($db, "ACCOUNTING_ENABLE_AUTOLETTERING", $setenableautolettering, 'yesno', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'mesgs');
}
}
/* /*
* View * View
@ -415,7 +444,7 @@ foreach ($list_binding as $key) {
print $form->selectDate((!empty($conf->global->$key) ? $db->idate($conf->global->$key) : -1), $key, 0, 0, 1); print $form->selectDate((!empty($conf->global->$key) ? $db->idate($conf->global->$key) : -1), $key, 0, 0, 1);
} elseif ($key == 'ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER') { } elseif ($key == 'ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER') {
$array = array(0=>$langs->trans("PreviousMonth"), 1=>$langs->trans("CurrentMonth"), 2=>$langs->trans("Fiscalyear")); $array = array(0=>$langs->trans("PreviousMonth"), 1=>$langs->trans("CurrentMonth"), 2=>$langs->trans("Fiscalyear"));
print $form->selectarray($key, $array, (isset($conf->global->ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER) ? $conf->global->ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER : 0)); print $form->selectarray($key, $array, (isset($conf->global->ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER) ? $conf->global->ACCOUNTING_DEFAULT_PERIOD_ON_TRANSFER : 0), 0, 0, 0, '', 0, 0, 0, '', 'onrightofpage');
} else { } else {
print '<input type="text" class="maxwidth100" id="'.$key.'" name="'.$key.'" value="'.getDolGlobalString($key).'">'; print '<input type="text" class="maxwidth100" id="'.$key.'" name="'.$key.'" value="'.getDolGlobalString($key).'">';
} }
@ -463,6 +492,43 @@ if (!empty($conf->global->ACCOUNTING_DISABLE_BINDING_ON_EXPENSEREPORTS)) {
} }
print '</tr>'; print '</tr>';
print '</table>';
print '<br>';
// Lettering params
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td colspan="2">'.$langs->trans('Options').' '.$langs->trans('Lettering').'</td>';
print "</tr>\n";
print '<tr class="oddeven">';
print '<td>'.$langs->trans("ACCOUNTING_ENABLE_LETTERING").'</td>';
if (!empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) {
print '<td class="right"><a class="reposition" href="'.$_SERVER['PHP_SELF'].'?token='.newToken().'&action=setenablelettering&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().'&action=setenablelettering&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
print '</tr>';
if (!empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) {
print '<tr class="oddeven">';
print '<td>' . $langs->trans("ACCOUNTING_ENABLE_AUTOLETTERING") . '</td>';
if (!empty($conf->global->ACCOUNTING_ENABLE_AUTOLETTERING)) {
print '<td class="right"><a class="reposition" href="' . $_SERVER['PHP_SELF'] . '?token=' . newToken() . '&action=setenableautolettering&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() . '&action=setenableautolettering&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a></td>';
}
print '</tr>';
}
print '</table>'; print '</table>';
print '<div class="center"><input type="submit" class="button button-edit" name="button" value="'.$langs->trans('Modify').'"></div>'; print '<div class="center"><input type="submit" class="button button-edit" name="button" value="'.$langs->trans('Modify').'"></div>';

View File

@ -26,6 +26,7 @@ if (!defined('CSRFCHECK_WITH_TOKEN')) {
define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET
} }
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
@ -45,7 +46,7 @@ $rowid = GETPOST('rowid', 'alpha');
$code = GETPOST('code', 'alpha'); $code = GETPOST('code', 'alpha');
// Security access // Security access
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -430,9 +431,9 @@ if ($id) {
print '<td>'; print '<td>';
print '<input type="hidden" name="id" value="'.$id.'">'; print '<input type="hidden" name="id" value="'.$id.'">';
print '</td>'; print '</td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '<td style="min-width: 26px;"></td>'; print '<td></td>';
print '</tr>'; print '</tr>';
// Line to enter new values // Line to enter new values
@ -586,7 +587,8 @@ if ($id) {
foreach ($fieldlist as $field => $value) { foreach ($fieldlist as $field => $value) {
$showfield = 1; $showfield = 1;
$class = "left"; $class = "left";
$valuetoshow = $obj->{$fieldlist[$field]}; $tmpvar = $fieldlist[$field];
$valuetoshow = $obj->$tmpvar;
if ($valuetoshow == 'all') { if ($valuetoshow == 'all') {
$valuetoshow = $langs->trans('All'); $valuetoshow = $langs->trans('All');
} elseif ($fieldlist[$field] == 'nature' && $tabname[$id] == MAIN_DB_PREFIX.'accounting_journal') { } elseif ($fieldlist[$field] == 'nature' && $tabname[$id] == MAIN_DB_PREFIX.'accounting_journal') {
@ -610,12 +612,6 @@ if ($id) {
if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) { if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i', $obj->code))) {
$iserasable = 0; $iserasable = 0;
$canbedisabled = 0; $canbedisabled = 0;
} elseif ($obj->code == 'RECEP') {
$iserasable = 0;
$canbedisabled = 0;
} elseif ($obj->code == 'EF0') {
$iserasable = 0;
$canbedisabled = 0;
} }
} }

View File

@ -45,7 +45,7 @@ $langs->loadLangs(array("companies", "compta", "accountancy", "products"));
if (!isModEnabled('accounting')) { if (!isModEnabled('accounting')) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->bind->write)) { if (!$user->hasRight('accounting', 'bind', 'write')) {
accessforbidden(); accessforbidden();
} }
@ -194,7 +194,7 @@ if ($action == 'update') {
} }
if ($result <= 0) { if ($result <= 0) {
// setEventMessages(null, $accounting->errors, 'errors'); // 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 class="error">'.$langs->trans("ErrorDB").' : '.$langs->trans("Product").' '.$productid.' '.$langs->trans("NotVentilatedinAccount").' : id='.$accounting_account_id.'<br> <pre>'.$sql.'</pre></span></div>';
$ko++; $ko++;
} else { } else {
$sql = ''; $sql = '';
@ -203,7 +203,7 @@ if ($action == 'update') {
$sql_exists .= " WHERE fk_product = " . ((int) $productid) . " AND entity = " . ((int) $conf->entity); $sql_exists .= " WHERE fk_product = " . ((int) $productid) . " AND entity = " . ((int) $conf->entity);
$resql_exists = $db->query($sql_exists); $resql_exists = $db->query($sql_exists);
if (!$resql_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>'; $msg .= '<div><span class="error">'.$langs->trans("ErrorDB").' : '.$langs->trans("Product").' '.$productid.' '.$langs->trans("NotVentilatedinAccount").' : id='.$accounting_account_id.'<br> <pre>'.$resql_exists.'</pre></span></div>';
$ko++; $ko++;
} else { } else {
$nb_exists = $db->num_rows($resql_exists); $nb_exists = $db->num_rows($resql_exists);
@ -522,7 +522,7 @@ if ($resql) {
// Filter on categories // Filter on categories
$moreforfilter = ''; $moreforfilter = '';
if (isModEnabled('categorie') && $user->rights->categorie->lire) { if (isModEnabled('categorie') && $user->hasRight('categorie', 'lire')) {
$moreforfilter .= '<div class="divsearchfield">'; $moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"'); $moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"');
$categoriesProductArr = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', '', 64, 0, 1); $categoriesProductArr = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', '', 64, 0, 1);

View File

@ -23,12 +23,14 @@
* \brief List of accounting sub-account (auxiliary accounts) * \brief List of accounting sub-account (auxiliary accounts)
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("compta", "bills", "admin", "accountancy", "salaries", "hrm", "errors")); $langs->loadLangs(array("accountancy", "admin", "bills", "compta", "errors", "hrm", "salaries"));
$mesg = ''; $mesg = '';
$action = GETPOST('action', 'aZ09'); $action = GETPOST('action', 'aZ09');
@ -47,7 +49,7 @@ $search_type = GETPOST('search_type', 'int');
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->chartofaccount)) { if (!$user->hasRight('accounting', 'chartofaccount')) {
accessforbidden(); accessforbidden();
} }
@ -80,6 +82,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL < 2) {
unset($arrayfields['reconcilable']); unset($arrayfields['reconcilable']);
} }
/* /*
* Actions * Actions
*/ */
@ -119,11 +122,13 @@ if (empty($reshook)) {
$form = new Form($db); $form = new Form($db);
$help_url = '';
$title = $langs->trans('ChartOfIndividualAccountsOfSubsidiaryLedger');
// Page Header
$help_url = 'EN:Module_Double_Entry_Accounting#Setup';
$title = $langs->trans('ChartOfIndividualAccountsOfSubsidiaryLedger');
llxHeader('', $title, $help_url); llxHeader('', $title, $help_url);
// Customer // Customer
$sql = "SELECT sa.rowid, sa.nom as label, sa.code_compta as subaccount, '1' as type, sa.entity"; $sql = "SELECT sa.rowid, sa.nom as label, sa.code_compta as subaccount, '1' as type, sa.entity";
$sql .= " FROM ".MAIN_DB_PREFIX."societe sa"; $sql .= " FROM ".MAIN_DB_PREFIX."societe sa";
@ -218,7 +223,7 @@ if (!empty($search_type) && $search_type >= 0) {
$sql .= " HAVING type LIKE '".$db->escape($search_type)."'"; $sql .= " HAVING type LIKE '".$db->escape($search_type)."'";
} }
// User // User - Employee
$sql .= " UNION "; $sql .= " UNION ";
$sql .= " SELECT u.rowid, u.lastname as label, u.accountancy_code as subaccount, '3' as type, u.entity FROM ".MAIN_DB_PREFIX."user u"; $sql .= " SELECT u.rowid, u.lastname as label, u.accountancy_code as subaccount, '3' as type, u.entity FROM ".MAIN_DB_PREFIX."user u";
$sql .= " WHERE u.entity IN (".getEntity('user').")"; $sql .= " WHERE u.entity IN (".getEntity('user').")";
@ -399,6 +404,7 @@ if ($resql) {
if (!empty($arrayfields['type']['checked'])) { if (!empty($arrayfields['type']['checked'])) {
print '<td class="center">'; print '<td class="center">';
$s = ''; $s = '';
// Customer // Customer
if ($obj->type == 1) { if ($obj->type == 1) {
$s .= '<a class="customer-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Customer").'" href="'.DOL_URL_ROOT.'/comm/card.php?socid='.$obj->rowid.'">'.$langs->trans("Customer").'</a>'; $s .= '<a class="customer-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Customer").'" href="'.DOL_URL_ROOT.'/comm/card.php?socid='.$obj->rowid.'">'.$langs->trans("Customer").'</a>';
@ -406,8 +412,8 @@ if ($resql) {
// Supplier // Supplier
$s .= '<a class="vendor-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Supplier").'" href="'.DOL_URL_ROOT.'/fourn/card.php?socid='.$obj->rowid.'">'.$langs->trans("Supplier").'</a>'; $s .= '<a class="vendor-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Supplier").'" href="'.DOL_URL_ROOT.'/fourn/card.php?socid='.$obj->rowid.'">'.$langs->trans("Supplier").'</a>';
} elseif ($obj->type == 3) { } elseif ($obj->type == 3) {
// User // User - Employee
$s .= '<a class="user-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Employee").'" href="'.DOL_URL_ROOT.'/user/card.php?id='.$obj->id.'">'.$langs->trans("Employee").'</a>'; $s .= '<a class="user-back" style="padding-left: 6px; padding-right: 6px" title="'.$langs->trans("Employee").'" href="'.DOL_URL_ROOT.'/user/card.php?id='.$obj->rowid.'">'.$langs->trans("Employee").'</a>';
} }
print $s; print $s;
print '</td>'; print '</td>';
@ -439,6 +445,7 @@ if ($resql) {
// Action // Action
print '<td class="center">'; print '<td class="center">';
$e = ''; $e = '';
// Customer // Customer
if ($obj->type == 1) { if ($obj->type == 1) {
$e .= '<a class="editfielda" title="'.$langs->trans("Customer").'" href="'.DOL_URL_ROOT.'/societe/card.php?action=edit&token='.newToken().'&socid='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>'; $e .= '<a class="editfielda" title="'.$langs->trans("Customer").'" href="'.DOL_URL_ROOT.'/societe/card.php?action=edit&token='.newToken().'&socid='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>';
@ -446,7 +453,7 @@ if ($resql) {
// Supplier // Supplier
$e .= '<a class="editfielda" title="'.$langs->trans("Supplier").'" href="'.DOL_URL_ROOT.'/societe/card.php?action=edit&token='.newToken().'&socid='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>'; $e .= '<a class="editfielda" title="'.$langs->trans("Supplier").'" href="'.DOL_URL_ROOT.'/societe/card.php?action=edit&token='.newToken().'&socid='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>';
} elseif ($obj->type == 3) { } elseif ($obj->type == 3) {
// User // User - Employee
$e .= '<a class="editfielda" title="'.$langs->trans("Employee").'" href="'.DOL_URL_ROOT.'/user/card.php?action=edit&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>'; $e .= '<a class="editfielda" title="'.$langs->trans("Employee").'" href="'.DOL_URL_ROOT.'/user/card.php?action=edit&token='.newToken().'&id='.$obj->rowid.'&backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.img_edit().'</a>';
} }
print $e; print $e;

View File

@ -1,7 +1,7 @@
<?php <?php
/* Copyright (C) 2016 Olivier Geffroy <jeff@jeffinfo.com> /* Copyright (C) 2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2016 Florian Henry <florian.henry@open-concept.pro> * Copyright (C) 2016 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2016-2022 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2016-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -24,6 +24,7 @@
* \brief Balance of book keeping * \brief Balance of book keeping
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
// Class // Class
@ -41,22 +42,13 @@ $langs->loadLangs(array("accountancy", "compta"));
$action = GETPOST('action', 'aZ09'); $action = GETPOST('action', 'aZ09');
$optioncss = GETPOST('optioncss', 'alpha'); $optioncss = GETPOST('optioncss', 'alpha');
$contextpage = GETPOST('contextpage', 'aZ09'); $type = GETPOST('type', 'alpha');
if ($type == 'sub') {
// Load variable for pagination $context_default = 'balancesubaccountlist';
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; } else {
$sortfield = GETPOST('sortfield', 'aZ09comma'); $context_default = 'balancelist';
$sortorder = GETPOST('sortorder', 'aZ09comma'); }
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int'); $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : $context_default;
if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
$page = 0;
} // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
$offset = $limit * $page;
$pageprev = $page - 1;
$pagenext = $page + 1;
//if (! $sortfield) $sortfield="p.date_fin";
//if (! $sortorder) $sortorder="DESC";
$show_subgroup = GETPOST('show_subgroup', 'alpha'); $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_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_date_end = dol_mktime(23, 59, 59, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
@ -69,10 +61,29 @@ $search_accountancy_code_end = GETPOST('search_accountancy_code_end', 'alpha');
if ($search_accountancy_code_end == - 1) { if ($search_accountancy_code_end == - 1) {
$search_accountancy_code_end = ''; $search_accountancy_code_end = '';
} }
$search_not_reconciled = GETPOST('search_not_reconciled', 'alpha');
// Load variable for pagination
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
$page = 0;
} // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
$offset = $limit * $page;
$pageprev = $page - 1;
$pagenext = $page + 1;
if ($sortorder == "") {
$sortorder = "ASC";
}
if ($sortfield == "") {
$sortfield = "t.numero_compte";
}
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$object = new BookKeeping($db); $object = new BookKeeping($db);
$hookmanager->initHooks(array('balancelist')); // Note that conf->hooks_modules contains array $hookmanager->initHooks(array($contextpage)); // Note that conf->hooks_modules contains array
$formaccounting = new FormAccounting($db); $formaccounting = new FormAccounting($db);
$formother = new FormOther($db); $formother = new FormOther($db);
@ -83,6 +94,7 @@ if (empty($search_date_start) && !GETPOSTISSET('formfilteraction')) {
$sql .= " WHERE date_start < '".$db->idate(dol_now())."' AND date_end > '".$db->idate(dol_now())."'"; $sql .= " WHERE date_start < '".$db->idate(dol_now())."' AND date_end > '".$db->idate(dol_now())."'";
$sql .= $db->plimit(1); $sql .= $db->plimit(1);
$res = $db->query($sql); $res = $db->query($sql);
if ($res->num_rows > 0) { if ($res->num_rows > 0) {
$fiscalYear = $db->fetch_object($res); $fiscalYear = $db->fetch_object($res);
$search_date_start = strtotime($fiscalYear->date_start); $search_date_start = strtotime($fiscalYear->date_start);
@ -103,45 +115,6 @@ if (empty($search_date_start) && !GETPOSTISSET('formfilteraction')) {
$search_date_end = dol_get_last_day($year_end, $month_end); $search_date_end = dol_get_last_day($year_end, $month_end);
} }
} }
if ($sortorder == "") {
$sortorder = "ASC";
}
if ($sortfield == "") {
$sortfield = "t.numero_compte";
}
$param = '';
if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
$param .= '&contextpage='.urlencode($contextpage);
}
if ($limit > 0 && $limit != $conf->liste_limit) {
$param .= '&limit='.urlencode($limit);
}
$filter = array();
if (!empty($search_date_start)) {
$filter['t.doc_date>='] = $search_date_start;
$param .= '&date_startmonth='.GETPOST('date_startmonth', 'int').'&date_startday='.GETPOST('date_startday', 'int').'&date_startyear='.GETPOST('date_startyear', 'int');
}
if (!empty($search_date_end)) {
$filter['t.doc_date<='] = $search_date_end;
$param .= '&date_endmonth='.GETPOST('date_endmonth', 'int').'&date_endday='.GETPOST('date_endday', 'int').'&date_endyear='.GETPOST('date_endyear', 'int');
}
if (!empty($search_accountancy_code_start)) {
$filter['t.numero_compte>='] = $search_accountancy_code_start;
$param .= '&search_accountancy_code_start='.urlencode($search_accountancy_code_start);
}
if (!empty($search_accountancy_code_end)) {
$filter['t.numero_compte<='] = $search_accountancy_code_end;
$param .= '&search_accountancy_code_end='.urlencode($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 (!isModEnabled('accounting')) { if (!isModEnabled('accounting')) {
accessforbidden(); accessforbidden();
@ -149,18 +122,17 @@ if (!isModEnabled('accounting')) {
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->mouvements->lire)) { if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
accessforbidden(); accessforbidden();
} }
/* /*
* Action * Action
*/ */
$parameters = array(); $param = '';
$arrayfields = array();
$parameters = array('socid'=>$socid);
$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 modified by some hooks
if ($reshook < 0) { if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
@ -171,16 +143,67 @@ if (empty($reshook)) {
$show_subgroup = ''; $show_subgroup = '';
$search_date_start = ''; $search_date_start = '';
$search_date_end = ''; $search_date_end = '';
$search_date_startyear = '';
$search_date_startmonth = '';
$search_date_startday = '';
$search_date_endyear = '';
$search_date_endmonth = '';
$search_date_endday = '';
$search_accountancy_code_start = ''; $search_accountancy_code_start = '';
$search_accountancy_code_end = ''; $search_accountancy_code_end = '';
$search_not_reconciled = '';
$search_ledger_code = array(); $search_ledger_code = array();
$filter = array(); $filter = array();
} }
// Must be after the remove filter action, before the export.
$filter = array();
if (!empty($search_date_start)) {
$filter['t.doc_date>='] = $search_date_start;
$param .= '&amp;date_startmonth=' . GETPOST('date_startmonth', 'int') . '&amp;date_startday=' . GETPOST('date_startday', 'int') . '&amp;date_startyear=' . GETPOST('date_startyear', 'int');
}
if (!empty($search_date_end)) {
$filter['t.doc_date<='] = $search_date_end;
$param .= '&amp;date_endmonth=' . GETPOST('date_endmonth', 'int') . '&amp;date_endday=' . GETPOST('date_endday', 'int') . '&amp;date_endyear=' . GETPOST('date_endyear', 'int');
}
if (!empty($search_doc_date)) {
$filter['t.doc_date'] = $search_doc_date;
$param .= '&doc_datemonth=' . GETPOST('doc_datemonth', 'int') . '&doc_dateday=' . GETPOST('doc_dateday', 'int') . '&doc_dateyear=' . GETPOST('doc_dateyear', 'int');
}
if (!empty($search_accountancy_code_start)) {
if ($type == 'sub') {
$filter['t.subledger_account>='] = $search_accountancy_code_start;
} else {
$filter['t.numero_compte>='] = $search_accountancy_code_start;
}
$param .= '&amp;search_accountancy_code_start=' . urlencode($search_accountancy_code_start);
}
if (!empty($search_accountancy_code_end)) {
if ($type == 'sub') {
$filter['t.subledger_account<='] = $search_accountancy_code_end;
} else {
$filter['t.numero_compte<='] = $search_accountancy_code_end;
}
$param .= '&amp;search_accountancy_code_end=' . urlencode($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($search_not_reconciled)) {
$filter['t.reconciled_option'] = $search_not_reconciled;
$param .= '&search_not_reconciled='.urlencode($search_not_reconciled);
} }
/* // param with type of list
* View $url_param = substr($param, 1); // remove first "&"
*/ if (!empty($type)) {
$param = '&type=' . $type . $param;
}
}
if ($action == 'export_csv') { if ($action == 'export_csv') {
$sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV; $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
@ -189,14 +212,23 @@ if ($action == 'export_csv') {
$type_export = 'balance'; $type_export = 'balance';
include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php'; include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
if ($type == 'sub') {
$result = $object->fetchAllBalance($sortorder, $sortfield, $limit, 0, $filter, 'AND', 1);
} else {
$result = $object->fetchAllBalance($sortorder, $sortfield, $limit, 0, $filter); $result = $object->fetchAllBalance($sortorder, $sortfield, $limit, 0, $filter);
}
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} }
foreach ($object->lines as $line) { foreach ($object->lines as $line) {
if ($type == 'sub') {
print '"' . length_accounta($line->subledger_account) . '"' . $sep;
print '"' . $line->subledger_label . '"' . $sep;
} else {
print '"' . length_accountg($line->numero_compte) . '"' . $sep; print '"' . length_accountg($line->numero_compte) . '"' . $sep;
print '"' . $object->get_compte_desc($line->numero_compte) . '"' . $sep; print '"' . $object->get_compte_desc($line->numero_compte) . '"' . $sep;
}
print '"'.price($line->debit).'"'.$sep; print '"'.price($line->debit).'"'.$sep;
print '"'.price($line->credit).'"'.$sep; print '"'.price($line->credit).'"'.$sep;
print '"'.price($line->debit - $line->credit).'"'.$sep; print '"'.price($line->debit - $line->credit).'"'.$sep;
@ -206,8 +238,15 @@ if ($action == 'export_csv') {
exit; exit;
} }
/*
* View
*/
if ($type == 'sub') {
$title_page = $langs->trans("AccountBalanceSubAccount");
} else {
$title_page = $langs->trans("AccountBalance"); $title_page = $langs->trans("AccountBalance");
}
llxHeader('', $title_page); llxHeader('', $title_page);
@ -216,39 +255,52 @@ if ($action != 'export_csv') {
// List // List
$nbtotalofrecords = ''; $nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
if ($type == 'sub') {
$nbtotalofrecords = $object->fetchAllBalance($sortorder, $sortfield, 0, 0, $filter, 'AND', 1);
} else {
$nbtotalofrecords = $object->fetchAllBalance($sortorder, $sortfield, 0, 0, $filter); $nbtotalofrecords = $object->fetchAllBalance($sortorder, $sortfield, 0, 0, $filter);
}
if ($nbtotalofrecords < 0) { if ($nbtotalofrecords < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} }
} }
if ($type == 'sub') {
$result = $object->fetchAllBalance($sortorder, $sortfield, $limit, $offset, $filter, 'AND', 1);
} else {
$result = $object->fetchAllBalance($sortorder, $sortfield, $limit, $offset, $filter); $result = $object->fetchAllBalance($sortorder, $sortfield, $limit, $offset, $filter);
}
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} }
print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'; print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" id="action" value="list">';
if ($optioncss != '') { if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">'; print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
} }
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
print '<input type="hidden" name="action" id="action" value="list">'; print '<input type="hidden" name="type" value="'.$type.'">';
print '<input type="hidden" name="sortfield" value="'.$sortfield.'">'; print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">'; print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
print '<input type="hidden" name="page" value="'.$page.'">'; print '<input type="hidden" name="page" value="'.$page.'">';
$parameters = array(); $parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtonsList', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) { if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
} }
$button = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint; $newcardbutton = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint;
if (empty($reshook)) { if (empty($reshook)) {
$button .= '<input type="button" id="exportcsvbutton" name="exportcsvbutton" class="butAction" value="'.$langs->trans("Export").' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />'; $newcardbutton = '<input type="button" id="exportcsvbutton" name="exportcsvbutton" class="butAction" value="'.$langs->trans("Export").' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />';
print '<script type="text/javascript"> print '<script type="text/javascript">
jQuery(document).ready(function() { jQuery(document).ready(function() {
@ -261,12 +313,32 @@ if ($action != 'export_csv') {
}); });
}); });
</script>'; </script>';
if ($type == 'sub') {
$newcardbutton .= dolGetButtonTitle($langs->trans('AccountBalance')." - ".$langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT . '/accountancy/bookkeeping/balance.php?' . $url_param, '', 1, array('morecss' => 'marginleftonly'));
$newcardbutton .= dolGetButtonTitle($langs->trans('AccountBalance')." - ".$langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT . '/accountancy/bookkeeping/balance.php?type=sub&' . $url_param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
} else {
$newcardbutton .= dolGetButtonTitle($langs->trans('AccountBalance')." - ".$langs->trans('GroupByAccountAccounting'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT . '/accountancy/bookkeeping/balance.php?' . $url_param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
$newcardbutton .= dolGetButtonTitle($langs->trans('AccountBalance')." - ".$langs->trans('GroupBySubAccountAccounting'), '', 'fa fa-align-left vmirror paddingleft imgforviewmode', DOL_URL_ROOT . '/accountancy/bookkeeping/balance.php?type=sub&' . $url_param, '', 1, array('morecss' => 'marginleftonly'));
}
$newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?action=create');
}
if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
$param .= '&contextpage='.urlencode($contextpage);
}
if ($limit > 0 && $limit != $conf->liste_limit) {
$param .= '&limit='.urlencode($limit);
} }
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit); print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $result, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
$selectedfields = ''; $selectedfields = '';
// Warning to explain why list of record is not consistent with the other list view (missing a lot of lines)
if ($type == 'sub') {
print info_admin($langs->trans("WarningRecordWithoutSubledgerAreExcluded"));
}
$moreforfilter = ''; $moreforfilter = '';
$moreforfilter .= '<div class="divsearchfield">'; $moreforfilter .= '<div class="divsearchfield">';
@ -274,18 +346,38 @@ if ($action != 'export_csv') {
$moreforfilter .= $form->selectDate($search_date_start ? $search_date_start : -1, 'date_start', 0, 0, 1, '', 1, 0); $moreforfilter .= $form->selectDate($search_date_start ? $search_date_start : -1, 'date_start', 0, 0, 1, '', 1, 0);
$moreforfilter .= $langs->trans('DateEnd').': '; $moreforfilter .= $langs->trans('DateEnd').': ';
$moreforfilter .= $form->selectDate($search_date_end ? $search_date_end : -1, 'date_end', 0, 0, 1, '', 1, 0); $moreforfilter .= $form->selectDate($search_date_end ? $search_date_end : -1, 'date_end', 0, 0, 1, '', 1, 0);
$moreforfilter .= ' - ';
$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>';
$moreforfilter .= '<div class="divsearchfield">'; $moreforfilter .= '<div class="divsearchfield">';
$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 .= $langs->trans("Journal"); $moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans("Journals").': ';
$moreforfilter .= $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1); $moreforfilter .= $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1);
$moreforfilter .= '</div>';
$moreforfilter .= '</br>';
$moreforfilter .= '<div class="divsearchfield">';
// Accountancy account
$moreforfilter .= $langs->trans('AccountAccounting').': ';
if ($type == 'sub') {
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), 'maxwidth200');
} else {
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, 'maxwidth200', 'accounts');
}
$moreforfilter .= ' ';
if ($type == 'sub') {
$moreforfilter .= $formaccounting->select_auxaccount($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), 'maxwidth200');
} else {
$moreforfilter .= $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, 'maxwidth200', 'accounts');
}
$moreforfilter .= '</div>';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= '<label for="notreconciled">'.$langs->trans('NotReconciled').'</label>: ';
$moreforfilter .= '<input type="checkbox" name="search_not_reconciled" id="notreconciled" value="notreconciled"'.($search_not_reconciled == 'notreconciled' ? ' checked' : '').'>';
$moreforfilter .= '</div>'; $moreforfilter .= '</div>';
if (!empty($moreforfilter)) { if (!empty($moreforfilter)) {
@ -304,9 +396,6 @@ if ($action != 'export_csv') {
print '<tr class="liste_titre_filter">'; print '<tr class="liste_titre_filter">';
print '<td class="liste_titre" colspan="'.$colspan.'">'; print '<td class="liste_titre" colspan="'.$colspan.'">';
print $formaccounting->select_account($search_accountancy_code_start, 'search_accountancy_code_start', $langs->trans('From'), array(), 1, 1, '', 'accounts');
print ' ';
print $formaccounting->select_account($search_accountancy_code_end, 'search_accountancy_code_end', $langs->trans('to'), array(), 1, 1, '', 'accounts');
print '</td>'; print '</td>';
// Fields from hook // Fields from hook
@ -323,6 +412,10 @@ if ($action != 'export_csv') {
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder); print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder);
// TODO : Retrieve the type of third party: Customer / Supplier / Employee
//if ($type == 'sub') {
// print_liste_field_titre("Type", $_SERVER['PHP_SELF'], "t.type", "", $param, "", $sortfield, $sortorder);
//}
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) { if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print_liste_field_titre("OpeningBalance", $_SERVER['PHP_SELF'], "", $param, "", 'class="right"', $sortfield, $sortorder); print_liste_field_titre("OpeningBalance", $_SERVER['PHP_SELF'], "", $param, "", 'class="right"', $sortfield, $sortorder);
} }
@ -358,7 +451,7 @@ if ($action != 'export_csv') {
$sql .= " GROUP BY t.numero_compte"; $sql .= " GROUP BY t.numero_compte";
$resql = $db->query($sql); $resql = $db->query($sql);
$nrows = $db->num_rows($resql); $nrows = $resql->num_rows;
$opening_balances = array(); $opening_balances = array();
for ($i = 0; $i < $nrows; $i++) { for ($i = 0; $i < $nrows; $i++) {
$arr = $resql->fetch_array(); $arr = $resql->fetch_array();
@ -371,12 +464,14 @@ if ($action != 'export_csv') {
$accountingaccountstatic->id = 0; $accountingaccountstatic->id = 0;
$accountingaccountstatic->account_number = ''; $accountingaccountstatic->account_number = '';
if ($type != 'sub') {
$accountingaccountstatic->fetch(null, $line->numero_compte, true); $accountingaccountstatic->fetch(null, $line->numero_compte, true);
if (!empty($accountingaccountstatic->account_number)) { if (!empty($accountingaccountstatic->account_number)) {
$accounting_account = $accountingaccountstatic->getNomUrl(0, 1, 0, '', 0, -1, 0, 'accountcard'); $accounting_account = $accountingaccountstatic->getNomUrl(0, 1, 1);
} else { } else {
$accounting_account = length_accountg($line->numero_compte); $accounting_account = length_accountg($line->numero_compte);
} }
}
$link = ''; $link = '';
$total_debit += $line->debit; $total_debit += $line->debit;
@ -426,7 +521,7 @@ if ($action != 'export_csv') {
// Show first line of a break // Show first line of a break
print '<tr class="trforbreak">'; print '<tr class="trforbreak">';
print '<td colspan="'.($colspan+1).'" class="tdforbreak">'.$line->numero_compte.($root_account_description ? ' - '.$root_account_description : '').'</td>'; print '<td colspan="'.($colspan+1).'" style="font-weight:bold; border-bottom: 1pt solid black;">'.$line->numero_compte.($root_account_description ? ' - '.$root_account_description : '').'</td>';
print '</tr>'; print '</tr>';
$displayed_account = $root_account_number; $displayed_account = $root_account_number;
@ -437,12 +532,35 @@ if ($action != 'export_csv') {
} }
print '<tr class="oddeven">'; print '<tr class="oddeven">';
// Accounting account
if ($type == 'sub') {
print '<td>'.$line->subledger_account.' <span class="opacitymedium">('.$line->subledger_label.')</span></td>';
} else {
print '<td>'.$accounting_account.'</td>'; print '<td>'.$accounting_account.'</td>';
}
// Type
// TODO Retrieve the type of third party: Customer / Supplier / Employee
//if ($type == 'sub') {
// print '<td></td>';
//}
if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) { if (!empty($conf->global->ACCOUNTANCY_SHOW_OPENING_BALANCE)) {
print '<td class="right nowraponall amount">'.price(price2num($opening_balance, 'MT')).'</td>'; print '<td class="right nowraponall amount">'.price(price2num($opening_balance, 'MT')).'</td>';
} }
$urlzoom = ''; $urlzoom = '';
if ($type == 'sub') {
if ($line->subledger_account) {
$urlzoom = DOL_URL_ROOT . '/accountancy/bookkeeping/listbyaccount.php?type=sub&search_accountancy_code_start=' . urlencode($line->subledger_account) . '&search_accountancy_code_end=' . urlencode($line->subledger_account);
if (GETPOSTISSET('date_startmonth')) {
$urlzoom .= '&search_date_startmonth=' . GETPOST('date_startmonth', 'int') . '&search_date_startday=' . GETPOST('date_startday', 'int') . '&search_date_startyear=' . GETPOST('date_startyear', 'int');
}
if (GETPOSTISSET('date_endmonth')) {
$urlzoom .= '&search_date_endmonth=' . GETPOST('date_endmonth', 'int') . '&search_date_endday=' . GETPOST('date_endday', 'int') . '&search_date_endyear=' . GETPOST('date_endyear', 'int');
}
}
} else {
if ($line->numero_compte) { if ($line->numero_compte) {
$urlzoom = DOL_URL_ROOT . '/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start=' . urlencode($line->numero_compte) . '&search_accountancy_code_end=' . urlencode($line->numero_compte); $urlzoom = DOL_URL_ROOT . '/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start=' . urlencode($line->numero_compte) . '&search_accountancy_code_end=' . urlencode($line->numero_compte);
if (GETPOSTISSET('date_startmonth')) { if (GETPOSTISSET('date_startmonth')) {
@ -452,6 +570,7 @@ if ($action != 'export_csv') {
$urlzoom .= '&search_date_endmonth=' . GETPOST('date_endmonth', 'int') . '&search_date_endday=' . GETPOST('date_endday', 'int') . '&search_date_endyear=' . GETPOST('date_endyear', 'int'); $urlzoom .= '&search_date_endmonth=' . GETPOST('date_endmonth', 'int') . '&search_date_endday=' . GETPOST('date_endday', 'int') . '&search_date_endyear=' . GETPOST('date_endyear', 'int');
} }
} }
}
// Debit // Debit
print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->debit, 'MT')).'</a></td>'; print '<td class="right nowraponall amount"><a href="'.$urlzoom.'">'.price(price2num($line->debit, 'MT')).'</a></td>';
// Credit // Credit
@ -503,6 +622,10 @@ if ($action != 'export_csv') {
print "<td></td>\n"; print "<td></td>\n";
print '</tr>'; print '</tr>';
$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print "</table>"; print "</table>";
print '</form>'; print '</form>';
} }

View File

@ -4,6 +4,7 @@
* Copyright (C) 2013-2022 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2013-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2022 Waël Almoman <info@almoman.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,6 +26,7 @@
* \brief Page to show book-entry * \brief Page to show book-entry
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
@ -43,7 +45,7 @@ $cancel = GETPOST('cancel', 'aZ09');
$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
$id = GETPOST('id', 'int'); // id of record $id = GETPOST('id', 'int'); // id of record
$mode = GETPOST('mode', 'aZ09'); // '' or '_tmp' $mode = $mode = $action == 'create' ? "_tmp" : GETPOST('mode', 'aZ09'); // '' or '_tmp'
$piece_num = GETPOST("piece_num", 'int'); // id of transaction (several lines share the same transaction id) $piece_num = GETPOST("piece_num", 'int'); // id of transaction (several lines share the same transaction id)
$accountingaccount = new AccountingAccount($db); $accountingaccount = new AccountingAccount($db);
@ -53,10 +55,15 @@ $accountingaccount_number = GETPOST('accountingaccount_number', 'alphanohtml');
$accountingaccount->fetch(null, $accountingaccount_number, true); $accountingaccount->fetch(null, $accountingaccount_number, true);
$accountingaccount_label = $accountingaccount->label; $accountingaccount_label = $accountingaccount->label;
$journal_code = GETPOST('code_journal', 'alpha'); $journal_code = GETPOST('code_journal', 'alpha') ? GETPOST('code_journal', 'alpha') : "NULL";
$accountingjournal->fetch(null, $journal_code); $accountingjournal->fetch(null, $journal_code);
$journal_label = $accountingjournal->label; $journal_label = $accountingjournal->label;
$next_num_mvt = (int) GETPOST('next_num_mvt', 'alpha');
$doc_ref = (string) GETPOST('doc_ref', 'alpha');
$doc_date = (string) GETPOST('doc_date', 'alpha');
$doc_date = $doc_date = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$subledger_account = GETPOST('subledger_account', 'alphanohtml'); $subledger_account = GETPOST('subledger_account', 'alphanohtml');
if ($subledger_account == -1) { if ($subledger_account == -1) {
$subledger_account = null; $subledger_account = null;
@ -71,6 +78,10 @@ $save = GETPOST('save', 'alpha');
if (!empty($save)) { if (!empty($save)) {
$action = 'add'; $action = 'add';
} }
$valid = GETPOST('validate', 'alpha');
if (!empty($valid)) {
$action = 'valid';
}
$update = GETPOST('update', 'alpha'); $update = GETPOST('update', 'alpha');
if (!empty($update)) { if (!empty($update)) {
$action = 'confirm_update'; $action = 'confirm_update';
@ -85,7 +96,7 @@ if (!isModEnabled('accounting')) {
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->mouvements->lire)) { if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
accessforbidden(); accessforbidden();
} }
@ -155,15 +166,29 @@ if ($action == "confirm_update") {
} }
} }
} }
} elseif ($action == "add") { } elseif ($action == 'add' || $action == 'valid') {
$error = 0; $error = 0;
if ((floatval($debit) != 0.0) && (floatval($credit) != 0.0)) { if (array_sum($debit) != array_sum($credit)) {
$action = 'add';
}
foreach ($accountingaccount_number as $key => $value) {
$accountingaccount->fetch(null, $accountingaccount_number[$key], true);
$accountingaccount_label[$key] = $accountingaccount->label[$key];
// if one added row is empty remove it before continue
if ($key < 1 && (empty($accountingaccount_number[$key]) || $accountingaccount_number[$key] == '-1') || (floatval($debit[$key]) == 0.0) && (floatval($credit[$key]) == 0.0)) {
continue;
}
if ((floatval($debit[$key]) != 0.0) && (floatval($credit[$key]) != 0.0)) {
$error++; $error++;
setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors'); setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors');
$action = ''; $action = '';
} }
if (empty($accountingaccount_number) || $accountingaccount_number == '-1') {
if (empty($accountingaccount_number[$key]) || $accountingaccount_number[$key] == '-1') {
$error++; $error++;
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors'); setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors');
$action = ''; $action = '';
@ -171,48 +196,49 @@ if ($action == "confirm_update") {
if (!$error) { if (!$error) {
$object = new BookKeeping($db); $object = new BookKeeping($db);
$object->numero_compte = $accountingaccount_number[$key];
$object->numero_compte = $accountingaccount_number; $object->subledger_account = $subledger_account[$key];
$object->subledger_account = $subledger_account; $object->subledger_label = $subledger_label[$key];
$object->subledger_label = $subledger_label; $object->label_compte = $accountingaccount_label[$key];
$object->label_compte = $accountingaccount_label; $object->label_operation = $label_operation[$key];
$object->label_operation = $label_operation; $object->debit = price2num($debit[$key]);
$object->debit = $debit; $object->credit = price2num($credit[$key]);
$object->credit = $credit; $object->doc_date = $doc_date;
$object->doc_date = (string) GETPOST('doc_date', 'alpha');
$object->doc_type = (string) GETPOST('doc_type', 'alpha'); $object->doc_type = (string) GETPOST('doc_type', 'alpha');
$object->piece_num = $piece_num; $object->piece_num = $piece_num;
$object->doc_ref = (string) GETPOST('doc_ref', 'alpha'); $object->doc_ref = $doc_ref;
$object->code_journal = $journal_code; $object->code_journal = $journal_code;
$object->journal_label = $journal_label; $object->journal_label = $journal_label;
$object->fk_doc = GETPOSTINT('fk_doc'); $object->fk_doc = GETPOSTINT('fk_doc');
$object->fk_docdet = GETPOSTINT('fk_docdet'); $object->fk_docdet = GETPOSTINT('fk_docdet');
if (floatval($debit) != 0.0) { if (floatval($debit[$key]) != 0.0) {
$object->montant = $debit; // deprecated $object->montant = $object->debit; // deprecated
$object->amount = $debit; $object->amount = $object->debit;
$object->sens = 'D'; $object->sens = 'D';
} }
if (floatval($credit) != 0.0) { if (floatval($credit[$key]) != 0.0) {
$object->montant = $credit; // deprecated $object->montant = $object->credit; // deprecated
$object->amount = $credit; $object->amount = $object->credit;
$object->sens = 'C'; $object->sens = 'C';
} }
$result = $object->createStd($user, false, $mode); $result = $object->createStd($user, false, $mode);
if ($result < 0) { if ($result < 0) {
$error++;
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} else { }
}
}
if (empty($error)) {
if ($mode != '_tmp') { if ($mode != '_tmp') {
setEventMessages($langs->trans('RecordSaved'), null, 'mesgs'); setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
} }
$debit = 0; $debit = 0;
$credit = 0; $credit = 0;
$action = ''; $action = $action == 'add' ? '' : $action ; // stay in valid mode when not adding line
}
} }
} elseif ($action == "confirm_delete") { } elseif ($action == "confirm_delete") {
$object = new BookKeeping($db); $object = new BookKeeping($db);
@ -229,17 +255,28 @@ if ($action == "confirm_update") {
} }
} }
$action = ''; $action = '';
} elseif ($action == "confirm_create") { } elseif ($action == 'create') {
$error = 0; $error = 0;
$object = new BookKeeping($db); $object = new BookKeeping($db);
$next_num_mvt = !empty($next_num_mvt) ? $next_num_mvt : $object->getNextNumMvt('_tmp');
$doc_ref = !empty($doc_ref) ? $doc_ref : $next_num_mvt;
if (empty($doc_date)) {
$tmp_date = dol_getdate(dol_now());
$_POST['doc_dateday'] = $tmp_date['mday'];
$_POST['doc_datemonth'] = $tmp_date['mon'];
$_POST['doc_dateyear'] = $tmp_date['year'];
unset($tmp_date);
}
if (!$journal_code || $journal_code == '-1') { if (!$journal_code || $journal_code == '-1') {
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Journal")), null, 'errors'); setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Journal")), null, 'errors');
$action = 'create'; $action = 'create';
$error++; $error++;
} }
if (!GETPOST('doc_ref', 'alpha')) { if (empty($doc_ref)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Piece")), null, 'errors'); setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Piece")), null, 'errors');
$action = 'create'; $action = 'create';
$error++; $error++;
@ -251,8 +288,8 @@ if ($action == "confirm_update") {
$object->credit = 0; $object->credit = 0;
$object->doc_date = $date_start = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int')); $object->doc_date = $date_start = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
$object->doc_type = GETPOST('doc_type', 'alpha'); $object->doc_type = GETPOST('doc_type', 'alpha');
$object->piece_num = GETPOST('next_num_mvt', 'alpha'); $object->piece_num = $next_num_mvt;
$object->doc_ref = GETPOST('doc_ref', 'alpha'); $object->doc_ref = $doc_ref;
$object->code_journal = $journal_code; $object->code_journal = $journal_code;
$object->journal_label = $journal_label; $object->journal_label = $journal_label;
$object->fk_doc = 0; $object->fk_doc = 0;
@ -301,7 +338,7 @@ if ($action == 'setjournal') {
} }
if ($action == 'setdocref') { if ($action == 'setdocref') {
$refdoc = GETPOST('doc_ref', 'alpha'); $refdoc = $doc_ref;
$result = $object->updateByMvt($piece_num, 'doc_ref', $refdoc, $mode); $result = $object->updateByMvt($piece_num, 'doc_ref', $refdoc, $mode);
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
@ -332,7 +369,9 @@ if ($action == 'valid') {
$html = new Form($db); $html = new Form($db);
$formaccounting = new FormAccounting($db); $formaccounting = new FormAccounting($db);
llxHeader('', $langs->trans("CreateMvts")); $title = $langs->trans($mode =="_tmp" ? "CreateMvts": "UpdateMvts");
llxHeader('', $title);
// Confirmation to delete the command // Confirmation to delete the command
if ($action == 'delete') { if ($action == 'delete') {
@ -340,66 +379,7 @@ if ($action == 'delete') {
print $formconfirm; print $formconfirm;
} }
if ($action == 'create') {
print load_fiche_titre($langs->trans("CreateMvts"));
$object = new BookKeeping($db);
$next_num_mvt = $object->getNextNumMvt('_tmp');
if (empty($next_num_mvt)) {
dol_print_error('', 'Failed to get next piece number');
}
print '<form action="'.$_SERVER["PHP_SELF"].'" name="create_mvt" method="POST">';
if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
}
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="confirm_create">'."\n";
print '<input type="hidden" name="next_num_mvt" value="'.$next_num_mvt.'">'."\n";
print '<input type="hidden" name="mode" value="_tmp">'."\n";
print dol_get_fiche_head();
print '<table class="border centpercent">';
/*print '<tr>';
print '<td class="titlefieldcreate fieldrequired">' . $langs->trans("NumPiece") . '</td>';
print '<td>' . $next_num_mvt . '</td>';
print '</tr>';*/
print '<tr>';
print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("Docdate").'</td>';
print '<td>';
print $html->selectDate('', 'doc_date', '', '', '', "create_mvt", 1, 1);
print '</td>';
print '</tr>';
print '<tr>';
print '<td class="fieldrequired">'.$langs->trans("Codejournal").'</td>';
print '<td>'.$formaccounting->select_journal($journal_code, 'code_journal', 0, 0, 1, 1).'</td>';
print '</tr>';
print '<tr>';
print '<td class="fieldrequired">'.$langs->trans("Piece").'</td>';
print '<td><input type="text" class="minwidth200" name="doc_ref" value="'.GETPOST('doc_ref', 'alpha').'"></td>';
print '</tr>';
/*
print '<tr>';
print '<td>' . $langs->trans("Doctype") . '</td>';
print '<td><input type="text" class="minwidth200 name="doc_type" value=""/></td>';
print '</tr>';
*/
print '</table>';
print dol_get_fiche_end();
print $form->buttonsSaveCancel("Create");
print '</form>';
} else {
$object = new BookKeeping($db); $object = new BookKeeping($db);
$result = $object->fetchPerMvt($piece_num, $mode); $result = $object->fetchPerMvt($piece_num, $mode);
if ($result < 0) { if ($result < 0) {
@ -409,8 +389,11 @@ if ($action == 'create') {
if (!empty($object->piece_num)) { if (!empty($object->piece_num)) {
$backlink = '<a href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?restore_lastsearch_values=1">'.$langs->trans('BackToList').'</a>'; $backlink = '<a href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?restore_lastsearch_values=1">'.$langs->trans('BackToList').'</a>';
print load_fiche_titre($langs->trans("UpdateMvts"), $backlink); print load_fiche_titre($langs->trans($mode =="_tmp" ? "CreateMvts": "UpdateMvts"), $backlink);
print '<form action="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'" method="post">'; if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'" />';
}
$head = array(); $head = array();
$h = 0; $h = 0;
$head[$h][0] = $_SERVER['PHP_SELF'].'?piece_num='.$object->piece_num.($mode ? '&mode='.$mode : ''); $head[$h][0] = $_SERVER['PHP_SELF'].'?piece_num='.$object->piece_num.($mode ? '&mode='.$mode : '');
@ -428,93 +411,35 @@ if ($action == 'create') {
print '<div class="underbanner clearboth"></div>'; print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield" width="100%">'; print '<table class="border tableforfield" width="100%">';
// Account movement /*print '<tr>';
print '<td class="titlefieldcreate fieldrequired">' . $langs->trans("NumPiece") . '</td>';
print '<td>' . $next_num_mvt . '</td>';
print '</tr>';*/
print '<tr>'; print '<tr>';
print '<td class="titlefield">'.$langs->trans("NumMvts").'</td>'; print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("Docdate").'</td>';
print '<td>'.($mode == '_tmp' ? '<span class="opacitymedium" title="Id tmp '.$object->piece_num.'">'.$langs->trans("Draft").'</span>' : $object->piece_num).'</td>'; print '<td>';
print '</tr>'; print $html->selectDate($doc_date, 'doc_date', '', '', '', "create_mvt", 1, 1);
// Date
print '<tr><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('Docdate');
print '</td>';
if ($action != 'editdate') {
print '<td class="right"><a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=editdate&token='.newToken().'&piece_num='.urlencode($object->piece_num).'&mode='.urlencode($mode).'">'.img_edit($langs->transnoentitiesnoconv('SetDate'), 1).'</a></td>';
}
print '</tr></table>';
print '</td><td colspan="3">';
if ($action == 'editdate') {
print '<form name="setdate" action="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'" method="post">';
if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
}
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="setdate">';
print '<input type="hidden" name="mode" value="'.$mode.'">';
print $form->selectDate($object->doc_date ? $object->doc_date : - 1, 'doc_date', '', '', '', "setdate");
print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
print '</form>';
} else {
print $object->doc_date ? dol_print_date($object->doc_date, 'day') : '&nbsp;';
}
print '</td>'; print '</td>';
print '</tr>'; print '</tr>';
// Journal print '<tr>';
print '<tr><td>'; print '<td class="fieldrequired">'.$langs->trans("Codejournal").'</td>';
print '<table class="nobordernopadding" width="100%"><tr><td>'; print '<td>'.$formaccounting->select_journal($journal_code, 'code_journal', 0, 0, 1, 1).'</td>';
print $langs->trans('Codejournal');
print '</td>';
if ($action != 'editjournal') {
print '<td class="right"><a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=editjournal&token='.newToken().'&piece_num='.urlencode($object->piece_num).'&mode='.urlencode($mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a></td>';
}
print '</tr></table>';
print '</td><td>';
if ($action == 'editjournal') {
print '<form name="setjournal" action="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'" method="post">';
if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
}
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="setjournal">';
print '<input type="hidden" name="mode" value="'.$mode.'">';
print $formaccounting->select_journal($object->code_journal, 'code_journal', 0, 0, array(), 1, 1);
print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
print '</form>';
} else {
print $object->code_journal;
}
print '</td>';
print '</tr>'; print '</tr>';
// Ref document print '<tr>';
print '<tr><td>'; print '<td class="fieldrequired">'.$langs->trans("Piece").'</td>';
print '<table class="nobordernopadding" width="100%"><tr><td>'; print '<td><input type="text" class="minwidth200" name="doc_ref" value="'.$doc_ref.'" /></td>';
print $langs->trans('Piece');
print '</td>';
if ($action != 'editdocref') {
print '<td class="right"><a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=editdocref&token='.newToken().'&piece_num='.urlencode($object->piece_num).'&mode='.urlencode($mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).'</a></td>';
}
print '</tr></table>';
print '</td><td>';
if ($action == 'editdocref') {
print '<form name="setdocref" action="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'" method="post">';
if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
}
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="setdocref">';
print '<input type="hidden" name="mode" value="'.$mode.'">';
print '<input type="text" size="20" name="doc_ref" value="'.dol_escape_htmltag($object->doc_ref).'">';
print '<input type="submit" class="button button-edit" value="'.$langs->trans('Modify').'">';
print '</form>';
} else {
print $object->doc_ref;
}
print '</td>';
print '</tr>'; print '</tr>';
/*
print '<tr>';
print '<td>' . $langs->trans("Doctype") . '</td>';
print '<td><input type="text" class="minwidth200 name="doc_type" value="" /></td>';
print '</tr>';
*/
print '</table>'; print '</table>';
print '</div>'; print '</div>';
@ -558,7 +483,6 @@ if ($action == 'create') {
print '</td>'; print '</td>';
print '</tr>'; print '</tr>';
} }
// Validate // Validate
/* /*
print '<tr>'; print '<tr>';
@ -581,8 +505,7 @@ if ($action == 'create') {
/* /*
print '<tr>'; print '<tr>';
print '<td class="titlefield">' . $langs->trans("Control") . '</td>'; print '<td class="titlefield">' . $langs->trans("Control") . '</td>';
if ($object->doc_type == 'customer_invoice') if ($object->doc_type == 'customer_invoice') {
{
$sqlmid = 'SELECT rowid as ref'; $sqlmid = 'SELECT rowid as ref';
$sqlmid .= " FROM ".MAIN_DB_PREFIX."facture as fac"; $sqlmid .= " FROM ".MAIN_DB_PREFIX."facture as fac";
$sqlmid .= " WHERE fac.rowid=" . ((int) $object->fk_doc); $sqlmid .= " WHERE fac.rowid=" . ((int) $object->fk_doc);
@ -593,41 +516,37 @@ if ($action == 'create') {
$invoicestatic = new Facture($db); $invoicestatic = new Facture($db);
$invoicestatic->fetch($objmid->ref); $invoicestatic->fetch($objmid->ref);
$ref=$langs->trans("Invoice").' '.$invoicestatic->getNomUrl(1); $ref=$langs->trans("Invoice").' '.$invoicestatic->getNomUrl(1);
} else {
dol_print_error($db);
} }
else dol_print_error($db);
} }
print '<td>' . $ref .'</td>'; print '<td>' . $ref .'</td>';
print '</tr>'; print '</tr>';
*/ */
print "</table>\n"; print "</table>\n";
print '</div>';
print dol_get_fiche_end(); print dol_get_fiche_end();
print '<div style="clear:both"></div>'; print '<div class="clearboth"></div>';
print '<br>'; print '<br>';
$result = $object->fetchAllPerMvt($piece_num, $mode); // This load $object->linesmvt $result = $object->fetchAllPerMvt($piece_num, $mode); // This load $object->linesmvt
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} else { } else {
// List of movements
print load_fiche_titre($langs->trans("ListeMvts"), '', ''); print load_fiche_titre($langs->trans("ListeMvts"), '', '');
print '<form action="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'" method="post">';
if ($optioncss != '') { if ($optioncss != '') {
print '<input type="hidden" name="optioncss" value="'.$optioncss.'">'; print '<input type="hidden" name="optioncss" value="'.$optioncss.'" />';
} }
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="doc_date" value="'.$object->doc_date.'">'."\n"; print '<input type="hidden" name="token" value="'.newToken().'" />';
print '<input type="hidden" name="doc_type" value="'.$object->doc_type.'">'."\n"; print '<input type="hidden" name="doc_type" value="'.$object->doc_type.'" />'."\n";
print '<input type="hidden" name="doc_ref" value="'.$object->doc_ref.'">'."\n"; print '<input type="hidden" name="fk_doc" value="'.$object->fk_doc.'" />'."\n";
print '<input type="hidden" name="code_journal" value="'.$object->code_journal.'">'."\n"; print '<input type="hidden" name="fk_docdet" value="'.$object->fk_docdet.'" />'."\n";
print '<input type="hidden" name="fk_doc" value="'.$object->fk_doc.'">'."\n"; print '<input type="hidden" name="mode" value="'.$mode.'" />'."\n";
print '<input type="hidden" name="fk_docdet" value="'.$object->fk_docdet.'">'."\n";
print '<input type="hidden" name="mode" value="'.$mode.'">'."\n";
if (count($object->linesmvt) > 0) { if (count($object->linesmvt) > 0) {
print '<div class="div-table-responsive-no-min">'; print '<div class="div-table-responsive-no-min">';
@ -636,13 +555,32 @@ if ($action == 'create') {
$total_debit = 0; $total_debit = 0;
$total_credit = 0; $total_credit = 0;
// Don't show in tmp mode, inevitably empty
if ($mode != "_tmp") {
// Date document export
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 validation
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>';
}
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
print_liste_field_titre("AccountAccountingShort"); print_liste_field_titre("AccountAccountingShort");
print_liste_field_titre("SubledgerAccount"); print_liste_field_titre("SubledgerAccount");
print_liste_field_titre("LabelOperation"); print_liste_field_titre("LabelOperation");
print_liste_field_titre("Debit", "", "", "", "", 'class="right"'); print_liste_field_titre("AccountingDebit", "", "", "", "", 'class="right"');
print_liste_field_titre("Credit", "", "", "", "", 'class="right"'); print_liste_field_titre("AccountingCredit", "", "", "", "", 'class="right"');
if (empty($object->date_validation)) { if (empty($object->date_validation)) {
print_liste_field_titre("Action", "", "", "", "", 'width="60"', "", "", 'center '); print_liste_field_titre("Action", "", "", "", "", 'width="60"', "", "", 'center ');
} else { } else {
@ -651,17 +589,26 @@ if ($action == 'create') {
print "</tr>\n"; print "</tr>\n";
// Add an empty line if there is not yet // In _tmp mode the first line is empty so we remove it
if (!empty($object->linesmvt[0])) { if ($mode == "_tmp") {
$tmpline = $object->linesmvt[0]; array_shift($object->linesmvt);
if (!empty($tmpline->numero_compte)) { }
// Add an empty line at the end to be able to add transaction
$line = new BookKeepingLine();
$object->linesmvt[] = $line;
// Add a second line empty line if there is not yet
if (empty($object->linesmvt[1])) {
$line = new BookKeepingLine(); $line = new BookKeepingLine();
$object->linesmvt[] = $line; $object->linesmvt[] = $line;
} }
}
foreach ($object->linesmvt as $line) { $count_line = count($object->linesmvt);
print '<tr class="oddeven">'; $num_line = 0;
foreach ($object->linesmvt as $key => $line) {
$num_line++;
print '<tr class="oddeven" data-lineid="'.((int) $line->id).'">';
$total_debit += $line->debit; $total_debit += $line->debit;
$total_credit += $line->credit; $total_credit += $line->credit;
@ -678,23 +625,23 @@ if ($action == 'create') {
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); print $formaccounting->select_auxaccount((GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account), 'subledger_account', 1, 'maxwidth250', '', 'subledger_label');
} else { } else {
print '<input type="text" class="maxwidth150" name="subledger_account" value="'.(GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'">'; print '<input type="text" class="maxwidth150" name="subledger_account" value="'.(GETPOSTISSET("subledger_account") ? GETPOST("subledger_account", "alpha") : $line->subledger_account).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccount")).'" />';
} }
// Add also input for subledger label // Add also input for subledger label
print '<br><input type="text" class="maxwidth150" name="subledger_label" value="'.(GETPOSTISSET("subledger_label") ? GETPOST("subledger_label", "alpha") : $line->subledger_label).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccountLabel")).'">'; print '<br><input type="text" class="maxwidth150" name="subledger_label" value="'.(GETPOSTISSET("subledger_label") ? GETPOST("subledger_label", "alpha") : $line->subledger_label).'" placeholder="'.dol_escape_htmltag($langs->trans("SubledgerAccountLabel")).'" />';
print '</td>'; print '</td>';
print '<td><input type="text" class="minwidth200" name="label_operation" value="'.(GETPOSTISSET("label_operation") ? GETPOST("label_operation", "alpha") : $line->label_operation).'"></td>'; print '<td><input type="text" class="minwidth200" name="label_operation" value="'.(GETPOSTISSET("label_operation") ? GETPOST("label_operation", "alpha") : $line->label_operation).'" /></td>';
print '<td class="right"><input type="text" size="6" class="right" name="debit" value="'.(GETPOSTISSET("debit") ? GETPOST("debit", "alpha") : price($line->debit)).'"></td>'; print '<td class="right"><input type="text" size="6" class="right" name="debit" value="'.(GETPOSTISSET("debit") ? GETPOST("debit", "alpha") : price($line->debit)).'" /></td>';
print '<td class="right"><input type="text" size="6" class="right" name="credit" value="'.(GETPOSTISSET("credit") ? GETPOST("credit", "alpha") : price($line->credit)).'"></td>'; print '<td class="right"><input type="text" size="6" class="right" name="credit" value="'.(GETPOSTISSET("credit") ? GETPOST("credit", "alpha") : price($line->credit)).'" /></td>';
print '<td>'; print '<td>';
print '<input type="hidden" name="id" value="'.$line->id.'">'."\n"; print '<input type="hidden" name="id" value="'.$line->id.'" />'."\n";
print '<input type="submit" class="button" name="update" value="'.$langs->trans("Update").'">'; print '<input type="submit" class="button" name="update" value="'.$langs->trans("Update").'" />';
print '</td>'; print '</td>';
} elseif (empty($line->numero_compte) || (empty($line->debit) && empty($line->credit))) { } elseif (empty($line->numero_compte) || (empty($line->debit) && empty($line->credit))) {
if ($action == "" || $action == 'add') { if ($action == "" || $action == 'add') {
print '<!-- td columns in add mode -->'; print '<!-- td columns in add mode -->';
print '<td>'; print '<td>';
print $formaccounting->select_account('', 'accountingaccount_number', 1, array(), 1, 1, ''); print $formaccounting->select_account((is_array($accountingaccount_number) ? $accountingaccount_number[$key] : $accountingaccount_number ), 'accountingaccount_number['.$key.']', 1, array(), 1, 1, '');
print '</td>'; print '</td>';
print '<td>'; print '<td>';
// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because: // TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because:
@ -702,16 +649,21 @@ if ($action == 'create') {
// Also, it is not possible to use a value that is not in the list. // 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. // Also, the label is not automatically filled when a value is selected.
if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) { if (!empty($conf->global->ACCOUNTANCY_COMBO_FOR_AUX)) {
print $formaccounting->select_auxaccount('', 'subledger_account', 1, 'maxwidth250', '', 'subledger_label'); print $formaccounting->select_auxaccount((is_array($subledger_account) ? $subledger_account[$key] : $subledger_account ), 'subledger_account['.$key.']', 1, 'maxwidth250', '', 'subledger_label');
} else { } else {
print '<input type="text" class="maxwidth150" name="subledger_account" value="" placeholder="' . dol_escape_htmltag($langs->trans("SubledgerAccount")) . '">'; print '<input type="text" class="maxwidth150" name="subledger_account['.$key.']" value="' . (is_array($subledger_account) ? $subledger_account[$key] : $subledger_account ) . '" 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 '<br><input type="text" class="maxwidth150" name="subledger_label['.$key.']" value="' . (is_array($subledger_label) ? $subledger_label[$key] : $subledger_label ) . '" placeholder="' . dol_escape_htmltag($langs->trans("SubledgerAccountLabel")) . '" />';
print '</td>'; print '</td>';
print '<td><input type="text" class="minwidth200" name="label_operation" value="' . $label_operation . '"/></td>'; print '<td><input type="text" class="minwidth200" name="label_operation['.$key.']" value="' . (is_array($label_operation) ? $label_operation[$key] : $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="debit['.$key.']" value="' . (is_array($debit) ? $debit[$key] : $debit ) . '" /></td>';
print '<td class="right"><input type="text" size="6" class="right" name="credit" value=""/></td>'; print '<td class="right"><input type="text" size="6" class="right" name="credit['.$key.']" value="' . (is_array($credit) ? $credit[$key] : $credit ) . '" /></td>';
print '<td class="center"><input type="submit" class="button" name="save" value="' . $langs->trans("Add") . '"></td>'; // Add button should not appear twice
if ($num_line === $count_line) {
print '<td><input type="submit" class="button small" name="save" value="' . $langs->trans("Add") . '" /></td>';
} else {
print '<td class="right"></td>';
}
} }
} else { } else {
print '<!-- td columns in display mode -->'; print '<!-- td columns in display mode -->';
@ -729,8 +681,8 @@ if ($action == 'create') {
} }
print '</td>'; print '</td>';
print '<td>'.$line->label_operation.'</td>'; print '<td>'.$line->label_operation.'</td>';
print '<td class="right nowraponall amount">'.price($line->debit).'</td>'; print '<td class="right nowraponall amount">'.($line->debit != 0 ? price($line->debit) : '').'</td>';
print '<td class="right nowraponall amount">'.price($line->credit).'</td>'; print '<td class="right nowraponall amount">'.($line->credit != 0 ? price($line->credit) : '').'</td>';
print '<td class="center nowraponall">'; print '<td class="center nowraponall">';
if (empty($line->date_export) && empty($line->date_validation)) { if (empty($line->date_export) && empty($line->date_validation)) {
@ -777,9 +729,9 @@ if ($action == 'create') {
print '<br>'; print '<br>';
print '<div class="center">'; print '<div class="center">';
if ($total_debit == $total_credit) { if ($total_debit == $total_credit) {
print '<a class="button" href="'.$_SERVER["PHP_SELF"].'?piece_num='.$object->piece_num.'&action=valid">'.$langs->trans("ValidTransaction").'</a>'; print '<input type="submit" class="button" name="validate" value="' . $langs->trans("ValidTransaction") . '" />';
} else { } else {
print '<input type="submit" class="button" disabled="disabled" href="#" title="'.dol_escape_htmltag($langs->trans("MvtNotCorrectlyBalanced", $debit, $credit)).'" value="'.dol_escape_htmltag($langs->trans("ValidTransaction")).'">'; print '<input type="submit" class="button" disabled="disabled" href="#" title="'.dol_escape_htmltag($langs->trans("MvtNotCorrectlyBalanced", $debit, $credit)).'" value="'.dol_escape_htmltag($langs->trans("ValidTransaction")).'" />';
} }
print ' &nbsp; '; print ' &nbsp; ';
@ -794,7 +746,6 @@ if ($action == 'create') {
} else { } else {
print load_fiche_titre($langs->trans("NoRecords")); print load_fiche_titre($langs->trans("NoRecords"));
} }
}
print dol_get_fiche_end(); print dol_get_fiche_end();

View File

@ -2,8 +2,10 @@
/* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com> /* Copyright (C) 2013-2016 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro> * Copyright (C) 2013-2016 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2013-2022 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2013-2022 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2022 Lionel Vessiller <lvessiller@open-dsi.fr>
* Copyright (C) 2016-2017 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2016-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2022 Progiseize <a.bisotti@progiseize.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,6 +27,7 @@
* \brief List operation of book keeping * \brief List operation of book keeping
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
@ -101,7 +104,9 @@ if (GETPOST("button_export_file_x") || GETPOST("button_export_file.x") || GETPOS
$action = 'export_file'; $action = 'export_file';
} }
$search_accountancy_code = GETPOST("search_accountancy_code"); $search_account_category = GETPOST('search_account_category', 'int');
$search_accountancy_code = GETPOST("search_accountancy_code", 'alpha');
$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha'); $search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
if ($search_accountancy_code_start == - 1) { if ($search_accountancy_code_start == - 1) {
$search_accountancy_code_start = ''; $search_accountancy_code_start = '';
@ -154,7 +159,7 @@ $hookmanager->initHooks(array('bookkeepinglist'));
$formaccounting = new FormAccounting($db); $formaccounting = new FormAccounting($db);
$form = new Form($db); $form = new Form($db);
if (!in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && !GETPOSTISSET('begin') && !GETPOSTISSET('formfilteraction') && GETPOST('page', 'int') == '' && !GETPOST('noreset', 'int') && $user->rights->accounting->mouvements->export) { if (!in_array($action, array('export_file', 'delmouv', 'delmouvconfirm')) && !GETPOSTISSET('begin') && !GETPOSTISSET('formfilteraction') && GETPOST('page', 'int') == '' && !GETPOST('noreset', 'int') && $user->hasRight('accounting', 'mouvements', 'export')) {
if (empty($search_date_start) && empty($search_date_end) && !GETPOSTISSET('restore_lastsearch_values') && !GETPOST('search_accountancy_code_start')) { if (empty($search_date_start) && empty($search_date_end) && !GETPOSTISSET('restore_lastsearch_values') && !GETPOST('search_accountancy_code_start')) {
$query = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear "; $query = "SELECT date_start, date_end from ".MAIN_DB_PREFIX."accounting_fiscalyear ";
$query .= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."' limit 1"; $query .= " where date_start < '".$db->idate(dol_now())."' and date_end > '".$db->idate(dol_now())."' limit 1";
@ -191,8 +196,8 @@ $arrayfields = array(
't.numero_compte'=>array('label'=>$langs->trans("AccountAccountingShort"), 'checked'=>1), 't.numero_compte'=>array('label'=>$langs->trans("AccountAccountingShort"), 'checked'=>1),
't.subledger_account'=>array('label'=>$langs->trans("SubledgerAccount"), 'checked'=>1), 't.subledger_account'=>array('label'=>$langs->trans("SubledgerAccount"), 'checked'=>1),
't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1), 't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
't.debit'=>array('label'=>$langs->trans("Debit"), 'checked'=>1), 't.debit'=>array('label'=>$langs->trans("AccountingDebit"), 'checked'=>1),
't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1), 't.credit'=>array('label'=>$langs->trans("AccountingCredit"), 'checked'=>1),
't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1), 't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1),
't.date_creation'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0), 't.date_creation'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0),
't.tms'=>array('label'=>$langs->trans("DateModification"), 'checked'=>0), 't.tms'=>array('label'=>$langs->trans("DateModification"), 'checked'=>0),
@ -220,7 +225,7 @@ if (!isModEnabled('accounting')) {
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->mouvements->lire)) { if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
accessforbidden(); accessforbidden();
} }
@ -234,7 +239,7 @@ $param = '';
if (GETPOST('cancel', 'alpha')) { if (GETPOST('cancel', 'alpha')) {
$action = 'list'; $massaction = ''; $action = 'list'; $massaction = '';
} }
if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'preunlettering' && $massaction != 'predeletebookkeepingwriting') { if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'preunletteringauto' && $massaction != 'preunletteringmanual' && $massaction != 'predeletebookkeepingwriting') {
$massaction = ''; $massaction = '';
} }
@ -252,6 +257,7 @@ if (empty($reshook)) {
$search_doc_type = ''; $search_doc_type = '';
$search_doc_ref = ''; $search_doc_ref = '';
$search_doc_date = ''; $search_doc_date = '';
$search_account_category = '';
$search_accountancy_code = ''; $search_accountancy_code = '';
$search_accountancy_code_start = ''; $search_accountancy_code_start = '';
$search_accountancy_code_end = ''; $search_accountancy_code_end = '';
@ -334,6 +340,20 @@ if (empty($reshook)) {
$filter['t.doc_ref'] = $search_doc_ref; $filter['t.doc_ref'] = $search_doc_ref;
$param .= '&search_doc_ref='.urlencode($search_doc_ref); $param .= '&search_doc_ref='.urlencode($search_doc_ref);
} }
if ($search_account_category != '-1' && !empty($search_account_category)) {
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancycategory.class.php';
$accountingcategory = new AccountancyCategory($db);
$listofaccountsforgroup = $accountingcategory->getCptsCat(0, 'fk_accounting_category = '.((int) $search_account_category));
$listofaccountsforgroup2 = array();
if (is_array($listofaccountsforgroup)) {
foreach ($listofaccountsforgroup as $tmpval) {
$listofaccountsforgroup2[] = "'".$db->escape($tmpval['id'])."'";
}
}
$filter['t.search_accounting_code_in'] = join(',', $listofaccountsforgroup2);
$param .= '&search_account_category='.urlencode($search_account_category);
}
if (!empty($search_accountancy_code)) { if (!empty($search_accountancy_code)) {
$filter['t.numero_compte'] = $search_accountancy_code; $filter['t.numero_compte'] = $search_accountancy_code;
$param .= '&search_accountancy_code='.urlencode($search_accountancy_code); $param .= '&search_accountancy_code='.urlencode($search_accountancy_code);
@ -437,7 +457,7 @@ if (empty($reshook)) {
$param .= '&search_import_key='.urlencode($search_import_key); $param .= '&search_import_key='.urlencode($search_import_key);
} }
//if ($action == 'delbookkeepingyearconfirm' && $user->rights->accounting->mouvements->supprimer_tous) { //if ($action == 'delbookkeepingyearconfirm' && !$user->hasRight('accounting', 'mouvements', 'supprimer_tous')) {
// $delmonth = GETPOST('delmonth', 'int'); // $delmonth = GETPOST('delmonth', 'int');
// $delyear = GETPOST('delyear', 'int'); // $delyear = GETPOST('delyear', 'int');
// if ($delyear == -1) { // if ($delyear == -1) {
@ -473,7 +493,7 @@ if (empty($reshook)) {
if ($conf->global->ACCOUNTING_REEXPORT == 1) { if ($conf->global->ACCOUNTING_REEXPORT == 1) {
setEventMessages($langs->trans("ExportOfPiecesAlreadyExportedIsEnable"), null, 'mesgs'); setEventMessages($langs->trans("ExportOfPiecesAlreadyExportedIsEnable"), null, 'mesgs');
} else { } else {
setEventMessages($langs->trans("ExportOfPiecesAlreadyExportedIsDisable"), null, 'mesgs'); setEventMessages($langs->trans("ExportOfPiecesAlreadyExportedIsDisable"), null, 'warnings');
} }
} else { } else {
setEventMessages($langs->trans("Error"), null, 'errors'); setEventMessages($langs->trans("Error"), null, 'errors');
@ -483,14 +503,26 @@ if (empty($reshook)) {
// Mass actions // Mass actions
$objectclass = 'Bookkeeping'; $objectclass = 'Bookkeeping';
$objectlabel = 'Bookkeeping'; $objectlabel = 'Bookkeeping';
$permissiontoread = $user->rights->societe->lire; $permissiontoread = $user->hasRight('societe', 'lire');
$permissiontodelete = $user->rights->societe->supprimer; $permissiontodelete = $user->hasRight('societe', 'supprimer');
$permissiontoadd = $user->rights->societe->creer; $permissiontoadd = $user->hasRight('societe', 'creer');
$uploaddir = $conf->societe->dir_output; $uploaddir = $conf->societe->dir_output;
include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
if (!$error && $action == 'deletebookkeepingwriting' && $confirm == "yes" && $user->rights->accounting->mouvements->supprimer) { if (!$error && $action == 'deletebookkeepingwriting' && $confirm == "yes" && $user->hasRight('accounting', 'mouvements', 'supprimer')) {
$db->begin();
if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING')) {
$lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true);
if ($nb_lettering < 0) {
setEventMessages('', $lettering->errors, 'errors');
$error++;
}
}
$nbok = 0; $nbok = 0;
if (!$error) {
foreach ($toselect as $toselectid) { foreach ($toselect as $toselectid) {
$result = $object->fetch($toselectid); $result = $object->fetch($toselectid);
if ($result > 0 && (!isset($object->date_validation) || $object->date_validation === '')) { if ($result > 0 && (!isset($object->date_validation) || $object->date_validation === '')) {
@ -508,25 +540,30 @@ if (empty($reshook)) {
break; break;
} }
} }
}
if (!$error) {
$db->commit();
// Message for elements well deleted // Message for elements well deleted
if ($nbok > 1) { if ($nbok > 1) {
setEventMessages($langs->trans("RecordsDeleted", $nbok), null, 'mesgs'); setEventMessages($langs->trans("RecordsDeleted", $nbok), null, 'mesgs');
} elseif ($nbok > 0) { } elseif ($nbok > 0) {
setEventMessages($langs->trans("RecordDeleted", $nbok), null, 'mesgs'); setEventMessages($langs->trans("RecordDeleted", $nbok), null, 'mesgs');
} elseif (!$error) { } else {
setEventMessages($langs->trans("NoRecordDeleted"), null, 'mesgs'); setEventMessages($langs->trans("NoRecordDeleted"), null, 'mesgs');
} }
if (!$error) {
header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : '')); header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : ''));
exit; exit;
} else {
$db->rollback();
} }
} }
// others mass actions // others mass actions
if (!$error && getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->rights->accounting->mouvements->creer) { if (!$error && getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->hasRight('accounting', 'mouvements', 'creer')) {
if ($massaction == 'lettering') { if ($massaction == 'letteringauto') {
$lettering = new Lettering($db); $lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect); $nb_lettering = $lettering->bookkeepingLetteringAll($toselect);
if ($nb_lettering < 0) { if ($nb_lettering < 0) {
@ -547,7 +584,17 @@ if (empty($reshook)) {
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param); header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit(); exit();
} }
} elseif ($action == 'unlettering' && $confirm == "yes") { } elseif ($massaction == 'letteringmanual') {
$lettering = new Lettering($db);
$result = $lettering->updateLettering($toselect);
if ($result < 0) {
setEventMessages('', $lettering->errors, 'errors');
} else {
setEventMessages($langs->trans('AccountancyOneLetteringModifiedSuccessfully'), array(), 'mesgs');
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit();
}
} elseif ($action == 'unletteringauto' && $confirm == "yes") {
$lettering = new Lettering($db); $lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true); $nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true);
if ($nb_lettering < 0) { if ($nb_lettering < 0) {
@ -568,6 +615,16 @@ if (empty($reshook)) {
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param); header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit(); exit();
} }
} elseif ($action == 'unletteringmanual' && $confirm == "yes") {
$lettering = new Lettering($db);
$nb_lettering = $lettering->deleteLettering($toselect);
if ($result < 0) {
setEventMessages('', $lettering->errors, 'errors');
} else {
setEventMessages($langs->trans('AccountancyOneUnletteringModifiedSuccessfully'), array(), 'mesgs');
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit();
}
} }
} }
} }
@ -604,6 +661,9 @@ $sql .= " t.tms as date_modification,";
$sql .= " t.date_export,"; $sql .= " t.date_export,";
$sql .= " t.date_validated as date_validation,"; $sql .= " t.date_validated as date_validation,";
$sql .= " t.import_key"; $sql .= " t.import_key";
$sqlfields = $sql; // $sql fields to remove for count total
$sql .= ' FROM '.MAIN_DB_PREFIX.$object->table_element.' as t'; $sql .= ' FROM '.MAIN_DB_PREFIX.$object->table_element.' as t';
// Manage filter // Manage filter
$sqlwhere = array(); $sqlwhere = array();
@ -634,7 +694,13 @@ if (count($filter) > 0) {
} elseif ($key == 't.reconciled_option') { } elseif ($key == 't.reconciled_option') {
$sqlwhere[] = 't.lettering_code IS NULL'; $sqlwhere[] = 't.lettering_code IS NULL';
} elseif ($key == 't.code_journal' && !empty($value)) { } elseif ($key == 't.code_journal' && !empty($value)) {
if (is_array($value)) {
$sqlwhere[] = natural_search("t.code_journal", join(',', $value), 3, 1); $sqlwhere[] = natural_search("t.code_journal", join(',', $value), 3, 1);
} else {
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
}
} elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
$sqlwhere[] = 't.numero_compte IN ('.$db->sanitize($value, 1).')';
} else { } else {
$sqlwhere[] = natural_search($key, $value, 0, 1); $sqlwhere[] = natural_search($key, $value, 0, 1);
} }
@ -647,36 +713,50 @@ if (empty($conf->global->ACCOUNTING_REEXPORT)) {
if (count($sqlwhere) > 0) { if (count($sqlwhere) > 0) {
$sql .= ' AND '.implode(' AND ', $sqlwhere); $sql .= ' AND '.implode(' AND ', $sqlwhere);
} }
if (!empty($sortfield)) {
$sql .= $db->order($sortfield, $sortorder);
}
//print $sql; //print $sql;
// Export into a file with format defined into setup (FEC, CSV, ...) // Export into a file with format defined into setup (FEC, CSV, ...)
// Must be after definition of $sql // Must be after definition of $sql
if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->export) { if ($action == 'export_fileconfirm' && $user->hasRight('accounting', 'mouvements', 'export')) {
// 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. // TODO Replace the fetchAll to get all ->line followed by call to ->export(). It currently consumes 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)); $result = $object->fetchAll($sortorder, $sortfield, 0, 0, $filter, 'AND', (empty($conf->global->ACCOUNTING_REEXPORT) ? 0 : 1));
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} else { } else {
// Export files // Export files then exit
$accountancyexport = new AccountancyExport($db); $accountancyexport = new AccountancyExport($db);
$accountancyexport->export($object->lines, $formatexportset);
$formatexport = GETPOST('formatexport', 'int');
$notexportlettering = GETPOST('notexportlettering', 'alpha');
if (!empty($notexportlettering)) {
if (is_array($object->lines)) {
foreach ($object->lines as $k => $movement) {
unset($object->lines[$k]->lettering_code);
unset($object->lines[$k]->date_lettering);
}
}
}
$notifiedexportdate = GETPOST('notifiedexportdate', 'alpha'); $notifiedexportdate = GETPOST('notifiedexportdate', 'alpha');
$notifiedvalidationdate = GETPOST('notifiedvalidationdate', 'alpha'); $notifiedvalidationdate = GETPOST('notifiedvalidationdate', 'alpha');
$withAttachment = !empty(trim(GETPOST('notifiedexportfull', 'alphanohtml'))) ? 1 : 0;
// Output data on screen or download
$result = $accountancyexport->export($object->lines, $formatexport, $withAttachment);
if (!empty($accountancyexport->errors)) {
setEventMessages('', $accountancyexport->errors, 'errors');
} elseif (!empty($notifiedexportdate) || !empty($notifiedvalidationdate)) {
// Specify as export : update field date_export or date_validated
$error = 0; $error = 0;
if ($result < 0) {
$error++;
} else {
if (!empty($notifiedexportdate) || !empty($notifiedvalidationdate)) {
if (is_array($object->lines)) {
// Specify as export : update field date_export or date_validated
$db->begin(); $db->begin();
if (is_array($object->lines)) {
foreach ($object->lines as $movement) { foreach ($object->lines as $movement) {
$now = dol_now(); $now = dol_now();
@ -700,18 +780,23 @@ if ($action == 'export_fileconfirm' && $user->rights->accounting->mouvements->ex
break; break;
} }
} }
}
if (!$error) { if (!$error) {
$db->commit(); $db->commit();
// setEventMessages($langs->trans("AllExportedMovementsWereRecordedAsExportedOrValidated"), null, 'mesgs');
} else { } else {
$error++; $error++;
$accountancyexport->errors[] = $langs->trans('NotAllExportedMovementsCouldBeRecordedAsExportedOrValidated');
$db->rollback(); $db->rollback();
setEventMessages($langs->trans("NotAllExportedMovementsCouldBeRecordedAsExportedOrValidated"), null, 'errors');
} }
} }
exit; }
}
if ($error) {
setEventMessages('', $accountancyexport->errors, 'errors');
header('Location: '.$_SERVER['PHP_SELF']);
}
exit(); // download or show errors
} }
} }
@ -728,18 +813,29 @@ $title_page = $langs->trans("Operations").' - '.$langs->trans("Journals");
// Count total nb of records // Count total nb of records
$nbtotalofrecords = ''; $nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
$resql = $db->query($sql); /* The fast and low memory method to get and count full list converts the sql into a sql count */
$nbtotalofrecords = $db->num_rows($resql); $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
$resql = $db->query($sqlforcount);
if ($resql) {
$objforcount = $db->fetch_object($resql);
$nbtotalofrecords = $objforcount->nbtotalofrecords;
} else {
dol_print_error($db);
}
if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
$page = 0; $page = 0;
$offset = 0; $offset = 0;
} }
$db->free($resql);
} }
// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set.
if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords) { // Complete request and execute it with limit
$num = $nbtotalofrecords; $sql .= $db->order($sortfield, $sortorder);
} else { if ($limit) {
$sql .= $db->plimit($limit + 1, $offset); $sql .= $db->plimit($limit + 1, $offset);
}
$resql = $db->query($sql); $resql = $db->query($sql);
if (!$resql) { if (!$resql) {
@ -748,7 +844,6 @@ if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords) {
} }
$num = $db->num_rows($resql); $num = $db->num_rows($resql);
}
$arrayofselected = is_array($toselect) ? $toselect : array(); $arrayofselected = is_array($toselect) ? $toselect : array();
@ -762,6 +857,30 @@ $formconfirm = '';
if ($action == 'export_file') { if ($action == 'export_file') {
$form_question = array(); $form_question = array();
$form_question['formatexport'] = array(
'name' => 'formatexport',
'type' => 'select',
'label' => $langs->trans('Modelcsv'), // TODO Use Selectmodelcsv and show a select combo
'values' => $listofformat,
'default' => $formatexportset,
'morecss' => 'minwidth200 maxwidth200'
);
$form_question['separator0'] = array('name'=>'separator0', 'type'=>'separator');
if (getDolGlobalInt("ACCOUNTING_ENABLE_LETTERING")) {
// If 1, we check by default.
$checked = !empty($conf->global->ACCOUNTING_DEFAULT_NOT_EXPORT_LETTERING) ? 'true' : 'false';
$form_question['notexportlettering'] = array(
'name' => 'notexportlettering',
'type' => 'checkbox',
'label' => $langs->trans('NotExportLettering'),
'value' => $checked,
);
$form_question['separator1'] = array('name'=>'separator1', 'type'=>'separator');
}
// If 1 or not set, we check by default. // If 1 or not set, we check by default.
$checked = (!isset($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) || !empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE)); $checked = (!isset($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) || !empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE));
$form_question['notifiedexportdate'] = array( $form_question['notifiedexportdate'] = array(
@ -771,7 +890,7 @@ if ($action == 'export_file') {
'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) ? 'false' : 'true'), 'value' => (!empty($conf->global->ACCOUNTING_DEFAULT_NOT_NOTIFIED_EXPORT_DATE) ? 'false' : 'true'),
); );
$form_question['separator'] = array('name'=>'separator', 'type'=>'separator'); $form_question['separator2'] = array('name'=>'separator2', 'type'=>'separator');
if (!getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) { if (!getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")) {
// If 0 or not set, we NOT check by default. // If 0 or not set, we NOT check by default.
@ -783,10 +902,20 @@ if ($action == 'export_file') {
'value' => $checked, 'value' => $checked,
); );
$form_question['separator2'] = array('name'=>'separator2', 'type'=>'separator'); $form_question['separator3'] = array('name'=>'separator3', 'type'=>'separator');
} }
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 300, 600); // add documents in an archive for accountancy export (Quadratus)
if (getDolGlobalString('ACCOUNTING_EXPORT_MODELCSV') == AccountancyExport::$EXPORT_TYPE_QUADRATUS) {
$form_question['notifiedexportfull'] = array(
'name' => 'notifiedexportfull',
'type' => 'checkbox',
'label' => $langs->trans('NotifiedExportFull'),
'value' => 'false',
);
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").'...', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 420, 600);
} }
//if ($action == 'delbookkeepingyear') { //if ($action == 'delbookkeepingyear') {
@ -843,16 +972,16 @@ if ($limit > 0 && $limit != $conf->liste_limit) {
// List of mass actions available // List of mass actions available
$arrayofmassactions = array(); $arrayofmassactions = array();
/*
if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->rights->accounting->mouvements->creer) { if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->rights->accounting->mouvements->creer) {
$arrayofmassactions['lettering'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('Lettering'); $arrayofmassactions['letteringauto'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('LetteringAuto');
$arrayofmassactions['preunlettering'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('Unlettering'); $arrayofmassactions['preunletteringauto'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('UnletteringAuto');
$arrayofmassactions['letteringmanual'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('LetteringManual');
$arrayofmassactions['preunletteringmanual'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('UnletteringManual');
} }
*/ if ($user->hasRight('accounting', 'mouvements', 'supprimer')) {
if ($user->rights->accounting->mouvements->supprimer) {
$arrayofmassactions['predeletebookkeepingwriting'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); $arrayofmassactions['predeletebookkeepingwriting'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
} }
if (GETPOST('nomassaction', 'int') || in_array($massaction, array('preunlettering', 'predeletebookkeepingwriting'))) { if (GETPOST('nomassaction', 'int') || in_array($massaction, array('preunletteringauto', 'preunletteringmanual', 'predeletebookkeepingwriting'))) {
$arrayofmassactions = array(); $arrayofmassactions = array();
} }
$massactionbutton = $form->selectMassAction($massaction, $arrayofmassactions); $massactionbutton = $form->selectMassAction($massaction, $arrayofmassactions);
@ -885,14 +1014,17 @@ $newcardbutton = empty($hookmanager->resPrint) ? '' : $hookmanager->resPrint;
if (empty($reshook)) { if (empty($reshook)) {
// Button re-export // Button re-export
if (!empty($conf->global->ACCOUNTING_REEXPORT)) { if (!empty($conf->global->ACCOUNTING_REEXPORT)) {
$newcardbutton .= '<a class="valignmiddle" href="'.$_SERVER['PHP_SELF'].'?action=setreexport&token='.newToken().'&value=0'.($param ? '&'.$param : '').'">'.img_picto($langs->trans("Activated"), 'switch_on').'</a> '; $newcardbutton .= '<a class="valignmiddle" href="'.$_SERVER['PHP_SELF'].'?action=setreexport&token='.newToken().'&value=0'.($param ? '&'.$param : '').'">'.img_picto($langs->trans("ClickToHideAlreadyExportedLines"), 'switch_off', 'class="small size15x valignmiddle"');
$newcardbutton .= '<span class="valignmiddle marginrightonly paddingleft">'.$langs->trans("ClickToHideAlreadyExportedLines").'</span>';
$newcardbutton .= '</a>';
} else { } else {
$newcardbutton .= '<a class="valignmiddle" href="'.$_SERVER['PHP_SELF'].'?action=setreexport&token='.newToken().'&value=1'.($param ? '&'.$param : '').'">'.img_picto($langs->trans("Disabled"), 'switch_off').'</a> '; $newcardbutton .= '<a class="valignmiddle" href="'.$_SERVER['PHP_SELF'].'?action=setreexport&token='.newToken().'&value=1'.($param ? '&'.$param : '').'">'.img_picto($langs->trans("DocsAlreadyExportedAreExcluded"), 'switch_on', 'class="warning size15x valignmiddle"');
$newcardbutton .= '<span class="valignmiddle marginrightonly paddingleft">'.$langs->trans("DocsAlreadyExportedAreExcluded").'</span>';
$newcardbutton .= '</a>';
} }
$newcardbutton .= '<span class="valignmiddle marginrightonly">'.$langs->trans("IncludeDocsAlreadyExported").'</span>';
if (!empty($user->rights->accounting->mouvements->export)) { if ($user->hasRight('accounting', 'mouvements', 'export')) {
$newcardbutton .= dolGetButtonTitle($buttonLabel, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', 'fa fa-file-export paddingleft', $_SERVER["PHP_SELF"].'?action=export_file'.($param ? '&'.$param : ''), $user->rights->accounting->mouvements->export); $newcardbutton .= dolGetButtonTitle($buttonLabel, $langs->trans("ExportFilteredList").' ('.$listofformat[$formatexportset].')', 'fa fa-file-export paddingleft', $_SERVER["PHP_SELF"].'?action=export_file&token='.newToken().($param ? '&'.$param : ''), $user->hasRight('accounting', 'mouvements', 'export'));
} }
$newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected')); $newcardbutton .= dolGetButtonTitle($langs->trans('ViewFlatList'), '', 'fa fa-list paddingleft imgforviewmode', DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?'.$param, '', 1, array('morecss' => 'marginleftonly btnTitleSelected'));
@ -903,13 +1035,15 @@ if (empty($reshook)) {
if (!empty($socid)) { if (!empty($socid)) {
$url .= '&socid='.$socid; $url .= '&socid='.$socid;
} }
$newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', $url, '', $user->rights->accounting->mouvements->creer); $newcardbutton .= dolGetButtonTitle($langs->trans('NewAccountingMvt'), '', 'fa fa-plus-circle paddingleft', $url, '', $user->hasRight('accounting', 'mouvements', 'creer'));
} }
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $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);
if ($massaction == 'preunlettering') { if ($massaction == 'preunletteringauto') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnlettering"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unlettering", null, '', 0, 200, 500, 1); print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnletteringAuto"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unletteringauto", null, '', 0, 200, 500, 1);
} elseif ($massaction == 'preunletteringmanual') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnletteringManual"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unletteringmanual", null, '', 0, 200, 500, 1);
} elseif ($massaction == 'predeletebookkeepingwriting') { } elseif ($massaction == 'predeletebookkeepingwriting') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDeleteBookkeepingWriting"), $langs->trans("ConfirmMassDeleteBookkeepingWritingQuestion", count($toselect)), "deletebookkeepingwriting", null, '', 0, 200, 500, 1); print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDeleteBookkeepingWriting"), $langs->trans("ConfirmMassDeleteBookkeepingWritingQuestion", count($toselect)), "deletebookkeepingwriting", null, '', 0, 200, 500, 1);
} }
@ -921,27 +1055,43 @@ if ($massaction == 'preunlettering') {
include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields
if ($massactionbutton && $contextpage != 'poslist') { if ($massactionbutton && $contextpage != 'poslist') {
$selectedfields .= $form->showCheckAddButtons('checkforselect', 1); $selectedfields .= $form->showCheckAddButtons('checkforselect', 1);
} }
$moreforfilter = ''; $moreforfilter = '';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans('AccountingCategory').': ';
$moreforfilter .= '<div class="nowrap inline-block">';
$moreforfilter .= $formaccounting->select_accounting_category($search_account_category, 'search_account_category', 1, 0, 0, 0);
$moreforfilter .= '</div>';
$moreforfilter .= '</div>';
$parameters = array(); $parameters = array();
$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) { if (empty($reshook)) {
$moreforfilter .= $hookmanager->resPrint; $moreforfilter .= $hookmanager->resPrint;
} else { } else {
$moreforfilter = $hookmanager->resPrint; $moreforfilter = $hookmanager->resPrint;
} }
print '<div class="liste_titre liste_titre_bydiv centpercent">';
print $moreforfilter;
print '</div>';
print '<div class="div-table-responsive">'; print '<div class="div-table-responsive">';
print '<table class="tagtable liste centpercent">'; print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">';
// Filters lines // Filters lines
print '<tr class="liste_titre_filter">'; print '<tr class="liste_titre_filter">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center">';
$searchpicto = $form->showFilterButtons('left');
print $searchpicto;
print '</td>';
}
// Movement number // Movement number
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
print '<td class="liste_titre"><input type="text" name="search_mvt_num" size="6" value="'.dol_escape_htmltag($search_mvt_num).'"></td>'; print '<td class="liste_titre"><input type="text" name="search_mvt_num" size="6" value="'.dol_escape_htmltag($search_mvt_num).'"></td>';
@ -949,7 +1099,7 @@ if (!empty($arrayfields['t.piece_num']['checked'])) {
// Code journal // Code journal
if (!empty($arrayfields['t.code_journal']['checked'])) { if (!empty($arrayfields['t.code_journal']['checked'])) {
print '<td class="liste_titre center">'; print '<td class="liste_titre center">';
print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1, 'small maxwidth150'); print $formaccounting->multi_select_journal($search_ledger_code, 'search_ledger_code', 0, 1, 1, 1, 'small maxwidth75');
print '</td>'; print '</td>';
} }
// Date document // Date document
@ -992,14 +1142,14 @@ if (!empty($arrayfields['t.subledger_account']['checked'])) {
print $formaccounting->select_auxaccount($search_accountancy_aux_code_end, 'search_accountancy_aux_code_end', $langs->trans('to'), 'maxwidth250', 'subledgeraccount'); print $formaccounting->select_auxaccount($search_accountancy_aux_code_end, 'search_accountancy_aux_code_end', $langs->trans('to'), 'maxwidth250', 'subledgeraccount');
print '</div>'; print '</div>';
} else { } else {
print '<input type="text" class="maxwidth75" name="search_accountancy_aux_code" value="'.$search_accountancy_aux_code.'">'; print '<input type="text" class="maxwidth75" name="search_accountancy_aux_code" value="'.dol_escape_htmltag($search_accountancy_aux_code).'">';
} }
print '</td>'; print '</td>';
} }
// Label operation // Label operation
if (!empty($arrayfields['t.label_operation']['checked'])) { if (!empty($arrayfields['t.label_operation']['checked'])) {
print '<td class="liste_titre">'; print '<td class="liste_titre">';
print '<input type="text" size="7" class="flat" name="search_mvt_label" value="'.$search_mvt_label.'"/>'; print '<input type="text" size="7" class="flat" name="search_mvt_label" value="'.dol_escape_htmltag($search_mvt_label).'"/>';
print '</td>'; print '</td>';
} }
// Debit // Debit
@ -1017,7 +1167,7 @@ if (!empty($arrayfields['t.credit']['checked'])) {
// Lettering code // Lettering code
if (!empty($arrayfields['t.lettering_code']['checked'])) { if (!empty($arrayfields['t.lettering_code']['checked'])) {
print '<td class="liste_titre center">'; print '<td class="liste_titre center">';
print '<input type="text" size="3" class="flat" name="search_lettering_code" value="'.$search_lettering_code.'"/>'; print '<input type="text" size="3" class="flat" name="search_lettering_code" value="'.dol_escape_htmltag($search_lettering_code).'"/>';
print '<br><span class="nowrap"><input type="checkbox" name="search_not_reconciled" value="notreconciled"'.($search_not_reconciled == 'notreconciled' ? ' checked' : '').'>'.$langs->trans("NotReconciled").'</span>'; print '<br><span class="nowrap"><input type="checkbox" name="search_not_reconciled" value="notreconciled"'.($search_not_reconciled == 'notreconciled' ? ' checked' : '').'>'.$langs->trans("NotReconciled").'</span>';
print '</td>'; print '</td>';
} }
@ -1077,13 +1227,17 @@ if (!empty($arrayfields['t.import_key']['checked'])) {
print '</td>'; print '</td>';
} }
// Action column // Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center">'; print '<td class="liste_titre center">';
$searchpicto = $form->showFilterButtons(); $searchpicto = $form->showFilterButtons();
print $searchpicto; print $searchpicto;
print '</td>'; print '</td>';
}
print "</tr>\n"; print "</tr>\n";
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch actioncolumn ');}
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, "", $sortfield, $sortorder); print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, "", $sortfield, $sortorder);
} }
@ -1125,15 +1279,17 @@ if (!empty($arrayfields['t.tms']['checked'])) {
print_liste_field_titre($arrayfields['t.tms']['label'], $_SERVER['PHP_SELF'], "t.tms", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre($arrayfields['t.tms']['label'], $_SERVER['PHP_SELF'], "t.tms", "", $param, '', $sortfield, $sortorder, 'center ');
} }
if (!empty($arrayfields['t.date_export']['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 '); print_liste_field_titre($arrayfields['t.date_export']['label'], $_SERVER['PHP_SELF'], "t.date_export,t.doc_date", "", $param, '', $sortfield, $sortorder, 'center ');
} }
if (!empty($arrayfields['t.date_validated']['checked'])) { 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($arrayfields['t.date_validated']['label'], $_SERVER['PHP_SELF'], "t.date_validated,t.doc_date", "", $param, '', $sortfield, $sortorder, 'center ');
} }
if (!empty($arrayfields['t.import_key']['checked'])) { if (!empty($arrayfields['t.import_key']['checked'])) {
print_liste_field_titre($arrayfields['t.import_key']['label'], $_SERVER["PHP_SELF"], "t.import_key", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre($arrayfields['t.import_key']['label'], $_SERVER["PHP_SELF"], "t.import_key", "", $param, '', $sortfield, $sortorder, 'center ');
} }
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
}
print "</tr>\n"; print "</tr>\n";
@ -1143,10 +1299,10 @@ $line = new BookKeepingLine();
// -------------------------------------------------------------------- // --------------------------------------------------------------------
$i = 0; $i = 0;
$totalarray = array(); $totalarray = array();
$totalarray['val'] = array ();
$totalarray['nbfield'] = 0; $totalarray['nbfield'] = 0;
$total_debit = 0; $total_debit = 0;
$total_credit = 0; $total_credit = 0;
$totalarray['val'] = array ();
$totalarray['val']['totaldebit'] = 0; $totalarray['val']['totaldebit'] = 0;
$totalarray['val']['totalcredit'] = 0; $totalarray['val']['totalcredit'] = 0;
@ -1188,6 +1344,18 @@ while ($i < min($num, $limit)) {
$total_credit += $line->credit; $total_credit += $line->credit;
print '<tr class="oddeven">'; print '<tr class="oddeven">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="nowraponall center">';
if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // 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($line->id, $arrayofselected)) {
$selected = 1;
}
print '<input id="cb'.$line->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$line->id.'"'.($selected ? ' checked="checked"' : '').' />';
}
print '</td>';
}
// Piece number // Piece number
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
@ -1206,7 +1374,7 @@ while ($i < min($num, $limit)) {
$accountingjournal = new AccountingJournal($db); $accountingjournal = new AccountingJournal($db);
$result = $accountingjournal->fetch('', $line->code_journal); $result = $accountingjournal->fetch('', $line->code_journal);
$journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $line->code_journal); $journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $line->code_journal);
print '<td class="center">'.$journaltoshow.'</td>'; print '<td class="center tdoverflowmax150">'.$journaltoshow.'</td>';
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
} }
@ -1392,6 +1560,7 @@ while ($i < min($num, $limit)) {
} }
// Action column // Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="nowraponall center">'; print '<td class="nowraponall center">';
if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
$selected = 0; $selected = 0;
@ -1401,6 +1570,7 @@ while ($i < min($num, $limit)) {
print '<input id="cb'.$line->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$line->id.'"'.($selected ? ' checked="checked"' : '').' />'; print '<input id="cb'.$line->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$line->id.'"'.($selected ? ' checked="checked"' : '').' />';
} }
print '</td>'; print '</td>';
}
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
@ -1414,6 +1584,20 @@ while ($i < min($num, $limit)) {
// Show total line // Show total line
include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
// If no record found
if ($num == 0) {
$colspan = 1;
foreach ($arrayfields as $key => $val) {
if (!empty($val['checked'])) {
$colspan++;
}
}
print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
}
$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print "</table>"; print "</table>";
print '</div>'; print '</div>';
@ -1429,4 +1613,5 @@ print '</form>';
// End of page // End of page
llxFooter(); llxFooter();
$db->close(); $db->close();

View File

@ -25,6 +25,7 @@
* \brief List operation of ledger ordered by account number * \brief List operation of ledger ordered by account number
*/ */
// Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
@ -78,7 +79,8 @@ $search_date_validation_start = dol_mktime(0, 0, 0, $search_date_validation_star
$search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear); $search_date_validation_end = dol_mktime(23, 59, 59, $search_date_validation_endmonth, $search_date_validation_endday, $search_date_validation_endyear);
$search_import_key = GETPOST("search_import_key", 'alpha'); $search_import_key = GETPOST("search_import_key", 'alpha');
$search_accountancy_code = GETPOST("search_accountancy_code"); $search_account_category = GETPOST('search_account_category', 'int');
$search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha'); $search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
if ($search_accountancy_code_start == - 1) { if ($search_accountancy_code_start == - 1) {
$search_accountancy_code_start = ''; $search_accountancy_code_start = '';
@ -162,8 +164,8 @@ $arrayfields = array(
't.doc_date'=>array('label'=>$langs->trans("Docdate"), 'checked'=>1), 't.doc_date'=>array('label'=>$langs->trans("Docdate"), 'checked'=>1),
't.doc_ref'=>array('label'=>$langs->trans("Piece"), 'checked'=>1), 't.doc_ref'=>array('label'=>$langs->trans("Piece"), 'checked'=>1),
't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1), 't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
't.debit'=>array('label'=>$langs->trans("Debit"), 'checked'=>1), 't.debit'=>array('label'=>$langs->trans("AccountingDebit"), 'checked'=>1),
't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1), 't.credit'=>array('label'=>$langs->trans("AccountingCredit"), 'checked'=>1),
't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1), 't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1),
't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1), 't.date_export'=>array('label'=>$langs->trans("DateExport"), 'checked'=>1),
't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1, 'enabled'=>!getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")), 't.date_validated'=>array('label'=>$langs->trans("DateValidation"), 'checked'=>1, 'enabled'=>!getDolGlobalString("ACCOUNTANCY_DISABLE_CLOSURE_LINE_BY_LINE")),
@ -193,10 +195,12 @@ if (!isModEnabled('accounting')) {
if ($user->socid > 0) { if ($user->socid > 0) {
accessforbidden(); accessforbidden();
} }
if (empty($user->rights->accounting->mouvements->lire)) { if (!$user->hasRight('accounting', 'mouvements', 'lire')) {
accessforbidden(); accessforbidden();
} }
$error = 0;
/* /*
* Action * Action
@ -208,7 +212,7 @@ if (GETPOST('cancel', 'alpha')) {
$action = 'list'; $action = 'list';
$massaction = ''; $massaction = '';
} }
if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'preunlettering' && $massaction != 'predeletebookkeepingwriting') { if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'preunletteringauto' && $massaction != 'preunletteringmanual' && $massaction != 'predeletebookkeepingwriting') {
$massaction = ''; $massaction = '';
} }
@ -223,7 +227,7 @@ 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 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
$search_doc_date = ''; $search_doc_date = '';
$search_accountancy_code = ''; $search_account_category = '';
$search_accountancy_code_start = ''; $search_accountancy_code_start = '';
$search_accountancy_code_end = ''; $search_accountancy_code_end = '';
$search_label_account = ''; $search_label_account = '';
@ -279,6 +283,20 @@ if (empty($reshook)) {
$filter['t.doc_date'] = $search_doc_date; $filter['t.doc_date'] = $search_doc_date;
$param .= '&doc_datemonth='.GETPOST('doc_datemonth', 'int').'&doc_dateday='.GETPOST('doc_dateday', 'int').'&doc_dateyear='.GETPOST('doc_dateyear', 'int'); $param .= '&doc_datemonth='.GETPOST('doc_datemonth', 'int').'&doc_dateday='.GETPOST('doc_dateday', 'int').'&doc_dateyear='.GETPOST('doc_dateyear', 'int');
} }
if ($search_account_category != '-1' && !empty($search_account_category)) {
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancycategory.class.php';
$accountingcategory = new AccountancyCategory($db);
$listofaccountsforgroup = $accountingcategory->getCptsCat(0, 'fk_accounting_category = '.((int) $search_account_category));
$listofaccountsforgroup2 = array();
if (is_array($listofaccountsforgroup)) {
foreach ($listofaccountsforgroup as $tmpval) {
$listofaccountsforgroup2[] = "'".$db->escape($tmpval['id'])."'";
}
}
$filter['t.search_accounting_code_in'] = join(',', $listofaccountsforgroup2);
$param .= '&search_account_category='.urlencode($search_account_category);
}
if (!empty($search_accountancy_code_start)) { if (!empty($search_accountancy_code_start)) {
if ($type == 'sub') { if ($type == 'sub') {
$filter['t.subledger_account>='] = $search_accountancy_code_start; $filter['t.subledger_account>='] = $search_accountancy_code_start;
@ -357,7 +375,6 @@ if (empty($reshook)) {
$filter['t.import_key'] = $search_import_key; $filter['t.import_key'] = $search_import_key;
$param .= '&search_import_key='.urlencode($search_import_key); $param .= '&search_import_key='.urlencode($search_import_key);
} }
// param with type of list // param with type of list
$url_param = substr($param, 1); // remove first "&" $url_param = substr($param, 1); // remove first "&"
if (!empty($type)) { if (!empty($type)) {
@ -394,14 +411,26 @@ if (empty($reshook)) {
// Mass actions // Mass actions
$objectclass = 'Bookkeeping'; $objectclass = 'Bookkeeping';
$objectlabel = 'Bookkeeping'; $objectlabel = 'Bookkeeping';
$permissiontoread = $user->rights->societe->lire; $permissiontoread = $user->hasRight('societe', 'lire');
$permissiontodelete = $user->rights->societe->supprimer; $permissiontodelete = $user->hasRight('societe', 'supprimer');
$permissiontoadd = $user->rights->societe->creer; $permissiontoadd = $user->hasRight('societe', 'creer');
$uploaddir = $conf->societe->dir_output; $uploaddir = $conf->societe->dir_output;
include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
if (!$error && $action == 'deletebookkeepingwriting' && $confirm == "yes" && $user->rights->accounting->mouvements->supprimer) { if (!$error && $action == 'deletebookkeepingwriting' && $confirm == "yes" && $user->hasRight('accounting', 'mouvements', 'supprimer')) {
$db->begin();
if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING')) {
$lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true);
if ($nb_lettering < 0) {
setEventMessages('', $lettering->errors, 'errors');
$error++;
}
}
$nbok = 0; $nbok = 0;
if (!$error) {
foreach ($toselect as $toselectid) { foreach ($toselect as $toselectid) {
$result = $object->fetch($toselectid); $result = $object->fetch($toselectid);
if ($result > 0 && (!isset($object->date_validation) || $object->date_validation === '')) { if ($result > 0 && (!isset($object->date_validation) || $object->date_validation === '')) {
@ -419,6 +448,10 @@ if (empty($reshook)) {
break; break;
} }
} }
}
if (!$error) {
$db->commit();
// Message for elements well deleted // Message for elements well deleted
if ($nbok > 1) { if ($nbok > 1) {
@ -429,15 +462,16 @@ if (empty($reshook)) {
setEventMessages($langs->trans("NoRecordDeleted"), null, 'mesgs'); setEventMessages($langs->trans("NoRecordDeleted"), null, 'mesgs');
} }
if (!$error) {
header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : '')); header("Location: ".$_SERVER["PHP_SELF"]."?noreset=1".($param ? '&'.$param : ''));
exit; exit;
} else {
$db->rollback();
} }
} }
// others mass actions // others mass actions
if (!$error && getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->rights->accounting->mouvements->creer) { if (!$error && getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->hasRight('accounting', 'mouvements', 'creer')) {
if ($massaction == 'lettering') { if ($massaction == 'letteringauto') {
$lettering = new Lettering($db); $lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect); $nb_lettering = $lettering->bookkeepingLetteringAll($toselect);
if ($nb_lettering < 0) { if ($nb_lettering < 0) {
@ -458,7 +492,17 @@ if (empty($reshook)) {
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param); header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit(); exit();
} }
} elseif ($action == 'unlettering' && $confirm == "yes") { } elseif ($massaction == 'letteringmanual') {
$lettering = new Lettering($db);
$result = $lettering->updateLettering($toselect);
if ($result < 0) {
setEventMessages('', $lettering->errors, 'errors');
} else {
setEventMessages($langs->trans('AccountancyOneLetteringModifiedSuccessfully'), array(), 'mesgs');
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit();
}
} elseif ($action == 'unletteringauto' && $confirm == "yes") {
$lettering = new Lettering($db); $lettering = new Lettering($db);
$nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true); $nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true);
if ($nb_lettering < 0) { if ($nb_lettering < 0) {
@ -479,6 +523,16 @@ if (empty($reshook)) {
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param); header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit(); exit();
} }
} elseif ($action == 'unletteringmanual' && $confirm == "yes") {
$lettering = new Lettering($db);
$nb_lettering = $lettering->deleteLettering($toselect);
if ($result < 0) {
setEventMessages('', $lettering->errors, 'errors');
} else {
setEventMessages($langs->trans('AccountancyOneUnletteringModifiedSuccessfully'), array(), 'mesgs');
header('Location: ' . $_SERVER['PHP_SELF'] . '?noreset=1' . $param);
exit();
}
} }
} }
} }
@ -506,26 +560,30 @@ llxHeader('', $title_page);
// List // List
$nbtotalofrecords = ''; $nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
// TODO Perf Replace this by a count
if ($type == 'sub') { if ($type == 'sub') {
$nbtotalofrecords = $object->fetchAllByAccount($sortorder, $sortfield, 0, 0, $filter, 'AND', 1); $nbtotalofrecords = $object->fetchAllByAccount($sortorder, $sortfield, 0, 0, $filter, 'AND', 1, 1);
} else { } else {
$nbtotalofrecords = $object->fetchAllByAccount($sortorder, $sortfield, 0, 0, $filter); $nbtotalofrecords = $object->fetchAllByAccount($sortorder, $sortfield, 0, 0, $filter, 'AND', 0, 1);
} }
if ($nbtotalofrecords < 0) { if ($nbtotalofrecords < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
$error++;
} }
} }
if (!$error) {
if ($type == 'sub') { if ($type == 'sub') {
$result = $object->fetchAllByAccount($sortorder, $sortfield, $limit, $offset, $filter, 'AND', 1); $result = $object->fetchAllByAccount($sortorder, $sortfield, $limit, $offset, $filter, 'AND', 1);
} else { } else {
$result = $object->fetchAllByAccount($sortorder, $sortfield, $limit, $offset, $filter); $result = $object->fetchAllByAccount($sortorder, $sortfield, $limit, $offset, $filter, 'AND', 0);
} }
if ($result < 0) { if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors'); setEventMessages($object->error, $object->errors, 'errors');
} }
}
$arrayofselected = is_array($toselect) ? $toselect : array(); $arrayofselected = is_array($toselect) ? $toselect : array();
@ -578,14 +636,16 @@ print $formconfirm;
// List of mass actions available // List of mass actions available
$arrayofmassactions = array(); $arrayofmassactions = array();
if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->rights->accounting->mouvements->creer) { if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING') && $user->hasRight('accounting', 'mouvements', 'creer')) {
$arrayofmassactions['lettering'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('Lettering'); $arrayofmassactions['letteringauto'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('LetteringAuto');
$arrayofmassactions['preunlettering'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('Unlettering'); $arrayofmassactions['preunletteringauto'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('UnletteringAuto');
$arrayofmassactions['letteringmanual'] = img_picto('', 'check', 'class="pictofixedwidth"') . $langs->trans('LetteringManual');
$arrayofmassactions['preunletteringmanual'] = img_picto('', 'uncheck', 'class="pictofixedwidth"') . $langs->trans('UnletteringManual');
} }
if ($user->rights->accounting->mouvements->supprimer) { if ($user->hasRight('accounting', 'mouvements', 'supprimer')) {
$arrayofmassactions['predeletebookkeepingwriting'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete"); $arrayofmassactions['predeletebookkeepingwriting'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
} }
if (GETPOST('nomassaction', 'int') || in_array($massaction, array('preunlettering', 'predeletebookkeepingwriting'))) { if (GETPOST('nomassaction', 'int') || in_array($massaction, array('preunletteringauto', 'preunletteringmanual', 'predeletebookkeepingwriting'))) {
$arrayofmassactions = array(); $arrayofmassactions = array();
} }
$massactionbutton = $form->selectMassAction($massaction, $arrayofmassactions); $massactionbutton = $form->selectMassAction($massaction, $arrayofmassactions);
@ -631,8 +691,10 @@ if ($limit > 0 && $limit != $conf->liste_limit) {
print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $result, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1); print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $result, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1);
if ($massaction == 'preunlettering') { if ($massaction == 'preunletteringauto') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnlettering"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unlettering", null, '', 0, 200, 500, 1); print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnletteringAuto"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unletteringauto", null, '', 0, 200, 500, 1);
} elseif ($massaction == 'preunletteringmanual') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassUnletteringManual"), $langs->trans("ConfirmMassUnletteringQuestion", count($toselect)), "unletteringmanual", null, '', 0, 200, 500, 1);
} elseif ($massaction == 'predeletebookkeepingwriting') { } elseif ($massaction == 'predeletebookkeepingwriting') {
print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDeleteBookkeepingWriting"), $langs->trans("ConfirmMassDeleteBookkeepingWritingQuestion", count($toselect)), "deletebookkeepingwriting", null, '', 0, 200, 500, 1); print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDeleteBookkeepingWriting"), $langs->trans("ConfirmMassDeleteBookkeepingWritingQuestion", count($toselect)), "deletebookkeepingwriting", null, '', 0, 200, 500, 1);
} }
@ -650,7 +712,7 @@ if ($massaction == 'preunlettering') {
include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields
if ($massactionbutton && $contextpage != 'poslist') { if ($massactionbutton && $contextpage != 'poslist') {
$selectedfields .= $form->showCheckAddButtons('checkforselect', 1); $selectedfields .= $form->showCheckAddButtons('checkforselect', 1);
} }
@ -669,7 +731,7 @@ if ($type == 'sub') {
$moreforfilter = ''; $moreforfilter = '';
// Accountancy account // Search on accountancy custom groups or account
$moreforfilter .= '<div class="divsearchfield">'; $moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans('AccountAccounting').': '; $moreforfilter .= $langs->trans('AccountAccounting').': ';
$moreforfilter .= '<div class="nowrap inline-block">'; $moreforfilter .= '<div class="nowrap inline-block">';
@ -687,6 +749,13 @@ if ($type == 'sub') {
$moreforfilter .= '</div>'; $moreforfilter .= '</div>';
$moreforfilter .= '</div>'; $moreforfilter .= '</div>';
$moreforfilter .= '<div class="divsearchfield">';
$moreforfilter .= $langs->trans('AccountingCategory').': ';
$moreforfilter .= '<div class="nowrap inline-block">';
$moreforfilter .= $formaccounting->select_accounting_category($search_account_category, 'search_account_category', 1, 0, 0, 0);
$moreforfilter .= '</div>';
$moreforfilter .= '</div>';
$parameters = array(); $parameters = array();
$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
if (empty($reshook)) { if (empty($reshook)) {
@ -704,15 +773,21 @@ print '<table class="tagtable liste centpercent">';
// Filters lines // Filters lines
print '<tr class="liste_titre_filter">'; print '<tr class="liste_titre_filter">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center">';
$searchpicto = $form->showFilterButtons('left');
print $searchpicto;
print '</td>';
}
// Movement number // Movement number
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
print '<td class="liste_titre"><input type="text" name="search_mvt_num" size="6" value="'.dol_escape_htmltag($search_mvt_num).'"></td>'; print '<td class="liste_titre"><input type="text" name="search_mvt_num" class="width50" value="'.dol_escape_htmltag($search_mvt_num).'"></td>';
} }
// Code journal // Code journal
if (!empty($arrayfields['t.code_journal']['checked'])) { if (!empty($arrayfields['t.code_journal']['checked'])) {
print '<td class="liste_titre center">'; 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, 'maxwidth75');
print '</td>'; print '</td>';
} }
// Date document // Date document
@ -783,15 +858,20 @@ $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // N
print $hookmanager->resPrint; print $hookmanager->resPrint;
// Action column // Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="liste_titre center">'; print '<td class="liste_titre center">';
$searchpicto = $form->showFilterButtons(); $searchpicto = $form->showFilterButtons();
print $searchpicto; print $searchpicto;
print '</td>'; print '</td>';
}
print "</tr>\n"; print "</tr>\n";
print '<tr class="liste_titre">'; print '<tr class="liste_titre">';
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
}
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, '', $sortfield, $sortorder); print_liste_field_titre($arrayfields['t.piece_num']['label'], $_SERVER['PHP_SELF'], "t.piece_num", "", $param, '', $sortfield, $sortorder, 'tdoverflowmax80imp ');
} }
if (!empty($arrayfields['t.code_journal']['checked'])) { if (!empty($arrayfields['t.code_journal']['checked'])) {
print_liste_field_titre($arrayfields['t.code_journal']['label'], $_SERVER['PHP_SELF'], "t.code_journal", "", $param, '', $sortfield, $sortorder, 'center '); print_liste_field_titre($arrayfields['t.code_journal']['label'], $_SERVER['PHP_SELF'], "t.code_journal", "", $param, '', $sortfield, $sortorder, 'center ');
@ -827,7 +907,9 @@ if (!empty($arrayfields['t.import_key']['checked'])) {
$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); $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 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint; print $hookmanager->resPrint;
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
}
print "</tr>\n"; print "</tr>\n";
$displayed_account_number = null; // Start with undefined to be able to distinguish with empty $displayed_account_number = null; // Start with undefined to be able to distinguish with empty
@ -880,8 +962,8 @@ while ($i < min($num, $limit)) {
} else { } else {
print '<td class="right" colspan="' . $colspan . '">' . $langs->trans("TotalForAccount") . ' ' . length_accountg($displayed_account_number) . ':</td>'; print '<td class="right" colspan="' . $colspan . '">' . $langs->trans("TotalForAccount") . ' ' . length_accountg($displayed_account_number) . ':</td>';
} }
print '<td class="nowrap right">'.price($sous_total_debit).'</td>'; print '<td class="nowrap right">'.price(price2num($sous_total_debit, 'MT')).'</td>';
print '<td class="nowrap right">'.price($sous_total_credit).'</td>'; print '<td class="nowrap right">'.price(price2num($sous_total_credit, 'MT')).'</td>';
print '<td colspan="'.$colspanend.'"></td>'; print '<td colspan="'.$colspanend.'"></td>';
print '</tr>'; print '</tr>';
// Show balance of last shown account // Show balance of last shown account
@ -890,13 +972,13 @@ while ($i < min($num, $limit)) {
print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>'; print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>';
if ($balance > 0) { if ($balance > 0) {
print '<td class="nowraponall right">'; print '<td class="nowraponall right">';
print price($sous_total_debit - $sous_total_credit); print price(price2num($sous_total_debit - $sous_total_credit, 'MT'));
print '</td>'; print '</td>';
print '<td></td>'; print '<td></td>';
} else { } else {
print '<td></td>'; print '<td></td>';
print '<td class="nowraponall right">'; print '<td class="nowraponall right">';
print price($sous_total_credit - $sous_total_debit); print price(price2num($sous_total_credit - $sous_total_debit, 'MT'));
print '</td>'; print '</td>';
} }
print '<td colspan="'.$colspanend.'"></td>'; print '<td colspan="'.$colspanend.'"></td>';
@ -940,7 +1022,18 @@ while ($i < min($num, $limit)) {
} }
print '<tr class="oddeven">'; print '<tr class="oddeven">';
// Action column
if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="nowraponall center">';
if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // 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($line->id, $arrayofselected)) {
$selected = 1;
}
print '<input id="cb' . $line->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $line->id . '"' . ($selected ? ' checked="checked"' : '') . ' />';
}
print '</td>';
}
// Piece number // Piece number
if (!empty($arrayfields['t.piece_num']['checked'])) { if (!empty($arrayfields['t.piece_num']['checked'])) {
print '<td>'; print '<td>';
@ -958,7 +1051,7 @@ while ($i < min($num, $limit)) {
$accountingjournal = new AccountingJournal($db); $accountingjournal = new AccountingJournal($db);
$result = $accountingjournal->fetch('', $line->code_journal); $result = $accountingjournal->fetch('', $line->code_journal);
$journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $line->code_journal); $journaltoshow = (($result > 0) ? $accountingjournal->getNomUrl(0, 0, 0, '', 0) : $line->code_journal);
print '<td class="center">'.$journaltoshow.'</td>'; print '<td class="center tdoverflowmax80">'.$journaltoshow.'</td>';
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
} }
@ -1054,7 +1147,7 @@ while ($i < min($num, $limit)) {
// Amount debit // Amount debit
if (!empty($arrayfields['t.debit']['checked'])) { if (!empty($arrayfields['t.debit']['checked'])) {
print '<td class="right nowraponall amount">'.($line->debit ? price($line->debit) : '').'</td>'; print '<td class="right nowraponall amount">'.($line->debit != 0 ? price($line->debit) : '').'</td>';
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
} }
@ -1066,7 +1159,7 @@ while ($i < min($num, $limit)) {
// Amount credit // Amount credit
if (!empty($arrayfields['t.credit']['checked'])) { if (!empty($arrayfields['t.credit']['checked'])) {
print '<td class="right nowraponall amount">'.($line->credit ? price($line->credit) : '').'</td>'; print '<td class="right nowraponall amount">'.($line->credit != 0 ? price($line->credit) : '').'</td>';
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
} }
@ -1113,6 +1206,7 @@ while ($i < min($num, $limit)) {
print $hookmanager->resPrint; print $hookmanager->resPrint;
// Action column // Action column
if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '<td class="nowraponall center">'; print '<td class="nowraponall center">';
if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined if (($massactionbutton || $massaction) && $contextpage != 'poslist') { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
$selected = 0; $selected = 0;
@ -1122,6 +1216,7 @@ while ($i < min($num, $limit)) {
print '<input id="cb' . $line->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $line->id . '"' . ($selected ? ' checked="checked"' : '') . ' />'; print '<input id="cb' . $line->id . '" class="flat checkforselect" type="checkbox" name="toselect[]" value="' . $line->id . '"' . ($selected ? ' checked="checked"' : '') . ' />';
} }
print '</td>'; print '</td>';
}
if (!$i) { if (!$i) {
$totalarray['nbfield']++; $totalarray['nbfield']++;
} }
@ -1138,8 +1233,8 @@ while ($i < min($num, $limit)) {
if ($num > 0 && $colspan > 0) { if ($num > 0 && $colspan > 0) {
print '<tr class="liste_total">'; print '<tr class="liste_total">';
print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.$accountg.':</td>'; print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("TotalForAccount").' '.$accountg.':</td>';
print '<td class="nowrap right">'.price($sous_total_debit).'</td>'; print '<td class="nowrap right">'.price(price2num($sous_total_debit, 'MT')).'</td>';
print '<td class="nowrap right">'.price($sous_total_credit).'</td>'; print '<td class="nowrap right">'.price(price2num($sous_total_credit, 'MT')).'</td>';
print '<td colspan="'.$colspanend.'"></td>'; print '<td colspan="'.$colspanend.'"></td>';
print '</tr>'; print '</tr>';
// Show balance of last shown account // Show balance of last shown account
@ -1148,22 +1243,46 @@ if ($num > 0 && $colspan > 0) {
print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>'; print '<td class="right" colspan="'.$colspan.'">'.$langs->trans("Balance").':</td>';
if ($balance > 0) { if ($balance > 0) {
print '<td class="nowraponall right">'; print '<td class="nowraponall right">';
print price($sous_total_debit - $sous_total_credit); print price(price2num($sous_total_debit - $sous_total_credit, 'MT'));
print '</td>'; print '</td>';
print '<td></td>'; print '<td></td>';
} else { } else {
print '<td></td>'; print '<td></td>';
print '<td class="nowraponall right">'; print '<td class="nowraponall right">';
print price($sous_total_credit - $sous_total_debit); print price(price2num($sous_total_credit - $sous_total_debit, 'MT'));
print '</td>'; print '</td>';
} }
print '<td colspan="'.$colspanend.'"></td>'; print '<td colspan="'.$colspanend.'"></td>';
print '</tr>'; print '</tr>';
} }
// Clean total values to round them
if (!empty($totalarray['val']['totaldebit'])) {
$totalarray['val']['totaldebit'] = price2num($totalarray['val']['totaldebit'], 'MT');
}
if (!empty($totalarray['val']['totalcredit'])) {
$totalarray['val']['totalcredit'] = price2num($totalarray['val']['totalcredit'], 'MT');
}
// Show total line // Show total line
include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
// If no record found
if ($num == 0) {
$colspan = 1;
foreach ($arrayfields as $key => $val) {
if (!empty($val['checked'])) {
$colspan++;
}
}
print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
}
$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
print $hookmanager->resPrint;
print "</table>"; print "</table>";
print '</div>'; print '</div>';

View File

@ -353,7 +353,7 @@ class AccountancyCategory // extends CommonObject
$sql .= " formula=".(isset($this->formula) ? "'".$this->db->escape($this->formula)."'" : "null").","; $sql .= " formula=".(isset($this->formula) ? "'".$this->db->escape($this->formula)."'" : "null").",";
$sql .= " position=".(isset($this->position) ? $this->position : "null").","; $sql .= " position=".(isset($this->position) ? $this->position : "null").",";
$sql .= " fk_country=".(isset($this->fk_country) ? $this->fk_country : "null").","; $sql .= " fk_country=".(isset($this->fk_country) ? $this->fk_country : "null").",";
$sql .= " active=".(isset($this->active) ? $this->active : "null").""; $sql .= " active=".(isset($this->active) ? $this->active : "null");
$sql .= " WHERE rowid=".((int) $this->id); $sql .= " WHERE rowid=".((int) $this->id);
$this->db->begin(); $this->db->begin();
@ -446,62 +446,12 @@ class AccountancyCategory // extends CommonObject
} else { } else {
$this->error = "Error ".$this->db->lasterror(); $this->error = "Error ".$this->db->lasterror();
$this->errors[] = $this->error; $this->errors[] = $this->error;
dol_syslog(__METHOD__." ".implode(','.$this->errors), LOG_ERR); dol_syslog(__METHOD__." ".implode(',', $this->errors), LOG_ERR);
return -1; return -1;
} }
} }
/**
* Function to fill ->lines_cptbk with accounting account used (into bookkeeping) and not yet into a custom group
*
* @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 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 ("; // 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 = ".((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 = ".((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();
dol_syslog(__METHOD__, LOG_DEBUG);
$resql = $this->db->query($sql);
if ($resql) {
$num = $this->db->num_rows($resql);
if ($num) {
while ($obj = $this->db->fetch_object($resql)) {
$this->lines_cptbk[] = $obj;
}
}
return $num;
} else {
$this->error = "Error ".$this->db->lasterror();
$this->errors[] = $this->error;
dol_syslog(__METHOD__." ".implode(','.$this->errors), LOG_ERR);
return -1;
}
}
*/
/** /**
* Function to fill ->lines_cptbk with accounting account (defined in chart of account) and not yet into a custom group * Function to fill ->lines_cptbk with accounting account (defined in chart of account) and not yet into a custom group
* *
@ -538,7 +488,7 @@ class AccountancyCategory // extends CommonObject
} else { } else {
$this->error = "Error ".$this->db->lasterror(); $this->error = "Error ".$this->db->lasterror();
$this->errors[] = $this->error; $this->errors[] = $this->error;
dol_syslog(__METHOD__." ".implode(','.$this->errors), LOG_ERR); dol_syslog(__METHOD__." ".implode(',', $this->errors), LOG_ERR);
return -1; return -1;
} }
@ -655,60 +605,6 @@ class AccountancyCategory // extends CommonObject
} }
} }
/**
* Function to know all custom groupd from an accounting account
*
* @return array|integer Result in table (array), -1 if KO
*/
public function getCatsCpts()
{
global $mysoc, $conf;
if (empty($mysoc->country_id)) {
dol_print_error('', 'Call to select_accounting_account with mysoc country not yet defined');
exit();
}
$sql = "SELECT t.rowid, t.account_number, t.label as account_label, cat.code, cat.position, cat.label as name_cat, cat.sens ";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as t, ".MAIN_DB_PREFIX."c_accounting_category as cat";
$sql .= " WHERE t.fk_accounting_category IN ( SELECT c.rowid ";
$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 = ".((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";
$resql = $this->db->query($sql);
if ($resql) {
$i = 0;
$obj = '';
$num = $this->db->num_rows($resql);
$data = array();
if ($num) {
while ($obj = $this->db->fetch_object($resql)) {
$name_cat = $obj->name_cat;
$data[$name_cat][$i] = array(
'id' => $obj->rowid,
'code' => $obj->code,
'position' => $obj->position,
'account_number' => $obj->account_number,
'account_label' => $obj->account_label,
'sens' => $obj->sens
);
$i++;
}
}
return $data;
} else {
$this->error = "Error ".$this->db->lasterror();
dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
return -1;
}
}
/** /**
* Function to show result of an accounting account from the ledger with a direction and a period * Function to show result of an accounting account from the ledger with a direction and a period
* *
@ -728,6 +624,22 @@ class AccountancyCategory // extends CommonObject
$this->sdc = 0; $this->sdc = 0;
$this->sdcpermonth = array(); $this->sdcpermonth = array();
if (is_array($cpt)) {
$listofaccount = '';
foreach ($cpt as $cptcursor) {
if (! is_null($cptcursor)) {
if ($listofaccount) {
$listofaccount .= ",";
}
$listofaccount .= "'".$cptcursor."'";
}
}
if (empty($listofaccount)) {
// List of account is empty, so we do no try sql request, we can say result is empty.
return 0;
}
}
$sql = "SELECT SUM(t.debit) as debit, SUM(t.credit) as credit"; $sql = "SELECT SUM(t.debit) as debit, SUM(t.credit) as credit";
if (is_array($cpt)) { if (is_array($cpt)) {
$sql .= ", t.numero_compte as accountancy_account"; $sql .= ", t.numero_compte as accountancy_account";
@ -736,14 +648,7 @@ class AccountancyCategory // extends CommonObject
//if (in_array($this->db->type, array('mysql', 'mysqli'))) $sql.=' USE INDEX idx_accounting_bookkeeping_doc_date'; //if (in_array($this->db->type, array('mysql', 'mysqli'))) $sql.=' USE INDEX idx_accounting_bookkeeping_doc_date';
$sql .= " WHERE t.entity = ".$conf->entity; $sql .= " WHERE t.entity = ".$conf->entity;
if (is_array($cpt)) { if (is_array($cpt)) {
$listofaccount = ''; $sql .= " AND t.numero_compte IN (".$this->db->sanitize($listofaccount, 1).")";
foreach ($cpt as $cptcursor) {
if ($listofaccount) {
$listofaccount .= ",";
}
$listofaccount .= "'".$cptcursor."'";
}
$sql .= " AND t.numero_compte IN (".$this->db->sanitize($listofaccount).")";
} else { } else {
$sql .= " AND t.numero_compte = '".$this->db->escape($cpt)."'"; $sql .= " AND t.numero_compte = '".$this->db->escape($cpt)."'";
} }
@ -759,13 +664,15 @@ class AccountancyCategory // extends CommonObject
if (is_array($cpt)) { if (is_array($cpt)) {
$sql .= " GROUP BY t.numero_compte"; $sql .= " GROUP BY t.numero_compte";
} }
//print $sql;
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if ($resql) { if ($resql) {
$num = $this->db->num_rows($resql); $num = $this->db->num_rows($resql);
if ($num) { if ($num) {
$i = 0;
while ($i < $num) {
$obj = $this->db->fetch_object($resql); $obj = $this->db->fetch_object($resql);
if ($obj) {
if ($sens == 1) { if ($sens == 1) {
$this->sdc = $obj->debit - $obj->credit; $this->sdc = $obj->debit - $obj->credit;
} else { } else {
@ -775,6 +682,10 @@ class AccountancyCategory // extends CommonObject
$this->sdcperaccount[$obj->accountancy_account] = $this->sdc; $this->sdcperaccount[$obj->accountancy_account] = $this->sdc;
} }
} }
$i++;
}
}
return $num; return $num;
} else { } else {
$this->error = "Error ".$this->db->lasterror(); $this->error = "Error ".$this->db->lasterror();
@ -784,12 +695,75 @@ class AccountancyCategory // extends CommonObject
} }
} }
/**
* Function to get an array of all active custom groups (llx_c_accunting_categories) with their accounts from the chart of account (ll_accounting_acount)
*
* @param int $catid Custom group ID
* @return array|integer Result in table (array), -1 if KO
* @see getCats(), getCptsCat()
*/
public function getCatsCpts($catid = 0)
{
global $mysoc, $conf;
if (empty($mysoc->country_id)) {
$this->error = "Error ".$this->db->lasterror();
dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
return -1;
}
$sql = "SELECT t.rowid, t.account_number, t.label as account_label,";
$sql .= " cat.code, cat.position, cat.label as name_cat, cat.sens, cat.category_type, cat.formula";
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as t, ".MAIN_DB_PREFIX."c_accounting_category as cat";
$sql .= " WHERE t.fk_accounting_category IN (SELECT c.rowid";
$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 = ".((int) $mysoc->country_id)." OR c.fk_country = 0)";
$sql .= " AND cat.rowid = t.fk_accounting_category";
$sql .= " AND t.entity = ".$conf->entity;
if ($catid > 0) {
$sql .= " AND cat.rowid = ".((int) $catid);
}
$sql .= " ORDER BY cat.position ASC";
$resql = $this->db->query($sql);
if ($resql) {
$obj = '';
$num = $this->db->num_rows($resql);
$data = array();
if ($num) {
while ($obj = $this->db->fetch_object($resql)) {
$name_cat = $obj->name_cat;
$data[$name_cat][$obj->rowid] = array(
'id' => $obj->rowid,
'code' => $obj->code,
'label' => $obj->label,
'position' => $obj->position,
'category_type' => $obj->category_type,
'formula' => $obj->formula,
'sens' => $obj->sens,
'account_number' => $obj->account_number,
'account_label' => $obj->account_label
);
}
}
return $data;
} else {
$this->error = "Error ".$this->db->lasterror();
dol_syslog(__METHOD__." ".$this->error, LOG_ERR);
return -1;
}
}
/** /**
* Return list of custom groups. * Return list of custom groups.
* For list + detail of accounting account, see getCatsCpt()
* *
* @param int $categorytype -1=All, 0=Only non computed groups, 1=Only computed groups * @param int $categorytype -1=All, 0=Only non computed groups, 1=Only computed groups
* @param int $active 1= active, 0=not active * @param int $active 1= active, 0=not active
* @return array|int Array of groups or -1 if error * @return array|int Array of groups or -1 if error
* @see getCatsCpts(), getCptsCat()
*/ */
public function getCats($categorytype = -1, $active = 1) public function getCats($categorytype = -1, $active = 1)
{ {
@ -824,9 +798,10 @@ class AccountancyCategory // extends CommonObject
'rowid' => $obj->rowid, 'rowid' => $obj->rowid,
'code' => $obj->code, 'code' => $obj->code,
'label' => $obj->label, 'label' => $obj->label,
'formula' => $obj->formula,
'position' => $obj->position, 'position' => $obj->position,
'category_type' => $obj->category_type, 'category_type' => $obj->category_type,
'formula' => $obj->formula,
'sens' => $obj->sens,
'bc' => $obj->sens 'bc' => $obj->sens
); );
$i++; $i++;
@ -844,12 +819,15 @@ class AccountancyCategory // extends CommonObject
/** /**
* Get all accounting account of a custom group (or a list of custom groups). * Get all accounting account of a given custom group (or a list of custom groups).
* You must choose between first parameter (personalized group) or the second (free criteria filter) * 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 int $cat_id Id if personalized accounting group/category
* @param string $predefinedgroupwhere Sql criteria filter to select accounting accounts. This value must not come from an input of a user. * @param string $predefinedgroupwhere Sql criteria filter to select accounting accounts. This value must be sanitized and not come from an input of a user.
* Example: "pcg_type = 'EXPENSE' AND fk_pcg_version = 'xx'"
* Example: "fk_accounting_category = 99"
* @return array|int Array of accounting accounts or -1 if error * @return array|int Array of accounting accounts or -1 if error
* @see getCats(), getCatsCpts()
*/ */
public function getCptsCat($cat_id, $predefinedgroupwhere = '') public function getCptsCat($cat_id, $predefinedgroupwhere = '')
{ {

View File

@ -6,12 +6,14 @@
* Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2016 Pierre-Henry Favre <phf@atm-consulting.fr> * Copyright (C) 2016 Pierre-Henry Favre <phf@atm-consulting.fr>
* Copyright (C) 2016-2023 Alexandre Spangaro <aspangaro@open-dsi.fr> * Copyright (C) 2016-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2022 Lionel Vessiller <lvessiller@open-dsi.fr>
* Copyright (C) 2013-2017 Olivier Geffroy <jeff@jeffinfo.com> * Copyright (C) 2013-2017 Olivier Geffroy <jeff@jeffinfo.com>
* Copyright (C) 2017 Elarifr. Ari Elbaz <github@accedinfo.com> * Copyright (C) 2017 Elarifr. Ari Elbaz <github@accedinfo.com>
* Copyright (C) 2017-2019 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2017-2019 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2017 André Schild <a.schild@aarboard.ch> * Copyright (C) 2017 André Schild <a.schild@aarboard.ch>
* Copyright (C) 2020 Guillaume Alexandre <guillaume@tag-info.fr> * Copyright (C) 2020 Guillaume Alexandre <guillaume@tag-info.fr>
* Copyright (C) 2022 Joachim Kueter <jkueter@gmx.de> * Copyright (C) 2022 Joachim Kueter <jkueter@gmx.de>
* Copyright (C) 2022 Progiseize <a.bisotti@progiseize.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -36,6 +38,7 @@
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
/** /**
@ -200,7 +203,7 @@ class AccountancyExport
'ACCOUNTING_EXPORT_FORMAT' => empty($conf->global->ACCOUNTING_EXPORT_FORMAT) ? 'txt' : $conf->global->ACCOUNTING_EXPORT_FORMAT, 'ACCOUNTING_EXPORT_FORMAT' => empty($conf->global->ACCOUNTING_EXPORT_FORMAT) ? 'txt' : $conf->global->ACCOUNTING_EXPORT_FORMAT,
'ACCOUNTING_EXPORT_SEPARATORCSV' => empty($conf->global->ACCOUNTING_EXPORT_SEPARATORCSV) ? ',' : $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV, 'ACCOUNTING_EXPORT_SEPARATORCSV' => empty($conf->global->ACCOUNTING_EXPORT_SEPARATORCSV) ? ',' : $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV,
'ACCOUNTING_EXPORT_ENDLINE' => empty($conf->global->ACCOUNTING_EXPORT_ENDLINE) ? 1 : $conf->global->ACCOUNTING_EXPORT_ENDLINE, 'ACCOUNTING_EXPORT_ENDLINE' => empty($conf->global->ACCOUNTING_EXPORT_ENDLINE) ? 1 : $conf->global->ACCOUNTING_EXPORT_ENDLINE,
'ACCOUNTING_EXPORT_DATE' => empty($conf->global->ACCOUNTING_EXPORT_DATE) ? '%d%m%Y' : $conf->global->ACCOUNTING_EXPORT_DATE, 'ACCOUNTING_EXPORT_DATE' => getDolGlobalString('ACCOUNTING_EXPORT_DATE', '%Y-%m-%d'),
), ),
self::$EXPORT_TYPE_CEGID => array( self::$EXPORT_TYPE_CEGID => array(
'label' => $langs->trans('Modelcsv_CEGID'), 'label' => $langs->trans('Modelcsv_CEGID'),
@ -286,14 +289,37 @@ class AccountancyExport
} }
/**
* Return the MIME type of a file
*
* @param int $formatexportset Id of export format
* @return string MIME type.
*/
public function getMimeType($formatexportset)
{
$mime = 'text/csv';
switch ($formatexportset) {
case self::$EXPORT_TYPE_FEC:
$mime = 'text/tab-separated-values';
break;
default:
$mime = 'text/csv';
break;
}
return $mime;
}
/** /**
* Function who chose which export to use with the default config, and make the export into a file * Function who chose which export to use with the default config, and make the export into a file
* *
* @param array $TData Array with data * @param array $TData Array with data
* @param int $formatexportset Id of export format * @param int $formatexportset Id of export format
* @return void * @param int $withAttachment [=0] Not add files or 1 to have attached in an archive (ex : Quadratus)
* @return int <0 if KO, >0 OK
*/ */
public function export(&$TData, $formatexportset) public function export(&$TData, $formatexportset, $withAttachment = 0)
{ {
global $conf, $langs; global $conf, $langs;
global $search_date_end; // Used into /accountancy/tpl/export_journal.tpl.php global $search_date_end; // Used into /accountancy/tpl/export_journal.tpl.php
@ -303,8 +329,44 @@ class AccountancyExport
$type_export = 'general_ledger'; $type_export = 'general_ledger';
global $db; // The tpl file use $db global $db; // The tpl file use $db
$completefilename = '';
$exportFile = null;
$exportFileName = '';
$exportFilePath = '';
$archiveFileList = array();
if ($withAttachment == 1) {
// PHP ZIP extension must be enabled
if (!extension_loaded('zip')) {
$langs->load('install');
$this->errors[] = $langs->trans('ErrorPHPDoesNotSupport', 'ZIP');
return -1;
}
} else {
$mimetype = $this->getMimeType($formatexportset);
top_httphead($mimetype, 1);
}
include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php'; include DOL_DOCUMENT_ROOT.'/accountancy/tpl/export_journal.tpl.php';
if ($withAttachment == 1 && !empty($completefilename)) {
// create export file
$tmpDir = !empty($conf->accounting->multidir_temp[$conf->entity]) ? $conf->accounting->multidir_temp[$conf->entity] : $conf->accounting->dir_temp;
$exportFileFullName = $completefilename;
$exportFileBaseName = basename($exportFileFullName);
$exportFileName = pathinfo($exportFileBaseName, PATHINFO_FILENAME);
$exportFilePath = $tmpDir.'/'.$exportFileFullName;
$exportFile = fopen($exportFilePath, 'w');
if (!$exportFile) {
$this->errors[] = $langs->trans('ErrorFileNotFound', $exportFilePath);
return -1;
}
$archiveFileList[0] = array(
'path' => $exportFilePath,
'name' => $exportFileFullName,
);
// archive name and path
$archiveFullName = $exportFileName.'.zip';
$archivePath = $tmpDir.'/'.$archiveFullName;
}
switch ($formatexportset) { switch ($formatexportset) {
case self::$EXPORT_TYPE_CONFIGURABLE: case self::$EXPORT_TYPE_CONFIGURABLE:
@ -323,7 +385,7 @@ class AccountancyExport
$this->exportCiel($TData); $this->exportCiel($TData);
break; break;
case self::$EXPORT_TYPE_QUADRATUS: case self::$EXPORT_TYPE_QUADRATUS:
$this->exportQuadratus($TData); $archiveFileList = $this->exportQuadratus($TData, $exportFile, $archiveFileList, $withAttachment);
break; break;
case self::$EXPORT_TYPE_WINFIC: case self::$EXPORT_TYPE_WINFIC:
$this->exportWinfic($TData); $this->exportWinfic($TData);
@ -377,6 +439,69 @@ class AccountancyExport
} }
break; break;
} }
// create and download export file or archive
if ($withAttachment == 1) {
$error = 0;
// close export file
if ($exportFile) {
fclose($exportFile);
}
if (!empty($archiveFullName) && !empty($archivePath) && !empty($archiveFileList)) {
// archive files
$downloadFileMimeType = 'application/zip';
$downloadFileFullName = $archiveFullName;
$downloadFilePath = $archivePath;
// create archive
$archive = new ZipArchive();
$res = $archive->open($archivePath, ZipArchive::OVERWRITE | ZipArchive::CREATE);
if ($res !== true) {
$error++;
$this->errors[] = $langs->trans('ErrorFileNotFound', $archivePath);
}
if (!$error) {
// add files
foreach ($archiveFileList as $archiveFileArr) {
$res = $archive->addFile($archiveFileArr['path'], $archiveFileArr['name']);
if (!$res) {
$error++;
$this->errors[] = $langs->trans('ErrorArchiveAddFile', $archiveFileArr['name']);
break;
}
}
}
if (!$error) {
// close archive
$archive->close();
}
} elseif (!empty($exportFileFullName) && !empty($exportFilePath)) {
// only one file to download
$downloadFileMimeType = 'text/csv';
$downloadFileFullName = $exportFileFullName;
$downloadFilePath = $exportFilePath;
}
if (!$error) {
// download export file
if (!empty($downloadFileMimeType) && !empty($downloadFileFullName) && !empty($downloadFilePath)) {
header('Content-Type: '.$downloadFileMimeType);
header('Content-Disposition: attachment; filename='.$downloadFileFullName);
header('Cache-Control: Public, must-revalidate');
header('Pragma: public');
header('Content-Length: '.dol_filesize($downloadFilePath));
readfileLowMemory($downloadFilePath);
}
}
if ($error) {
return -1;
}
}
return 1;
} }
@ -422,14 +547,14 @@ class AccountancyExport
print $date.$separator; print $date.$separator;
print $line->piece_num.$separator; print $line->piece_num.$separator;
print length_accountg($line->numero_compte).$separator; print length_accountg($line->numero_compte).$separator;
print ''.$separator; print $separator;
print $line->label_operation.$separator; print $line->label_operation.$separator;
print $date.$separator; print $date.$separator;
if ($line->sens == 'D') { if ($line->sens == 'D') {
print price($line->debit).$separator; print price($line->debit).$separator;
print ''.$separator; print $separator;
} elseif ($line->sens == 'C') { } elseif ($line->sens == 'C') {
print ''.$separator; print $separator;
print price($line->credit).$separator; print price($line->credit).$separator;
} }
print $line->doc_ref.$separator; print $line->doc_ref.$separator;
@ -562,10 +687,13 @@ class AccountancyExport
* Help : https://docplayer.fr/20769649-Fichier-d-entree-ascii-dans-quadracompta.html * Help : https://docplayer.fr/20769649-Fichier-d-entree-ascii-dans-quadracompta.html
* In QuadraCompta | Use menu : "Outils" > "Suivi des dossiers" > "Import ASCII(Compta)" * In QuadraCompta | Use menu : "Outils" > "Suivi des dossiers" > "Import ASCII(Compta)"
* *
* @param array $TData data * @param array $TData Data
* @return void * @param resource $exportFile [=null] File resource to export or print if null
* @param array $archiveFileList [=array()] Archive file list : array of ['path', 'name']
* @param bool $withAttachment [=0] Not add files or 1 to have attached in an archive
* @return array Archive file list : array of ['path', 'name']
*/ */
public function exportQuadratus(&$TData) public function exportQuadratus(&$TData, $exportFile = null, $archiveFileList = array(), $withAttachment = 0)
{ {
global $conf, $db; global $conf, $db;
@ -623,8 +751,12 @@ class AccountancyExport
$Tab['end_line'] = $end_line; $Tab['end_line'] = $end_line;
if ($exportFile) {
fwrite($exportFile, implode($Tab));
} else {
print implode($Tab); print implode($Tab);
} }
}
$Tab = array(); $Tab = array();
$Tab['type_ligne'] = 'M'; $Tab['type_ligne'] = 'M';
@ -694,14 +826,65 @@ class AccountancyExport
// We need to keep the 10 lastest number of invoice doc_ref not the beginning part that is the unusefull almost same part // We need to keep the 10 lastest number of invoice doc_ref not the beginning part that is the unusefull almost same part
// $Tab['num_piece3'] = str_pad(self::trunc($data->piece_num, 10), 10); // $Tab['num_piece3'] = str_pad(self::trunc($data->piece_num, 10), 10);
$Tab['num_piece3'] = substr(self::trunc($data->doc_ref, 20), -10); $Tab['num_piece3'] = substr(self::trunc($data->doc_ref, 20), -10);
$Tab['filler4'] = str_repeat(' ', 73); $Tab['reserved'] = str_repeat(' ', 10); // position 159
$Tab['currency_amount'] = str_repeat(' ', 13); // position 169
// get document file
$attachmentFileName = '';
if ($withAttachment == 1) {
$attachmentFileKey = trim($data->piece_num);
if (!isset($archiveFileList[$attachmentFileKey])) {
$objectDirPath = '';
$objectFileName = dol_sanitizeFileName($data->doc_ref);
if ($data->doc_type == 'customer_invoice') {
$objectDirPath = !empty($conf->facture->multidir_output[$conf->entity]) ? $conf->facture->multidir_output[$conf->entity] : $conf->facture->dir_output;
} elseif ($data->doc_type == 'expense_report') {
$objectDirPath = !empty($conf->expensereport->multidir_output[$conf->entity]) ? $conf->expensereport->multidir_output[$conf->entity] : $conf->factureexpensereport->dir_output;
} elseif ($data->doc_type == 'supplier_invoice') {
$objectDirPath = !empty($conf->fournisseur->facture->multidir_output[$conf->entity]) ? $conf->fournisseur->facture->multidir_output[$conf->entity] : $conf->fournisseur->facture->dir_output;
}
$arrayofinclusion = array();
$arrayofinclusion[] = '^'.preg_quote($objectFileName, '/').'\.pdf$';
$fileFoundList = dol_dir_list($objectDirPath.'/'.$objectFileName, 'files', 0, implode('|', $arrayofinclusion), '(\.meta|_preview.*\.png)$', 'date', SORT_DESC, 0, true);
if (!empty($fileFoundList)) {
$attachmentFileNameTrunc = str_pad(self::trunc($data->piece_num, 8), 8, '0', STR_PAD_LEFT);
foreach ($fileFoundList as $fileFound) {
if (strstr($fileFound['name'], $objectFileName)) {
$fileFoundPath = $objectDirPath.'/'.$objectFileName.'/'.$fileFound['name'];
if (file_exists($fileFoundPath)) {
$archiveFileList[$attachmentFileKey] = array(
'path' => $fileFoundPath,
'name' => $attachmentFileNameTrunc.'.pdf',
);
break;
}
}
}
}
}
if (isset($archiveFileList[$attachmentFileKey])) {
$attachmentFileName = $archiveFileList[$attachmentFileKey]['name'];
}
}
if (dol_strlen($attachmentFileName) == 12) {
$Tab['attachment'] = $attachmentFileName; // position 182
} else {
$Tab['attachment'] = str_repeat(' ', 12); // position 182
}
$Tab['filler4'] = str_repeat(' ', 38);
$Tab['end_line'] = $end_line; $Tab['end_line'] = $end_line;
if ($exportFile) {
fwrite($exportFile, implode($Tab));
} else {
print implode($Tab); print implode($Tab);
} }
} }
return $archiveFileList;
}
/** /**
* Export format : WinFic - eWinfic - WinSis Compta * Export format : WinFic - eWinfic - WinSis Compta
* Last review for this format : 2022-11-01 Alexandre Spangaro (aspangaro@open-dsi.fr) * Last review for this format : 2022-11-01 Alexandre Spangaro (aspangaro@open-dsi.fr)
@ -994,7 +1177,9 @@ class AccountancyExport
print $line->code_journal . $separator; print $line->code_journal . $separator;
// FEC:JournalLib // FEC:JournalLib
print dol_string_unaccent($langs->transnoentities($line->journal_label)) . $separator; $labeljournal = dol_string_unaccent($langs->transnoentities($line->journal_label));
$labeljournal = dol_string_nospecial($labeljournal, ' ');
print $labeljournal . $separator;
// FEC:EcritureNum // FEC:EcritureNum
print $line->piece_num . $separator; print $line->piece_num . $separator;
@ -1125,7 +1310,9 @@ class AccountancyExport
print $line->code_journal . $separator; print $line->code_journal . $separator;
// FEC:JournalLib // FEC:JournalLib
print dol_string_unaccent($langs->transnoentities($line->journal_label)) . $separator; $labeljournal = dol_string_unaccent($langs->transnoentities($line->journal_label));
$labeljournal = dol_string_nospecial($labeljournal, ' ');
print $labeljournal . $separator;
// FEC:EcritureNum // FEC:EcritureNum
print $line->piece_num . $separator; print $line->piece_num . $separator;
@ -1947,14 +2134,16 @@ class AccountancyExport
//Calcul de la longueur des numéros de comptes //Calcul de la longueur des numéros de comptes
$taille_numero = strlen(length_accountg($line->numero_compte)); $taille_numero = strlen(length_accountg($line->numero_compte));
//Création du numéro de client générique //Création du numéro de client et fournisseur générique
$numero_cpt_client = '411'; $numero_cpt_client = '411';
$numero_cpt_fourn = '401';
for ($i = 1; $i <= ($taille_numero - 3); $i++) { for ($i = 1; $i <= ($taille_numero - 3); $i++) {
$numero_cpt_client .= '0'; $numero_cpt_client .= '0';
$numero_cpt_fourn .= '0';
} }
//Création des comptes auxiliaire des clients //Création des comptes auxiliaire des clients et fournisseur
if (length_accountg($line->numero_compte) == $numero_cpt_client) { if (length_accountg($line->numero_compte) == $numero_cpt_client || length_accountg($line->numero_compte) == $numero_cpt_fourn) {
$tab[] = rtrim(length_accounta($line->subledger_account), "0"); $tab[] = rtrim(length_accounta($line->subledger_account), "0");
} else { } else {
$tab[] = length_accountg($line->numero_compte); $tab[] = length_accountg($line->numero_compte);

View File

@ -38,6 +38,11 @@ class AccountancySystem
*/ */
public $error = ''; public $error = '';
/**
* @var string[] Array of Errors code (or messages)
*/
public $errors = array();
/** /**
* @var int ID * @var int ID
*/ */

View File

@ -723,16 +723,18 @@ class AccountingAccount extends CommonObject
} }
/** /**
* Return Suggest accounting accounts to bind * Return a suggested account (from chart of accounts) to bind
* *
* @param Societe $buyer Object buyer * @param Societe $buyer Object buyer
* @param Societe $seller Object seller * @param Societe $seller Object seller
* @param Product $product Product object sell or buy * @param Product $product Product object sell or buy
* @param Facture|FactureFournisseur $facture Facture * @param Facture|FactureFournisseur $facture Facture
* @param FactureLigne|SupplierInvoiceLine $factureDet Facture Det * @param FactureLigne|SupplierInvoiceLine $factureDet Facture Det
* @param array $accountingAccount Array of Account account * @param array $accountingAccount Array of Accounting account
* @param string $type Customer / Supplier * @param string $type Customer / Supplier
* @return array|int Accounting accounts suggested or < 0 if technical error. * @return array|int Accounting accounts suggested or < 0 if technical error.
* 'suggestedaccountingaccountbydefaultfor'=>Will be used for the label to show on tooltip for account by default on any product
* 'suggestedaccountingaccountfor'=>Is the account suggested for this product
*/ */
public function getAccountingCodeToBind(Societe $buyer, Societe $seller, Product $product, $facture, $factureDet, $accountingAccount = array(), $type = '') public function getAccountingCodeToBind(Societe $buyer, Societe $seller, Product $product, $facture, $factureDet, $accountingAccount = array(), $type = '')
{ {
@ -868,18 +870,46 @@ class AccountingAccount extends CommonObject
} }
// Manage Deposit // Manage Deposit
if (getDolGlobalString('ACCOUNTING_ACCOUNT_' . strtoupper($type) . '_DEPOSIT')) {
if ($factureDet->desc == "(DEPOSIT)" || $facture->type == $facture::TYPE_DEPOSIT) { if ($factureDet->desc == "(DEPOSIT)" || $facture->type == $facture::TYPE_DEPOSIT) {
$accountdeposittoventilated = new self($this->db); $accountdeposittoventilated = new self($this->db);
if ($type == 'customer') {
$result = $accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT, 1); $result = $accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT, 1);
if ($result < 0) { } elseif ($type == 'supplier') {
$result = $accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT, 1);
}
if (isset($result) && $result < 0) {
return -1; return -1;
} }
$code_l = $accountdeposittoventilated->ref; $code_l = $accountdeposittoventilated->ref;
$code_p = '';
$code_t = '';
$suggestedid = $accountdeposittoventilated->rowid; $suggestedid = $accountdeposittoventilated->rowid;
$suggestedaccountingaccountfor = 'deposit'; $suggestedaccountingaccountfor = 'deposit';
} }
// For credit note invoice, if origin invoice is a deposit invoice, force also on specific customer/supplier deposit account
if (!empty($facture->fk_facture_source)) {
$invoiceSource = new $facture($this->db);
$invoiceSource->fetch($facture->fk_facture_source);
if ($facture->type == $facture::TYPE_CREDIT_NOTE && $invoiceSource->type == $facture::TYPE_DEPOSIT) {
$accountdeposittoventilated = new self($this->db);
if ($type == 'customer') {
$accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT, 1);
} elseif ($type == 'supplier') {
$accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER_DEPOSIT, 1);
}
$code_l = $accountdeposittoventilated->ref;
$code_p = '';
$code_t = '';
$suggestedid = $accountdeposittoventilated->rowid;
$suggestedaccountingaccountfor = 'deposit';
}
}
}
// If $suggestedid could not be guessed yet, we set it from the generic default accounting code $code_l // If $suggestedid could not be guessed yet, we set it from the generic default accounting code $code_l
if (empty($suggestedid) && empty($code_p) && !empty($code_l) && empty($conf->global->ACCOUNTANCY_DO_NOT_AUTOFILL_ACCOUNT_WITH_GENERIC)) { if (empty($suggestedid) && empty($code_p) && !empty($code_l) && empty($conf->global->ACCOUNTANCY_DO_NOT_AUTOFILL_ACCOUNT_WITH_GENERIC)) {
if (empty($this->accountingaccount_codetotid_cache[$code_l])) { if (empty($this->accountingaccount_codetotid_cache[$code_l])) {

View File

@ -231,7 +231,7 @@ class AccountingJournal extends CommonObject
* Return clicable name (with picto eventually) * Return clicable name (with picto eventually)
* *
* @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
* @param int $withlabel 0=No label, 1=Include label of journal * @param int $withlabel 0=No label, 1=Include label of journal, 2=Include nature of journal
* @param int $nourl 1=Disable url * @param int $nourl 1=Disable url
* @param string $moretitle Add more text to title tooltip * @param string $moretitle Add more text to title tooltip
* @param int $notooltip 1=Disable tooltip * @param int $notooltip 1=Disable tooltip
@ -281,9 +281,14 @@ class AccountingJournal extends CommonObject
} }
$label_link = $this->code; $label_link = $this->code;
if ($withlabel && !empty($this->label)) { if ($withlabel != 2 && !empty($this->label)) {
$label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : ''); $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
} }
if ($withlabel == 2 && !empty($this->nature)) {
$key = $langs->trans("AccountingJournalType".strtoupper($this->nature));
$transferlabel = ($this->nature && $key != "AccountingJournalType".strtoupper($langs->trans($this->nature)) ? $key : $this->label);
$label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$transferlabel.($nourl ? '</span>' : '');
}
$result .= $linkstart; $result .= $linkstart;
if ($withpicto) { if ($withpicto) {
@ -449,27 +454,12 @@ class AccountingJournal extends CommonObject
} }
$sql = ""; $sql = "";
// FIXME sql error with Mysql 5.7
/*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
$sql .= "WITH in_accounting_bookkeeping(fk_docdet) AS (";
$sql .= " SELECT DISTINCT fk_docdet";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
$sql .= " WHERE doc_type = 'asset'";
$sql .= ") ";
}*/
$sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht"; $sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht";
$sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat"; $sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat";
$sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit"; $sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit";
$sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad"; $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
// FIXME sql error with Mysql 5.7
/*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
$sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
}*/
$sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
// Compatibility with Mysql 5.7
if ($in_bookkeeping == 'already') { if ($in_bookkeeping == 'already') {
$sql .= " AND EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')"; $sql .= " AND EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
} elseif ($in_bookkeeping == 'notyet') { } elseif ($in_bookkeeping == 'notyet') {
@ -483,11 +473,6 @@ class AccountingJournal extends CommonObject
if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) { if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) {
$sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'"; $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'";
} }
// Already in bookkeeping or not
// FIXME sql error with Mysql 5.7
/*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
$sql .= " AND iab.fk_docdet IS" . ($in_bookkeeping == 'already' ? " NOT" : "") . " NULL";
}*/
$sql .= " ORDER BY ad.depreciation_date"; $sql .= " ORDER BY ad.depreciation_date";
dol_syslog(__METHOD__, LOG_DEBUG); dol_syslog(__METHOD__, LOG_DEBUG);
@ -750,7 +735,7 @@ class AccountingJournal extends CommonObject
} }
} }
$journal_data[$pre_data_id] = $element; $journal_data[(int) $pre_data_id] = $element;
} }
unset($pre_data); unset($pre_data);
@ -982,8 +967,8 @@ class AccountingJournal extends CommonObject
$langs->transnoentitiesnoconv("LedgerAccount"), $langs->transnoentitiesnoconv("LedgerAccount"),
$langs->transnoentitiesnoconv("SubledgerAccount"), $langs->transnoentitiesnoconv("SubledgerAccount"),
$langs->transnoentitiesnoconv("Label"), $langs->transnoentitiesnoconv("Label"),
$langs->transnoentitiesnoconv("Debit"), $langs->transnoentitiesnoconv("AccountingDebit"),
$langs->transnoentitiesnoconv("Credit"), $langs->transnoentitiesnoconv("AccountingCredit"),
$langs->transnoentitiesnoconv("Journal"), $langs->transnoentitiesnoconv("Journal"),
$langs->transnoentitiesnoconv("Note"), $langs->transnoentitiesnoconv("Note"),
); );
@ -993,8 +978,8 @@ class AccountingJournal extends CommonObject
$langs->transnoentitiesnoconv("Piece"), $langs->transnoentitiesnoconv("Piece"),
$langs->transnoentitiesnoconv("AccountAccounting"), $langs->transnoentitiesnoconv("AccountAccounting"),
$langs->transnoentitiesnoconv("LabelOperation"), $langs->transnoentitiesnoconv("LabelOperation"),
$langs->transnoentitiesnoconv("Debit"), $langs->transnoentitiesnoconv("AccountingDebit"),
$langs->transnoentitiesnoconv("Credit"), $langs->transnoentitiesnoconv("AccountingCredit"),
); );
} elseif ($this->nature == 1) { } elseif ($this->nature == 1) {
$header = array( $header = array(
@ -1002,8 +987,8 @@ class AccountingJournal extends CommonObject
$langs->transnoentitiesnoconv("Piece"), $langs->transnoentitiesnoconv("Piece"),
$langs->transnoentitiesnoconv("AccountAccounting"), $langs->transnoentitiesnoconv("AccountAccounting"),
$langs->transnoentitiesnoconv("LabelOperation"), $langs->transnoentitiesnoconv("LabelOperation"),
$langs->transnoentitiesnoconv("Debit"), $langs->transnoentitiesnoconv("AccountingDebit"),
$langs->transnoentitiesnoconv("Credit"), $langs->transnoentitiesnoconv("AccountingCredit"),
); );
} }

View File

@ -817,7 +817,7 @@ class BookKeeping extends CommonObject
/** /**
* Load object in memory from the database * Load object in memory from the database in ->lines. Or just make a simple count if $countonly=1.
* *
* @param string $sortorder Sort Order * @param string $sortorder Sort Order
* @param string $sortfield Sort field * @param string $sortfield Sort field
@ -826,18 +826,22 @@ class BookKeeping extends CommonObject
* @param array $filter filter array * @param array $filter filter array
* @param string $filtermode filter mode (AND or OR) * @param string $filtermode filter mode (AND or OR)
* @param int $option option (0: general account or 1: subaccount) * @param int $option option (0: general account or 1: subaccount)
* * @param int $countonly Do not fill the $object->lines, return only the count.
* @return int <0 if KO, >=0 if OK * @return int <0 if KO, Number of lines if OK
*/ */
public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0) public function fetchAllByAccount($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0, $countonly = 0)
{ {
global $conf; global $conf;
dol_syslog(__METHOD__, LOG_DEBUG); dol_syslog(__METHOD__, LOG_DEBUG);
$this->lines = array(); $this->lines = array();
$num = 0;
$sql = 'SELECT'; $sql = 'SELECT';
if ($countonly) {
$sql .= ' COUNT(t.rowid) as nb';
} else {
$sql .= ' t.rowid,'; $sql .= ' t.rowid,';
$sql .= " t.doc_date,"; $sql .= " t.doc_date,";
$sql .= " t.doc_type,"; $sql .= " t.doc_type,";
@ -867,6 +871,7 @@ class BookKeeping extends CommonObject
$sql .= " t.date_export,"; $sql .= " t.date_export,";
$sql .= " t.date_validated as date_validation,"; $sql .= " t.date_validated as date_validation,";
$sql .= " t.import_key"; $sql .= " t.import_key";
}
// Manage filter // Manage filter
$sqlwhere = array(); $sqlwhere = array();
if (count($filter) > 0) { if (count($filter) > 0) {
@ -880,7 +885,7 @@ class BookKeeping extends CommonObject
} elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') { } elseif ($key == 't.fk_doc' || $key == 't.fk_docdet' || $key == 't.piece_num') {
$sqlwhere[] = $key.'='.$value; $sqlwhere[] = $key.'='.$value;
} elseif ($key == 't.subledger_account' || $key == 't.numero_compte') { } elseif ($key == 't.subledger_account' || $key == 't.numero_compte') {
$sqlwhere[] = $key.' LIKE \''.$this->db->escape($value).'%\''; $sqlwhere[] = $key.' LIKE \''.$this->db->escapeforlike($this->db->escape($value)).'%\'';
} elseif ($key == 't.date_creation>=' || $key == 't.date_creation<=') { } elseif ($key == 't.date_creation>=' || $key == 't.date_creation<=') {
$sqlwhere[] = $key.'\''.$this->db->idate($value).'\''; $sqlwhere[] = $key.'\''.$this->db->idate($value).'\'';
} elseif ($key == 't.date_export>=' || $key == 't.date_export<=') { } elseif ($key == 't.date_export>=' || $key == 't.date_export<=') {
@ -897,18 +902,19 @@ class BookKeeping extends CommonObject
} else { } else {
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1); $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
} }
} elseif ($key == 't.search_accounting_code_in' && !empty($value)) {
$sqlwhere[] = 't.numero_compte IN ('.$this->db->sanitize($value, 1).')';
} else { } else {
$sqlwhere[] = natural_search($key, $value, 0, 1); $sqlwhere[] = natural_search($key, $value, 0, 1);
} }
} }
} }
$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
$sql .= ' WHERE 1 = 1'; $sql .= ' WHERE entity = ' . ((int) $conf->entity); // Do not use getEntity for accounting features
$sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features
if (count($sqlwhere) > 0) { if (count($sqlwhere) > 0) {
$sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere); $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
} }
// Affichage par compte comptable // Filter by ledger account or subledger account
if (!empty($option)) { if (!empty($option)) {
$sql .= " AND t.subledger_account IS NOT NULL"; $sql .= " AND t.subledger_account IS NOT NULL";
$sql .= " AND t.subledger_account <> ''"; $sql .= " AND t.subledger_account <> ''";
@ -919,13 +925,21 @@ class BookKeeping extends CommonObject
$sortorder = 'ASC'.($sortorder ? ','.$sortorder : ''); $sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
} }
if (!$countonly) {
$sql .= $this->db->order($sortfield, $sortorder); $sql .= $this->db->order($sortfield, $sortorder);
if (!empty($limit)) { if (!empty($limit)) {
$sql .= $this->db->plimit($limit + 1, $offset); $sql .= $this->db->plimit($limit + 1, $offset);
} }
}
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if ($resql) { if ($resql) {
if ($countonly) {
$obj = $this->db->fetch_object($resql);
if ($obj) {
$num = $obj->nb;
}
} else {
$num = $this->db->num_rows($resql); $num = $this->db->num_rows($resql);
$i = 0; $i = 0;
@ -968,6 +982,7 @@ class BookKeeping extends CommonObject
$i++; $i++;
} }
}
$this->db->free($resql); $this->db->free($resql);
return $num; return $num;
@ -1139,9 +1154,10 @@ class BookKeeping extends CommonObject
* @param int $offset offset limit * @param int $offset offset limit
* @param array $filter filter array * @param array $filter filter array
* @param string $filtermode filter mode (AND or OR) * @param string $filtermode filter mode (AND or OR)
* @param int $option option (0: general account or 1: subaccount)
* @return int <0 if KO, >0 if OK * @return int <0 if KO, >0 if OK
*/ */
public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') public function fetchAllBalance($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND', $option = 0)
{ {
global $conf; global $conf;
@ -1151,6 +1167,11 @@ class BookKeeping extends CommonObject
$sql = 'SELECT'; $sql = 'SELECT';
$sql .= " t.numero_compte,"; $sql .= " t.numero_compte,";
$sql .= " t.label_compte,";
if (!empty($option)) {
$sql .= " t.subledger_account,";
$sql .= " t.subledger_label,";
}
$sql .= " SUM(t.debit) as debit,"; $sql .= " SUM(t.debit) as debit,";
$sql .= " SUM(t.credit) as credit"; $sql .= " SUM(t.credit) as credit";
$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
@ -1176,6 +1197,8 @@ class BookKeeping extends CommonObject
} else { } else {
$sqlwhere[] = natural_search("t.code_journal", $value, 3, 1); $sqlwhere[] = natural_search("t.code_journal", $value, 3, 1);
} }
} elseif ($key == 't.reconciled_option') {
$sqlwhere[] = 't.lettering_code IS NULL';
} else { } else {
$sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'"; $sqlwhere[] = $key." LIKE '%".$this->db->escape($value)."%'";
} }
@ -1186,7 +1209,17 @@ class BookKeeping extends CommonObject
$sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere); $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
} }
$sql .= ' GROUP BY t.numero_compte'; if (!empty($option)) {
$sql .= ' AND t.subledger_account IS NOT NULL';
$sql .= ' AND t.subledger_account != ""';
$sql .= ' GROUP BY t.numero_compte, t.label_compte, t.subledger_account, t.subledger_label';
$sortfield = 't.subledger_account'.($sortfield ? ','.$sortfield : '');
$sortorder = 'ASC'.($sortfield ? ','.$sortfield : '');
} else {
$sql .= ' GROUP BY t.numero_compte, t.label_compte';
$sortfield = 't.numero_compte'.($sortfield ? ','.$sortfield : '');
$sortorder = 'ASC'.($sortorder ? ','.$sortorder : '');
}
if (!empty($sortfield)) { if (!empty($sortfield)) {
$sql .= $this->db->order($sortfield, $sortorder); $sql .= $this->db->order($sortfield, $sortorder);
@ -1204,6 +1237,9 @@ class BookKeeping extends CommonObject
$line = new BookKeepingLine(); $line = new BookKeepingLine();
$line->numero_compte = $obj->numero_compte; $line->numero_compte = $obj->numero_compte;
$line->label_compte = $obj->label_compte;
$line->subledger_account = $obj->subledger_account;
$line->subledger_label = $obj->subledger_label;
$line->debit = $obj->debit; $line->debit = $obj->debit;
$line->credit = $obj->credit; $line->credit = $obj->credit;

View File

@ -33,11 +33,52 @@ include_once DOL_DOCUMENT_ROOT."/core/lib/date.lib.php";
*/ */
class Lettering extends BookKeeping class Lettering extends BookKeeping
{ {
/** public static $doc_type_infos = array(
* @var BookKeeping[] Bookkeeping cached 'customer_invoice' => array(
*/ 'payment_table' => 'paiement',
public static $bookkeeping_cached = array(); 'payment_table_fk_bank' => 'fk_bank',
'doc_payment_table' => 'paiement_facture',
'doc_payment_table_fk_payment' => 'fk_paiement',
'doc_payment_table_fk_doc' => 'fk_facture',
'linked_info' => array(
array(
'table' => 'paiement_facture',
'fk_doc' => 'fk_facture',
'fk_link' => 'fk_paiement',
'prefix' => 'p',
),
array(
'table' => 'societe_remise_except',
'fk_doc' => 'fk_facture_source',
'fk_link' => 'fk_facture',
'prefix' => 'a',
'is_fk_link_is_also_fk_doc' => true,
),
),
),
'supplier_invoice' => array(
'payment_table' => 'paiementfourn',
'payment_table_fk_bank' => 'fk_bank',
'doc_payment_table' => 'paiementfourn_facturefourn',
'doc_payment_table_fk_payment' => 'fk_paiementfourn',
'doc_payment_table_fk_doc' => 'fk_facturefourn',
'linked_info' => array(
array(
'table' => 'paiementfourn_facturefourn',
'fk_doc' => 'fk_facturefourn',
'fk_link' => 'fk_paiementfourn',
'prefix' => 'p',
),
array(
'table' => 'societe_remise_except',
'fk_doc' => 'fk_invoice_supplier_source',
'fk_link' => 'fk_invoice_supplier',
'prefix' => 'a',
'is_fk_link_is_also_fk_doc' => true,
),
),
),
);
/** /**
* letteringThirdparty * letteringThirdparty
@ -250,18 +291,9 @@ class Lettering extends BookKeeping
$lettre = 'AAA'; $lettre = 'AAA';
$sql = "SELECT DISTINCT ab2.lettering_code"; $sql = "SELECT DISTINCT ab2.lettering_code";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping As ab"; $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "bank_url AS bu ON bu.fk_bank = ab.fk_doc"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab2 ON ab2.subledger_account = ab.subledger_account";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "bank_url AS bu2 ON bu2.url_id = bu.url_id";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab2 ON ab2.fk_doc = bu2.fk_bank";
$sql .= " WHERE ab.rowid IN (" . $this->db->sanitize(implode(',', $ids)) . ")"; $sql .= " WHERE ab.rowid IN (" . $this->db->sanitize(implode(',', $ids)) . ")";
$sql .= " AND ab.doc_type = 'bank'";
$sql .= " AND ab2.doc_type = 'bank'";
$sql .= " AND bu.type = 'company'";
$sql .= " AND bu2.type = 'company'";
$sql .= " AND ab.subledger_account != ''";
$sql .= " AND ab2.subledger_account != ''";
$sql .= " AND ab.lettering_code IS NULL";
$sql .= " AND ab2.lettering_code != ''"; $sql .= " AND ab2.lettering_code != ''";
$sql .= " ORDER BY ab2.lettering_code DESC"; $sql .= " ORDER BY ab2.lettering_code DESC";
$sql .= " LIMIT 1 "; $sql .= " LIMIT 1 ";
@ -269,7 +301,7 @@ class Lettering extends BookKeeping
$resqla = $this->db->query($sql); $resqla = $this->db->query($sql);
if ($resqla) { if ($resqla) {
$obj = $this->db->fetch_object($resqla); $obj = $this->db->fetch_object($resqla);
$lettre = (empty($obj->lettering_code) ? 'AAA' : $obj->lettering_code); $lettre = (empty($obj->lettering_code) ? $lettre : $obj->lettering_code);
if (!empty($obj->lettering_code)) { if (!empty($obj->lettering_code)) {
$lettre++; $lettre++;
} }
@ -374,16 +406,7 @@ class Lettering extends BookKeeping
$errors = array(); $errors = array();
$nb_lettering = 0; $nb_lettering = 0;
$result = $this->bookkeepingLettering($bookkeeping_ids, 'customer_invoice', $unlettering); $result = $this->bookkeepingLettering($bookkeeping_ids, $unlettering);
if ($result < 0) {
$error++;
$errors = array_merge($errors, $this->errors);
$nb_lettering += abs($result) - 2;
} else {
$nb_lettering += $result;
}
$result = $this->bookkeepingLettering($bookkeeping_ids, 'supplier_invoice', $unlettering);
if ($result < 0) { if ($result < 0) {
$error++; $error++;
$errors = array_merge($errors, $this->errors); $errors = array_merge($errors, $this->errors);
@ -404,11 +427,10 @@ class Lettering extends BookKeeping
* Lettering bookkeeping lines * Lettering bookkeeping lines
* *
* @param array $bookkeeping_ids Lettering specific list of bookkeeping id * @param array $bookkeeping_ids Lettering specific list of bookkeeping id
* @param string $type Type of bookkeeping type to lettering ('customer_invoice' or 'supplier_invoice')
* @param bool $unlettering Do unlettering * @param bool $unlettering Do unlettering
* @return int <0 if error (nb lettered = result -1), 0 if noting to lettering, >0 if OK (nb lettered) * @return int <0 if error (nb lettered = result -1), 0 if noting to lettering, >0 if OK (nb lettered)
*/ */
public function bookkeepingLettering($bookkeeping_ids, $type = 'customer_invoice', $unlettering = false) public function bookkeepingLettering($bookkeeping_ids, $unlettering = false)
{ {
global $langs; global $langs;
@ -416,11 +438,14 @@ class Lettering extends BookKeeping
// Clean parameters // Clean parameters
$bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array(); $bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array();
$type = trim($type);
$error = 0; $error = 0;
$nb_lettering = 0; $nb_lettering = 0;
$grouped_lines = $this->getLinkedLines($bookkeeping_ids, $type); $grouped_lines = $this->getLinkedLines($bookkeeping_ids);
if (!is_array($grouped_lines)) {
return -2;
}
foreach ($grouped_lines as $lines) { foreach ($grouped_lines as $lines) {
$group_error = 0; $group_error = 0;
$total = 0; $total = 0;
@ -479,51 +504,213 @@ class Lettering extends BookKeeping
* Lettering bookkeeping lines * Lettering bookkeeping lines
* *
* @param array $bookkeeping_ids Lettering specific list of bookkeeping id * @param array $bookkeeping_ids Lettering specific list of bookkeeping id
* @param string $type Type of bookkeeping type to lettering ('customer_invoice' or 'supplier_invoice') * @param bool $only_has_subledger_account Get only lines who have subledger account
* @return array|int <0 if error otherwise all linked lines by block * @return array|int <0 if error otherwise all linked lines by block
*/ */
public function getLinkedLines($bookkeeping_ids, $type = 'customer_invoice') public function getLinkedLines($bookkeeping_ids, $only_has_subledger_account = true)
{ {
global $conf, $langs; global $conf, $langs;
$this->errors = array(); $this->errors = array();
// Clean parameters // Clean parameters
$bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array(); $bookkeeping_ids = is_array($bookkeeping_ids) ? $bookkeeping_ids : array();
$type = trim($type);
if ($type == 'customer_invoice') { // Get all bookkeeping lines
$doc_type = 'customer_invoice'; $sql = "SELECT DISTINCT ab.doc_type, ab.fk_doc";
$bank_url_type = 'payment'; $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab";
$payment_element = 'paiement_facture'; $sql .= " WHERE ab.entity IN (" . getEntity('accountancy') . ")";
$fk_payment_element = 'fk_paiement'; $sql .= " AND ab.fk_doc > 0";
$fk_element = 'fk_facture'; if (!empty($bookkeeping_ids)) {
$account_number = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER; // Get all bookkeeping lines of piece number
} elseif ($type == 'supplier_invoice') { $sql .= " AND EXISTS (";
$doc_type = 'supplier_invoice'; $sql .= " SELECT rowid";
$bank_url_type = 'payment_supplier'; $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS pn";
$payment_element = 'paiementfourn_facturefourn'; $sql .= " WHERE pn.entity IN (" . getEntity('accountancy') . ")";
$fk_payment_element = 'fk_paiementfourn'; $sql .= " AND pn.rowid IN (" . $this->db->sanitize(implode(',', $bookkeeping_ids)) . ")";
$fk_element = 'fk_facturefourn'; $sql .= " AND pn.piece_num = ab.piece_num";
$account_number = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER; $sql .= " )";
} else { }
if ($only_has_subledger_account) $sql .= " AND ab.subledger_account != ''";
dol_syslog(__METHOD__ . " - Get all bookkeeping lines", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
$bookkeeping_lines_by_type = array();
while ($obj = $this->db->fetch_object($resql)) {
$bookkeeping_lines_by_type[$obj->doc_type][$obj->fk_doc] = $obj->fk_doc;
}
$this->db->free($resql);
if (empty($bookkeeping_lines_by_type)) {
return array();
}
if (!empty($bookkeeping_lines_by_type['bank'])) {
$new_bookkeeping_lines_by_type = $this->getDocTypeAndFkDocFromBankLines($bookkeeping_lines_by_type['bank']);
if (!is_array($new_bookkeeping_lines_by_type)) {
return -1;
}
foreach ($new_bookkeeping_lines_by_type as $doc_type => $fk_docs) {
foreach ($fk_docs as $fk_doc) {
$bookkeeping_lines_by_type[$doc_type][$fk_doc] = $fk_doc;
}
}
}
$grouped_lines = array();
foreach (self::$doc_type_infos as $doc_type => $doc_type_info) {
if (!is_array($bookkeeping_lines_by_type[$doc_type])) {
continue;
}
// Get all document ids grouped
$doc_grouped = $this->getLinkedDocumentByGroup($bookkeeping_lines_by_type[$doc_type], $doc_type);
if (!is_array($doc_grouped)) {
return -1;
}
// Group all lines by document/piece number
foreach ($doc_grouped as $doc_ids) {
$bank_ids = $this->getBankLinesFromFkDocAndDocType($doc_ids, $doc_type);
if (!is_array($bank_ids)) {
return -1;
}
// Get all bookkeeping lines linked
$sql = "SELECT DISTINCT ab.rowid, ab.piece_num, ab.debit, ab.credit, ab.lettering_code";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab";
$sql .= " WHERE ab.entity IN (" . getEntity('accountancy') . ")";
$sql .= " AND (";
if (!empty($bank_ids)) {
$sql .= " EXISTS (";
$sql .= " SELECT bpn.rowid";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS bpn";
$sql .= " WHERE bpn.entity IN (" . getEntity('accountancy') . ")";
$sql .= " AND bpn.doc_type = 'bank'";
$sql .= " AND bpn.fk_doc IN (" . $this->db->sanitize(implode(',', $bank_ids)) . ")";
$sql .= " AND bpn.piece_num = ab.piece_num";
$sql .= " ) OR ";
}
$sql .= " EXISTS (";
$sql .= " SELECT dpn.rowid";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS dpn";
$sql .= " WHERE dpn.entity IN (" . getEntity('accountancy') . ")";
$sql .= " AND dpn.doc_type = '" . $this->db->escape($doc_type) . "'";
$sql .= " AND dpn.fk_doc IN (" . $this->db->sanitize(implode(',', $doc_ids)) . ")";
$sql .= " AND dpn.piece_num = ab.piece_num";
$sql .= " )";
$sql .= ")";
if ($only_has_subledger_account) $sql .= " AND ab.subledger_account != ''";
dol_syslog(__METHOD__ . " - Get all bookkeeping lines linked", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
$group = array();
while ($obj = $this->db->fetch_object($resql)) {
$group[$obj->rowid] = array(
'id' => $obj->rowid,
'piece_num' => $obj->piece_num,
'debit' => $obj->debit,
'credit' => $obj->credit,
'lettering_code' => $obj->lettering_code,
);
}
$this->db->free($resql);
if (!empty($group)) $grouped_lines[] = $group;
}
}
return $grouped_lines;
}
/**
* Get all fk_doc by doc_type from list of bank ids
*
* @param array $bank_ids List of bank ids
* @return array|int <0 if error otherwise all fk_doc by doc_type
*/
public function getDocTypeAndFkDocFromBankLines($bank_ids)
{
dol_syslog(__METHOD__ . " - bank_ids=".json_encode($bank_ids), LOG_DEBUG);
// Clean parameters
$bank_ids = is_array($bank_ids) ? $bank_ids : array();
if (empty($bank_ids)) {
return array();
}
$bookkeeping_lines_by_type = array();
foreach (self::$doc_type_infos as $doc_type => $doc_type_info) {
// Get all fk_doc by doc_type from bank ids
$sql = "SELECT DISTINCT dp." . $doc_type_info['doc_payment_table_fk_doc'] . " AS fk_doc";
$sql .= " FROM " . MAIN_DB_PREFIX . $doc_type_info['payment_table'] . " AS p";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . $doc_type_info['doc_payment_table'] . " AS dp ON dp." . $doc_type_info['doc_payment_table_fk_payment'] . " = p.rowid";
$sql .= " WHERE p." . $doc_type_info['payment_table_fk_bank'] . " IN (" . $this->db->sanitize(implode(',', $bank_ids)) . ")";
$sql .= " AND dp." . $doc_type_info['doc_payment_table_fk_doc'] . " > 0";
dol_syslog(__METHOD__ . " - Get all fk_doc by doc_type from list of bank ids for '" . $doc_type . "'", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
while ($obj = $this->db->fetch_object($resql)) {
$bookkeeping_lines_by_type[$doc_type][$obj->fk_doc] = $obj->fk_doc;
}
$this->db->free($resql);
}
return $bookkeeping_lines_by_type;
}
/**
* Get all bank ids from list of document ids of a type
*
* @param array $document_ids List of document id
* @param string $doc_type Type of document ('customer_invoice' or 'supplier_invoice', ...)
* @return array|int <0 if error otherwise all all bank ids from list of document ids of a type
*/
public function getBankLinesFromFkDocAndDocType($document_ids, $doc_type)
{
global $langs;
dol_syslog(__METHOD__ . " - bank_ids=".json_encode($document_ids) . ", doc_type=$doc_type", LOG_DEBUG);
// Clean parameters
$document_ids = is_array($document_ids) ? $document_ids : array();
$doc_type = trim($doc_type);
if (empty($document_ids)) {
return array();
}
if (!is_array(self::$doc_type_infos[$doc_type])) {
$langs->load('errors'); $langs->load('errors');
$this->errors[] = $langs->trans('ErrorBadParameters'); $this->errors[] = $langs->trans('ErrorBadParameters');
return -1; return -1;
} }
$payment_ids = array(); $doc_type_info = self::$doc_type_infos[$doc_type];
$bank_ids = array();
// Get all payment id from bank lines // Get all fk_doc by doc_type from bank ids
$sql = "SELECT DISTINCT bu.url_id AS payment_id"; $sql = "SELECT DISTINCT p." . $doc_type_info['payment_table_fk_bank'] . " AS fk_doc";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab"; $sql .= " FROM " . MAIN_DB_PREFIX . $doc_type_info['payment_table'] . " AS p";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "bank_url AS bu ON bu.fk_bank = ab.fk_doc"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . $doc_type_info['doc_payment_table'] . " AS dp ON dp." . $doc_type_info['doc_payment_table_fk_payment'] . " = p.rowid";
$sql .= " WHERE ab.doc_type = 'bank'"; $sql .= " WHERE dp." . $doc_type_info['doc_payment_table_fk_doc'] . " IN (" . $this->db->sanitize(implode(',', $document_ids)) . ")";
// $sql .= " AND ab.subledger_account != ''"; $sql .= " AND p." . $doc_type_info['payment_table_fk_bank'] . " > 0";
// $sql .= " AND ab.numero_compte = '" . $this->db->escape($account_number) . "'";
$sql .= " AND bu.type = '" . $this->db->escape($bank_url_type) . "'";
if (!empty($bookkeeping_ids)) $sql .= " AND ab.rowid IN (" . $this->db->sanitize(implode(',', $bookkeeping_ids)) . ")";
dol_syslog(__METHOD__ . " - Get all payment id from bank lines", LOG_DEBUG); dol_syslog(__METHOD__ . " - Get all bank ids from list of document ids of a type '" . $doc_type . "'", LOG_DEBUG);
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if (!$resql) { if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror(); $this->errors[] = "Error " . $this->db->lasterror();
@ -531,218 +718,137 @@ class Lettering extends BookKeeping
} }
while ($obj = $this->db->fetch_object($resql)) { while ($obj = $this->db->fetch_object($resql)) {
$payment_ids[$obj->payment_id] = $obj->payment_id; $bank_ids[$obj->fk_doc] = $obj->fk_doc;
} }
$this->db->free($resql); $this->db->free($resql);
// Get all payment id from payment lines return $bank_ids;
$sql = "SELECT DISTINCT pe.$fk_payment_element AS payment_id";
$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "$payment_element AS pe ON pe.$fk_element = ab.fk_doc";
$sql .= " WHERE ab.doc_type = '" . $this->db->escape($doc_type) . "'";
// $sql .= " AND ab.subledger_account != ''";
// $sql .= " AND ab.numero_compte = '" . $this->db->escape($account_number) . "'";
$sql .= " AND pe.$fk_payment_element IS NOT NULL";
if (!empty($bookkeeping_ids)) $sql .= " AND ab.rowid IN (" . $this->db->sanitize(implode(',', $bookkeeping_ids)) . ")";
dol_syslog(__METHOD__ . " - Get all payment id from bank lines", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
while ($obj = $this->db->fetch_object($resql)) {
$payment_ids[$obj->payment_id] = $obj->payment_id;
}
$this->db->free($resql);
if (empty($payment_ids)) {
return array();
}
// Get all payments linked by group
$payment_by_group = $this->getLinkedPaymentByGroup($payment_ids, $type);
$groups = array();
foreach ($payment_by_group as $payment_list) {
$lines = array();
// Get bank lines
$sql = "SELECT DISTINCT ab.rowid, ab.piece_num, ab.lettering_code, ab.debit, ab.credit";
$sql .= " FROM " . MAIN_DB_PREFIX . "bank_url AS bu";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab ON ab.fk_doc = bu.fk_bank";
$sql .= " WHERE bu.url_id IN (" . $this->db->sanitize(implode(',', $payment_list)) . ")";
$sql .= " AND bu.type = '" . $this->db->escape($bank_url_type) . "'";
$sql .= " AND ab.doc_type = 'bank'";
$sql .= " AND ab.subledger_account != ''";
$sql .= " AND ab.numero_compte = '" . $this->db->escape($account_number) . "'";
dol_syslog(__METHOD__ . " - Get bank lines", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
while ($obj = $this->db->fetch_object($resql)) {
$lines[$obj->rowid] = array('id' => $obj->rowid, 'piece_num' => $obj->piece_num, 'lettering_code' => $obj->lettering_code, 'debit' => $obj->debit, 'credit' => $obj->credit);
}
$this->db->free($resql);
// Get payment lines
$sql = "SELECT DISTINCT ab.rowid, ab.piece_num, ab.lettering_code, ab.debit, ab.credit";
$sql .= " FROM " . MAIN_DB_PREFIX . "$payment_element AS pe";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_bookkeeping AS ab ON ab.fk_doc = pe.$fk_element";
$sql .= " WHERE pe.$fk_payment_element IN (" . $this->db->sanitize(implode(',', $payment_list)) . ")";
$sql .= " AND ab.doc_type = '" . $this->db->escape($doc_type) . "'";
$sql .= " AND ab.subledger_account != ''";
$sql .= " AND ab.numero_compte = '" . $this->db->escape($account_number) . "'";
dol_syslog(__METHOD__ . " - Get payment lines", LOG_DEBUG);
$resql = $this->db->query($sql);
if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror();
return -1;
}
while ($obj = $this->db->fetch_object($resql)) {
$lines[$obj->rowid] = array('id' => $obj->rowid, 'piece_num' => $obj->piece_num, 'lettering_code' => $obj->lettering_code, 'debit' => $obj->debit, 'credit' => $obj->credit);
}
$this->db->free($resql);
if (!empty($lines)) {
$groups[] = $lines;
}
}
return $groups;
} }
/** /**
* Linked payment by group * Get all linked document ids by group and type
* *
* @param array $payment_ids list of payment id * @param array $document_ids List of document id
* @param string $type Type of bookkeeping type to lettering ('customer_invoice' or 'supplier_invoice') * @param string $doc_type Type of document ('customer_invoice' or 'supplier_invoice', ...)
* @return array|int <0 if error otherwise all linked lines by block * @return array|int <0 if error otherwise all linked document ids by group and type [ [ 'doc_type' => [ doc_id, ... ], ... ], ... ]
*/ */
public function getLinkedPaymentByGroup($payment_ids, $type) public function getLinkedDocumentByGroup($document_ids, $doc_type)
{ {
global $langs; global $langs;
// Clean parameters // Clean parameters
$payment_ids = is_array($payment_ids) ? $payment_ids : array(); $document_ids = is_array($document_ids) ? $document_ids : array();
$type = trim($type); $doc_type = trim($doc_type);
if (empty($payment_ids)) { if (empty($document_ids)) {
return array(); return array();
} }
if (!is_array(self::$doc_type_infos[$doc_type])) {
if ($type == 'customer_invoice') {
$payment_element = 'paiement_facture';
$fk_payment_element = 'fk_paiement';
$fk_element = 'fk_facture';
} elseif ($type == 'supplier_invoice') {
$payment_element = 'paiementfourn_facturefourn';
$fk_payment_element = 'fk_paiementfourn';
$fk_element = 'fk_facturefourn';
} else {
$langs->load('errors'); $langs->load('errors');
$this->errors[] = $langs->trans('ErrorBadParameters'); $this->errors[] = $langs->trans('ErrorBadParameters');
return -1; return -1;
} }
// Get payment lines $doc_type_info = self::$doc_type_infos[$doc_type];
$sql = "SELECT DISTINCT pe2.$fk_payment_element, pe2.$fk_element";
$sql .= " FROM " . MAIN_DB_PREFIX . "$payment_element AS pe";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "$payment_element AS pe2 ON pe2.$fk_element = pe.$fk_element";
$sql .= " WHERE pe.$fk_payment_element IN (" . $this->db->sanitize(implode(',', $payment_ids)) . ")";
dol_syslog(__METHOD__ . " - Get payment lines", LOG_DEBUG); // Get document lines
$current_document_ids = array();
$link_by_element = array();
$element_by_link = array();
foreach ($doc_type_info['linked_info'] as $linked_info) {
$sql = "SELECT DISTINCT tl2." . $linked_info['fk_link'] . " AS fk_link, tl2." . $linked_info['fk_doc'] . " AS fk_doc";
$sql .= " FROM " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl";
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl2 ON tl2." . $linked_info['fk_link'] . " = tl." . $linked_info['fk_link'];
$sql .= " WHERE tl." . $linked_info['fk_doc'] . " IN (" . $this->db->sanitize(implode(',', $document_ids)) . ")";
dol_syslog(__METHOD__ . " - Get document lines", LOG_DEBUG);
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if (!$resql) { if (!$resql) {
$this->errors[] = "Error " . $this->db->lasterror(); $this->errors[] = "Error " . $this->db->lasterror();
return -1; return -1;
} }
$current_payment_ids = array(); $is_fk_link_is_also_fk_doc = !empty($linked_info['is_fk_link_is_also_fk_doc']);
$payment_by_element = array();
$element_by_payment = array();
while ($obj = $this->db->fetch_object($resql)) { while ($obj = $this->db->fetch_object($resql)) {
$current_payment_ids[$obj->$fk_payment_element] = $obj->$fk_payment_element; $current_document_ids[$obj->fk_doc] = $obj->fk_doc;
$element_by_payment[$obj->$fk_payment_element][$obj->$fk_element] = $obj->$fk_element;
$payment_by_element[$obj->$fk_element][$obj->$fk_payment_element] = $obj->$fk_payment_element; $link_key = $linked_info['prefix'] . $obj->fk_link;
$element_by_link[$link_key][$obj->fk_doc] = $obj->fk_doc;
$link_by_element[$obj->fk_doc][$link_key] = $link_key;
if ($is_fk_link_is_also_fk_doc) {
$element_by_link[$link_key][$obj->fk_link] = $obj->fk_link;
$link_by_element[$obj->fk_link][$link_key] = $link_key;
}
} }
$this->db->free($resql); $this->db->free($resql);
if (count(array_diff($payment_ids, $current_payment_ids))) {
return $this->getLinkedPaymentByGroup($current_payment_ids, $type);
} }
return $this->getGroupElements($payment_by_element, $element_by_payment); if (count(array_diff($document_ids, $current_document_ids))) {
return $this->getLinkedDocumentByGroup($current_document_ids, $doc_type);
}
return $this->getGroupElements($link_by_element, $element_by_link);
} }
/** /**
* Get payment ids grouped by payment id and element id in common * Get element ids grouped by link or element in common
* *
* @param array $payment_by_element List of payment ids by element id * @param array $link_by_element List of payment ids by link key
* @param array $element_by_payment List of element ids by payment id * @param array $element_by_link List of element ids by link key
* @param int $element_id Element Id (used for recursive function) * @param string $link_key Link key (used for recursive function)
* @param array $current_group Current group (used for recursive function) * @param array $current_group Current group (used for recursive function)
* @return array List of payment ids grouped by payment id and element id in common * @return array List of element ids grouped by link or element in common
*/ */
public function getGroupElements(&$payment_by_element, &$element_by_payment, $element_id = 0, &$current_group = array()) public function getGroupElements(&$link_by_element, &$element_by_link, $link_key = '', &$current_group = array())
{ {
$grouped_payments = array(); $grouped_elements = array();
if ($element_id > 0 && !isset($payment_by_element[$element_id])) { if (!empty($link_key) && !isset($element_by_link[$link_key])) {
// Return if specific element id not found // Return if specific link key not found
return $grouped_payments; return $grouped_elements;
} }
$save_payment_by_element = null; if (empty($link_key)) {
$save_element_by_payment = null;
if ($element_id == 0) {
// Save list when is the begin of recursive function // Save list when is the begin of recursive function
$save_payment_by_element = $payment_by_element; $save_link_by_element = $link_by_element;
$save_element_by_payment = $element_by_payment; $save_element_by_link = $element_by_link;
} }
do { do {
// Get current element id, get this payment id list and delete the entry // Get current element id, get this payment id list and delete the entry
$current_element_id = $element_id > 0 ? $element_id : array_keys($payment_by_element)[0]; $current_link_key = !empty($link_key) ? $link_key : array_keys($element_by_link)[0];
$payment_ids = $payment_by_element[$current_element_id]; $element_ids = $element_by_link[$current_link_key];
unset($payment_by_element[$current_element_id]); unset($element_by_link[$current_link_key]);
foreach ($payment_ids as $payment_id) { foreach ($element_ids as $element_id) {
// Continue if payment id in not found // Continue if element id in not found
if (!isset($element_by_payment[$payment_id])) continue; if (!isset($link_by_element[$element_id])) continue;
// Set the payment in the current group // Set the element in the current group
$current_group[$payment_id] = $payment_id; $current_group[$element_id] = $element_id;
// Get current element ids, get this payment id list and delete the entry // Get current link keys, get this element id list and delete the entry
$element_ids = $element_by_payment[$payment_id]; $link_keys = $link_by_element[$element_id];
unset($element_by_payment[$payment_id]); unset($link_by_element[$element_id]);
// Set payment id on the current group for each element id of the payment // Set element id on the current group for each link key of the element
foreach ($element_ids as $id) { foreach ($link_keys as $key) {
$this->getGroupElements($payment_by_element, $element_by_payment, $id, $current_group); $this->getGroupElements($link_by_element, $element_by_link, $key, $current_group);
} }
} }
if ($element_id == 0) { if (empty($link_key)) {
// Save current group and reset the current group when is the begin of recursive function // Save current group and reset the current group when is the begin of recursive function
$grouped_payments[] = $current_group; $grouped_elements[] = $current_group;
$current_group = array(); $current_group = array();
} }
} while (!empty($payment_by_element) && $element_id == 0); } while (!empty($element_by_link) && empty($link_key));
if ($element_id == 0) { if (empty($link_key)) {
// Restore list when is the begin of recursive function // Restore list when is the begin of recursive function
$payment_by_element = $save_payment_by_element; $link_by_element = $save_link_by_element;
$element_by_payment = $save_element_by_payment; $element_by_link = $save_element_by_link;
} }
return $grouped_payments; return $grouped_elements;
} }
} }

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