From c735653180965a040d1356def8722ae0789b3b8d Mon Sep 17 00:00:00 2001 From: atm-greg Date: Thu, 26 Jul 2018 13:49:12 +0200 Subject: [PATCH 01/44] add postgresql to test + add test on installation process --- .travis.yml | 69 +++++++++++++++++++++++++++++++++------- htdocs/install/step1.php | 1 + htdocs/install/step2.php | 9 ++++++ 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 10a2b6e8347..a4d6dbc92d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,16 +64,6 @@ matrix: - php: nightly # We exclude some combinations not usefull to save Travis CPU exclude: - - php: '5.4' - env: DB=postgresql - - php: '5.5' - env: DB=postgresql - - php: '5.6' - env: DB=postgresql - - php: '7.0' - env: DB=postgresql - - php: '7.1' - env: DB=postgresql - php: hhvm env: DB=postgresql - php: nightly @@ -201,7 +191,7 @@ before_script: mysql -e 'CREATE DATABASE IF NOT EXISTS travis;' mysql -e 'GRANT ALL PRIVILEGES ON travis.* TO travis@127.0.0.1;' mysql -e 'FLUSH PRIVILEGES;' - mysql -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql + #mysql -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql fi if [ "$DB" = 'postgresql' ]; then #pgsql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql @@ -298,6 +288,63 @@ script: # TODO: Check CSS (csslint?) +- | + export INSTALL_FORCED_FILE=htdocs/install/install.forced.php + echo "Setting up Dolibarr $INSTALL_FORCED_FILE" + # Ensure we catch errors + set +e + echo ' $INSTALL_FORCED_FILE + echo '$'force_install_noedit=2';' >> $INSTALL_FORCED_FILE + if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ]; then + echo '$'force_install_type=\'mysqli\'';' >> $INSTALL_FORCED_FILE + fi + if [ "$DB" = 'postgresql' ]; then + echo '$'force_install_type=\'pgsql\'';' >> $INSTALL_FORCED_FILE + fi + echo '$'force_install_dbserver=\'127.0.0.1\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_database=\'travis\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_databaselogin=\'travis\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_databasepass=\'\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_port=\'5432\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_prefix=\'llx_\'';' >> $INSTALL_FORCED_FILE + echo '$'force_install_createdatabase=false';' >> $INSTALL_FORCED_FILE + echo '$'force_install_createuser=false';' >> $INSTALL_FORCED_FILE + echo '$'force_install_mainforcehttps=false';' >> $INSTALL_FORCED_FILE + echo '$'force_install_main_data_root=\'$TRAVIS_BUILD_DIR/htdocs\'';' >> $INSTALL_FORCED_FILE + # TODO: SQLite + #cat $INSTALL_FORCED_FILE + echo "Installation test" + cd htdocs/install + php step1.php $TRAVIS_BUILD_DIR/htdocs > $TRAVIS_BUILD_DIR/install.log + php step2.php set >> $TRAVIS_BUILD_DIR/install.log + if [ "$?" -ne "0" ]; then + echo "SORRY, AN ERROR OCCURED DURING INSTALLATION PROCESS" + exit 1 + fi + cd ../.. + rm $INSTALL_FORCED_FILE + #cat $TRAVIS_BUILD_DIR/install.log + set +e + echo + + - | + echo "Setting up database to test migrations" + if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ] || [ "$DB" = 'postgresql' ]; then + echo "MySQL" + mysql -e 'DROP DATABASE IF EXISTS travis;' + mysql -e 'CREATE DATABASE IF NOT EXISTS travis;' + mysql -e 'GRANT ALL PRIVILEGES ON travis.* TO travis@127.0.0.1;' + mysql -e 'FLUSH PRIVILEGES;' + mysql -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql + fi + if [ "$DB" = 'postgresql' ]; then + #pgsql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql + #pgloader mysql://root:pass@127.0.0.1/base postgresql://dolibarrowner@127.0.0.1/dolibarr + pgloader mysql://root@127.0.0.1/travis postgresql:///travis + fi + # TODO: SQLite + echo + - | echo "Upgrading Dolibarr" # Ensure we catch errors diff --git a/htdocs/install/step1.php b/htdocs/install/step1.php index 838ef34afa3..add57f5d853 100644 --- a/htdocs/install/step1.php +++ b/htdocs/install/step1.php @@ -82,6 +82,7 @@ if (@file_exists($forcedfile)) { // If forced install is enabled, let's replace post values. These are empty because form fields are disabled. if ($force_install_noedit) { $main_dir = detect_dolibarr_main_document_root(); + if (!empty($argv[1])) $main_dir = $argv[1]; // override when executing the script in command line if (!empty($force_install_main_data_root)) { $main_data_dir = $force_install_main_data_root; } else { diff --git a/htdocs/install/step2.php b/htdocs/install/step2.php index 44661c191d7..e0e7d71c25d 100644 --- a/htdocs/install/step2.php +++ b/htdocs/install/step2.php @@ -65,6 +65,8 @@ if ($conffile == "/etc/dolibarr/conf.php") $forcedfile="/etc/dolibarr/install.fo if (@file_exists($forcedfile)) { $useforcedwizard = true; include_once $forcedfile; + // test for travis + if (!empty($argv[1]) && $argv[1] == "set") $action = "set"; } dolibarr_install_syslog("--- step2: entering step2.php page"); @@ -620,8 +622,15 @@ else print 'Parameter action=set not defined'; } +$ret=0; +if (! $ok && isset($argv[1])) $ret=1; +dol_syslog("Exit ".$ret); + dolibarr_install_syslog("--- step2: end"); pFooter($ok?0:1,$setuplang); if (isset($db) && is_object($db)) $db->close(); + +// Return code if ran from command line +if ($ret) exit($ret); From 9a080a5d62b34dfef364f4d9cf44c350fca398df Mon Sep 17 00:00:00 2001 From: atm-greg Date: Thu, 26 Jul 2018 13:53:44 +0200 Subject: [PATCH 02/44] add sourceline for fastcgi --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index a4d6dbc92d2..99bdd8f083f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,7 @@ addons: - apache2 # mod_php is not supported by Travis. Add fcgi. We install FPM later on. - libapache2-mod-fastcgi + - sourceline: 'deb http://http.us.debian.org/debian main non-free' # We need pgloader for import mysql database into pgsql - pgloader From c8b035659cb21e2c7dd0f72cca6dd9bae5a7ce67 Mon Sep 17 00:00:00 2001 From: atm-greg Date: Thu, 26 Jul 2018 14:04:22 +0200 Subject: [PATCH 03/44] add sourceline for fastcgi on the right place --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99bdd8f083f..9c7f562de23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,13 +21,13 @@ addons: - postgresql - sourceline: 'deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main' - key_url: 'https://www.postgresql.org/media/keys/ACCC4CF8.asc' + - sourceline: 'deb http://http.us.debian.org/debian main non-free' packages: # We need a webserver to test the webservices # Let's install Apache with. - apache2 # mod_php is not supported by Travis. Add fcgi. We install FPM later on. - libapache2-mod-fastcgi - - sourceline: 'deb http://http.us.debian.org/debian main non-free' # We need pgloader for import mysql database into pgsql - pgloader From aef850f6d3c5af5f6b98d5b6a882480eff045891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 19 May 2019 21:12:22 +0200 Subject: [PATCH 04/44] zapier for dolibarr --- dev/examples/zapier/.gitignore | 7 + dev/examples/zapier/.travis.yml | 7 + dev/examples/zapier/action.json | 56 ++ dev/examples/zapier/authentication.js | 76 ++ dev/examples/zapier/creates/thirdparty.js | 83 ++ dev/examples/zapier/index.js | 72 ++ dev/examples/zapier/package-lock.json | 405 +++++++++ dev/examples/zapier/package.json | 24 + dev/examples/zapier/resources/resources.js | 0 dev/examples/zapier/searches/thirdparty.js | 66 ++ dev/examples/zapier/test/index.js | 17 + dev/examples/zapier/triggers/action.js | 156 ++++ dev/examples/zapier/triggers/order.js | 148 ++++ dev/examples/zapier/triggers/thirdparty.js | 175 ++++ htdocs/core/modules/modZapier.class.php | 375 +++++++++ ...face_99_modZapier_ZapierTriggers.class.php | 567 +++++++++++++ htdocs/langs/en_US/zapier.lang | 53 ++ htdocs/langs/fr_FR/zapier.lang | 48 ++ htdocs/zapier/admin/about.php | 76 ++ htdocs/zapier/admin/setup.php | 124 +++ htdocs/zapier/class/api_zapier.class.php | 382 +++++++++ htdocs/zapier/class/hook.class.php | 773 ++++++++++++++++++ htdocs/zapier/hook_agenda.php | 261 ++++++ htdocs/zapier/hook_card.php | 471 +++++++++++ htdocs/zapier/hook_document.php | 166 ++++ htdocs/zapier/hook_list.php | 642 +++++++++++++++ htdocs/zapier/hook_note.php | 164 ++++ htdocs/zapier/img/object_hook.png | Bin 0 -> 360 bytes .../zapier/img/object_zapierfordolibarr.png | Bin 0 -> 360 bytes htdocs/zapier/img/zapier.png | Bin 0 -> 683 bytes htdocs/zapier/lib/zapier.lib.php | 58 ++ htdocs/zapier/lib/zapier_hook.lib.php | 83 ++ htdocs/zapier/sql/llx_zapier_hook.key.sql | 22 + htdocs/zapier/sql/llx_zapier_hook.sql | 29 + .../sql/llx_zapier_hook_extrafields.sql | 23 + htdocs/zapier/zapierindex.php | 238 ++++++ 36 files changed, 5847 insertions(+) create mode 100644 dev/examples/zapier/.gitignore create mode 100644 dev/examples/zapier/.travis.yml create mode 100644 dev/examples/zapier/action.json create mode 100644 dev/examples/zapier/authentication.js create mode 100644 dev/examples/zapier/creates/thirdparty.js create mode 100644 dev/examples/zapier/index.js create mode 100644 dev/examples/zapier/package-lock.json create mode 100644 dev/examples/zapier/package.json create mode 100644 dev/examples/zapier/resources/resources.js create mode 100644 dev/examples/zapier/searches/thirdparty.js create mode 100644 dev/examples/zapier/test/index.js create mode 100644 dev/examples/zapier/triggers/action.js create mode 100644 dev/examples/zapier/triggers/order.js create mode 100644 dev/examples/zapier/triggers/thirdparty.js create mode 100644 htdocs/core/modules/modZapier.class.php create mode 100644 htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php create mode 100644 htdocs/langs/en_US/zapier.lang create mode 100644 htdocs/langs/fr_FR/zapier.lang create mode 100644 htdocs/zapier/admin/about.php create mode 100644 htdocs/zapier/admin/setup.php create mode 100644 htdocs/zapier/class/api_zapier.class.php create mode 100644 htdocs/zapier/class/hook.class.php create mode 100644 htdocs/zapier/hook_agenda.php create mode 100644 htdocs/zapier/hook_card.php create mode 100644 htdocs/zapier/hook_document.php create mode 100644 htdocs/zapier/hook_list.php create mode 100644 htdocs/zapier/hook_note.php create mode 100644 htdocs/zapier/img/object_hook.png create mode 100644 htdocs/zapier/img/object_zapierfordolibarr.png create mode 100644 htdocs/zapier/img/zapier.png create mode 100644 htdocs/zapier/lib/zapier.lib.php create mode 100644 htdocs/zapier/lib/zapier_hook.lib.php create mode 100644 htdocs/zapier/sql/llx_zapier_hook.key.sql create mode 100644 htdocs/zapier/sql/llx_zapier_hook.sql create mode 100644 htdocs/zapier/sql/llx_zapier_hook_extrafields.sql create mode 100644 htdocs/zapier/zapierindex.php diff --git a/dev/examples/zapier/.gitignore b/dev/examples/zapier/.gitignore new file mode 100644 index 00000000000..d81e057e6d3 --- /dev/null +++ b/dev/examples/zapier/.gitignore @@ -0,0 +1,7 @@ +build +docs +node_modules +*.log +.environment +.env +.zapierapprc diff --git a/dev/examples/zapier/.travis.yml b/dev/examples/zapier/.travis.yml new file mode 100644 index 00000000000..5b8db5906a8 --- /dev/null +++ b/dev/examples/zapier/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - 8.10.0 +before_script: 'npm install -g zapier-platform-cli' +script: 'zapier test' +notifications: + email: false diff --git a/dev/examples/zapier/action.json b/dev/examples/zapier/action.json new file mode 100644 index 00000000000..e3aa4e69881 --- /dev/null +++ b/dev/examples/zapier/action.json @@ -0,0 +1,56 @@ +{ + "table_rowid": "id", + "id": 6764, + "ref": null, + "type_id": "5", + "type_code": "AC_RDV", + "type": null, + "type_color": null, + "code": null, + "label": "azerty", + "datec": null, + "datem": null, + "authorid": null, + "usermodid": null, + "datep": 1555365600, + "datef": 1555538399, + "durationp": 172799, + "fulldayevent": 1, + "punctual": 1, + "percentage": "-1", + "location": "", + "transparency": 1, + "priority": 0, + "userassigned": { + "1": { + "id": "1", + "transparency": 1 + } + }, + "userownerid": "1", + "userdoneid": null, + "usertodo": null, + "userdone": null, + "socid": null, + "contactid": null, + "elementtype": "", + "icalname": null, + "icalcolor": null, + "actions": [], + "email_msgid": null, + "email_from": null, + "email_sender": null, + "email_to": null, + "email_tocc": null, + "email_tobcc": null, + "email_subject": null, + "errors_to": null, + "import_key": null, + "linkedObjectsIds": null, + "fk_project": 0, + "modelpdf": null, + "note_public": null, + "note_private": null, + "note": "wxcvbn", + "duree": 0 +} \ No newline at end of file diff --git a/dev/examples/zapier/authentication.js b/dev/examples/zapier/authentication.js new file mode 100644 index 00000000000..8c373d0b78b --- /dev/null +++ b/dev/examples/zapier/authentication.js @@ -0,0 +1,76 @@ +const testAuth = (z , bundle) => { + const url = bundle.authData.url+'/api/index.php/login'; + // Normally you want to make a request to an endpoint that is either specifically designed to test auth, or one that + // every user will have access to, such as an account or profile endpoint like /me. + // In this example, we'll hit httpbin, which validates the Authorization Header against the arguments passed in the URL path + const promise = z.request({ + url: url, + }); + + // This method can return any truthy value to indicate the credentials are valid. + // Raise an error to show + return promise.then((response) => { + if (response.status === 401) { + throw new Error('The Session Key you supplied is invalid'); + } + return response; + }); +}; + +const getSessionKey = (z, bundle) => { + const url = bundle.authData.url + '/api/index.php/login'; + + const promise = z.request({ + method: 'POST', + url: url, + body: { + login: bundle.authData.login, + password: bundle.authData.password, + } + }); + + return promise.then((response) => { + if (response.status === 401) { + throw new Error('The login/password you supplied is invalid'); + } + const json = JSON.parse(response.content); + return { + sessionKey: json.success.token || 'secret' + }; + }); +}; + +module.exports = { + type: 'session', + // Define any auth fields your app requires here. The user will be prompted to enter this info when + // they connect their account. + fields: [ + { + key: 'url', + label: 'Url of service', + required: true, + type: 'string' + }, + { + key: 'login', + label: 'Login', + required: true, + type: 'string' + }, + { + key: 'password', + label: 'Password', + required: true, + type: 'password' + } + ], + // The test method allows Zapier to verify that the credentials a user provides are valid. We'll execute this + // method whenever a user connects their account for the first time. + test: testAuth, + // The method that will exchange the fields provided by the user for session credentials. + sessionConfig: { + perform: getSessionKey + }, + // assuming "login" is a key returned from the test + connectionLabel: '{{login}}' +}; diff --git a/dev/examples/zapier/creates/thirdparty.js b/dev/examples/zapier/creates/thirdparty.js new file mode 100644 index 00000000000..05928c3f15b --- /dev/null +++ b/dev/examples/zapier/creates/thirdparty.js @@ -0,0 +1,83 @@ +// create a particular thirdparty by name +const createThirdparty = async (z, bundle) => { + const apiurl = bundle.authData.url + '/api/index.php/thirdparties'; + + const response = await z.request({ + method: 'POST', + url: apiurl, + body: JSON.stringify({ + name: bundle.inputData.name, + name_alias: bundle.inputData.name_alias, + address: bundle.inputData.address, + zip: bundle.inputData.zip, + town: bundle.inputData.town, + email: bundle.inputData.email, + client: bundle.inputData.client, + fournisseur: bundle.inputData.fournisseur, + code_client: bundle.inputData.code_client, + code_fournisseur: bundle.inputData.code_fournisseur, + sens: 'fromzapier' + }) + }); + const result = z.JSON.parse(response.content); + // api returns an integer when ok, a json when ko + return result.response || {id: response}; +}; + +module.exports = { + key: 'thirdparty', + noun: 'Thirdparty', + + display: { + label: 'Create Thirdparty', + description: 'Creates a thirdparty.' + }, + + operation: { + inputFields: [ + {key: 'name', required: true}, + {key: 'name_alias', required: false}, + {key: 'address', required: false}, + {key: 'zip', required: false}, + {key: 'town', required: false}, + {key: 'email', required: false}, + {key: 'client', type: 'integer', required: false}, + {key: 'fournisseur', type: 'integer', required: false}, + {key: 'code_client', required: false}, + {key: 'code_fournisseur', required: false} + ], + perform: createThirdparty, + + sample: { + id: 1, + name: 'DUPOND', + name_alias: 'DUPOND Ltd', + address: 'Rue des Canaries', + zip: '34090', + town: 'MONTPELLIER', + phone: '0123456789', + fax: '2345678901', + email: 'robot@domain.com', + client: 1, + fournisseur: 0, + code_client: 'CU1903-1234', + code_fournisseur: 'SU1903-2345' + }, + + outputFields: [ + {key: 'id', label: 'ID'}, + {key: 'name', label: 'Name'}, + {key: 'name_alias', label: 'Name alias'}, + {key: 'address', label: 'Address'}, + {key: 'zip', label: 'Zip'}, + {key: 'town', label: 'Town'}, + {key: 'phone', label: 'Phone'}, + {key: 'fax', label: 'Fax'}, + {key: 'email', label: 'Email'}, + {key: 'client', label: 'Customer/Prospect 0/1/2/3'}, + {key: 'fournisseur', label: 'Supplier 0/1'}, + {key: 'code_client', label: 'Customer code'}, + {key: 'code_fournisseur', label: 'Supplier code'} + ] + } +}; \ No newline at end of file diff --git a/dev/examples/zapier/index.js b/dev/examples/zapier/index.js new file mode 100644 index 00000000000..cd62d6cd7ee --- /dev/null +++ b/dev/examples/zapier/index.js @@ -0,0 +1,72 @@ +const triggerThirdparty = require('./triggers/thirdparty'); +const triggerOrder = require('./triggers/order'); +const triggerAction = require('./triggers/action'); + +const searchThirdparty = require('./searches/thirdparty'); + +const createThirdparty = require('./creates/thirdparty'); + +const authentication = require('./authentication'); + +// To include the session key header on all outbound requests, simply define a function here. +// It runs runs before each request is sent out, allowing you to make tweaks to the request in a centralized spot +const includeSessionKeyHeader = (request, z, bundle) => { + if (bundle.authData.sessionKey) { + request.headers = request.headers || {}; + request.headers['DOLAPIKEY'] = bundle.authData.sessionKey; + } + return request; +}; + +// If we get a response and it is a 401, we can raise a special error telling Zapier to retry this after another exchange. +const sessionRefreshIf401 = (response, z, bundle) => { + if (bundle.authData.sessionKey) { + if (response.status === 401) { + throw new z.errors.RefreshAuthError('Session apikey needs refreshing.'); + } + } + return response; +}; + +// We can roll up all our behaviors in an App. +const App = { + // This is just shorthand to reference the installed dependencies you have. Zapier will + // need to know these before we can upload + version: require('./package.json').version, + platformVersion: require('zapier-platform-core').version, + + authentication: authentication, + + // beforeRequest & afterResponse are optional hooks into the provided HTTP client + beforeRequest: [ + includeSessionKeyHeader + ], + + afterResponse: [ + sessionRefreshIf401 + ], + + // If you want to define optional resources to simplify creation of triggers, searches, creates - do that here! + resources: { + }, + + // If you want your trigger to show up, you better include it here! + triggers: { + [triggerThirdparty.key]: triggerThirdparty, + [triggerOrder.key]: triggerOrder, + [triggerAction.key]: triggerAction + }, + + // If you want your searches to show up, you better include it here! + searches: { + [searchThirdparty.key]: searchThirdparty, + }, + + // If you want your creates to show up, you better include it here! + creates: { + [createThirdparty.key]: createThirdparty, + } +}; + +// Finally, export the app. +module.exports = App; diff --git a/dev/examples/zapier/package-lock.json b/dev/examples/zapier/package-lock.json new file mode 100644 index 00000000000..7483948d5b8 --- /dev/null +++ b/dev/examples/zapier/package-lock.json @@ -0,0 +1,405 @@ +{ + "name": "Dolibarr", + "version": "1.0.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "8.10.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.20.tgz", + "integrity": "sha512-M7x8+5D1k/CuA6jhiwuSCmE8sbUWJF0wYsjcig9WrXvwUI5ArEoUBdOXpV4JcEMrLp02/QbDjw+kI+vQeKyQgg==", + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dotenv": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", + "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "json-tryparse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/json-tryparse/-/json-tryparse-1.0.5.tgz", + "integrity": "sha1-Khy6CLTjEjNo+p+2o01GQwBFeyc=" + }, + "jsonschema": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.1.1.tgz", + "integrity": "sha1-PO3o4+QR03eHLu+8n98mODy8Ptk=" + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "requires": { + "mime-db": "~1.38.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node-fetch": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", + "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + }, + "should": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", + "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", + "dev": true, + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", + "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "zapier-platform-core": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/zapier-platform-core/-/zapier-platform-core-8.0.1.tgz", + "integrity": "sha512-vuAe7JkFQ88AeQ//NwwNEh8ZjiZr30GRWtwYo7Wo/nx1cqZwq+CRc9zJU2WRrhJfJOtOOTUF6w+pArBTtMOC5A==", + "requires": { + "@types/node": "8.10.20", + "bluebird": "3.5.0", + "content-disposition": "0.5.2", + "dotenv": "5.0.1", + "form-data": "2.3.2", + "lodash": "4.17.11", + "node-fetch": "1.7.1", + "oauth-sign": "0.9.0", + "semver": "5.6.0", + "zapier-platform-schema": "8.0.1" + } + }, + "zapier-platform-schema": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/zapier-platform-schema/-/zapier-platform-schema-8.0.1.tgz", + "integrity": "sha512-97KJ0xVLtpU4BiXVaMTPQpiA0T6CQIEzWfzAWwJAWbu5336+6DMFUzDWN4bANBeD3CIsRHHPcZkP8n/17U05ag==", + "requires": { + "jsonschema": "1.1.1", + "lodash": "4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + } + } + } + } +} diff --git a/dev/examples/zapier/package.json b/dev/examples/zapier/package.json new file mode 100644 index 00000000000..30ea4939915 --- /dev/null +++ b/dev/examples/zapier/package.json @@ -0,0 +1,24 @@ +{ + "name": "Dolibarr", + "version": "1.0.2", + "description": "An app for connecting Dolibarr to the Zapier platform.", + "repository": "frederic34/ZapierForDolibarr", + "homepage": "https://netlogic-dev.fr/", + "author": "Frédéric France ", + "license": "BSD-3-Clause", + "main": "index.js", + "scripts": { + "test": "mocha --recursive" + }, + "engines": { + "node": "8.10.0", + "npm": ">=5.6.0" + }, + "dependencies": { + "zapier-platform-core": "8.0.1" + }, + "devDependencies": { + "mocha": "^5.2.0", + "should": "^13.2.0" + } +} diff --git a/dev/examples/zapier/resources/resources.js b/dev/examples/zapier/resources/resources.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dev/examples/zapier/searches/thirdparty.js b/dev/examples/zapier/searches/thirdparty.js new file mode 100644 index 00000000000..c71c2965789 --- /dev/null +++ b/dev/examples/zapier/searches/thirdparty.js @@ -0,0 +1,66 @@ +module.exports = { + key: 'thirdparty', + + // You'll want to provide some helpful display labels and descriptions + // for users. Zapier will put them into the UX. + noun: 'Thirdparty', + display: { + label: 'Find a Thirdparty', + description: 'Search for thirdparty.' + }, + + // `operation` is where we make the call to your API to do the search + operation: { + // This search only has one search field. Your searches might have just one, or many + // search fields. + inputFields: [ + { + key: 'name', + type: 'string', + label: 'Name', + helpText: 'Name to limit to the search to (i.e. The company or %company%).' + } + ], + + perform: (z, bundle) => { + const url = bundle.authData.url + '/api/index.php/thirdparties/'; + + // Put the search value in a query param. The details of how to build + // a search URL will depend on how your API works. + const options = { + params: { + sqlfilters: "t.nom like \'%"+bundle.inputData.name+"%\'" + } + }; + + return z.request(url, options).then(response => JSON.parse(response.content)); + }, + + // In cases where Zapier needs to show an example record to the user, but we are unable to get a live example + // from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of + // returned records, and have obviously dummy values that we can show to any user. + sample: { + id: 1, + createdAt: 1472069465, + name: 'DOE', + firstname: 'John', + authorId: 1, + directions: '1. Boil Noodles\n2.Serve with sauce', + style: 'italian' + }, + + // If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom + // field definitions. The result will be used to augment the sample. + // outputFields: () => { return []; } + // Alternatively, a static field definition should be provided, to specify labels for the fields + outputFields: [ + {key: 'id', label: 'ID'}, + {key: 'createdAt', label: 'Created At'}, + {key: 'name', label: 'Name'}, + {key: 'firstname', label: 'Firstname'}, + {key: 'directions', label: 'Directions'}, + {key: 'authorId', label: 'Author ID'}, + {key: 'style', label: 'Style'} + ] + } +}; diff --git a/dev/examples/zapier/test/index.js b/dev/examples/zapier/test/index.js new file mode 100644 index 00000000000..220e48f540f --- /dev/null +++ b/dev/examples/zapier/test/index.js @@ -0,0 +1,17 @@ +require('should'); + +const zapier = require('zapier-platform-core'); + +// Use this to make test calls into your app: +const App = require('../index'); +const appTester = zapier.createAppTester(App); + +describe('My App', () => { + + it('should test something', (done) => { + const x = 1; + x.should.eql(1); + done(); + }); + +}); diff --git a/dev/examples/zapier/triggers/action.js b/dev/examples/zapier/triggers/action.js new file mode 100644 index 00000000000..d387d88ec1f --- /dev/null +++ b/dev/examples/zapier/triggers/action.js @@ -0,0 +1,156 @@ +const subscribeHook = (z, bundle) => { + // `z.console.log()` is similar to `console.log()`. + z.console.log('suscribing hook!'); + + // bundle.targetUrl has the Hook URL this app should call when an action is created. + const data = { + url: bundle.targetUrl, + event: bundle.event, + module: 'action', + action: bundle.inputData.action + }; + + const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: url, + method: 'POST', + body: JSON.stringify(data) + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const unsubscribeHook = (z, bundle) => { + // bundle.subscribeData contains the parsed response JSON from the subscribe + // request made initially. + z.console.log('unsuscribing hook!'); + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, + method: 'DELETE', + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const getAction = (z, bundle) => { + // bundle.cleanedRequest will include the parsed JSON object (if it's not a + // test poll) and also a .querystring property with the URL's query string. + const action = { + id: bundle.cleanedRequest.id, + ref: bundle.cleanedRequest.ref, + ref_client: bundle.cleanedRequest.ref_client, + name: bundle.cleanedRequest.name, + firstname: bundle.cleanedRequest.firstname, + usertodo__name: bundle.cleanedRequest.usertodo__name, + location: bundle.cleanedRequest.location, + label: bundle.cleanedRequest.label, + authorId: bundle.cleanedRequest.authorId, + createdAt: bundle.cleanedRequest.createdAt, + module: bundle.cleanedRequest.module, + datep: bundle.cleanedRequest.datep, + datef: bundle.cleanedRequest.datef, + fulldayevent: bundle.cleanedRequest.fulldayevent, + transparency: bundle.cleanedRequest.transparency, + icalname: bundle.cleanedRequest.icalname, + icalcolor: bundle.cleanedRequest.icalcolor, + note: bundle.cleanedRequest.note, + note_public: bundle.cleanedRequest.note_public, + note_private: bundle.cleanedRequest.note_private, + action: bundle.cleanedRequest.action + }; + + return [action]; +}; + +const getFallbackRealAction = (z, bundle) => { + // For the test poll, you should get some real data, to aid the setup process. + const module = bundle.inputData.module; + const options = { + url: bundle.authData.url + '/api/index.php/agendaevents/0', + }; + + return z.request(options).then((response) => [JSON.parse(response.content)]); +}; + +// const getActionsChoices = (z, bundle) => { +// // For the test poll, you should get some real data, to aid the setup process. +// const module = bundle.inputData.module; +// const options = { +// url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/actions', +// }; + +// return z.request(options).then((response) => JSON.parse(response.content)); +// }; + +// We recommend writing your actions separate like this and rolling them +// into the App definition at the end. +module.exports = { + key: 'action', + + // You'll want to provide some helpful display labels and descriptions + // for users. Zapier will put them into the UX. + noun: 'Action', + display: { + label: 'New Agenda', + description: 'Trigger when a new agenda with action is done in Dolibarr.' + }, + + // `operation` is where the business logic goes. + operation: { + + // `inputFields` can define the fields a user could provide, + // we'll pass them in as `bundle.inputData` later. + inputFields: [ + { + key: 'action', + type: 'string', + helpText: 'Which action of agenda this should trigger on.', + choices: { + create: "Create", + modify: "Modify", + delete: "Delete", + } + } + ], + + type: 'hook', + + performSubscribe: subscribeHook, + performUnsubscribe: unsubscribeHook, + + perform: getAction, + performList: getFallbackRealAction, + + // In cases where Zapier needs to show an example record to the user, but we are unable to get a live example + // from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of + // returned records, and have obviously dummy values that we can show to any user. + sample: { + id: 1, + createdAt: 1472069465, + name: 'Best Spagetti Ever', + authorId: 1, + action: 'create' + }, + + // If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom + // field definitions. The result will be used to augment the sample. + // outputFields: () => { return []; } + // Alternatively, a static field definition should be provided, to specify labels for the fields + outputFields: [ + {key: 'id', label: 'ID'}, + {key: 'createdAt', label: 'Created At'}, + {key: 'name', label: 'Name'}, + {key: 'usertodo__name', label: 'UserToDo Name'}, + {key: 'authorId', label: 'Author ID'}, + {key: 'action', label: 'Action'} + ] + } +}; diff --git a/dev/examples/zapier/triggers/order.js b/dev/examples/zapier/triggers/order.js new file mode 100644 index 00000000000..6262d734edc --- /dev/null +++ b/dev/examples/zapier/triggers/order.js @@ -0,0 +1,148 @@ +const subscribeHook = (z, bundle) => { + // `z.console.log()` is similar to `console.log()`. + z.console.log('suscribing hook!'); + + // bundle.targetUrl has the Hook URL this app should call when an action is created. + const data = { + url: bundle.targetUrl, + event: bundle.event, + module: 'order', + action: bundle.inputData.action + }; + + const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: url, + method: 'POST', + body: JSON.stringify(data) + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const unsubscribeHook = (z, bundle) => { + // bundle.subscribeData contains the parsed response JSON from the subscribe + // request made initially. + z.console.log('unsuscribing hook!'); + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, + method: 'DELETE', + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const getOrder = (z, bundle) => { + // bundle.cleanedRequest will include the parsed JSON object (if it's not a + // test poll) and also a .querystring property with the URL's query string. + const order = { + id: bundle.cleanedRequest.id, + ref: bundle.cleanedRequest.ref, + ref_client: bundle.cleanedRequest.ref_client, + name: bundle.cleanedRequest.name, + firstname: bundle.cleanedRequest.firstname, + directions: bundle.cleanedRequest.directions, + authorId: bundle.cleanedRequest.authorId, + createdAt: bundle.cleanedRequest.createdAt, + note_public: bundle.cleanedRequest.note_public, + note_private: bundle.cleanedRequest.note_private, + action: bundle.cleanedRequest.action + }; + + return [order]; +}; + +const getFallbackRealOrder = (z, bundle) => { + // For the test poll, you should get some real data, to aid the setup process. + const module = bundle.inputData.module; + const options = { + url: bundle.authData.url + '/api/index.php/orders/0', + }; + + return z.request(options).then((response) => [JSON.parse(response.content)]); +}; + +// const getActionsChoices = (z, bundle) => { +// // For the test poll, you should get some real data, to aid the setup process. +// const module = bundle.inputData.module; +// const options = { +// url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/orders', +// }; + +// return z.request(options).then((response) => JSON.parse(response.content)); +// }; + +// We recommend writing your orders separate like this and rolling them +// into the App definition at the end. +module.exports = { + key: 'order', + + // You'll want to provide some helpful display labels and descriptions + // for users. Zapier will put them into the UX. + noun: 'Order', + display: { + label: 'New Order', + description: 'Trigger when a new order with action is done in Dolibarr.' + }, + + // `operation` is where the business logic goes. + operation: { + + // `inputFields` can define the fields a user could provide, + // we'll pass them in as `bundle.inputData` later. + inputFields: [ + { + key: 'action', + type: 'string', + helpText: 'Which action of order this should trigger on.', + choices: { + create: "Create", + modify: "Modify", + validate: "Validate", + } + } + ], + + type: 'hook', + + performSubscribe: subscribeHook, + performUnsubscribe: unsubscribeHook, + + perform: getOrder, + performList: getFallbackRealOrder, + + // In cases where Zapier needs to show an example record to the user, but we are unable to get a live example + // from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of + // returned records, and have obviously dummy values that we can show to any user. + sample: { + id: 1, + createdAt: 1472069465, + name: 'Best Spagetti Ever', + authorId: 1, + directions: '1. Boil Noodles\n2.Serve with sauce', + action: 'create' + }, + + // If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom + // field definitions. The result will be used to augment the sample. + // outputFields: () => { return []; } + // Alternatively, a static field definition should be provided, to specify labels for the fields + outputFields: [ + {key: 'id', label: 'ID'}, + {key: 'createdAt', label: 'Created At'}, + {key: 'name', label: 'Name'}, + {key: 'directions', label: 'Directions'}, + {key: 'authorId', label: 'Author ID'}, + {key: 'module', label: 'Module'}, + {key: 'action', label: 'Action'} + ] + } +}; diff --git a/dev/examples/zapier/triggers/thirdparty.js b/dev/examples/zapier/triggers/thirdparty.js new file mode 100644 index 00000000000..4b13e23ff1c --- /dev/null +++ b/dev/examples/zapier/triggers/thirdparty.js @@ -0,0 +1,175 @@ +const subscribeHook = (z, bundle) => { + // `z.console.log()` is similar to `console.log()`. + z.console.log('suscribing hook!'); + + // bundle.targetUrl has the Hook URL this app should call when an action is created. + const data = { + url: bundle.targetUrl, + event: bundle.event, + module: 'company', + action: bundle.inputData.action + }; + + const url = bundle.authData.url + '/api/index.php/zapierapi/hook'; + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: url, + method: 'POST', + body: JSON.stringify(data) + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const unsubscribeHook = (z, bundle) => { + // bundle.subscribeData contains the parsed response JSON from the subscribe + // request made initially. + z.console.log('unsuscribing hook!'); + + // You can build requests and our client will helpfully inject all the variables + // you need to complete. You can also register middleware to control this. + const options = { + url: bundle.authData.url + '/api/index.php/zapierapi/hook/' + bundle.subscribeData.id, + method: 'DELETE', + }; + + // You may return a promise or a normal data structure from any perform method. + return z.request(options).then((response) => JSON.parse(response.content)); +}; + +const getThirdparty = (z, bundle) => { + // bundle.cleanedRequest will include the parsed JSON object (if it's not a + // test poll) and also a .querystring property with the URL's query string. + const thirdparty = { + id: bundle.cleanedRequest.id, + name: bundle.cleanedRequest.name, + name_alias: bundle.cleanedRequest.name_alias, + firstname: bundle.cleanedRequest.firstname, + address: bundle.cleanedRequest.address, + zip: bundle.cleanedRequest.zip, + town: bundle.cleanedRequest.town, + email: bundle.cleanedRequest.email, + client: bundle.cleanedRequest.client, + fournisseur: bundle.cleanedRequest.fournisseur, + code_client: bundle.cleanedRequest.code_client, + code_fournisseur: bundle.cleanedRequest.code_fournisseur, + authorId: bundle.cleanedRequest.authorId, + createdAt: bundle.cleanedRequest.createdAt, + action: bundle.cleanedRequest.action + }; + + return [thirdparty]; +}; + +const getFallbackRealThirdparty = (z, bundle) => { + // For the test poll, you should get some real data, to aid the setup process. + const module = bundle.inputData.module; + const options = { + url: bundle.authData.url + '/api/index.php/thirdparties/0', + }; + + return z.request(options).then((response) => [JSON.parse(response.content)]); +}; + +// const getModulesChoices = (z/*, bundle*/) => { +// // For the test poll, you should get some real data, to aid the setup process. +// const options = { +// url: bundle.authData.url + '/api/index.php/zapierapi/getmoduleschoices', +// }; + +// return z.request(options).then((response) => JSON.parse(response.content)); +// }; +// const getModulesChoices = () => { + +// return { +// orders: "Order", +// invoices: "Invoice", +// thirdparties: "Thirdparty", +// contacts: "Contacts" +// }; +// }; + +// const getActionsChoices = (z, bundle) => { +// // For the test poll, you should get some real data, to aid the setup process. +// const module = bundle.inputData.module; +// const options = { +// url: url: bundle.authData.url + '/api/index.php/zapierapi/getactionschoices/thirparty`, +// }; + +// return z.request(options).then((response) => JSON.parse(response.content)); +// }; + +// We recommend writing your triggers separate like this and rolling them +// into the App definition at the end. +module.exports = { + key: 'thirdparty', + + // You'll want to provide some helpful display labels and descriptions + // for users. Zapier will put them into the UX. + noun: 'Thirdparty', + display: { + label: 'New Thirdparty', + description: 'Trigger when a new thirdpaty action is done in Dolibarr.' + }, + + // `operation` is where the business logic goes. + operation: { + + // `inputFields` can define the fields a user could provide, + // we'll pass them in as `bundle.inputData` later. + inputFields: [ + { + key: 'action', + type: 'string', + helpText: 'Which action of thirdparty this should trigger on.', + choices: { + create: "Create", + modify: "Modify", + validate: "Validate", + } + } + ], + + type: 'hook', + + performSubscribe: subscribeHook, + performUnsubscribe: unsubscribeHook, + + perform: getThirdparty, + performList: getFallbackRealThirdparty, + + // In cases where Zapier needs to show an example record to the user, but we are unable to get a live example + // from the API, Zapier will fallback to this hard-coded sample. It should reflect the data structure of + // returned records, and have obviously dummy values that we can show to any user. + sample: { + id: 1, + createdAt: 1472069465, + name: 'DOE', + name_alias: 'DOE Ltd', + firstname: 'John', + authorId: 1, + action: 'create' + }, + + // If the resource can have fields that are custom on a per-user basis, define a function to fetch the custom + // field definitions. The result will be used to augment the sample. + // outputFields: () => { return []; } + // Alternatively, a static field definition should be provided, to specify labels for the fields + outputFields: [ + {key: 'id', label: 'ID'}, + {key: 'createdAt', label: 'Created At'}, + {key: 'name', label: 'Name'}, + {key: 'name_alias', label: 'Name alias'}, + {key: 'firstname', label: 'Firstame'}, + {key: 'authorId', label: 'Author ID'}, + {key: 'action', label: 'Action'}, + {key: 'client', label: 'Customer/Prospect 0/1/2/3'}, + {key: 'fournisseur', label: 'Supplier 0/1'}, + {key: 'code_client', label: 'Customer code'}, + {key: 'code_fournisseur', label: 'Supplier code'} + ] + } +}; diff --git a/htdocs/core/modules/modZapier.class.php b/htdocs/core/modules/modZapier.class.php new file mode 100644 index 00000000000..7f7ee47ba1e --- /dev/null +++ b/htdocs/core/modules/modZapier.class.php @@ -0,0 +1,375 @@ + + * Copyright (C) 2019 Frédéric France + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** + * \defgroup zapier Module Zapier + * \brief Zapier module descriptor. + * + * \file htdocs/zapier/core/modules/modZapier.class.php + * \ingroup zapier + * \brief Description and activation file for module Zapier + */ +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + +/** + * Description and activation class for module Zapier + */ +class modZapier extends DolibarrModules +{ + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $langs,$conf; + + $this->db = $db; + // Id for module (must be unique). + // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). + $this->numero = 792000; // TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve id number for your module + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'zapier'; + // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...' + // It is used to group modules by family in module setup page + $this->family = "interface"; + // Module position in the family on 2 digits ('01', '10', '20', ...) + $this->module_position = 100; + // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) + //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily"))); + // Module label (no space allowed), used if translation string 'ModuleZapierName' not found (Zapier is name of module). + $this->name = preg_replace('/^mod/i', '', get_class($this)); + // Module description, used if translation string 'ModuleZapierDesc' not found (Zapier is name of module). + $this->description = "ZapierDescription"; + // Used only if file README.md and README-LL.md not found. + $this->descriptionlong = "Zapier description (Long)"; + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' + $this->version = 'development'; + //Url to the file with your last numberversion of this module + //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; + // Key used in llx_const table to save module status enabled/disabled (where ZAPIERFORDOLIBARR is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + $this->picto = 'technic'; + // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) + $this->module_parts = array( + // Set this to 1 if module has its own trigger directory (core/triggers) + 'triggers' => 1, + // Set this to 1 if module has its own login method file (core/login) + 'login' => 0, + // Set this to 1 if module has its own substitution function file (core/substitutions) + 'substitutions' => 0, + // Set this to 1 if module has its own menus handler directory (core/menus) + 'menus' => 0, + // Set this to 1 if module overwrite template dir (core/tpl) + 'tpl' => 0, + // Set this to 1 if module has its own barcode directory (core/modules/barcode) + 'barcode' => 0, + // Set this to 1 if module has its own models directory (core/modules/xxx) + 'models' => 0, + // Set this to 1 if module has its own theme directory (theme) + 'theme' => 0, + // Set this to relative path of css file if module has its own css file + 'css' => array( + // '/zapier/css/zapier.css.php', + ), + // Set this to relative path of js file if module must load a js on all pages + 'js' => array( + // '/zapier/js/zapier.js.php', + ), + // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context 'all' + 'hooks' => array( + // 'data' => array( + // 'hookcontext1', + // 'hookcontext2', + // ), + // 'entity' => '0', + ), + // Set this to 1 if feature of module are opened to external users + 'moduleforexternal' => 0, + ); + // Data directories to create when module is enabled. + // Example: this->dirs = array("/zapier/temp","/zapier/subdir"); + $this->dirs = array("/zapier/temp"); + // Config pages. Put here list of php page, stored into zapier/admin directory, to use to setup module. + $this->config_page_url = array("setup.php@zapier"); + // Dependencies + // A condition to hide module + $this->hidden = false; + // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) + $this->depends = array(); + // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->requiredby = array(); + // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) + $this->conflictwith = array(); + $this->langfiles = array("zapier@zapier"); + // Minimum version of PHP required by module + //$this->phpmin = array(5, 5); + // Minimum version of Dolibarr required by module + $this->need_dolibarr_version = array(10, 0); + // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + $this->warnings_activation = array(); + // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + $this->warnings_activation_ext = array(); + // $this->automatic_activation = array( + // 'FR'=>'ZapierWasAutomaticallyActivatedBecauseOfYourCountryChoice', + // ); + // If true, can't be disabled + // $this->always_enabled = true; + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array( + // 1 => array('ZAPIERFORDOLIBARR_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1), + // 2 => array('ZAPIERFORDOLIBARR_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1) + // ); + $this->const = array( + // 1 => array('ZAPIERFORDOLIBARR_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1) + ); + // Some keys to add into the overwriting translation tables + /*$this->overwrite_translation = array( + 'en_US:ParentCompany'=>'Parent company or reseller', + 'fr_FR:ParentCompany'=>'Maison mère ou revendeur' + )*/ + if (! isset($conf->zapier) || ! isset($conf->zapier->enabled)) { + $conf->zapier=new stdClass(); + $conf->zapier->enabled=0; + } + // Array to add new pages in new tabs + $this->tabs = array(); + // Example: + // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@zapier:$user->rights->zapier->read:/zapier/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 + // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@zapier:$user->rights->othermodule->read:/zapier/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. + // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + // + // Where objecttype can be + // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) + // 'contact' to add a tab in contact view + // 'contract' to add a tab in contract view + // 'group' to add a tab in group view + // 'intervention' to add a tab in intervention view + // 'invoice' to add a tab in customer invoice view + // 'invoice_supplier' to add a tab in supplier invoice view + // 'member' to add a tab in fundation member view + // 'opensurveypoll' to add a tab in opensurvey poll view + // 'order' to add a tab in customer order view + // 'order_supplier' to add a tab in supplier order view + // 'payment' to add a tab in payment view + // 'payment_supplier' to add a tab in supplier payment view + // 'product' to add a tab in product view + // 'propal' to add a tab in propal view + // 'project' to add a tab in project view + // 'stock' to add a tab in stock view + // 'thirdparty' to add a tab in third party view + // 'user' to add a tab in user view + // Dictionaries + $this->dictionaries=array(); + /* Example: + $this->dictionaries=array( + 'langs'=>'mylangfile@zapier', + // List of tables we want to see into dictonnary editor + 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), + // Label of tables + 'tablib'=>array("Table1","Table2","Table3"), + // Request to select fields + 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), + // Sort order + 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), + // List of fields (result of select to show dictionary) + 'tabfield'=>array("code,label","code,label","code,label"), + // List of fields (list of fields to edit a record) + 'tabfieldvalue'=>array("code,label","code,label","code,label"), + // List of fields (list of fields for insert) + 'tabfieldinsert'=>array("code,label","code,label","code,label"), + // Name of columns with primary key (try to always name it 'rowid') + 'tabrowid'=>array("rowid","rowid","rowid"), + // Condition to show each dictionary + 'tabcond'=>array($conf->zapier->enabled,$conf->zapier->enabled,$conf->zapier->enabled) + ); + */ + // Boxes/Widgets + // Add here list of php file(s) stored in zapier/core/boxes that contains class to show a widget. + $this->boxes = array( + // 0 => array( + // 'file' => 'zapierwidget1.php@zapier', + // 'note' => 'Widget provided by Zapier', + // 'enabledbydefaulton' => 'Home', + // ), + //1=>array('file'=>'zapierwidget2.php@zapier','note'=>'Widget provided by Zapier'), + //2=>array('file'=>'zapierwidget3.php@zapier','note'=>'Widget provided by Zapier') + ); + // Cronjobs (List of cron jobs entries to add when module is enabled) + // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week + $this->cronjobs = array( + // 0 => array( + // 'label' => 'MyJob label', + // 'jobtype' => 'method', + // 'class' => '/zapier/class/myobject.class.php', + // 'objectname' => 'MyObject', + // 'method' => 'doScheduledJob', + // 'parameters' => '', + // 'comment' => 'Comment', + // 'frequency' => 2, + // 'unitfrequency' => 3600, + // 'status' => 0, + // 'test' => '$conf->zapier->enabled', + // 'priority' => 50, + // ), + ); + // Example: $this->cronjobs=array( + // 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->zapier->enabled', 'priority'=>50), + // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->zapier->enabled', 'priority'=>50) + // ); + // Permissions + // Permission array used by this module + $this->rights = array(); + + $r=0; + // Permission id (must not be already used) + $this->rights[$r][0] = $this->numero + $r; + // Permission label + $this->rights[$r][1] = 'Read myobject of Zapier'; + // Permission by default for new user (0/1) + $this->rights[$r][3] = 1; + // In php code, permission will be checked by test if ($user->rights->zapier->level1->level2) + $this->rights[$r][4] = 'read'; + // In php code, permission will be checked by test if ($user->rights->zapier->level1->level2) + $this->rights[$r][5] = ''; + $r++; + $this->rights[$r][0] = $this->numero + $r; + $this->rights[$r][1] = 'Create/Update myobject of Zapier'; + $this->rights[$r][3] = 1; + $this->rights[$r][4] = 'write'; + $this->rights[$r][5] = ''; + $r++; + $this->rights[$r][0] = $this->numero + $r; + $this->rights[$r][1] = 'Delete myobject of Zapier'; + $this->rights[$r][3] = 1; + $this->rights[$r][4] = 'delete'; + $this->rights[$r][5] = ''; + + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; + + // Add here entries to declare new menus + // $this->menu[$r++]=array( + // 'fk_menu' => '', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + // 'type' => 'top', // This is a Top menu entry + // 'titre' => 'Zapier', + // 'mainmenu' => 'zapier', + // 'leftmenu' => '', + // 'url' => '/zapier/zapierindex.php', + // 'langs' => 'zapier@zapier', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + // 'position' => 1000+$r, + // 'enabled' => '$conf->zapier->enabled', // Define condition to show or hide menu entry. Use '$conf->zapier->enabled' if entry must be visible if module is enabled. + // 'perms' => '1', // Use 'perms'=>'$user->rights->zapier->level1->level2' if you want your menu with a permission rules + // 'target' => '', + // 'user' => 2, // 0=Menu for internal users, 1=external users, 2=both + // ); + + /* + $this->menu[$r++]=array( + 'fk_menu'=>'fk_mainmenu=zapier', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'List MyObject', + 'mainmenu'=>'zapier', + 'leftmenu'=>'zapier_myobject_list', + 'url'=>'/zapier/myobject_list.php', + 'langs'=>'zapier@zapier', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->zapier->enabled', // Define condition to show or hide menu entry. Use '$conf->zapier->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'1', // Use 'perms'=>'$user->rights->zapier->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both + ); + $this->menu[$r++]=array( + 'fk_menu'=>'fk_mainmenu=zapier,fk_leftmenu=zapier', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'New MyObject', + 'mainmenu'=>'zapier', + 'leftmenu'=>'zapier_myobject_new', + 'url'=>'/zapier/myobject_page.php?action=create', + 'langs'=>'zapier@zapier', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->zapier->enabled', // Define condition to show or hide menu entry. Use '$conf->zapier->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'1', // Use 'perms'=>'$user->rights->zapier->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both + ); + */ + // Exports + $r=1; + /* EXPORT */ + /* + $langs->load("zapier@zapier"); + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_icon[$r]='myobject@zapier'; + $keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject'; + include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php'; + $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + //$this->export_dependencies_array[$r]=array('mysubobject'=>'ts.rowid', 't.myfield'=>array('t.myfield2','t.myfield3')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields) + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'myobject as t'; + $this->export_sql_end[$r] .=' WHERE 1 = 1'; + $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')'; + $r++; */ + } + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function init($options = '') + { + $result = $this->_load_tables('/zapier/sql/'); + if ($result < 0) return -1; // Do not activate module if not allowed errors found on module SQL queries (the _load_table run sql with run_sql with error allowed parameter to 'default') + + // Create extrafields + //include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + //$extrafields = new ExtraFields($this->db); + //$result1=$extrafields->addExtraField('myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', 0, 0, '', '', 'zapier@zapier', '$conf->zapier->enabled'); + //$result2=$extrafields->addExtraField('myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', 0, 0, '', '', 'zapier@zapier', '$conf->zapier->enabled'); + //$result3=$extrafields->addExtraField('myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'zapier@zapier', '$conf->zapier->enabled'); + //$result4=$extrafields->addExtraField('myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', 0, 0, '', '', 'zapier@zapier', '$conf->zapier->enabled'); + //$result5=$extrafields->addExtraField('myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', 0, 0, '', '', 'zapier@zapier', '$conf->zapier->enabled'); + $sql = array(); + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function remove($options = '') + { + $sql = array(); + return $this->_remove($sql, $options); + } +} diff --git a/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php b/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php new file mode 100644 index 00000000000..ae08b55d651 --- /dev/null +++ b/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php @@ -0,0 +1,567 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file core/triggers/interface_99_modZapier_ZapierTriggers.class.php + * \ingroup zapier + * \brief Example trigger. + * + * + * \remarks You can create other triggers by copying this one. + * - File name should be either: + * - interface_99_modZapier_MyTrigger.class.php + * - interface_99_all_MyTrigger.class.php + * - The file must stay in core/triggers + * - The class name must be InterfaceMytrigger + * - The constructor method must be named InterfaceMytrigger + * - The name property name must be MyTrigger + */ + +require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php'; + + +/** + * Class of triggers for Zapier module + */ +class InterfaceZapierTriggers extends DolibarrTriggers +{ + /** + * @var DoliDB Database handler + */ + protected $db; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + + $this->name = preg_replace('/^Interface/i', '', get_class($this)); + $this->family = "demo"; + $this->description = "Zapier triggers."; + // 'development', 'experimental', 'dolibarr' or version + $this->version = 'development'; + $this->picto = 'zapier@zapier'; + } + + /** + * Trigger name + * + * @return string Name of trigger file + */ + public function getName() + { + return $this->name; + } + + /** + * Trigger description + * + * @return string Description of trigger file + */ + public function getDesc() + { + return $this->description; + } + + + /** + * Function called when a Dolibarrr business event is done. + * All functions "runTrigger" are triggered if file + * is inside directory core/triggers + * + * @param string $action Event action code + * @param CommonObject $object Object + * @param User $user Object user + * @param Translate $langs Object langs + * @param Conf $conf Object conf + * @return int <0 if KO, 0 if no triggered ran, >0 if OK + */ + public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf) + { + global $db; + if (empty($conf->zapier->enabled)) { + // Module not active, we do nothing + return 0; + } + $logtriggeraction = false; + if ($action!='') { + $actions = explode('_', $action); + $sql = 'SELECT rowid, url FROM '.MAIN_DB_PREFIX.'zapier_hook WHERE'; + $sql .= ' module="'.$db->escape(strtolower($actions[0])).'" AND action="'.$db->escape(strtolower($actions[1])).'"'; + //setEventMessages($sql, null); + } + + switch ($action) { + + // Users + //case 'USER_CREATE': + //case 'USER_MODIFY': + //case 'USER_NEW_PASSWORD': + //case 'USER_ENABLEDISABLE': + //case 'USER_DELETE': + //case 'USER_SETINGROUP': + //case 'USER_REMOVEFROMGROUP': + + case 'USER_LOGIN': + //$logtriggeraction = true; + break; + case 'USER_LOGIN_FAILED': + //$logtriggeraction = true; + break; + case 'USER_LOGOUT': + //$logtriggeraction = true; + break; + // Warning: To increase performances, this action is triggered only if constant MAIN_ACTIVATE_UPDATESESSIONTRIGGER is set to 1. + //case 'USER_UPDATE_SESSION': + + case 'DOSSIERISOLATION_CREATE': + //$logtriggeraction = true; + break; + case 'DOSSIERISOLATION_MODIFY': + //$logtriggeraction = true; + break; + case 'DOSSIERISOLATION_DELETE': + //$logtriggeraction = true; + break; + + // Actions + case 'ACTION_MODIFY': + //$logtriggeraction = true; + break; + case 'ACTION_CREATE': + $resql = $db->query($sql); + // TODO voir comment regrouper les webhooks en un post + while ($resql && $obj = $db->fetch_array($resql)) { + $cleaned = cleanObjectDatas(dol_clone($object)); + $cleaned = cleanAgendaEventsDatas($cleaned); + $json = json_encode($cleaned); + // call the zapierPostWebhook() function + zapierPostWebhook($obj['url'], $json); + //setEventMessages($obj['url'], null); + } + $logtriggeraction = true; + break; + case 'ACTION_DELETE': + //$logtriggeraction = true; + break; + + // Groups + //case 'GROUP_CREATE': + //case 'GROUP_MODIFY': + //case 'GROUP_DELETE': + + // Companies + case 'COMPANY_CREATE': + $resql = $db->query($sql); + while ($resql && $obj = $db->fetch_array($resql)) { + $cleaned = cleanObjectDatas(dol_clone($object)); + $json = json_encode($cleaned); + // call the zapierPostWebhook() function + zapierPostWebhook($obj['url'], $json); + } + $logtriggeraction = true; + break; + case 'COMPANY_MODIFY': + $resql = $db->query($sql); + while ($resql && $obj = $db->fetch_array($resql)) { + $cleaned = cleanObjectDatas(dol_clone($object)); + $json = json_encode($cleaned); + // call the zapierPostWebhook() function + zapierPostWebhook($obj['url'], $json); + } + $logtriggeraction = true; + break; + case 'COMPANY_DELETE': + //$logtriggeraction = true; + break; + + // Contacts + case 'CONTACT_CREATE': + case 'CONTACT_MODIFY': + case 'CONTACT_DELETE': + case 'CONTACT_ENABLEDISABLE': + + // Products + case 'PRODUCT_CREATE': + case 'PRODUCT_MODIFY': + case 'PRODUCT_DELETE': + case 'PRODUCT_PRICE_MODIFY': + case 'PRODUCT_SET_MULTILANGS': + case 'PRODUCT_DEL_MULTILANGS': + + //Stock mouvement + case 'STOCK_MOVEMENT': + + //MYECMDIR + case 'MYECMDIR_DELETE': + case 'MYECMDIR_CREATE': + case 'MYECMDIR_MODIFY': + + // Customer orders + case 'ORDER_CREATE': + $resql = $db->query($sql); + while ($resql && $obj = $db->fetch_array($resql)) { + $cleaned = cleanObjectDatas(dol_clone($object)); + $json = json_encode($cleaned); + // call the zapierPostWebhook() function + zapierPostWebhook($obj['url'], $json); + } + $logtriggeraction = true; + break; + case 'ORDER_CLONE': + break; + case 'ORDER_VALIDATE': + break; + case 'ORDER_DELETE': + case 'ORDER_CANCEL': + case 'ORDER_SENTBYMAIL': + case 'ORDER_CLASSIFY_BILLED': + case 'ORDER_SETDRAFT': + case 'LINEORDER_INSERT': + case 'LINEORDER_UPDATE': + case 'LINEORDER_DELETE': + + // Supplier orders + case 'ORDER_SUPPLIER_CREATE': + case 'ORDER_SUPPLIER_CLONE': + case 'ORDER_SUPPLIER_VALIDATE': + case 'ORDER_SUPPLIER_DELETE': + case 'ORDER_SUPPLIER_APPROVE': + case 'ORDER_SUPPLIER_REFUSE': + case 'ORDER_SUPPLIER_CANCEL': + case 'ORDER_SUPPLIER_SENTBYMAIL': + case 'ORDER_SUPPLIER_DISPATCH': + case 'LINEORDER_SUPPLIER_DISPATCH': + case 'LINEORDER_SUPPLIER_CREATE': + case 'LINEORDER_SUPPLIER_UPDATE': + + // Proposals + case 'PROPAL_CREATE': + case 'PROPAL_CLONE': + case 'PROPAL_MODIFY': + case 'PROPAL_VALIDATE': + case 'PROPAL_SENTBYMAIL': + case 'PROPAL_CLOSE_SIGNED': + //$logtriggeraction = true; + break; + case 'PROPAL_CLOSE_REFUSED': + //$logtriggeraction = true; + break; + case 'PROPAL_DELETE': + //$logtriggeraction = true; + break; + case 'LINEPROPAL_INSERT': + case 'LINEPROPAL_UPDATE': + case 'LINEPROPAL_DELETE': + + // SupplierProposal + case 'SUPPLIER_PROPOSAL_CREATE': + case 'SUPPLIER_PROPOSAL_CLONE': + case 'SUPPLIER_PROPOSAL_MODIFY': + case 'SUPPLIER_PROPOSAL_VALIDATE': + case 'SUPPLIER_PROPOSAL_SENTBYMAIL': + case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED': + case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED': + case 'SUPPLIER_PROPOSAL_DELETE': + case 'LINESUPPLIER_PROPOSAL_INSERT': + case 'LINESUPPLIER_PROPOSAL_UPDATE': + case 'LINESUPPLIER_PROPOSAL_DELETE': + + // Contracts + case 'CONTRACT_CREATE': + case 'CONTRACT_ACTIVATE': + case 'CONTRACT_CANCEL': + case 'CONTRACT_CLOSE': + case 'CONTRACT_DELETE': + case 'LINECONTRACT_INSERT': + case 'LINECONTRACT_UPDATE': + case 'LINECONTRACT_DELETE': + + // Bills + case 'BILL_CREATE': + //$logtriggeraction = true; + break; + case 'BILL_CLONE': + case 'BILL_MODIFY': + case 'BILL_VALIDATE': + case 'BILL_UNVALIDATE': + //$logtriggeraction = true; + break; + case 'BILL_SENTBYMAIL': + //$logtriggeraction = true; + break; + case 'BILL_CANCEL': + //$logtriggeraction = true; + break; + case 'BILL_DELETE': + //$logtriggeraction = true; + break; + case 'BILL_PAYED': + case 'LINEBILL_INSERT': + case 'LINEBILL_UPDATE': + case 'LINEBILL_DELETE': + + //Supplier Bill + case 'BILL_SUPPLIER_CREATE': + case 'BILL_SUPPLIER_UPDATE': + case 'BILL_SUPPLIER_DELETE': + case 'BILL_SUPPLIER_PAYED': + case 'BILL_SUPPLIER_UNPAYED': + case 'BILL_SUPPLIER_VALIDATE': + case 'BILL_SUPPLIER_UNVALIDATE': + case 'LINEBILL_SUPPLIER_CREATE': + case 'LINEBILL_SUPPLIER_UPDATE': + case 'LINEBILL_SUPPLIER_DELETE': + + // Payments + case 'PAYMENT_CUSTOMER_CREATE': + case 'PAYMENT_SUPPLIER_CREATE': + case 'PAYMENT_ADD_TO_BANK': + case 'PAYMENT_DELETE': + + // Online + case 'PAYMENT_PAYBOX_OK': + case 'PAYMENT_PAYPAL_OK': + case 'PAYMENT_STRIPE_OK': + + // Donation + case 'DON_CREATE': + case 'DON_UPDATE': + case 'DON_DELETE': + + // Interventions + case 'FICHINTER_CREATE': + case 'FICHINTER_MODIFY': + case 'FICHINTER_VALIDATE': + case 'FICHINTER_DELETE': + case 'LINEFICHINTER_CREATE': + case 'LINEFICHINTER_UPDATE': + case 'LINEFICHINTER_DELETE': + + // Members + case 'MEMBER_CREATE': + case 'MEMBER_VALIDATE': + case 'MEMBER_SUBSCRIPTION': + case 'MEMBER_MODIFY': + case 'MEMBER_NEW_PASSWORD': + case 'MEMBER_RESILIATE': + case 'MEMBER_DELETE': + + // Categories + case 'CATEGORY_CREATE': + case 'CATEGORY_MODIFY': + case 'CATEGORY_DELETE': + case 'CATEGORY_SET_MULTILANGS': + + // Projects + case 'PROJECT_CREATE': + case 'PROJECT_MODIFY': + case 'PROJECT_DELETE': + + // Project tasks + case 'TASK_CREATE': + case 'TASK_MODIFY': + case 'TASK_DELETE': + + // Task time spent + case 'TASK_TIMESPENT_CREATE': + case 'TASK_TIMESPENT_MODIFY': + case 'TASK_TIMESPENT_DELETE': + + // Shipping + case 'SHIPPING_CREATE': + case 'SHIPPING_MODIFY': + case 'SHIPPING_VALIDATE': + case 'SHIPPING_SENTBYMAIL': + case 'SHIPPING_BILLED': + case 'SHIPPING_CLOSED': + case 'SHIPPING_REOPEN': + //$logtriggeraction = true; + break; + case 'SHIPPING_DELETE': + //$logtriggeraction = true; + break; + } + if ($logtriggeraction) { + dol_syslog("Trigger '" . $this->name . "' for action '.$action.' launched by " . __FILE__ . " id=" . $object->id); + } + return 0; + } +} +/** + * Post webhook in zapier with object data + * + * @param string $url url provided by zapier + * @param string $json data to send + * @return void + */ +function zapierPostWebhook($url, $json) +{ + $headers = array('Accept: application/json', 'Content-Type: application/json'); + // TODO supprimer le webhook en cas de mauvaise réponse + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $json); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + $output = curl_exec($ch); + curl_close($ch); +} + +/** + * Clean sensible object datas + * + * @param object $toclean Object to clean + * @return array Array of cleaned object properties + */ +function cleanObjectDatas($toclean) +{ + // Remove $db object property for object + unset($toclean->db); + + // Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses + unset($toclean->linkedObjects); + + unset($toclean->lines); // should be ->lines + + unset($toclean->fields); + + unset($toclean->oldline); + + unset($toclean->error); + unset($toclean->errors); + + unset($toclean->ref_previous); + unset($toclean->ref_next); + unset($toclean->ref_int); + + unset($toclean->projet); // Should be fk_project + unset($toclean->project); // Should be fk_project + unset($toclean->author); // Should be fk_user_author + unset($toclean->timespent_old_duration); + unset($toclean->timespent_id); + unset($toclean->timespent_duration); + unset($toclean->timespent_date); + unset($toclean->timespent_datehour); + unset($toclean->timespent_withhour); + unset($toclean->timespent_fk_user); + unset($toclean->timespent_note); + + unset($toclean->statuts); + unset($toclean->statuts_short); + unset($toclean->statuts_logo); + unset($toclean->statuts_long); + + unset($toclean->element); + unset($toclean->fk_element); + unset($toclean->table_element); + unset($toclean->table_element_line); + unset($toclean->picto); + + unset($toclean->skip_update_total); + unset($toclean->context); + + // Remove the $oldcopy property because it is not supported by the JSON + // encoder. The following error is generated when trying to serialize + // it: "Error encoding/decoding JSON: Type is not supported" + // Note: Event if this property was correctly handled by the JSON + // encoder, it should be ignored because keeping it would let the API + // have a very strange behavior: calling PUT and then GET on the same + // resource would give different results: + // PUT /objects/{id} -> returns object with oldcopy = previous version of the object + // GET /objects/{id} -> returns object with oldcopy empty + unset($toclean->oldcopy); + + // If object has lines, remove $db property + if (isset($toclean->lines) && count($toclean->lines) > 0) { + $nboflines = count($toclean->lines); + for ($i=0; $i < $nboflines; $i++) { + $this->cleanObjectDatas($toclean->lines[$i]); + } + } + + // If object has linked objects, remove $db property + /* + if(isset($toclean->linkedObjects) && count($toclean->linkedObjects) > 0) { + foreach($toclean->linkedObjects as $type_object => $linked_object) { + foreach($linked_object as $toclean2clean) { + $this->cleanObjectDatas($toclean2clean); + } + } + }*/ + + return $toclean; +} + +/** + * Clean sensible object datas + * + * @param object $toclean Object to clean + * @return array Array of cleaned object properties + */ +function cleanAgendaEventsDatas($toclean) +{ + unset($toclean->usermod); + unset($toclean->libelle); + //unset($toclean->array_options); + unset($toclean->context); + unset($toclean->canvas); + unset($toclean->contact); + unset($toclean->contact_id); + unset($toclean->thirdparty); + unset($toclean->user); + unset($toclean->origin); + unset($toclean->origin_id); + unset($toclean->ref_ext); + unset($toclean->statut); + unset($toclean->country); + unset($toclean->country_id); + unset($toclean->country_code); + unset($toclean->barcode_type); + unset($toclean->barcode_type_code); + unset($toclean->barcode_type_label); + unset($toclean->barcode_type_coder); + unset($toclean->mode_reglement_id); + unset($toclean->cond_reglement_id); + unset($toclean->cond_reglement); + unset($toclean->fk_delivery_address); + unset($toclean->shipping_method_id); + unset($toclean->fk_account); + unset($toclean->total_ht); + unset($toclean->total_tva); + unset($toclean->total_localtax1); + unset($toclean->total_localtax2); + unset($toclean->total_ttc); + unset($toclean->fk_incoterms); + unset($toclean->libelle_incoterms); + unset($toclean->location_incoterms); + unset($toclean->name); + unset($toclean->lastname); + unset($toclean->firstname); + unset($toclean->civility_id); + unset($toclean->contact); + unset($toclean->societe); + + return $toclean; +} diff --git a/htdocs/langs/en_US/zapier.lang b/htdocs/langs/en_US/zapier.lang new file mode 100644 index 00000000000..2699f54b721 --- /dev/null +++ b/htdocs/langs/en_US/zapier.lang @@ -0,0 +1,53 @@ +# Copyright (C) 2019 Frédéric FRANCE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# Generic +# + +# Module label 'ModuleZapierForDolibarrName' +ModuleZapierForDolibarrName = ZapierForDolibarr +# Module description 'ModuleZapierForDolibarrDesc' +ModuleZapierForDolibarrDesc = ZapierForDolibarr description + +# +# Admin page +# +ZapierForDolibarrSetup = ZapierForDolibarr setup +Settings = Settings +ZapierForDolibarrSetupPage = ZapierForDolibarr setup page +ZAPIERFORDOLIBARR_MYPARAM1 = My param 1 +ZAPIERFORDOLIBARR_MYPARAM1Tooltip = My param 1 tooltip +ZAPIERFORDOLIBARR_MYPARAM2=My param 2 +ZAPIERFORDOLIBARR_MYPARAM2Tooltip=My param 2 tooltip + + +# +# About page +# +About = About +ZapierForDolibarrAbout = About ZapierForDolibarr +ZapierForDolibarrAboutPage = ZapierForDolibarr about page + +# +# Sample page +# +MyPageName = My page name + +# +# Sample widget +# +MyWidget = My widget +MyWidgetDescription = My widget description diff --git a/htdocs/langs/fr_FR/zapier.lang b/htdocs/langs/fr_FR/zapier.lang new file mode 100644 index 00000000000..78103a55bae --- /dev/null +++ b/htdocs/langs/fr_FR/zapier.lang @@ -0,0 +1,48 @@ +# Copyright (C) 2019 Frédéric FRANCE +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# Générique +# + +# Module label 'ModuleZapierForDolibarrName' +ModuleZapierForDolibarrName = ZapierForDolibarr +# Module description 'ModuleZapierForDolibarrDesc' +ModuleZapierForDolibarrDesc = Description de ZapierForDolibarr + +# +# Page d'administration +# +ZapierForDolibarrSetup = Configuration du module ZapierForDolibarr +Settings = Réglages +ZapierForDolibarrSetupPage = Page de configuration du module ZapierForDolibarr + +# +# Page À propos +# +About = À propos +ZapierForDolibarrAbout = À propos de ZapierForDolibarr +ZapierForDolibarrAboutPage = Page à propos de ZapierForDolibarr + +# +# Page d'exemple +# +MyPageName = Nom de ma page + +# +# Box d'exemple +# +MyWidget = Mon widget +MyWidgetDescription = Description de mon widget diff --git a/htdocs/zapier/admin/about.php b/htdocs/zapier/admin/about.php new file mode 100644 index 00000000000..d875928ae8f --- /dev/null +++ b/htdocs/zapier/admin/about.php @@ -0,0 +1,76 @@ + + * Copyright (C) 2019 Frédéric FRANCE + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file zapier/admin/about.php + * \ingroup zapier + * \brief About page of module Zapier. + */ + +// Load Dolibarr environment +require '../../main.inc.php'; + +// Libraries +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once '../lib/zapier.lib.php'; + +// Translations +$langs->loadLangs(array("errors","admin","zapier@zapier")); + +// Access control +if (! $user->admin) accessforbidden(); + +// Parameters +$action = GETPOST('action', 'alpha'); +$backtopage = GETPOST('backtopage', 'alpha'); + + +/* + * Actions + */ + +// None + + +/* + * View + */ + +$form = new Form($db); + +$page_name = "ZapierAbout"; +llxHeader('', $langs->trans($page_name)); + +// Subheader +$linkback = ''.$langs->trans("BackToModuleList").''; + +print load_fiche_titre($langs->trans($page_name), $linkback, 'object_zapier@zapier'); + +// Configuration header +$head = zapierAdminPrepareHead(); +dol_fiche_head($head, 'about', '', 0, 'zapier@zapier'); + +dol_include_once('/zapier/core/modules/modZapier.class.php'); +$tmpmodule = new modZapier($db); +print $tmpmodule->getDescLong(); + +// Page end +dol_fiche_end(); +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/admin/setup.php b/htdocs/zapier/admin/setup.php new file mode 100644 index 00000000000..b8b203b8ab1 --- /dev/null +++ b/htdocs/zapier/admin/setup.php @@ -0,0 +1,124 @@ + + * Copyright (C) 2019 Frédéric FRANCE + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file zapier/admin/setup.php + * \ingroup zapier + * \brief Zapier setup page. + */ + +// Load Dolibarr environment +require '../../main.inc.php'; + +// Libraries +require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php"; +require_once '../lib/zapier.lib.php'; + +// Translations +$langs->loadLangs(array("admin", "zapier@zapier")); + +// Access control +if (! $user->admin) accessforbidden(); + +// Parameters +$action = GETPOST('action', 'alpha'); +$backtopage = GETPOST('backtopage', 'alpha'); + +$arrayofparameters=array( + 'ZAPIERFORDOLIBARR_MYPARAM1'=>array('css'=>'minwidth200','enabled'=>1), + 'ZAPIERFORDOLIBARR_MYPARAM2'=>array('css'=>'minwidth500','enabled'=>1) +); + + +/* + * Actions + */ +if ((float) DOL_VERSION >= 6) { + include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; +} + + +/* + * View + */ + +$page_name = "ZapierSetup"; +llxHeader('', $langs->trans($page_name)); + +// Subheader +$linkback = ''.$langs->trans("BackToModuleList").''; + +print load_fiche_titre($langs->trans($page_name), $linkback, 'object_zapier@zapier'); + +// Configuration header +$head = zapierAdminPrepareHead(); +dol_fiche_head($head, 'settings', '', -1, "zapier@zapier"); + +// Setup page goes here +echo $langs->trans("ZapierSetupPage").'

'; + + +if ($action == 'edit') { + print '
'; + print ''; + print ''; + + print ''; + print ''; + + foreach($arrayofparameters as $key => $val) { + print ''; + } + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; + print $form->textwithpicto($langs->trans($key), $langs->trans($key.'Tooltip')); + print '
'; + + print '
'; + print ''; + print '
'; + + print '
'; + print '
'; +} else { + if (! empty($arrayofparameters)) { + print ''; + print ''; + + foreach($arrayofparameters as $key => $val) { + print ''; + } + + print '
'.$langs->trans("Parameter").''.$langs->trans("Value").'
'; + print $form->textwithpicto($langs->trans($key), $langs->trans($key.'Tooltip')); + print '' . $conf->global->$key . '
'; + + print '
'; + print ''.$langs->trans("Modify").''; + print '
'; + } else + { + print '
'.$langs->trans("NothingToSetup"); + } +} + + +// Page end +dol_fiche_end(); + +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/class/api_zapier.class.php b/htdocs/zapier/class/api_zapier.class.php new file mode 100644 index 00000000000..239ee5227d6 --- /dev/null +++ b/htdocs/zapier/class/api_zapier.class.php @@ -0,0 +1,382 @@ + + * Copyright (C) 2019 Frédéric France + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +use Luracast\Restler\RestException; + +dol_include_once('/zapier/class/hook.class.php'); + + + +/** + * \file htdocs/modulebuilder/template/class/api_zapier.class.php + * \ingroup zapier + * \brief File for API management of hook. + */ + +/** + * API class for zapier hook + * + * @access protected + * @class DolibarrApiAccess {@requires user,external} + */ +class ZapierApi extends DolibarrApi +{ + /** + * @var array $FIELDS Mandatory fields, checked when create and update object + */ + static $FIELDS = array( + 'url', + ); + + + /** + * @var Hook $hook {@type Hook} + */ + public $hook; + + /** + * Constructor + * + * @url GET / + * + */ + public function __construct() + { + global $db, $conf; + $this->db = $db; + $this->hook = new Hook($this->db); + } + + /** + * Get properties of a hook object + * + * Return an array with hook informations + * + * @param int $id ID of hook + * @return array|mixed data without useless information + * + * @url GET /hooks/{id} + * @throws RestException + */ + public function get($id) + { + if(! DolibarrApiAccess::$user->rights->zapier->read) { + throw new RestException(401); + } + + $result = $this->hook->fetch($id); + if (! $result ) { + throw new RestException(404, 'Hook not found'); + } + + if (! DolibarrApi::_checkAccessToResource('hook', $this->hook->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + return $this->_cleanObjectDatas($this->hook); + } + + + /** + * Get list of possibles choices for module + * + * Return an array with hook informations + * @param integer $id ID + * + * @return array|mixed data + * + * @url GET /getmoduleschoices/ + * @throws RestException + */ + public function getModulesChoices($id) + { + if(! DolibarrApiAccess::$user->rights->zapier->read) { + throw new RestException(401); + } + $arraychoices = array( + 'invoices' => 'Invoices', + 'orders' => 'Orders', + 'thirdparties' => 'Thirparties', + 'contacts' => 'Contacts', + ); + // $result = $this->hook->fetch($id); + // if (! $result ) { + // throw new RestException(404, 'Hook not found'); + // } + + // if (! DolibarrApi::_checkAccessToResource('hook', $this->hook->id)) { + // throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + // } + + return $arraychoices; + } + + + /** + * List hooks + * + * Get a list of hooks + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Limit for list + * @param int $page Page number + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + * @return array Array of order objects + * + * @throws RestException + * + * @url GET /hooks/ + */ + public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '') + { + global $db, $conf; + + $obj_ret = array(); + + $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : ''; + + // Set to 1 if there is a field socid in table of object + $restrictonsocid = 0; + + // If the internal user must only see his customers, force searching by him + $search_sale = 0; + if ($restrictonsocid && ! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) { + $search_sale = DolibarrApiAccess::$user->id; + } + + $sql = "SELECT t.rowid"; + if ($restrictonsocid && (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) { + // We need these fields in order to filter by sale (including the case where the user can only see his prospects) + $sql .= ", sc.fk_soc, sc.fk_user"; + } + $sql.= " FROM ".MAIN_DB_PREFIX."hook_mytable as t"; + + if ($restrictonsocid && (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale + $sql.= " WHERE 1 = 1"; + + // Example of use $mode + //if ($mode == 1) $sql.= " AND s.client IN (1, 3)"; + //if ($mode == 2) $sql.= " AND s.client IN (2, 3)"; + + $tmpobject = new Hook($db); + if ($tmpobject->ismultientitymanaged) { + $sql.= ' AND t.entity IN ('.getEntity('hook').')'; + } + if ($restrictonsocid && (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) { + $sql.= " AND t.fk_soc = sc.fk_soc"; + } + if ($restrictonsocid && $socid) { + $sql.= " AND t.fk_soc = ".$socid; + } + if ($restrictonsocid && $search_sale > 0) { + // Join for the needed table to filter by sale + $sql.= " AND t.rowid = sc.fk_soc"; + } + // Insert sale filter + if ($restrictonsocid && $search_sale > 0) { + $sql .= " AND sc.fk_user = ".$search_sale; + } + if ($sqlfilters) { + if (! DolibarrApi::_checkFilters($sqlfilters)) { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + $sql.= $db->order($sortfield, $sortorder); + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql.= $db->plimit($limit + 1, $offset); + } + + $result = $db->query($sql); + if ($result) { + $num = $db->num_rows($result); + while ($i < $num) { + $obj = $db->fetch_object($result); + $hook_static = new Hook($db); + if ($hook_static->fetch($obj->rowid)) { + $obj_ret[] = $this->_cleanObjectDatas($hook_static); + } + $i++; + } + } else { + throw new RestException(503, 'Error when retrieve hook list'); + } + if (! count($obj_ret)) { + throw new RestException(404, 'No hook found'); + } + return $obj_ret; + } + + /** + * Create hook object + * + * @param array $request_data Request datas + * @return int ID of hook + * + * @url POST /hook/ + */ + public function post($request_data = null) + { + // $debug = '
'.print_r($request_data, true).'
'; + // $debug .= '
'.print_r(DolibarrApiAccess::$user->rights->zapier, true).'
'; + // mail('frederic.france@free.fr', 'test hook', $debug); + if (! DolibarrApiAccess::$user->rights->zapier->write) { + throw new RestException(401); + } + // Check mandatory fields + $fields = array( + 'url', + ); + $result = $this->validate($request_data, $fields); + + foreach($request_data as $field => $value) { + $this->hook->$field = $value; + } + $this->hook->fk_user = DolibarrApiAccess::$user->id; + // on crée le hook dans la base + if( ! $this->hook->create(DolibarrApiAccess::$user)) { + throw new RestException(500, "Error creating Hook", array_merge(array($this->hook->error), $this->hook->errors)); + } + return array( + 'id' => $this->hook->id, + ); + } + + /** + * Update hook + * + * @param int $id Id of hook to update + * @param array $request_data Datas + * @return int + * + * @url PUT /hooks/{id} + */ + /*public function put($id, $request_data = null) + { + if (! DolibarrApiAccess::$user->rights->zapier->write) { + throw new RestException(401); + } + + $result = $this->hook->fetch($id); + if( ! $result ) { + throw new RestException(404, 'Hook not found'); + } + + if( ! DolibarrApi::_checkAccessToResource('hook', $this->hook->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + foreach($request_data as $field => $value) { + if ($field == 'id') { + continue; + } + $this->hook->$field = $value; + } + + if ($this->hook->update($id, DolibarrApiAccess::$user) > 0) { + return $this->get($id); + } else { + throw new RestException(500, $this->hook->error); + } + }*/ + + /** + * Delete hook + * + * @param int $id Hook ID + * @return array + * + * @url DELETE /hook/{id} + */ + public function delete($id) + { + if (! DolibarrApiAccess::$user->rights->zapier->delete) { + throw new RestException(401); + } + $result = $this->hook->fetch($id); + if (! $result) { + throw new RestException(404, 'Hook not found'); + } + + if (! DolibarrApi::_checkAccessToResource('hook', $this->hook->id)) { + throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); + } + + if (! $this->hook->delete(DolibarrApiAccess::$user)) { + throw new RestException(500, 'Error when deleting Hook : '.$this->hook->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Hook deleted' + ) + ); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore + /** + * Clean sensible object datas + * + * @param object $object Object to clean + * @return array Array of cleaned object properties + */ + public function _cleanObjectDatas($object) + { + // phpcs:disable + $object = parent::_cleanObjectDatas($object); + + /*unset($object->note); + unset($object->address); + unset($object->barcode_type); + unset($object->barcode_type_code); + unset($object->barcode_type_label); + unset($object->barcode_type_coder);*/ + + return $object; + } + + /** + * Validate fields before create or update object + * + * @param array $data Array of data to validate + * @param array $fields Array of fields needed + * @return array + * + * @throws RestException + */ + private function validate($data, $fields) + { + $hook = array(); + foreach ($fields as $field) { + if (!isset($data[$field])) { + throw new RestException(400, $field." field missing"); + } + $hook[$field] = $data[$field]; + } + return $hook; + } +} diff --git a/htdocs/zapier/class/hook.class.php b/htdocs/zapier/class/hook.class.php new file mode 100644 index 00000000000..4a3e670056e --- /dev/null +++ b/htdocs/zapier/class/hook.class.php @@ -0,0 +1,773 @@ + + * Copyright (C) 2019 Frédéric France + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/class/hook.class.php + * \ingroup zapier + * \brief This file is a CRUD class file for Hook (Create/Read/Update/Delete) + */ + +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; + +/** + * Class for Hook + */ +class Hook extends CommonObject +{ + /** + * @var string ID to identify managed object + */ + public $element = 'hook'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'zapier_hook'; + + /** + * @var int Does hook support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + */ + public $ismultientitymanaged = 0; + + /** + * @var int Does hook support extrafields ? 0=No, 1=Yes + */ + public $isextrafieldmanaged = 1; + + /** + * @var string String with name of icon for hook. Must be the part after the 'object_' into object_hook.png + */ + public $picto = 'hook@zapier'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_DISABLED = -1; + + + /** + * 'type' if the field format ('integer', 'integer:Class:pathtoclass', 'varchar(x)', 'double(24,8)', 'text', 'html', 'datetime', 'timestamp', 'float') + * 'label' the translation key. + * 'enabled' is a condition when the field must be managed. + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'default' is a default value for creation (can still be replaced by the global setup of default values) + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...). + * 'position' is the sort order of field. + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8). + * 'css' is the CSS style to use on field. For example: 'maxwidth200' + * 'help' is a string visible as a tooltip on field + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel") + */ + + /** + * @var array Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array( + 'rowid' => array( + 'type' => 'integer', + 'label' => 'TechnicalID', + 'enabled' => 1, + 'visible' => -2, + 'noteditable' => 1, + 'notnull' => 1, + 'index' => 1, + 'position' => 1, + 'comment' => 'Id', + ), + 'entity' => array( + 'type' => 'integer', + 'label' => 'Entity', + 'enabled' => 1, + 'visible' => 0, + 'notnull' => 1, + 'default' => 1, + 'index' => 1, + 'position' => 20, + ), + 'fk_user' => array( + 'type' => 'integer', + 'label' => 'UserOwner', + 'enabled' => 1, + 'visible' => -2, + 'notnull' => 1, + 'position' => 510, + 'foreignkey' => MAIN_DB_PREFIX.'user.rowid', + ), + 'url' => array( + 'type' => 'varchar(255)', + 'label' => 'Url', + 'enabled' => 1, + 'visible' => 1, + 'position' => 30, + 'searchall' => 1, + 'css' => 'minwidth200', + 'help' => 'Hook url', + 'showoncombobox' => 1, + ), + 'module' => array( + 'type' => 'varchar(128)', + 'label' => 'Url', + 'enabled' => 1, + 'visible' => 1, + 'position' => 30, + 'searchall' => 1, + 'css' => 'minwidth200', + 'help' => 'Hook module', + 'showoncombobox' => 1, + ), + 'action' => array( + 'type' => 'varchar(128)', + 'label' => 'Url', + 'enabled' => 1, + 'visible' => 1, + 'position' => 30, + 'searchall' => 1, + 'css' => 'minwidth200', + 'help' => 'Hook action trigger', + 'showoncombobox' => 1, + ), + 'event' => array( + 'type' => 'varchar(255)', + 'label' => 'Event', + 'enabled' => 1, + 'visible' => 1, + 'position' => 30, + 'searchall' => 1, + 'css' => 'minwidth200', + 'help' => 'Event', + 'showoncombobox' => 1, + ), + 'date_creation' => array( + 'type' => 'datetime', + 'label' => 'DateCreation', + 'enabled' => 1, + 'visible' => -2, + 'notnull' => 1, + 'position' => 500, + ), + 'import_key' => array( + 'type' => 'varchar(14)', + 'label' => 'ImportId', + 'enabled' => 1, + 'visible' => -2, + 'notnull' => -1, + 'index' => 0, + 'position' => 1000, + ), + 'status' => array( + 'type' => 'integer', + 'label' => 'Status', + 'enabled' => 1, + 'visible' => 1, + 'notnull' => 1, + 'default' => 0, + 'index' => 1, + 'position' => 1000, + 'arrayofkeyval' => array( + 0 => 'Draft', + 1 => 'Active', + -1 => 'Canceled', + ), + ), + ); + + /** + * @var int ID + */ + public $rowid; + + /** + * @var string Ref + */ + public $ref; + + /** + * @var int Entity + */ + public $entity; + + /** + * @var string label + */ + public $label; + + /** + * @var string amount + */ + public $amount; + + /** + * @var int Status + */ + public $status; + + /** + * @var integer|string date_creation + */ + public $date_creation; + + /** + * @var integer tms + */ + public $tms; + + /** + * @var int ID + */ + public $fk_user_creat; + + /** + * @var int ID + */ + public $fk_user_modif; + + /** + * @var string import_key + */ + public $import_key; + + + // If this object has a subtable with lines + + /** + * @var int Name of subtable line + */ + //public $table_element_line = 'hookdet'; + + /** + * @var int Field with ID of parent key if this field has a parent + */ + //public $fk_element = 'fk_hook'; + + /** + * @var int Name of subtable class that manage subtable lines + */ + //public $class_element_line = 'MyObjectline'; + + /** + * @var array Array of child tables (child tables to delete before deleting a record) + */ + //protected $childtables=array('hookdet'); + + /** + * @var MyObjectLine[] Array of subtable lines + */ + //public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs, $user; + + $this->db = $db; + + if (empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && isset($this->fields['rowid'])) { + $this->fields['rowid']['visible']=0; + } + if (empty($conf->multicompany->enabled) && isset($this->fields['entity'])) { + $this->fields['entity']['enabled']=0; + } + + // Unset fields that are disabled + foreach($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + foreach($this->fields as $key => $val) { + if (is_array($this->fields['status']['arrayofkeyval'])) { + foreach($this->fields['status']['arrayofkeyval'] as $key2 => $val2) { + $this->fields['status']['arrayofkeyval'][$key2]=$langs->trans($val2); + } + } + } + } + + /** + * Create object into database + * + * @param User $user User that creates + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + public function create(User $user, $notrigger = false) + { + return $this->createCommon($user, $notrigger); + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return mixed New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $hookmanager, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $object->fetchCommon($fromid); + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + $object->ref = "copy_of_".$object->ref; + $object->title = $langs->trans("CopyOf")." ".$object->title; + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->element); + foreach($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (! empty($extrafields->attributes[$this->element]['unique'][$shortkey])) { + // var_dump($key); + // var_dump($clonedObj->array_options[$key]); + // exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->error = $object->error; + $this->errors = $object->errors; + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @return int <0 if KO, 0 if not found, >0 if OK + */ + public function fetch($id, $ref = null) + { + $result = $this->fetchCommon($id, $ref); + if ($result > 0 && ! empty($this->table_element_line)) { + $this->fetchLines(); + } + return $result; + } + + /** + * Load object lines in memory from the database + * + * @return int <0 if KO, 0 if not found, >0 if OK + */ + /*public function fetchLines() + { + $this->lines=array(); + + // Load lines with object MyObjectLine + + return count($this->lines)?1:0; + }*/ + + /** + * Load list of objects in memory from the database. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int $limit limit + * @param int $offset Offset + * @param array $filter Filter array. Example array('field'=>'valueforlike', 'customurl'=>...) + * @param string $filtermode Filter mode (AND or OR) + * @return array|int int <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND') + { + global $conf; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $records=array(); + + $sql = 'SELECT'; + $sql .= ' t.rowid'; + // TODO Get all fields + $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t'; + $sql .= ' WHERE t.entity = '.$conf->entity; + // Manage filter + $sqlwhere = array(); + if (count($filter) > 0) { + foreach ($filter as $key => $value) { + if ($key=='t.rowid') { + $sqlwhere[] = $key . '='. $value; + } elseif (strpos($key, 'date') !== false) { + $sqlwhere[] = $key.' = \''.$this->db->idate($value).'\''; + } elseif ($key=='customsql') { + $sqlwhere[] = $value; + } else { + $sqlwhere[] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\''; + } + } + } + if (count($sqlwhere) > 0) { + $sql .= ' AND (' . implode(' '.$filtermode.' ', $sqlwhere).')'; + } + + if (!empty($sortfield)) { + $sql .= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql .= ' ' . $this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + + while ($obj = $this->db->fetch_object($resql)) { + $record = new self($this->db); + + $record->id = $obj->rowid; + // TODO Get other fields + + //var_dump($record->id); + $records[$record->id] = $record; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error ' . $this->db->lasterror(); + dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = false) + { + return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param bool $notrigger false=launch triggers after, true=disable triggers + * @return int <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = false) + { + return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Return a link to the object card (with optionaly the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $db, $conf, $langs, $hookmanager, $action; + global $dolibarr_main_authentication, $dolibarr_main_demo; + global $menumanager; + + if (! empty($conf->dol_no_mouse_hover)) { + // Force disable tooltips + $notooltip=1; + } + + $result = ''; + + $label = '' . $langs->trans("Hook") . ''; + $label.= '
'; + $label.= '' . $langs->trans('Ref') . ': ' . $this->ref; + + $url = dol_buildpath('/zapier/hook_card.php', 1).'?id='.$this->id; + + if ($option != 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values=1; + } + if ($add_save_lastsearch_values) { + $url.='&save_lastsearch_values=1'; + } + } + + $linkclose=''; + if (empty($notooltip)) { + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { + $label=$langs->trans("ShowMyObject"); + $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"'; + + /* + $hookmanager->initHooks(array('hookdao')); + $parameters=array('id'=>$this->id); + $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) $linkclose = $hookmanager->resPrint; + */ + } else { + $linkclose = ($morecss?' class="'.$morecss.'"':''); + } + + $linkstart = ''; + $linkend=''; + + $result .= $linkstart; + if ($withpicto) { + $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1); + } + if ($withpicto != 2) { + $result.= $this->ref; + } + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + $hookmanager->initHooks(array('hookdao')); + $parameters = array( + 'id' => $this->id, + 'getnomurl' => $result, + ); + // Note that $action and $object may have been modified by some hooks + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return label of the status + * + * @param int $mode 0 = long label + * 1 = short label + * 2 = Picto + short label + * 3 = Picto, 4=Picto + long label + * 5 = Short label + Picto + * 6 = Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the status + * + * @param int $status Id status + * @param int $mode 0 = long label, + * 1 = short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (empty($this->labelstatus)) { + global $langs; + //$langs->load("zapier@zapier"); + $this->labelstatus[1] = $langs->trans('Enabled'); + $this->labelstatus[0] = $langs->trans('Disabled'); + } + + if ($mode == 0) { + return $this->labelstatus[$status]; + } elseif ($mode == 1) { + return $this->labelstatus[$status]; + } elseif ($mode == 2) { + if ($status == 1) { + return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status]; + } elseif ($status == 0) { + return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status]; + } + } elseif ($mode == 3) { + if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle'); + elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle'); + } elseif ($mode == 4) { + if ($status == 1) return img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status]; + elseif ($status == 0) return img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle').' '.$this->labelstatus[$status]; + } elseif ($mode == 5) { + if ($status == 1) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle'); + elseif ($status == 0) return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle'); + } elseif ($mode == 6) { + if ($status == 1) { + return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut4', '', false, 0, 0, '', 'valignmiddle'); + } elseif ($status == 0) { + return $this->labelstatus[$status].' '.img_picto($this->labelstatus[$status], 'statut5', '', false, 0, 0, '', 'valignmiddle'); + } + } + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = 'SELECT rowid, date_creation as datec, tms as datem,'; + $sql.= ' fk_user_creat, fk_user_modif'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t'; + $sql.= ' WHERE t.rowid = '.$id; + $result=$this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_valid) { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_validation = $this->db->jdate($obj->datev); + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + public function initAsSpecimen() + { + $this->initAsSpecimenCommon(); + } + + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + //public function doScheduledJob($param1, $param2, ...) + public function doScheduledJob() + { + global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlofile.log'; + + $error = 0; + $this->output = ''; + $this->error=''; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + return $error; + } +} + +/** + * Class MyObjectLine. You can also remove this and generate a CRUD class for lines objects. + */ +/* +class MyObjectLine +{ + // @var int ID + public $id; + // @var mixed Sample line property 1 + public $prop1; + // @var mixed Sample line property 2 + public $prop2; +} +*/ diff --git a/htdocs/zapier/hook_agenda.php b/htdocs/zapier/hook_agenda.php new file mode 100644 index 00000000000..924db3b8632 --- /dev/null +++ b/htdocs/zapier/hook_agenda.php @@ -0,0 +1,261 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/myobject_agenda.php + * \ingroup mymodule + * \brief Page of MyObject events + */ + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +dol_include_once('/mymodule/class/myobject.class.php'); +dol_include_once('/mymodule/lib/mymodule_myobject.lib.php'); + + +// Load translation files required by the page +$langs->loadLangs(array("mymodule@mymodule","other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +if (GETPOST('actioncode', 'array')) +{ + $actioncode=GETPOST('actioncode', 'array', 3); + if (! count($actioncode)) $actioncode='0'; +} +else +{ + $actioncode=GETPOST("actioncode", "alpha", 3)?GETPOST("actioncode", "alpha", 3):(GETPOST("actioncode")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT)); +} +$search_agenda_label=GETPOST('search_agenda_label'); + +// Security check - Protection if external user +//if ($user->societe_id > 0) access_forbidden(); +//if ($user->societe_id > 0) $socid = $user->societe_id; +//$result = restrictedArea($user, 'mymodule', $id); + +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOST("page", 'int'); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortfield) $sortfield='a.datep,a.id'; +if (! $sortorder) $sortorder='DESC'; + +// Initialize technical objects +$object=new MyObject($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->mymodule->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('myobjectagenda','globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('myobject'); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || ! empty($ref)) $upload_dir = $conf->mymodule->multidir_output[$object->entity] . "/" . $object->id; + + + +/* + * Actions + */ + +$parameters=array('id'=>$socid); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + // Cancel + if (GETPOST('cancel', 'alpha') && ! empty($backtopage)) + { + header("Location: ".$backtopage); + exit; + } + + // Purge search criteria + 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 + { + $actioncode=''; + $search_agenda_label=''; + } +} + + + +/* + * View + */ + +$contactstatic = new Contact($db); + +$form = new Form($db); + +if ($object->id > 0) +{ + $title=$langs->trans("Agenda"); + //if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/thirdpartynameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->name." - ".$title; + $help_url = ''; + llxHeader('', $title, $help_url); + + if (! empty($conf->notification->enabled)) $langs->load("mails"); + $head = myobjectPrepareHead($object); + + + dol_fiche_head($head, 'agenda', $langs->trans("MyObject"), -1, 'myobject@mymodule'); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref='
'; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($user->rights->mymodule->creer) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref.=''; + $morehtmlref.=$proj->ref; + $morehtmlref.=''; + } else { + $morehtmlref.=''; + } + } + }*/ + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
'; + print '
'; + + $object->info($object->id); + print dol_print_object_info($object, 1); + + print '
'; + + dol_fiche_end(); + + + + // Actions buttons + + $objthirdparty=$object; + $objcon=new stdClass(); + + $out=''; + $permok=$user->rights->agenda->myactions->create; + if ((! empty($objthirdparty->id) || ! empty($objcon->id)) && $permok) + { + //$out.='trans("AddAnAction"),'filenew'); + //$out.=""; + } + + + print '
'; + + if (! empty($conf->agenda->enabled)) + { + if (! empty($user->rights->agenda->myactions->create) || ! empty($user->rights->agenda->allactions->create)) + { + print ''.$langs->trans("AddAction").''; + } + else + { + print ''.$langs->trans("AddAction").''; + } + } + + print '
'; + + if (! empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read) )) + { + $param='&socid='.$socid; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + + + print load_fiche_titre($langs->trans("ActionsOnMyObject"), '', ''); + + // List of all actions + $filters=array(); + $filters['search_agenda_label']=$search_agenda_label; + + // TODO Replace this with same code than into list.php + //show_actions_done($conf,$langs,$db,$object,null,0,$actioncode, '', $filters, $sortfield, $sortorder); + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/hook_card.php b/htdocs/zapier/hook_card.php new file mode 100644 index 00000000000..283e0a29749 --- /dev/null +++ b/htdocs/zapier/hook_card.php @@ -0,0 +1,471 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/myobject_card.php + * \ingroup mymodule + * \brief Page to create/edit/view myobject + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION','1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION','1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK','1'); // Do not check style html tag into posted data +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN",'1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too. +//if (! defined('NOIPCHECK')) define('NOIPCHECK','1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT','auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE','aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN',1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("FORCECSP")) define('FORCECSP','none'); // Disable all Content Security Policies + + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +dol_include_once('/mymodule/class/myobject.class.php'); +dol_include_once('/mymodule/lib/mymodule_myobject.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("mymodule@mymodule","other")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$contextpage= GETPOST('contextpage', 'aZ')?GETPOST('contextpage', 'aZ'):'myobjectcard'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object=new MyObject($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->mymodule->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('myobjectcard','globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); +$search_array_options=$extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Initialize array of search criterias +$search_all=trim(GETPOST("search_all", 'alpha')); +$search=array(); +foreach($object->fields as $key => $val) +{ + if (GETPOST('search_'.$key, 'alpha')) $search[$key]=GETPOST('search_'.$key, 'alpha'); +} + +if (empty($action) && empty($id) && empty($ref)) $action='view'; + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +// Security check - Protection if external user +//if ($user->societe_id > 0) access_forbidden(); +//if ($user->societe_id > 0) $socid = $user->societe_id; +//$isdraft = (($object->statut == MyObject::STATUS_DRAFT) ? 1 : 0); +//$result = restrictedArea($user, 'mymodule', $object->id, '', '', 'fk_soc', 'rowid', $isdraft); + + +/* + * Actions + * + * Put here all code to do according to value of "action" parameter + */ + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + $error=0; + + $permissiontoadd = $user->rights->mymodule->write; + $permissiontodelete = $user->rights->mymodule->delete || ($permissiontoadd && $object->status == 0); + $backurlforlist = dol_buildpath('/mymodule/myobject_list.php', 1); + if (empty($backtopage)) { + if (empty($id)) $backtopage = $backurlforlist; + else $backtopage = dol_buildpath('/mymodule/myobject_card.php', 1).($id > 0 ? $id : '__ID__'); + } + $triggermodname = 'MYMODULE_MYOBJECT_MODIFY'; // Name of trigger action code to execute when we modify record + + // Actions cancel, add, update, delete or clone + include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php'; + + // Actions when linking object each other + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + // Actions to send emails + $trigger_name='MYOBJECT_SENTBYMAIL'; + $autocopy='MAIN_MAIL_AUTOCOPY_MYOBJECT_TO'; + $trackid='myobject'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; +} + + + + +/* + * View + * + * Put here all code to build page + */ + +$form=new Form($db); +$formfile=new FormFile($db); + +llxHeader('', 'MyObject', ''); + +// Example : Adding jquery code +print ''; + + +// Part to create +if ($action == 'create') +{ + print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("MyObject"))); + + print '
'; + print ''; + print ''; + print ''; + + dol_fiche_head(array(), ''); + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php'; + + print '
'."\n"; + + dol_fiche_end(); + + print '
'; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
'; + + print '
'; +} + +// Part to edit record +if (($id || $ref) && $action == 'edit') +{ + print load_fiche_titre($langs->trans("MyObject")); + + print '
'; + print ''; + print ''; + print ''; + print ''; + + dol_fiche_head(); + + print ''."\n"; + + // Common attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_edit.tpl.php'; + + print '
'; + + dol_fiche_end(); + + print '
'; + print '   '; + print '
'; + + print '
'; +} + +// Part to show record +if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) +{ + $res = $object->fetch_optionals(); + + $head = myobjectPrepareHead($object); + dol_fiche_head($head, 'card', $langs->trans("MyObject"), -1, 'myobject@mymodule'); + + $formconfirm = ''; + + // Confirmation to delete + if ($action == 'delete') + { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteMyObject'), $langs->trans('ConfirmDeleteMyObject'), 'confirm_delete', '', 0, 1); + } + + // Clone confirmation + if ($action == 'clone') { + // Create an array for form + $formquestion = array(); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneMyObject', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Confirmation of action xxxx + if ($action == 'xxx') + { + $formquestion=array(); + /* + $forcecombo=0; + if ($conf->browser->name == 'ie') $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy + $formquestion = array( + // 'text' => $langs->trans("ConfirmClone"), + // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + // array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1, 0, 0, '', 0, $forcecombo)) + ); + */ + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220); + } + + // Call Hook formConfirm + $parameters = array('lineid' => $lineid); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint; + + // Print form confirm + print $formconfirm; + + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref='
'; + /* + // Ref bis + $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($user->rights->mymodule->write) + { + if ($action != 'classify') + $morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref.=$proj->getNomUrl(); + } else { + $morehtmlref.=''; + } + } + } + */ + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + print '
'; + print '
'; + print ''."\n"; + + // Common attributes + //$keyforbreak='fieldkeytoswithonsecondcolumn'; + include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_view.tpl.php'; + + // Other attributes + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
'; + print '
'; + print '
'; + + print '

'; + + dol_fiche_end(); + + + // Buttons for actions + if ($action != 'presend' && $action != 'editline') { + print '
'."\n"; + $parameters=array(); + $reshook=$hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + if (empty($reshook)) + { + // Send + print '' . $langs->trans('SendMail') . ''."\n"; + + // Modify + if ($user->rights->mymodule->write) + { + print ''.$langs->trans("Modify").''."\n"; + } + else + { + print ''.$langs->trans('Modify').''."\n"; + } + + // Clone + if ($user->rights->mymodule->write) + { + print ''; + } + + /* + if ($user->rights->mymodule->write) + { + if ($object->status == 1) + { + print ''.$langs->trans("Disable").''."\n"; + } + else + { + print ''.$langs->trans("Enable").''."\n"; + } + } + */ + + if ($user->rights->mymodule->delete) + { + print ''.$langs->trans('Delete').''."\n"; + } + else + { + print ''.$langs->trans('Delete').''."\n"; + } + } + print '
'."\n"; + } + + + // Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + + if ($action != 'presend') + { + print '
'; + print ''; // ancre + + // Documents + /*$objref = dol_sanitizeFileName($object->ref); + $relativepath = $comref . '/' . $comref . '.pdf'; + $filedir = $conf->mymodule->dir_output . '/' . $objref; + $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $genallowed = $user->rights->mymodule->read; // If you can read, you can build the PDF to read content + $delallowed = $user->rights->mymodule->create; // If you can create/edit, you can remove a file on card + print $formfile->showdocuments('mymodule', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang); + */ + + // Show links to link elements + $linktoelem = $form->showLinkToObjectBlock($object, null, array('myobject')); + $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + + + print '
'; + + $MAXEVENT = 10; + + $morehtmlright = ''; + $morehtmlright.= $langs->trans("SeeAll"); + $morehtmlright.= ''; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, 'myobject', $socid, 1, '', $MAXEVENT, '', $morehtmlright); + + print '
'; + } + + //Select mail models is same action as presend + /* + if (GETPOST('modelselected')) $action = 'presend'; + + // Presend form + $modelmail='inventory'; + $defaulttopic='InformationMessage'; + $diroutput = $conf->product->dir_output.'/inventory'; + $trackid = 'stockinv'.$object->id; + + include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php'; + */ +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/hook_document.php b/htdocs/zapier/hook_document.php new file mode 100644 index 00000000000..d9542daf64f --- /dev/null +++ b/htdocs/zapier/hook_document.php @@ -0,0 +1,166 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/myobject_document.php + * \ingroup mymodule + * \brief Tab for documents linked to MyObject + */ + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +dol_include_once('/mymodule/class/myobject.class.php'); +dol_include_once('/mymodule/lib/mymodule_myobject.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("mymodule@mymodule","companies","other","mails")); + + +$action=GETPOST('action', 'aZ09'); +$confirm=GETPOST('confirm'); +$id=(GETPOST('socid', 'int') ? GETPOST('socid', 'int') : GETPOST('id', 'int')); +$ref = GETPOST('ref', 'alpha'); + +// Security check - Protection if external user +//if ($user->societe_id > 0) access_forbidden(); +//if ($user->societe_id > 0) $socid = $user->societe_id; +//$result = restrictedArea($user, 'mymodule', $id); + +// Get parameters +$sortfield = GETPOST("sortfield", 'alpha'); +$sortorder = GETPOST("sortorder", 'alpha'); +$page = GETPOST("page", 'int'); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortorder) $sortorder="ASC"; +if (! $sortfield) $sortfield="name"; +//if (! $sortfield) $sortfield="position_name"; + +// Initialize technical objects +$object=new MyObject($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->mymodule->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('myobjectdocument','globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('myobject'); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals + +//if ($id > 0 || ! empty($ref)) $upload_dir = $conf->sellyoursaas->multidir_output[$object->entity] . "/myobject/" . dol_sanitizeFileName($object->id); +if ($id > 0 || ! empty($ref)) $upload_dir = $conf->sellyoursaas->multidir_output[$object->entity] . "/myobject/" . dol_sanitizeFileName($object->ref); + + +/* + * Actions + */ + +include_once DOL_DOCUMENT_ROOT . '/core/actions_linkedfiles.inc.php'; + + +/* + * View + */ + +$form = new Form($db); + +$title=$langs->trans("MyObject").' - '.$langs->trans("Files"); +$help_url=''; +//$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas'; +llxHeader('', $title, $help_url); + +if ($object->id) +{ + /* + * Show tabs + */ + $head = myobjectPrepareHead($object); + + dol_fiche_head($head, 'document', $langs->trans("MyObject"), -1, 'myobject@mymodule'); + + + // Build file list + $filearray=dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC), 1); + $totalsize=0; + foreach($filearray as $key => $file) + { + $totalsize+=$file['size']; + } + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + print '
'; + + print '
'; + print ''; + + // Number of files + print ''; + + // Total size + print ''; + + print '
'.$langs->trans("NbOfAttachedFiles").''.count($filearray).'
'.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").'
'; + + print '
'; + + dol_fiche_end(); + + $modulepart = 'mymodule'; + //$permission = $user->rights->mymodule->create; + $permission = 1; + //$permtoedit = $user->rights->mymodule->create; + $permtoedit = 1; + $param = '&id=' . $object->id; + + //$relativepathwithnofile='myobject/' . dol_sanitizeFileName($object->id).'/'; + $relativepathwithnofile='myobject/' . dol_sanitizeFileName($object->ref).'/'; + + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; +} +else +{ + accessforbidden('', 0, 0); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/hook_list.php b/htdocs/zapier/hook_list.php new file mode 100644 index 00000000000..015d1d8b1cd --- /dev/null +++ b/htdocs/zapier/hook_list.php @@ -0,0 +1,642 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/hook_list.php + * \ingroup mymodule + * \brief List page for hook + */ + +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); // Do not create database handler $db +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); // Do not load object $user +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); // Do not load object $mysoc +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); // Do not load object $langs +//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION','1'); // Do not check injection attack on GET parameters +//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION','1'); // Do not check injection attack on POST parameters +//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on). +//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on) +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK','1'); // Do not check style html tag into posted data +//if (! defined('NOIPCHECK')) define('NOIPCHECK','1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip +//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); // If there is no need to load and show top and left menu +//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); // If we don't need to load the html.form.class.php +//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); // Do not load ajax.lib.php library +//if (! defined("NOLOGIN")) define("NOLOGIN",'1'); // If this page is public (can be called outside logged session) +//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT','auto'); // Force lang to a particular value +//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE','aloginmodule'); // Force authentication handler +//if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN',1); // The main.inc.php does not make a redirect if not logged, instead show simple error message +//if (! defined("XFRAMEOPTIONS_ALLOWALL")) define('XFRAMEOPTIONS_ALLOWALL',1); // Do not add the HTTP header 'X-Frame-Options: SAMEORIGIN' but 'X-Frame-Options: ALLOWALL' + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once __DIR__.'/class/hook.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("mymodule@mymodule","other")); + +// The action 'add', 'create', 'edit', 'update', 'view', ... +$action = GETPOST('action', 'aZ09')?GETPOST('action', 'aZ09'):'view'; +// The bulk action (combo box choice into lists) +$massaction = GETPOST('massaction', 'alpha'); +$show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ? +$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation +$cancel = GETPOST('cancel', 'alpha'); // We click on a Cancel button +$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list +$contextpage = GETPOST('contextpage', 'aZ')?GETPOST('contextpage', 'aZ'):'hooklist'; // To manage different context of search +$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page +$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') + +$id = GETPOST('id', 'int'); + +// Load variable for pagination +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOST('page', 'int'); +if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) { + // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +//if (! $sortfield) $sortfield="p.date_fin"; +//if (! $sortorder) $sortorder="DESC"; + +// Initialize technical objects +$object = new Hook($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction = $conf->mymodule->dir_output . '/temp/massgeneration/'.$user->id; +// Note that conf->hooks_modules contains array +$hookmanager->initHooks(array('hooklist')); +// Fetch optionals attributes and labels +// Load $extrafields->attributes['hook'] +$extralabels = $extrafields->fetch_name_optionals_label('hook'); +$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); + +// Default sort order (if not yet defined by previous GETPOST) +if (! $sortfield) { + // Set here default search field. By default 1st field in definition. + $sortfield="t.".key($object->fields); +} +if (! $sortorder) { + $sortorder="ASC"; +} + +// Security check +$socid=0; +if ($user->societe_id > 0) { + // Protection if external user + //$socid = $user->societe_id; + accessforbidden(); +} +//$result = restrictedArea($user, 'mymodule', $id, ''); + +// Initialize array of search criterias +$search_all=trim(GETPOST("search_all", 'alpha')); +$search=array(); +foreach($object->fields as $key => $val) { + if (GETPOST('search_'.$key, 'alpha')) $search[$key]=GETPOST('search_'.$key, 'alpha'); +} + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array(); +foreach($object->fields as $key => $val) { + if ($val['searchall']) $fieldstosearchall['t.'.$key]=$val['label']; +} + +// Definition of fields for list +$arrayfields=array(); +foreach($object->fields as $key => $val) { + // If $val['visible']==0, then we never show the field + if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled'], 'position'=>$val['position']); +} +// Extra fields +if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) { + foreach($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + if (! empty($extrafields->attributes[$object->table_element]['list'][$key])) + $arrayfields["ef.".$key]=array('label'=>$extrafields->attributes[$object->table_element]['label'][$key], 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key]<0)?0:1), 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], 'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key])!=3 && $extrafields->attributes[$object->table_element]['perms'][$key])); + } +} +$object->fields = dol_sort_array($object->fields, 'position'); +$arrayfields = dol_sort_array($arrayfields, 'position'); + + + +/* + * Actions + */ + +if (GETPOST('cancel', 'alpha')) { + $action='list'; + $massaction=''; +} +if (! GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') { + $massaction=''; +} + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) { + // Selection of new fields + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + + // Purge search criteria + 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 + foreach($object->fields as $key => $val) { + $search[$key]=''; + } + $toselect=''; + $search_array_options=array(); + } + if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha') + || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) { + $massaction=''; // Protection to avoid mass action if we force a new search during a mass action confirmation + } + + // Mass actions + $objectclass='Hook'; + $objectlabel='Hook'; + $permtoread = $user->rights->mymodule->read; + $permtodelete = $user->rights->mymodule->delete; + $uploaddir = $conf->mymodule->dir_output; + include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; +} + + + +/* + * View + */ + +$form=new Form($db); + +$now=dol_now(); + +//$help_url="EN:Module_Hook|FR:Module_Hook_FR|ES:Módulo_Hook"; +$help_url=''; +$title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("Hooks")); + + +// Build and execute select +// -------------------------------------------------------------------- +$sql = 'SELECT '; +foreach($object->fields as $key => $val) { + $sql.='t.'.$key.', '; +} +// Add fields from extrafields +if (! empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) { + $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.' as options_'.$key.', ' : ''); + } +} +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql=preg_replace('/, $/', '', $sql); +$sql.= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t"; +if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)"; +if ($object->ismultientitymanaged == 1) { + $sql.= " WHERE t.entity IN (".getEntity($object->element).")"; +} else { + $sql.=" WHERE 1 = 1"; +} +foreach($search as $key => $val) { + if ($key == 'status' && $search[$key] == -1) { + continue; + } + $mode_search=(($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key]))?1:0); + if ($search[$key] != '') { + $sql.=natural_search($key, $search[$key], (($key == 'status')?2:$mode_search)); + } +} +if ($search_all) { + $sql.= natural_search(array_keys($fieldstosearchall), $search_all); +} +// Add where from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +/* If a group by is required +$sql.= " GROUP BY " +foreach($object->fields as $key => $val) +{ + $sql.='t.'.$key.', '; +} +// Add fields from extrafields +if (! empty($extrafields->attributes[$object->table_element]['label'])) { + foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : ''); +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListGroupBy',$parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql=preg_replace('/, $/','', $sql); +*/ + +$sql.=$db->order($sortfield, $sortorder); + +// Count total nb of records +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { + $resql = $db->query($sql); + $nbtotalofrecords = $db->num_rows($resql); + if (($page * $limit) > $nbtotalofrecords) { + // if total of record found is smaller than page * limit, goto and load page 0 + $page = 0; + $offset = 0; + } +} +// 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) { + $num = $nbtotalofrecords; +} else { + $sql.= $db->plimit($limit+1, $offset); + + $resql=$db->query($sql); + if (! $resql) { + dol_print_error($db); + exit; + } + + $num = $db->num_rows($resql); +} + +// Direct jump if only one record found +if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all) { + $obj = $db->fetch_object($resql); + $id = $obj->rowid; + header("Location: ".dol_buildpath('/zapierfordolibarr/hook_card.php', 1).'?id='.$id); + exit; +} + + +// Output page +// -------------------------------------------------------------------- + +llxHeader('', $title, $help_url); + +// Example : Adding jquery code +print ''; + +$arrayofselected=is_array($toselect)?$toselect:array(); + +$param=''; +if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); +foreach($search as $key => $val) { + if (is_array($search[$key]) && count($search[$key])) { + foreach($search[$key] as $skey) { + $param.='&search_'.$key.'[]='.urlencode($skey); + } + } else { + $param.= '&search_'.$key.'='.urlencode($search[$key]); + } +} +if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss); +// Add $param from extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; + +// List of mass actions available +$arrayofmassactions = array( + //'presend'=>$langs->trans("SendByMail"), + //'builddoc'=>$langs->trans("PDFMerge"), +); +if ($user->rights->mymodule->delete) $arrayofmassactions['predelete']=''.$langs->trans("Delete"); +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend','predelete'))) $arrayofmassactions=array(); +$massactionbutton=$form->selectMassAction('', $arrayofmassactions); + +print '
'; +if ($optioncss != '') print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +$newcardbutton=''; +//if ($user->rights->mymodule->creer) +//{ + $newcardbutton=''.$langs->trans('New').''; + $newcardbutton.= ''; + $newcardbutton.= ''; +//} +//else +//{ +// $newcardbutton=''.$langs->trans('New').'; +// $newcardbutton.= ''; +// $newcardbutton.= ''; +//} + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_companies', 0, $newcardbutton, '', $limit); + +// Add code for pre mass action (confirmation or email presend form) +$topicmail="SendHookRef"; +$modelmail="hook"; +$objecttmp=new Hook($db); +$trackid='xxxx'.$object->id; +include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; + +if ($sall) { + foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + print '
'.$langs->trans("FilterOnInto", $sall) . join(', ', $fieldstosearchall).'
'; +} + +$moreforfilter = ''; +/*$moreforfilter.='
'; +$moreforfilter.= $langs->trans('MyFilter') . ': '; +$moreforfilter.= '
';*/ + +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +if (empty($reshook)) $moreforfilter .= $hookmanager->resPrint; +else $moreforfilter = $hookmanager->resPrint; + +if (! empty($moreforfilter)) { + print '
'; + print $moreforfilter; + print '
'; +} + +$varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; +$selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields +$selectedfields.=(count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : ''); + +print '
'; // You can use div-table-responsive-no-min if you dont need reserved height for your table +print ''."\n"; + + +// Fields title search +// -------------------------------------------------------------------- +print ''; +foreach($object->fields as $key => $val) { + $cssforfield=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) { + $cssforfield.=($cssforfield?' ':'').'center'; + } + if (in_array($val['type'], array('timestamp'))) { + $cssforfield.=($cssforfield?' ':'').'nowrap'; + } + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real'))) { + $cssforfield.=($cssforfield?' ':'').'right'; + } + if ($key == 'status') { + $cssforfield.=($cssforfield?' ':'').'center'; + } + if (! empty($arrayfields['t.'.$key]['checked'])) { + print ''; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; + +// Fields from hook +$parameters=array('arrayfields'=>$arrayfields); +$reshook=$hookmanager->executeHooks('printFieldListOption', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print ''; +print ''."\n"; + + +// Fields title label +// -------------------------------------------------------------------- +print ''; +foreach($object->fields as $key => $val) { + $cssforfield=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) $cssforfield.=($cssforfield?' ':'').'center'; + if (in_array($val['type'], array('timestamp'))) $cssforfield.=($cssforfield?' ':'').'nowrap'; + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real'))) $cssforfield.=($cssforfield?' ':'').'right'; + if ($key == 'status') { + $cssforfield.=($cssforfield?' ':'').'center'; + } + if (! empty($arrayfields['t.'.$key]['checked'])) { + print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield?'class="'.$cssforfield.'"':''), $sortfield, $sortorder, ($cssforfield?$cssforfield.' ':''))."\n"; + } +} +// Extra fields +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php'; +// Hook fields +$parameters = array( + 'arrayfields' => $arrayfields, + 'param' => $param, + 'sortfield' => $sortfield, + 'sortorder' => $sortorder, +); +$reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; +// Action column +print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n"; +print ''."\n"; + + +// Detect if we need a fetch on each output line +$needToFetchEachLine=0; +if (is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0) { + foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) { + if (preg_match('/\$object/', $val)) { + // There is at least one compute field that use $object + $needToFetchEachLine++; + } + } +} + + +// Loop on record +// -------------------------------------------------------------------- +$i=0; +$totalarray=array(); +while ($i < min($num, $limit)) { + $obj = $db->fetch_object($resql); + if (empty($obj)) { + break; // Should not happen + } + + // Store properties in $object + $object->id = $obj->rowid; + foreach($object->fields as $key => $val) { + if (isset($obj->$key)) $object->$key = $obj->$key; + } + + // Show here line of result + print ''; + foreach($object->fields as $key => $val) { + $cssforfield=''; + if (in_array($val['type'], array('date','datetime','timestamp'))) { + $cssforfield.=($cssforfield?' ':'').'center'; + } elseif ($key == 'status') { + $cssforfield.=($cssforfield?' ':'').'center'; + } + + if (in_array($val['type'], array('timestamp'))) $cssforfield.=($cssforfield?' ':'').'nowrap'; + elseif ($key == 'ref') $cssforfield.=($cssforfield?' ':'').'nowrap'; + + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real'))) $cssforfield.=($cssforfield?' ':'').'right'; + + if (! empty($arrayfields['t.'.$key]['checked'])) { + print ''; + if ($key == 'status') print $object->getLibStatut(5); + elseif (in_array($val['type'], array('date','datetime','timestamp'))) print $object->showOutputField($val, $key, $db->jdate($obj->$key), ''); + else print $object->showOutputField($val, $key, $obj->$key, ''); + print ''; + if (! $i) $totalarray['nbfield']++; + if (! empty($val['isameasure'])) + { + if (! $i) $totalarray['pos'][$totalarray['nbfield']]='t.'.$key; + $totalarray['val']['t.'.$key] += $obj->$key; + } + } + } + // Extra fields + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php'; + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj); + $reshook=$hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Action column + print ''; + if (! $i) $totalarray['nbfield']++; + + print ''; + + $i++; +} + +// Show total line +if (isset($totalarray['pos'])) { + print ''; + $i=0; + while ($i < $totalarray['nbfield']) { + $i++; + if (! empty($totalarray['pos'][$i])) { + print ''; + } else { + if ($i == 1) { + if ($num < $limit) { + print ''; + } else { + print ''; + } + } else { + print ''; + } + } + } + print ''; +} + +// If no record found +if ($num == 0) { + $colspan=1; + foreach($arrayfields as $key => $val) { + if (! empty($val['checked'])) { + $colspan++; + } + } + print ''; +} + + +$db->free($resql); + +$parameters = array( + 'arrayfields' => $arrayfields, + 'sql' => $sql, +); +$reshook=$hookmanager->executeHooks('printFieldListFooter', $parameters, $object); // Note that $action and $object may have been modified by hook +print $hookmanager->resPrint; + +print '
'; +$searchpicto=$form->showFilterButtons(); +print $searchpicto; +print '
'; + if ($massactionbutton || $massaction) { + // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + $selected=0; + if (in_array($obj->rowid, $arrayofselected)) $selected=1; + print ''; + } + print '
'.price($totalarray['val'][$totalarray['pos'][$i]]).''.$langs->trans("Total").''.$langs->trans("Totalforthispage").'
'.$langs->trans("NoRecordFound").'
'."\n"; +print '
'."\n"; + +print '
'."\n"; + +if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords)) { + $hidegeneratedfilelistifempty=1; + if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) { + $hidegeneratedfilelistifempty=0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + $formfile = new FormFile($db); + + // Show list of available documents + $urlsource=$_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; + $urlsource.=str_replace('&', '&', $param); + + $filedir=$diroutputmassaction; + $genallowed=$user->rights->mymodule->read; + $delallowed=$user->rights->mymodule->create; + + print $formfile->showdocuments('massfilesarea_mymodule', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/hook_note.php b/htdocs/zapier/hook_note.php new file mode 100644 index 00000000000..0cbf4c40d8b --- /dev/null +++ b/htdocs/zapier/hook_note.php @@ -0,0 +1,164 @@ + + * Copyright (C) ---Put here your own copyright and developer email--- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/modulebuilder/template/myobject_note.php + * \ingroup mymodule + * \brief Car with notes on MyObject + */ + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +dol_include_once('/mymodule/class/myobject.class.php'); +dol_include_once('/mymodule/lib/mymodule_myobject.lib.php'); + +// Load translation files required by the page +$langs->loadLangs(array("mymodule@mymodule","companies")); + +// Get parameters +$id = GETPOST('id', 'int'); +$ref = GETPOST('ref', 'alpha'); +$action = GETPOST('action', 'alpha'); +$cancel = GETPOST('cancel', 'aZ09'); +$backtopage = GETPOST('backtopage', 'alpha'); + +// Initialize technical objects +$object=new MyObject($db); +$extrafields = new ExtraFields($db); +$diroutputmassaction=$conf->mymodule->dir_output . '/temp/massgeneration/'.$user->id; +$hookmanager->initHooks(array('myobjectnote','globalcard')); // Note that conf->hooks_modules contains array +// Fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('myobject'); + +// Security check - Protection if external user +//if ($user->societe_id > 0) access_forbidden(); +//if ($user->societe_id > 0) $socid = $user->societe_id; +//$result = restrictedArea($user, 'mymodule', $id); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals +if ($id > 0 || ! empty($ref)) $upload_dir = $conf->mymodule->multidir_output[$object->entity] . "/" . $object->id; + +$permissionnote=1; +//$permissionnote=$user->rights->mymodule->creer; // Used by the include of actions_setnotes.inc.php + + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once + + +/* + * View + */ + +$form = new Form($db); + +//$help_url='EN:Customers_Orders|FR:Commandes_Clients|ES:Pedidos de clientes'; +$help_url=''; +llxHeader('', $langs->trans('MyObject'), $help_url); + +if ($id > 0 || ! empty($ref)) +{ + $object->fetch_thirdparty(); + + $head = myobjectPrepareHead($object); + + dol_fiche_head($head, 'note', $langs->trans("MyObject"), -1, 'myobject@mymodule'); + + // Object card + // ------------------------------------------------------------ + $linkback = '' . $langs->trans("BackToList") . ''; + + $morehtmlref='
'; + /* + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, 0, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($user->rights->mymodule->creer) + { + if ($action != 'classify') + //$morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + $morehtmlref.=' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref.=''; + $morehtmlref.=$proj->ref; + $morehtmlref.=''; + } else { + $morehtmlref.=''; + } + } + }*/ + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + print '
'; + + + $cssclass="titlefield"; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + print '
'; + + dol_fiche_end(); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/zapier/img/object_hook.png b/htdocs/zapier/img/object_hook.png new file mode 100644 index 0000000000000000000000000000000000000000..5a307bfc62f85df909a3cf024f27ee87d44be275 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt)eIT^vI+ zChono-m4{0gyqBiz=Ju)w^;&N<{#X1a0!1>bC%GsW3bBL=<%|p84;9-@5SwA|2OIEL% zb=QtBT0T9C&(LA{syqXqqW_DHn`b;(x5}@uA-g2{Ncy)Mhpp~Sy0eY()*3IP6|4C4 z(mDEHWvtPCEP7WZe7{4e?P9&>AE%^j|Mz!&9rL?{G_w^d>;^y&GkCiCxvX~}U&Kt)eIT^vI+ zChono-m4{0gyqBiz=Ju)w^;&N<{#X1a0!1>bC%GsW3bBL=<%|p84;9-@5SwA|2OIEL% zb=QtBT0T9C&(LA{syqXqqW_DHn`b;(x5}@uA-g2{Ncy)Mhpp~Sy0eY()*3IP6|4C4 z(mDEHWvtPCEP7WZe7{4e?P9&>AE%^j|Mz!&9rL?{G_w^d>;^y&GkCiCxvX&bpol<(u!rW?;H+EQ%enXNbFO(BxM6em zT6?Xvzwg`ooU^Y){|U(ZFQBI!m!$&}L7j!5{;fYTRT7^Ei2`otSo}~$jn`>$_0GV8{|=a0ceV}S zT##S2)dC>kW)OEac4ad=0PF{D)D5n&1&hE|5*Fn>+!87O7%&6uq>(Lac(63vU3r8dAUkz5(vJ*$kYi!M+3>2Chh&smne_ z0k^l4oC%S=;mTvomp7S=zUfMq-Pa*-4U* z(fYvM9@LwZ^Z;0LC%nYcD^%FWV(tM!t@kx*iR5*SB+L^EYlZ(WSOrixfZrRuvN}?F RO?LnQ002ovPDHLkV1iP-B{u*7 literal 0 HcmV?d00001 diff --git a/htdocs/zapier/lib/zapier.lib.php b/htdocs/zapier/lib/zapier.lib.php new file mode 100644 index 00000000000..8fc4810599d --- /dev/null +++ b/htdocs/zapier/lib/zapier.lib.php @@ -0,0 +1,58 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file zapier/lib/zapier.lib.php + * \ingroup zapier + * \brief Library files with common functions for ZapierForDolibarr + */ + +/** + * Prepare admin pages header + * + * @return array + */ +function zapierAdminPrepareHead() +{ + global $langs, $conf; + + $langs->load("zapier@zapier"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/zapier/admin/setup.php", 1); + $head[$h][1] = $langs->trans("Settings"); + $head[$h][2] = 'settings'; + $h++; + $head[$h][0] = dol_buildpath("/zapier/admin/about.php", 1); + $head[$h][1] = $langs->trans("About"); + $head[$h][2] = 'about'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@zapier:/zapier/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@zapier:/zapier/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'zapier'); + + return $head; +} diff --git a/htdocs/zapier/lib/zapier_hook.lib.php b/htdocs/zapier/lib/zapier_hook.lib.php new file mode 100644 index 00000000000..e1af0259062 --- /dev/null +++ b/htdocs/zapier/lib/zapier_hook.lib.php @@ -0,0 +1,83 @@ +. + */ + +/** + * \file htdocs/modulebuilder/template/lib/mymodule_myobject.lib.php + * \ingroup mymodule + * \brief Library files with common functions for MyObject + */ + +/** + * Prepare array of tabs for MyObject + * + * @param MyObject $object MyObject + * @return array Array of tabs + */ +function myobjectPrepareHead($object) +{ + global $db, $langs, $conf; + + $langs->load("mymodule@mymodule"); + + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/mymodule/myobject_card.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Card"); + $head[$h][2] = 'card'; + $h++; + + if (isset($object->fields['note_public']) || isset($object->fields['note_private'])) + { + $nbNote = 0; + if (!empty($object->note_private)) $nbNote++; + if (!empty($object->note_public)) $nbNote++; + $head[$h][0] = dol_buildpath('/mymodule/myobject_note.php', 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) $head[$h][1].= ' '.$nbNote.''; + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; + $upload_dir = $conf->mymodule->dir_output . "/myobject/" . dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); + $nbLinks=Link::count($db, $object->element, $object->id); + $head[$h][0] = dol_buildpath("/mymodule/myobject_document.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if (($nbFiles+$nbLinks) > 0) $head[$h][1].= ' '.($nbFiles+$nbLinks).''; + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = dol_buildpath("/mymodule/myobject_agenda.php", 1).'?id='.$object->id; + $head[$h][1] = $langs->trans("Events"); + $head[$h][2] = 'agenda'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + //$this->tabs = array( + // 'entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__' + //); // to add new tab + //$this->tabs = array( + // 'entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__' + //); // to remove a tab + complete_head_from_modules($conf, $langs, $object, $head, $h, 'myobject@mymodule'); + + return $head; +} diff --git a/htdocs/zapier/sql/llx_zapier_hook.key.sql b/htdocs/zapier/sql/llx_zapier_hook.key.sql new file mode 100644 index 00000000000..d707e6bba1a --- /dev/null +++ b/htdocs/zapier/sql/llx_zapier_hook.key.sql @@ -0,0 +1,22 @@ +-- Copyright (C) ---Put here your own copyright and developer email--- +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see http://www.gnu.org/licenses/. + + +--ALTER TABLE llx_zapierfordolibarr_hook ADD INDEX idx_fieldobject (fieldobject); + +--ALTER TABLE llx_zapierfordolibarr_hook ADD UNIQUE INDEX uk_zapierfordolibarr_hook_fieldxy(fieldx, fieldy); + +--ALTER TABLE llx_zapierfordolibarr_hook ADD CONSTRAINT llx_zapierfordolibarr_hook_fk_field FOREIGN KEY (fk_field) REFERENCES llx_zapierfordolibarr_myotherobject(rowid); + diff --git a/htdocs/zapier/sql/llx_zapier_hook.sql b/htdocs/zapier/sql/llx_zapier_hook.sql new file mode 100644 index 00000000000..829ec2bfdc4 --- /dev/null +++ b/htdocs/zapier/sql/llx_zapier_hook.sql @@ -0,0 +1,29 @@ +-- Copyright (C) ---Put here your own copyright and developer email--- +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see http://www.gnu.org/licenses/. + + +CREATE TABLE llx_zapierfordolibarr_hook( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, + url varchar(255), + event varchar(255), + module varchar(128), + action varchar(128), + status integer, + date_creation DATETIME NOT NULL, + fk_user integer NOT NULL, + tms TIMESTAMP NOT NULL, + import_key varchar(14) +) ENGINE=innodb; \ No newline at end of file diff --git a/htdocs/zapier/sql/llx_zapier_hook_extrafields.sql b/htdocs/zapier/sql/llx_zapier_hook_extrafields.sql new file mode 100644 index 00000000000..c840007412b --- /dev/null +++ b/htdocs/zapier/sql/llx_zapier_hook_extrafields.sql @@ -0,0 +1,23 @@ +-- Copyright (C) ---Put here your own copyright and developer email--- +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see http://www.gnu.org/licenses/. + +create table llx_zapierfordolibarr_hook_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + diff --git a/htdocs/zapier/zapierindex.php b/htdocs/zapier/zapierindex.php new file mode 100644 index 00000000000..6e9e0491946 --- /dev/null +++ b/htdocs/zapier/zapierindex.php @@ -0,0 +1,238 @@ + + * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2015 Jean-François Ferry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/zapierfordolibarr/template/zapierfordolibarrindex.php + * \ingroup zapierfordolibarr + * \brief Home page of zapierfordolibarr top menu + */ + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + +// Load translation files required by the page +$langs->loadLangs(array("zapierfordolibarr@zapierfordolibarr")); + +$action=GETPOST('action', 'alpha'); + + +// Securite acces client +if (! $user->rights->zapierfordolibarr->read) accessforbidden(); +$socid=GETPOST('socid', 'int'); +if (isset($user->societe_id) && $user->societe_id > 0) +{ + $action = ''; + $socid = $user->societe_id; +} + +$max=5; +$now=dol_now(); + + +/* + * Actions + */ + +// None + + +/* + * View + */ + +$form = new Form($db); +$formfile = new FormFile($db); + +llxHeader("", $langs->trans("ZapierForDolibarrArea")); + +print load_fiche_titre($langs->trans("ZapierForDolibarrArea"), '', 'zapierfordolibarr.png@zapierfordolibarr'); + +print '
'; + + +/* BEGIN MODULEBUILDER DRAFT MYOBJECT +// Draft MyObject +if (! empty($conf->zapierfordolibarr->enabled) && $user->rights->zapierfordolibarr->read) +{ + $langs->load("orders"); + + $sql = "SELECT c.rowid, c.ref, c.ref_client, c.total_ht, c.tva as total_tva, c.total_ttc, s.rowid as socid, s.nom as name, s.client, s.canvas"; + $sql.= ", s.code_client"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande as c"; + $sql.= ", ".MAIN_DB_PREFIX."societe as s"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.fk_statut = 0"; + $sql.= " AND c.entity IN (".getEntity('commande').")"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid) $sql.= " AND c.fk_soc = ".$socid; + + $resql = $db->query($sql); + if ($resql) + { + $total = 0; + $num = $db->num_rows($resql); + + print ''; + print ''; + print ''; + + $var = true; + if ($num > 0) + { + $i = 0; + while ($i < $num) + { + + $obj = $db->fetch_object($resql); + print ''; + print ''; + print ''; + $i++; + $total += $obj->total_ttc; + } + if ($total>0) + { + + print '"; + } + } + else + { + + print ''; + } + print "
'.$langs->trans("DraftOrders").($num?' '.$num.'':'').'
'; + $orderstatic->id=$obj->rowid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_client=$obj->ref_client; + $orderstatic->total_ht = $obj->total_ht; + $orderstatic->total_tva = $obj->total_tva; + $orderstatic->total_ttc = $obj->total_ttc; + print $orderstatic->getNomUrl(1); + print ''; + $companystatic->id=$obj->socid; + $companystatic->name=$obj->name; + $companystatic->client=$obj->client; + $companystatic->code_client = $obj->code_client; + $companystatic->code_fournisseur = $obj->code_fournisseur; + $companystatic->canvas=$obj->canvas; + print $companystatic->getNomUrl(1,'customer',16); + print ''.price($obj->total_ttc).'
'.$langs->trans("Total").''.price($total)."
'.$langs->trans("NoOrder").'

"; + + $db->free($resql); + } + else + { + dol_print_error($db); + } +} +END MODULEBUILDER DRAFT MYOBJECT */ + + +print '
'; + + +$NBMAX=3; +$max=3; + +/* BEGIN MODULEBUILDER LASTMODIFIED MYOBJECT +// Last modified myobject +if (! empty($conf->zapierfordolibarr->enabled) && $user->rights->zapierfordolibarr->read) +{ + $sql = "SELECT s.rowid, s.nom as name, s.client, s.datec, s.tms, s.canvas"; + $sql.= ", s.code_client"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE s.client IN (1, 2, 3)"; + $sql.= " AND s.entity IN (".getEntity($companystatic->element).")"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid) $sql.= " AND s.rowid = $socid"; + $sql .= " ORDER BY s.tms DESC"; + $sql .= $db->plimit($max, 0); + + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + + print ''; + print ''; + print ''; + print ''; + print ''; + if ($num) + { + while ($i < $num) + { + $objp = $db->fetch_object($resql); + $companystatic->id=$objp->rowid; + $companystatic->name=$objp->name; + $companystatic->client=$objp->client; + $companystatic->code_client = $objp->code_client; + $companystatic->code_fournisseur = $objp->code_fournisseur; + $companystatic->canvas=$objp->canvas; + print ''; + print ''; + print '"; + print '"; + print ''; + $i++; + + + } + + $db->free($resql); + } + else + { + print ''; + } + print "
'; + if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) print $langs->trans("BoxTitleLastCustomersOrProspects",$max); + else if (! empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) print $langs->trans("BoxTitleLastModifiedProspects",$max); + else print $langs->trans("BoxTitleLastModifiedCustomers",$max); + print ''.$langs->trans("DateModificationShort").'
'.$companystatic->getNomUrl(1,'customer',48).''; + print $companystatic->getLibCustProspStatut(); + print "'.dol_print_date($db->jdate($objp->tms),'day')."
'.$langs->trans("None").'

"; + } +} +*/ + +print '
'; + +// End of page +llxFooter(); +$db->close(); From 872800f604225203f018ff89c8cc89a7486ffab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 19 May 2019 21:38:29 +0200 Subject: [PATCH 05/44] zapier for dolibarr --- .tx/config | 6 ++++++ htdocs/zapier/class/hook.class.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.tx/config b/.tx/config index 0044fb91f49..5c52849c29c 100644 --- a/.tx/config +++ b/.tx/config @@ -410,3 +410,9 @@ source_file = htdocs/langs/en_US/workflow.lang source_lang = en_US type = MOZILLAPROPERTIES +[dolibarr.zapier] +file_filter = htdocs/langs//zapier.lang +source_file = htdocs/langs/en_US/zapier.lang +source_lang = en_US +type = MOZILLAPROPERTIES + diff --git a/htdocs/zapier/class/hook.class.php b/htdocs/zapier/class/hook.class.php index 4a3e670056e..666e3e6df57 100644 --- a/htdocs/zapier/class/hook.class.php +++ b/htdocs/zapier/class/hook.class.php @@ -111,7 +111,7 @@ class Hook extends CommonObject 'visible' => -2, 'notnull' => 1, 'position' => 510, - 'foreignkey' => MAIN_DB_PREFIX.'user.rowid', + 'foreignkey' => (MAIN_DB_PREFIX.'user.rowid'), ), 'url' => array( 'type' => 'varchar(255)', From 08b1f123b0a24a26d7adbf3a212cb1d004378e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 19 May 2019 21:49:34 +0200 Subject: [PATCH 06/44] zapier for dolibarr --- dev/examples/zapier/package.json | 8 ++++---- htdocs/zapier/class/hook.class.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/examples/zapier/package.json b/dev/examples/zapier/package.json index 30ea4939915..8fbd203f962 100644 --- a/dev/examples/zapier/package.json +++ b/dev/examples/zapier/package.json @@ -1,10 +1,10 @@ { "name": "Dolibarr", - "version": "1.0.2", + "version": "1.0.0", "description": "An app for connecting Dolibarr to the Zapier platform.", - "repository": "frederic34/ZapierForDolibarr", - "homepage": "https://netlogic-dev.fr/", - "author": "Frédéric France ", + "repository": "Dolibarr/dolibarr", + "homepage": "https://www.dolibarr.fr/", + "author": "Frédéric France ", "license": "BSD-3-Clause", "main": "index.js", "scripts": { diff --git a/htdocs/zapier/class/hook.class.php b/htdocs/zapier/class/hook.class.php index 666e3e6df57..81b76b1c81f 100644 --- a/htdocs/zapier/class/hook.class.php +++ b/htdocs/zapier/class/hook.class.php @@ -111,7 +111,7 @@ class Hook extends CommonObject 'visible' => -2, 'notnull' => 1, 'position' => 510, - 'foreignkey' => (MAIN_DB_PREFIX.'user.rowid'), + 'foreignkey' => 'llx_user.rowid', ), 'url' => array( 'type' => 'varchar(255)', From ecc4d4227b106a430f647fcd0b252b61120fc20b Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Sat, 29 Jun 2019 10:14:46 +0200 Subject: [PATCH 07/44] translations --- .../core/modules/project/doc/pdf_baleine.modules.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/core/modules/project/doc/pdf_baleine.modules.php b/htdocs/core/modules/project/doc/pdf_baleine.modules.php index c7005206fcc..b9ecd61c61c 100644 --- a/htdocs/core/modules/project/doc/pdf_baleine.modules.php +++ b/htdocs/core/modules/project/doc/pdf_baleine.modules.php @@ -139,15 +139,15 @@ class pdf_baleine extends ModelePDFProjects $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; - $this->option_logo = 1; // Affiche logo FAC_PDF_LOGO - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_logo = 1; // Display logo FAC_PDF_LOGO + $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION + $this->option_codeproduitservice = 1; // Display product-service code - // Recupere emmetteur + // Get source company $this->emetteur=$mysoc; if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang, -2); // By default if not defined - // Defini position des colonnes + // Define position of columns $this->posxref=$this->marge_gauche+1; $this->posxlabel=$this->marge_gauche+25; $this->posxworkload=$this->marge_gauche+120; @@ -168,7 +168,7 @@ class pdf_baleine extends ModelePDFProjects // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** - * Fonction generant le projet sur le disque + * Function to build pdf project onto disk * * @param Project $object Object project a generer * @param Translate $outputlangs Lang output object From 05e9885ba71e6517bfc3d24f1f10ffbe9c7df839 Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Sat, 29 Jun 2019 10:18:45 +0200 Subject: [PATCH 08/44] translations --- htdocs/core/modules/project/doc/pdf_beluga.modules.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/core/modules/project/doc/pdf_beluga.modules.php b/htdocs/core/modules/project/doc/pdf_beluga.modules.php index dfbe97c3fd5..97414e745eb 100644 --- a/htdocs/core/modules/project/doc/pdf_beluga.modules.php +++ b/htdocs/core/modules/project/doc/pdf_beluga.modules.php @@ -21,7 +21,7 @@ /** * \file htdocs/core/modules/project/doc/pdf_beluga.modules.php * \ingroup project - * \brief Fichier de la classe permettant de generer les projets au modele beluga + * \brief File of class to generate project document beluga * \author Charlie Benke */ @@ -50,7 +50,7 @@ if (! empty($conf->agenda->enabled)) require_once DOL_DOCUMENT_ROOT.'/com /** - * Class to manage generation of project document Baleine + * Class to manage generation of project document beluga */ class pdf_beluga extends ModelePDFProjects @@ -100,9 +100,9 @@ class pdf_beluga extends ModelePDFProjects $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; - $this->option_logo = 1; // Affiche logo FAC_PDF_LOGO - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_logo = 1; // Display logo FAC_PDF_LOGO + $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION + $this->option_codeproduitservice = 1; // Display product-service code // Recupere emmetteur $this->emetteur=$mysoc; From 59424f228ea2a39965198a588de580668df6a157 Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Sat, 29 Jun 2019 10:21:26 +0200 Subject: [PATCH 09/44] translations --- htdocs/core/modules/project/doc/pdf_beluga.modules.php | 4 ++-- .../core/modules/project/doc/pdf_timespent.modules.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/core/modules/project/doc/pdf_beluga.modules.php b/htdocs/core/modules/project/doc/pdf_beluga.modules.php index 97414e745eb..30a983f0b2e 100644 --- a/htdocs/core/modules/project/doc/pdf_beluga.modules.php +++ b/htdocs/core/modules/project/doc/pdf_beluga.modules.php @@ -104,11 +104,11 @@ class pdf_beluga extends ModelePDFProjects $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION $this->option_codeproduitservice = 1; // Display product-service code - // Recupere emmetteur + // Get source company $this->emetteur=$mysoc; if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang, -2); // By default if not defined - // Defini position des colonnes + // Define position of columns if ($this->orientation == 'L' || $this->orientation == 'Landscape') { $this->posxref=$this->marge_gauche+1; $this->posxdate=$this->marge_gauche+105; diff --git a/htdocs/core/modules/project/doc/pdf_timespent.modules.php b/htdocs/core/modules/project/doc/pdf_timespent.modules.php index 2c69fbd6bab..99c7fe99cd9 100644 --- a/htdocs/core/modules/project/doc/pdf_timespent.modules.php +++ b/htdocs/core/modules/project/doc/pdf_timespent.modules.php @@ -71,15 +71,15 @@ class pdf_timespent extends ModelePDFProjects $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; - $this->option_logo = 1; // Affiche logo FAC_PDF_LOGO - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_logo = 1; // Display logo FAC_PDF_LOGO + $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION + $this->option_codeproduitservice = 1; // Display product-service code - // Recupere emmetteur + // Get source company $this->emetteur=$mysoc; if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang, -2); // By default if not defined - // Defini position des colonnes + // Define position of columns $this->posxref=$this->marge_gauche+1; $this->posxlabel=$this->marge_gauche+25; $this->posxtimespent=$this->marge_gauche+120; From bd43e90c2bcd59b2c6becebdf7e6fa3bf67cad54 Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Sat, 29 Jun 2019 10:28:29 +0200 Subject: [PATCH 10/44] translations --- .../modules/propale/doc/pdf_azur.modules.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index 54fe56421ea..6cef67a3d21 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -27,7 +27,7 @@ /** * \file htdocs/core/modules/propale/doc/pdf_azur.modules.php * \ingroup propale - * \brief Fichier de la classe permettant de generer les propales au modele Azur + * \brief File of Class to generate PDF proposal with Azur template */ require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; @@ -148,16 +148,16 @@ class pdf_azur extends ModelePDFPropales $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; - $this->option_logo = 1; // Affiche logo - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_modereg = 1; // Affiche mode reglement - $this->option_condreg = 1; // Affiche conditions reglement - $this->option_codeproduitservice = 1; // Affiche code produit-service - $this->option_multilang = 1; // Dispo en plusieurs langues - $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_logo = 1; // Display logo + $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION + $this->option_modereg = 1; // Display payment mode + $this->option_condreg = 1; // Display payment terms + $this->option_codeproduitservice = 1; // Display product-service code + $this->option_multilang = 1; // Available in several languages + $this->option_escompte = 0; // Displays if there has been a discount $this->option_credit_note = 0; // Support credit notes $this->option_freetext = 1; // Support add of a personalised text - $this->option_draft_watermark = 1; //Support add of a watermark on drafts + $this->option_draft_watermark = 1; // Support add of a watermark on drafts $this->franchise=!$mysoc->tva_assuj; From bebd219e5a522616b3d30793469ab42948dba95d Mon Sep 17 00:00:00 2001 From: Philippe GRAND Date: Sat, 29 Jun 2019 10:30:26 +0200 Subject: [PATCH 11/44] translations --- .../modules/propale/doc/pdf_cyan.modules.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 14a2456157a..8d0c9eea3e6 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -27,7 +27,7 @@ /** * \file htdocs/core/modules/propale/doc/pdf_cyan.modules.php * \ingroup propale - * \brief Fichier de la classe permettant de generer les propales au modele Cyan + * \brief File of Class to generate PDF proposal with Cyan template */ require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; @@ -148,16 +148,16 @@ class pdf_cyan extends ModelePDFPropales $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; - $this->option_logo = 1; // Affiche logo - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_modereg = 1; // Affiche mode reglement - $this->option_condreg = 1; // Affiche conditions reglement - $this->option_codeproduitservice = 1; // Affiche code produit-service - $this->option_multilang = 1; // Dispo en plusieurs langues - $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_logo = 1; // Display logo + $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION + $this->option_modereg = 1; // Display payment mode + $this->option_condreg = 1; // Display payment terms + $this->option_codeproduitservice = 1; // Display product-service code + $this->option_multilang = 1; // Available in several languages + $this->option_escompte = 0; // Displays if there has been a discount $this->option_credit_note = 0; // Support credit notes $this->option_freetext = 1; // Support add of a personalised text - $this->option_draft_watermark = 1; //Support add of a watermark on drafts + $this->option_draft_watermark = 1; // Support add of a watermark on drafts $this->franchise=!$mysoc->tva_assuj; From 5aa27a126aa8cd795a3c67e7f82c9bb68ff4bffd Mon Sep 17 00:00:00 2001 From: atm-ph Date: Wed, 28 Aug 2019 13:45:02 +0200 Subject: [PATCH 12/44] Fix trigger create on widthdraw is missing --- .../prelevement/class/bonprelevement.class.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 7a5a190c465..5c2204dc216 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -775,12 +775,13 @@ class BonPrelevement extends CommonObject * @param string $mode real=do action, simu=test only * @param string $format FRST, RCUR or ALL * @param string $executiondate Date to execute the transfer + * @param int $notrigger Disable triggers * @return int <0 if KO, nbre of invoice withdrawed if OK */ - function Create($banque=0, $agence=0, $mode='real', $format='ALL',$executiondate='') + function Create($banque=0, $agence=0, $mode='real', $format='ALL',$executiondate='', $notrigger = 0) { // phpcs:enable - global $conf,$langs; + global $conf, $langs, $user; dol_syslog(__METHOD__."::Bank=".$banque." Office=".$agence." mode=".$mode." format=".$format, LOG_DEBUG); @@ -1091,6 +1092,7 @@ class BonPrelevement extends CommonObject } $this->factures = $factures_prev_id; + $this->factures_prev = $factures_prev; // Generation of SEPA file $this->filename $this->generate($format,$executiondate); @@ -1114,6 +1116,14 @@ class BonPrelevement extends CommonObject dol_syslog(__METHOD__."::Error update total: ".$this->db->error(), LOG_ERR); } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('BON_PRELEVEMENT_CREATE', $user); + if ($result < 0) $error++; + // End call triggers + } + if (!$error) { $this->db->commit(); From f7fe3d2842993a7232f722adeafe301711a207c7 Mon Sep 17 00:00:00 2001 From: atm-ph Date: Wed, 4 Sep 2019 16:30:55 +0200 Subject: [PATCH 13/44] Fix set var in context attribute instead of object attribute --- htdocs/compta/prelevement/class/bonprelevement.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 5c2204dc216..a7a17c3f18a 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -1092,7 +1092,7 @@ class BonPrelevement extends CommonObject } $this->factures = $factures_prev_id; - $this->factures_prev = $factures_prev; + $this->context['factures_prev'] = $factures_prev; // Generation of SEPA file $this->filename $this->generate($format,$executiondate); From 61d432865b6b42707323b10c8192d64770c9c8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sat, 7 Sep 2019 14:33:36 +0200 Subject: [PATCH 14/44] wip --- ...face_99_modZapier_ZapierTriggers.class.php | 309 ++++++++---------- 1 file changed, 136 insertions(+), 173 deletions(-) diff --git a/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php b/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php index ae08b55d651..9d24af321e7 100644 --- a/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php +++ b/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php @@ -54,7 +54,7 @@ class InterfaceZapierTriggers extends DolibarrTriggers $this->db = $db; $this->name = preg_replace('/^Interface/i', '', get_class($this)); - $this->family = "demo"; + $this->family = "technic"; $this->description = "Zapier triggers."; // 'development', 'experimental', 'dolibarr' or version $this->version = 'development'; @@ -104,8 +104,8 @@ class InterfaceZapierTriggers extends DolibarrTriggers $logtriggeraction = false; if ($action!='') { $actions = explode('_', $action); - $sql = 'SELECT rowid, url FROM '.MAIN_DB_PREFIX.'zapier_hook WHERE'; - $sql .= ' module="'.$db->escape(strtolower($actions[0])).'" AND action="'.$db->escape(strtolower($actions[1])).'"'; + $sql = 'SELECT rowid, url FROM '.MAIN_DB_PREFIX.'zapier_hook'; + $sql .= ' WHERE module="'.$db->escape(strtolower($actions[0])).'" AND action="'.$db->escape(strtolower($actions[1])).'"'; //setEventMessages($sql, null); } @@ -119,28 +119,11 @@ class InterfaceZapierTriggers extends DolibarrTriggers //case 'USER_DELETE': //case 'USER_SETINGROUP': //case 'USER_REMOVEFROMGROUP': - - case 'USER_LOGIN': - //$logtriggeraction = true; - break; - case 'USER_LOGIN_FAILED': - //$logtriggeraction = true; - break; - case 'USER_LOGOUT': - //$logtriggeraction = true; - break; + // case 'USER_LOGIN': + // case 'USER_LOGIN_FAILED': + // case 'USER_LOGOUT': // Warning: To increase performances, this action is triggered only if constant MAIN_ACTIVATE_UPDATESESSIONTRIGGER is set to 1. - //case 'USER_UPDATE_SESSION': - - case 'DOSSIERISOLATION_CREATE': - //$logtriggeraction = true; - break; - case 'DOSSIERISOLATION_MODIFY': - //$logtriggeraction = true; - break; - case 'DOSSIERISOLATION_DELETE': - //$logtriggeraction = true; - break; + // // case 'USER_UPDATE_SESSION': // Actions case 'ACTION_MODIFY': @@ -200,20 +183,20 @@ class InterfaceZapierTriggers extends DolibarrTriggers case 'CONTACT_ENABLEDISABLE': // Products - case 'PRODUCT_CREATE': - case 'PRODUCT_MODIFY': - case 'PRODUCT_DELETE': - case 'PRODUCT_PRICE_MODIFY': - case 'PRODUCT_SET_MULTILANGS': - case 'PRODUCT_DEL_MULTILANGS': + // case 'PRODUCT_CREATE': + // case 'PRODUCT_MODIFY': + // case 'PRODUCT_DELETE': + // case 'PRODUCT_PRICE_MODIFY': + // case 'PRODUCT_SET_MULTILANGS': + // case 'PRODUCT_DEL_MULTILANGS': //Stock mouvement - case 'STOCK_MOVEMENT': + // case 'STOCK_MOVEMENT': //MYECMDIR - case 'MYECMDIR_DELETE': - case 'MYECMDIR_CREATE': - case 'MYECMDIR_MODIFY': + // case 'MYECMDIR_DELETE': + // case 'MYECMDIR_CREATE': + // case 'MYECMDIR_MODIFY': // Customer orders case 'ORDER_CREATE': @@ -240,165 +223,145 @@ class InterfaceZapierTriggers extends DolibarrTriggers case 'LINEORDER_DELETE': // Supplier orders - case 'ORDER_SUPPLIER_CREATE': - case 'ORDER_SUPPLIER_CLONE': - case 'ORDER_SUPPLIER_VALIDATE': - case 'ORDER_SUPPLIER_DELETE': - case 'ORDER_SUPPLIER_APPROVE': - case 'ORDER_SUPPLIER_REFUSE': - case 'ORDER_SUPPLIER_CANCEL': - case 'ORDER_SUPPLIER_SENTBYMAIL': - case 'ORDER_SUPPLIER_DISPATCH': - case 'LINEORDER_SUPPLIER_DISPATCH': - case 'LINEORDER_SUPPLIER_CREATE': - case 'LINEORDER_SUPPLIER_UPDATE': + // case 'ORDER_SUPPLIER_CREATE': + // case 'ORDER_SUPPLIER_CLONE': + // case 'ORDER_SUPPLIER_VALIDATE': + // case 'ORDER_SUPPLIER_DELETE': + // case 'ORDER_SUPPLIER_APPROVE': + // case 'ORDER_SUPPLIER_REFUSE': + // case 'ORDER_SUPPLIER_CANCEL': + // case 'ORDER_SUPPLIER_SENTBYMAIL': + // case 'ORDER_SUPPLIER_DISPATCH': + // case 'LINEORDER_SUPPLIER_DISPATCH': + // case 'LINEORDER_SUPPLIER_CREATE': + // case 'LINEORDER_SUPPLIER_UPDATE': // Proposals - case 'PROPAL_CREATE': - case 'PROPAL_CLONE': - case 'PROPAL_MODIFY': - case 'PROPAL_VALIDATE': - case 'PROPAL_SENTBYMAIL': - case 'PROPAL_CLOSE_SIGNED': - //$logtriggeraction = true; - break; - case 'PROPAL_CLOSE_REFUSED': - //$logtriggeraction = true; - break; - case 'PROPAL_DELETE': - //$logtriggeraction = true; - break; - case 'LINEPROPAL_INSERT': - case 'LINEPROPAL_UPDATE': - case 'LINEPROPAL_DELETE': + // case 'PROPAL_CREATE': + // case 'PROPAL_CLONE': + // case 'PROPAL_MODIFY': + // case 'PROPAL_VALIDATE': + // case 'PROPAL_SENTBYMAIL': + // case 'PROPAL_CLOSE_SIGNED': + // case 'PROPAL_CLOSE_REFUSED': + // case 'PROPAL_DELETE': + // case 'LINEPROPAL_INSERT': + // case 'LINEPROPAL_UPDATE': + // case 'LINEPROPAL_DELETE': // SupplierProposal - case 'SUPPLIER_PROPOSAL_CREATE': - case 'SUPPLIER_PROPOSAL_CLONE': - case 'SUPPLIER_PROPOSAL_MODIFY': - case 'SUPPLIER_PROPOSAL_VALIDATE': - case 'SUPPLIER_PROPOSAL_SENTBYMAIL': - case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED': - case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED': - case 'SUPPLIER_PROPOSAL_DELETE': - case 'LINESUPPLIER_PROPOSAL_INSERT': - case 'LINESUPPLIER_PROPOSAL_UPDATE': - case 'LINESUPPLIER_PROPOSAL_DELETE': + // case 'SUPPLIER_PROPOSAL_CREATE': + // case 'SUPPLIER_PROPOSAL_CLONE': + // case 'SUPPLIER_PROPOSAL_MODIFY': + // case 'SUPPLIER_PROPOSAL_VALIDATE': + // case 'SUPPLIER_PROPOSAL_SENTBYMAIL': + // case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED': + // case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED': + // case 'SUPPLIER_PROPOSAL_DELETE': + // case 'LINESUPPLIER_PROPOSAL_INSERT': + // case 'LINESUPPLIER_PROPOSAL_UPDATE': + // case 'LINESUPPLIER_PROPOSAL_DELETE': // Contracts - case 'CONTRACT_CREATE': - case 'CONTRACT_ACTIVATE': - case 'CONTRACT_CANCEL': - case 'CONTRACT_CLOSE': - case 'CONTRACT_DELETE': - case 'LINECONTRACT_INSERT': - case 'LINECONTRACT_UPDATE': - case 'LINECONTRACT_DELETE': + // case 'CONTRACT_CREATE': + // case 'CONTRACT_ACTIVATE': + // case 'CONTRACT_CANCEL': + // case 'CONTRACT_CLOSE': + // case 'CONTRACT_DELETE': + // case 'LINECONTRACT_INSERT': + // case 'LINECONTRACT_UPDATE': + // case 'LINECONTRACT_DELETE': // Bills - case 'BILL_CREATE': - //$logtriggeraction = true; - break; - case 'BILL_CLONE': - case 'BILL_MODIFY': - case 'BILL_VALIDATE': - case 'BILL_UNVALIDATE': - //$logtriggeraction = true; - break; - case 'BILL_SENTBYMAIL': - //$logtriggeraction = true; - break; - case 'BILL_CANCEL': - //$logtriggeraction = true; - break; - case 'BILL_DELETE': - //$logtriggeraction = true; - break; - case 'BILL_PAYED': - case 'LINEBILL_INSERT': - case 'LINEBILL_UPDATE': - case 'LINEBILL_DELETE': + // case 'BILL_CREATE': + // case 'BILL_CLONE': + // case 'BILL_MODIFY': + // case 'BILL_VALIDATE': + // case 'BILL_UNVALIDATE': + // case 'BILL_SENTBYMAIL': + // case 'BILL_CANCEL': + // case 'BILL_DELETE': + // case 'BILL_PAYED': + // case 'LINEBILL_INSERT': + // case 'LINEBILL_UPDATE': + // case 'LINEBILL_DELETE': //Supplier Bill - case 'BILL_SUPPLIER_CREATE': - case 'BILL_SUPPLIER_UPDATE': - case 'BILL_SUPPLIER_DELETE': - case 'BILL_SUPPLIER_PAYED': - case 'BILL_SUPPLIER_UNPAYED': - case 'BILL_SUPPLIER_VALIDATE': - case 'BILL_SUPPLIER_UNVALIDATE': - case 'LINEBILL_SUPPLIER_CREATE': - case 'LINEBILL_SUPPLIER_UPDATE': - case 'LINEBILL_SUPPLIER_DELETE': + // case 'BILL_SUPPLIER_CREATE': + // case 'BILL_SUPPLIER_UPDATE': + // case 'BILL_SUPPLIER_DELETE': + // case 'BILL_SUPPLIER_PAYED': + // case 'BILL_SUPPLIER_UNPAYED': + // case 'BILL_SUPPLIER_VALIDATE': + // case 'BILL_SUPPLIER_UNVALIDATE': + // case 'LINEBILL_SUPPLIER_CREATE': + // case 'LINEBILL_SUPPLIER_UPDATE': + // case 'LINEBILL_SUPPLIER_DELETE': - // Payments - case 'PAYMENT_CUSTOMER_CREATE': - case 'PAYMENT_SUPPLIER_CREATE': - case 'PAYMENT_ADD_TO_BANK': - case 'PAYMENT_DELETE': + // Payments + // case 'PAYMENT_CUSTOMER_CREATE': + // case 'PAYMENT_SUPPLIER_CREATE': + // case 'PAYMENT_ADD_TO_BANK': + // case 'PAYMENT_DELETE': - // Online - case 'PAYMENT_PAYBOX_OK': - case 'PAYMENT_PAYPAL_OK': - case 'PAYMENT_STRIPE_OK': + // Online + // case 'PAYMENT_PAYBOX_OK': + // case 'PAYMENT_PAYPAL_OK': + // case 'PAYMENT_STRIPE_OK': - // Donation - case 'DON_CREATE': - case 'DON_UPDATE': - case 'DON_DELETE': + // Donation + // case 'DON_CREATE': + // case 'DON_UPDATE': + // case 'DON_DELETE': - // Interventions - case 'FICHINTER_CREATE': - case 'FICHINTER_MODIFY': - case 'FICHINTER_VALIDATE': - case 'FICHINTER_DELETE': - case 'LINEFICHINTER_CREATE': - case 'LINEFICHINTER_UPDATE': - case 'LINEFICHINTER_DELETE': + // Interventions + // case 'FICHINTER_CREATE': + // case 'FICHINTER_MODIFY': + // case 'FICHINTER_VALIDATE': + // case 'FICHINTER_DELETE': + // case 'LINEFICHINTER_CREATE': + // case 'LINEFICHINTER_UPDATE': + // case 'LINEFICHINTER_DELETE': - // Members - case 'MEMBER_CREATE': - case 'MEMBER_VALIDATE': - case 'MEMBER_SUBSCRIPTION': - case 'MEMBER_MODIFY': - case 'MEMBER_NEW_PASSWORD': - case 'MEMBER_RESILIATE': - case 'MEMBER_DELETE': + // Members + // case 'MEMBER_CREATE': + // case 'MEMBER_VALIDATE': + // case 'MEMBER_SUBSCRIPTION': + // case 'MEMBER_MODIFY': + // case 'MEMBER_NEW_PASSWORD': + // case 'MEMBER_RESILIATE': + // case 'MEMBER_DELETE': - // Categories - case 'CATEGORY_CREATE': - case 'CATEGORY_MODIFY': - case 'CATEGORY_DELETE': - case 'CATEGORY_SET_MULTILANGS': + // Categories + // case 'CATEGORY_CREATE': + // case 'CATEGORY_MODIFY': + // case 'CATEGORY_DELETE': + // case 'CATEGORY_SET_MULTILANGS': - // Projects - case 'PROJECT_CREATE': - case 'PROJECT_MODIFY': - case 'PROJECT_DELETE': + // Projects + // case 'PROJECT_CREATE': + // case 'PROJECT_MODIFY': + // case 'PROJECT_DELETE': - // Project tasks - case 'TASK_CREATE': - case 'TASK_MODIFY': - case 'TASK_DELETE': + // Project tasks + // case 'TASK_CREATE': + // case 'TASK_MODIFY': + // case 'TASK_DELETE': - // Task time spent - case 'TASK_TIMESPENT_CREATE': - case 'TASK_TIMESPENT_MODIFY': - case 'TASK_TIMESPENT_DELETE': + // Task time spent + // case 'TASK_TIMESPENT_CREATE': + // case 'TASK_TIMESPENT_MODIFY': + // case 'TASK_TIMESPENT_DELETE': - // Shipping - case 'SHIPPING_CREATE': - case 'SHIPPING_MODIFY': - case 'SHIPPING_VALIDATE': - case 'SHIPPING_SENTBYMAIL': - case 'SHIPPING_BILLED': - case 'SHIPPING_CLOSED': - case 'SHIPPING_REOPEN': - //$logtriggeraction = true; - break; - case 'SHIPPING_DELETE': - //$logtriggeraction = true; - break; + // Shipping + // case 'SHIPPING_CREATE': + // case 'SHIPPING_MODIFY': + // case 'SHIPPING_VALIDATE': + // case 'SHIPPING_SENTBYMAIL': + // case 'SHIPPING_BILLED': + // case 'SHIPPING_CLOSED': + // case 'SHIPPING_REOPEN': + // case 'SHIPPING_DELETE': } if ($logtriggeraction) { dol_syslog("Trigger '" . $this->name . "' for action '.$action.' launched by " . __FILE__ . " id=" . $object->id); From bd4c9a64a868f17b58c37a26a7333377e5a0b601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sat, 7 Sep 2019 14:48:25 +0200 Subject: [PATCH 15/44] wip --- htdocs/comm/action/class/actioncomm.class.php | 3 +- .../action/class/api_agendaevents.class.php | 33 ++++++++++--------- htdocs/contact/class/contact.class.php | 3 +- htdocs/contrat/class/api_contracts.class.php | 2 +- htdocs/societe/class/api_contacts.class.php | 7 ++-- .../societe/class/api_thirdparties.class.php | 7 ++-- htdocs/societe/class/societe.class.php | 3 +- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 12926f9b360..4da7686b0a2 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -1637,7 +1637,7 @@ class ActionComm extends CommonObject * Used to build previews or test instances. * id must be 0 if object instance is a specimen. * - * @return void + * @return int >0 if ok */ public function initAsSpecimen() { @@ -1669,6 +1669,7 @@ class ActionComm extends CommonObject $this->userownerid=$user->id; $this->userassigned[$user->id]=array('id'=>$user->id, 'transparency'=> 1); + return 1; } /** diff --git a/htdocs/comm/action/class/api_agendaevents.class.php b/htdocs/comm/action/class/api_agendaevents.class.php index 833f97b3b6b..1109112284a 100644 --- a/htdocs/comm/action/class/api_agendaevents.class.php +++ b/htdocs/comm/action/class/api_agendaevents.class.php @@ -64,25 +64,28 @@ class AgendaEvents extends DolibarrApi public function get($id) { if (! DolibarrApiAccess::$user->rights->agenda->myactions->read) { - throw new RestException(401, "Insuffisant rights to read an event"); + throw new RestException(401, "Insufficient rights to read an event"); + } + if ($id == 0) { + $result = $this->actioncomm->initAsSpecimen(); + } else { + $result = $this->actioncomm->fetch($id); + if ($result) { + $this->actioncomm->fetch_optionals(); + $this->actioncomm->fetchObjectLinked(); + } } - - $result = $this->actioncomm->fetch($id); if ( ! $result ) { throw new RestException(404, 'Agenda Events not found'); } if (! DolibarrApiAccess::$user->rights->agenda->allactions->read && $this->actioncomm->ownerid != DolibarrApiAccess::$user->id) { - throw new RestException(401, "Insuffisant rights to read event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); + throw new RestException(401, "Insufficient rights to read event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); } if ( ! DolibarrApi::_checkAccessToResource('agenda', $this->actioncomm->id, 'actioncomm', '', 'fk_soc', 'id')) { throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - - $result = $this->actioncomm->fetch_optionals(); - - $this->actioncomm->fetchObjectLinked(); return $this->_cleanObjectDatas($this->actioncomm); } @@ -106,7 +109,7 @@ class AgendaEvents extends DolibarrApi $obj_ret = array(); if (! DolibarrApiAccess::$user->rights->agenda->myactions->read) { - throw new RestException(401, "Insuffisant rights to read events"); + throw new RestException(401, "Insufficient rights to read events"); } // case of external user @@ -191,10 +194,10 @@ class AgendaEvents extends DolibarrApi public function post($request_data = null) { if (! DolibarrApiAccess::$user->rights->agenda->myactions->create) { - throw new RestException(401, "Insuffisant rights to create your Agenda Event"); + throw new RestException(401, "Insufficient rights to create your Agenda Event"); } if (! DolibarrApiAccess::$user->rights->agenda->allactions->create && DolibarrApiAccess::$user->id != $request_data['userownerid']) { - throw new RestException(401, "Insuffisant rights to create an Agenda Event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); + throw new RestException(401, "Insufficient rights to create an Agenda Event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); } // Check mandatory fields @@ -230,10 +233,10 @@ class AgendaEvents extends DolibarrApi public function put($id, $request_data = null) { if (! DolibarrApiAccess::$user->rights->agenda->myactions->create) { - throw new RestException(401, "Insuffisant rights to create your Agenda Event"); + throw new RestException(401, "Insufficient rights to create your Agenda Event"); } if (! DolibarrApiAccess::$user->rights->agenda->allactions->create && DolibarrApiAccess::$user->id != $request_data['userownerid']) { - throw new RestException(401, "Insuffisant rights to create an Agenda Event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); + throw new RestException(401, "Insufficient rights to create an Agenda Event for owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); } $result = $this->actioncomm->fetch($id); @@ -266,13 +269,13 @@ class AgendaEvents extends DolibarrApi public function delete($id) { if(! DolibarrApiAccess::$user->rights->agenda->myactions->delete) { - throw new RestException(401, "Insuffisant rights to delete your Agenda Event"); + throw new RestException(401, "Insufficient rights to delete your Agenda Event"); } $result = $this->actioncomm->fetch($id); if(! DolibarrApiAccess::$user->rights->agenda->allactions->delete && DolibarrApiAccess::$user->id != $this->actioncomm->userownerid) { - throw new RestException(401, "Insuffisant rights to delete an Agenda Event of owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); + throw new RestException(401, "Insufficient rights to delete an Agenda Event of owner id ".$request_data['userownerid'].' Your id is '.DolibarrApiAccess::$user->id); } if( ! $result ) { diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index ebfafa698b7..177f2dd2e93 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -1288,7 +1288,7 @@ class Contact extends CommonObject * Used to build previews or test instances. * id must be 0 if object instance is a specimen. * - * @return void + * @return int >0 if ok */ public function initAsSpecimen() { @@ -1325,6 +1325,7 @@ class Contact extends CommonObject $this->socid = $socid; $this->statut=1; + return 1; } /** diff --git a/htdocs/contrat/class/api_contracts.class.php b/htdocs/contrat/class/api_contracts.class.php index 194e145210f..d49214dfb4d 100644 --- a/htdocs/contrat/class/api_contracts.class.php +++ b/htdocs/contrat/class/api_contracts.class.php @@ -187,7 +187,7 @@ class Contracts extends DolibarrApi public function post($request_data = null) { if(! DolibarrApiAccess::$user->rights->contrat->creer) { - throw new RestException(401, "Insuffisant rights"); + throw new RestException(401, "Insufficient rights"); } // Check mandatory fields $result = $this->_validate($request_data); diff --git a/htdocs/societe/class/api_contacts.class.php b/htdocs/societe/class/api_contacts.class.php index 38dfdf71fd8..b2adc8ce5ff 100644 --- a/htdocs/societe/class/api_contacts.class.php +++ b/htdocs/societe/class/api_contacts.class.php @@ -74,8 +74,11 @@ class Contacts extends DolibarrApi { throw new RestException(401, 'No permission to read contacts'); } - - $result = $this->contact->fetch($id); + if ($id ==0) { + $result = $this->contact->intiAsSpecimen(); + } else { + $result = $this->contact->fetch($id); + } if (!$result) { diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index ddb19c563fe..919961b4f8f 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -76,8 +76,11 @@ class Thirdparties extends DolibarrApi if(! DolibarrApiAccess::$user->rights->societe->lire) { throw new RestException(401); } - - $result = $this->company->fetch($id); + if ($id ==0) { + $result = $this->company->intiAsSpecimen(); + } else { + $result = $this->company->fetch($id); + } if( ! $result ) { throw new RestException(404, 'Thirdparty not found'); } diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 26ad0c6bed9..86408c482cc 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -3539,7 +3539,7 @@ class Societe extends CommonObject * Used to build previews or test instances. * id must be 0 if object instance is a specimen. * - * @return void + * @return int >0 if ok */ public function initAsSpecimen() { @@ -3586,6 +3586,7 @@ class Societe extends CommonObject $this->idprof4='idprof4'; $this->idprof5='idprof5'; $this->idprof6='idprof6'; + return 1; } /** From 4054ebaf27da13e7d607d232997aba35d8071796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sat, 7 Sep 2019 15:12:07 +0200 Subject: [PATCH 16/44] wip --- htdocs/core/modules/modZapier.class.php | 10 +++++--- .../mysql/tables}/llx_zapier_hook.key.sql | 6 ++--- .../mysql/tables}/llx_zapier_hook.sql | 24 +++++++++--------- .../tables}/llx_zapier_hook_extrafields.sql | 4 +-- .../img/{zapier.png => object_zapier.png} | Bin .../zapier/img/object_zapierfordolibarr.png | Bin 360 -> 0 bytes 6 files changed, 23 insertions(+), 21 deletions(-) rename htdocs/{zapier/sql => install/mysql/tables}/llx_zapier_hook.key.sql (66%) rename htdocs/{zapier/sql => install/mysql/tables}/llx_zapier_hook.sql (68%) rename htdocs/{zapier/sql => install/mysql/tables}/llx_zapier_hook_extrafields.sql (93%) rename htdocs/zapier/img/{zapier.png => object_zapier.png} (100%) delete mode 100644 htdocs/zapier/img/object_zapierfordolibarr.png diff --git a/htdocs/core/modules/modZapier.class.php b/htdocs/core/modules/modZapier.class.php index 7f7ee47ba1e..da6a8aa1547 100644 --- a/htdocs/core/modules/modZapier.class.php +++ b/htdocs/core/modules/modZapier.class.php @@ -67,7 +67,7 @@ class modZapier extends DolibarrModules // Name of image file used for this module. // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' - $this->picto = 'technic'; + $this->picto = 'zapier@zapier'; // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) $this->module_parts = array( // Set this to 1 if module has its own trigger directory (core/triggers) @@ -109,7 +109,9 @@ class modZapier extends DolibarrModules // Example: this->dirs = array("/zapier/temp","/zapier/subdir"); $this->dirs = array("/zapier/temp"); // Config pages. Put here list of php page, stored into zapier/admin directory, to use to setup module. - $this->config_page_url = array("setup.php@zapier"); + $this->config_page_url = array( + // "setup.php@zapier" + ); // Dependencies // A condition to hide module $this->hidden = false; @@ -119,7 +121,7 @@ class modZapier extends DolibarrModules $this->requiredby = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) $this->conflictwith = array(); - $this->langfiles = array("zapier@zapier"); + $this->langfiles = array("zapier"); // Minimum version of PHP required by module //$this->phpmin = array(5, 5); // Minimum version of Dolibarr required by module @@ -148,7 +150,7 @@ class modZapier extends DolibarrModules 'fr_FR:ParentCompany'=>'Maison mère ou revendeur' )*/ if (! isset($conf->zapier) || ! isset($conf->zapier->enabled)) { - $conf->zapier=new stdClass(); + $conf->zapier = new stdClass(); $conf->zapier->enabled=0; } // Array to add new pages in new tabs diff --git a/htdocs/zapier/sql/llx_zapier_hook.key.sql b/htdocs/install/mysql/tables/llx_zapier_hook.key.sql similarity index 66% rename from htdocs/zapier/sql/llx_zapier_hook.key.sql rename to htdocs/install/mysql/tables/llx_zapier_hook.key.sql index d707e6bba1a..4bce26ae0ea 100644 --- a/htdocs/zapier/sql/llx_zapier_hook.key.sql +++ b/htdocs/install/mysql/tables/llx_zapier_hook.key.sql @@ -14,9 +14,9 @@ -- along with this program. If not, see http://www.gnu.org/licenses/. ---ALTER TABLE llx_zapierfordolibarr_hook ADD INDEX idx_fieldobject (fieldobject); +--ALTER TABLE llx_zapier_hook ADD INDEX idx_fieldobject (fieldobject); ---ALTER TABLE llx_zapierfordolibarr_hook ADD UNIQUE INDEX uk_zapierfordolibarr_hook_fieldxy(fieldx, fieldy); +--ALTER TABLE llx_zapier_hook ADD UNIQUE INDEX uk_zapier_hook_fieldxy(fieldx, fieldy); ---ALTER TABLE llx_zapierfordolibarr_hook ADD CONSTRAINT llx_zapierfordolibarr_hook_fk_field FOREIGN KEY (fk_field) REFERENCES llx_zapierfordolibarr_myotherobject(rowid); +--ALTER TABLE llx_zapier_hook ADD CONSTRAINT llx_zapier_hook_fk_field FOREIGN KEY (fk_field) REFERENCES llx_zapier_myotherobject(rowid); diff --git a/htdocs/zapier/sql/llx_zapier_hook.sql b/htdocs/install/mysql/tables/llx_zapier_hook.sql similarity index 68% rename from htdocs/zapier/sql/llx_zapier_hook.sql rename to htdocs/install/mysql/tables/llx_zapier_hook.sql index 829ec2bfdc4..27d56352bff 100644 --- a/htdocs/zapier/sql/llx_zapier_hook.sql +++ b/htdocs/install/mysql/tables/llx_zapier_hook.sql @@ -14,16 +14,16 @@ -- along with this program. If not, see http://www.gnu.org/licenses/. -CREATE TABLE llx_zapierfordolibarr_hook( - rowid integer AUTO_INCREMENT PRIMARY KEY, - entity integer DEFAULT 1 NOT NULL, - url varchar(255), - event varchar(255), - module varchar(128), - action varchar(128), - status integer, - date_creation DATETIME NOT NULL, +CREATE TABLE llx_zapier_hook( + rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, + url varchar(255), + event varchar(255), + module varchar(128), + action varchar(128), + status integer, + date_creation DATETIME NOT NULL, fk_user integer NOT NULL, - tms TIMESTAMP NOT NULL, - import_key varchar(14) -) ENGINE=innodb; \ No newline at end of file + tms TIMESTAMP NOT NULL, + import_key varchar(14) +) ENGINE=innodb; diff --git a/htdocs/zapier/sql/llx_zapier_hook_extrafields.sql b/htdocs/install/mysql/tables/llx_zapier_hook_extrafields.sql similarity index 93% rename from htdocs/zapier/sql/llx_zapier_hook_extrafields.sql rename to htdocs/install/mysql/tables/llx_zapier_hook_extrafields.sql index c840007412b..09fef4cc399 100644 --- a/htdocs/zapier/sql/llx_zapier_hook_extrafields.sql +++ b/htdocs/install/mysql/tables/llx_zapier_hook_extrafields.sql @@ -13,11 +13,11 @@ -- You should have received a copy of the GNU General Public License -- along with this program. If not, see http://www.gnu.org/licenses/. -create table llx_zapierfordolibarr_hook_extrafields +create table llx_zapier_hook_extrafields ( rowid integer AUTO_INCREMENT PRIMARY KEY, tms timestamp, fk_object integer NOT NULL, - import_key varchar(14) -- import key + import_key varchar(14) -- import key ) ENGINE=innodb; diff --git a/htdocs/zapier/img/zapier.png b/htdocs/zapier/img/object_zapier.png similarity index 100% rename from htdocs/zapier/img/zapier.png rename to htdocs/zapier/img/object_zapier.png diff --git a/htdocs/zapier/img/object_zapierfordolibarr.png b/htdocs/zapier/img/object_zapierfordolibarr.png deleted file mode 100644 index 5a307bfc62f85df909a3cf024f27ee87d44be275..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt)eIT^vI+ zChono-m4{0gyqBiz=Ju)w^;&N<{#X1a0!1>bC%GsW3bBL=<%|p84;9-@5SwA|2OIEL% zb=QtBT0T9C&(LA{syqXqqW_DHn`b;(x5}@uA-g2{Ncy)Mhpp~Sy0eY()*3IP6|4C4 z(mDEHWvtPCEP7WZe7{4e?P9&>AE%^j|Mz!&9rL?{G_w^d>;^y&GkCiCxvX Date: Tue, 10 Sep 2019 19:42:31 +0000 Subject: [PATCH 17/44] Fixing style errors. --- htdocs/core/modules/propale/doc/pdf_azur.modules.php | 2 +- htdocs/core/modules/propale/doc/pdf_cyan.modules.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index 4691cb9d6c5..cc91f1323af 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -27,7 +27,7 @@ /** * \file htdocs/core/modules/propale/doc/pdf_azur.modules.php * \ingroup propale - * \brief File of Class to generate PDF proposal with Azur template + * \brief File of Class to generate PDF proposal with Azur template */ require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 9bd86c990d2..8d7f643b902 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -27,7 +27,7 @@ /** * \file htdocs/core/modules/propale/doc/pdf_cyan.modules.php * \ingroup propale - * \brief File of Class to generate PDF proposal with Cyan template + * \brief File of Class to generate PDF proposal with Cyan template */ require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; From d37dd4ed3c265db01845a7ea479a6d01b6056eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 11 Sep 2019 18:07:21 +0200 Subject: [PATCH 18/44] jshint --- dev/examples/zapier/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/examples/zapier/index.js b/dev/examples/zapier/index.js index cd62d6cd7ee..fc452a196e6 100644 --- a/dev/examples/zapier/index.js +++ b/dev/examples/zapier/index.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6 */ const triggerThirdparty = require('./triggers/thirdparty'); const triggerOrder = require('./triggers/order'); const triggerAction = require('./triggers/action'); From 638362f3732b421c2f36e94f3f8948eb3a21f5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 11 Sep 2019 18:17:12 +0200 Subject: [PATCH 19/44] jshint --- dev/examples/zapier/authentication.js | 1 + dev/examples/zapier/creates/thirdparty.js | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dev/examples/zapier/authentication.js b/dev/examples/zapier/authentication.js index 8c373d0b78b..1c95c76f9c2 100644 --- a/dev/examples/zapier/authentication.js +++ b/dev/examples/zapier/authentication.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6 */ const testAuth = (z , bundle) => { const url = bundle.authData.url+'/api/index.php/login'; // Normally you want to make a request to an endpoint that is either specifically designed to test auth, or one that diff --git a/dev/examples/zapier/creates/thirdparty.js b/dev/examples/zapier/creates/thirdparty.js index 05928c3f15b..d53692afd09 100644 --- a/dev/examples/zapier/creates/thirdparty.js +++ b/dev/examples/zapier/creates/thirdparty.js @@ -8,9 +8,15 @@ const createThirdparty = async (z, bundle) => { body: JSON.stringify({ name: bundle.inputData.name, name_alias: bundle.inputData.name_alias, + ref_ext: bundle.inputData.ref_ext, + ref_int: bundle.inputData.ref_int, address: bundle.inputData.address, zip: bundle.inputData.zip, town: bundle.inputData.town, + country_code: bundle.inputData.country_code, + country_id: bundle.inputData.country_id, + country: bundle.inputData.country, + phone: bundle.inputData.phone, email: bundle.inputData.email, client: bundle.inputData.client, fournisseur: bundle.inputData.fournisseur, @@ -80,4 +86,4 @@ module.exports = { {key: 'code_fournisseur', label: 'Supplier code'} ] } -}; \ No newline at end of file +}; From 9e18f5243aa36a15a8ad0685c285c4c4a4115d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 11 Sep 2019 18:21:59 +0200 Subject: [PATCH 20/44] jshint --- dev/examples/zapier/creates/thirdparty.js | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/examples/zapier/creates/thirdparty.js b/dev/examples/zapier/creates/thirdparty.js index d53692afd09..82cc39f8fab 100644 --- a/dev/examples/zapier/creates/thirdparty.js +++ b/dev/examples/zapier/creates/thirdparty.js @@ -1,3 +1,4 @@ +/*jshint esversion: 6 */ // create a particular thirdparty by name const createThirdparty = async (z, bundle) => { const apiurl = bundle.authData.url + '/api/index.php/thirdparties'; From 34be514326e1f5e8a358b0ca55460be77abd246b Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 29 Sep 2019 20:56:24 +0200 Subject: [PATCH 21/44] Custom receipt tab in TakePOS --- htdocs/langs/en_US/cashdesk.lang | 2 + htdocs/takepos/admin/receipt.php | 153 +++++++++++++++++++++++++++++++ htdocs/takepos/admin/setup.php | 48 ++-------- htdocs/takepos/receipt.php | 46 ++++++++-- 4 files changed, 199 insertions(+), 50 deletions(-) create mode 100644 htdocs/takepos/admin/receipt.php diff --git a/htdocs/langs/en_US/cashdesk.lang b/htdocs/langs/en_US/cashdesk.lang index 33ea50dfb0f..0516de208fc 100644 --- a/htdocs/langs/en_US/cashdesk.lang +++ b/htdocs/langs/en_US/cashdesk.lang @@ -75,3 +75,5 @@ DirectPayment=Direct payment DirectPaymentButton=Direct cash payment button InvoiceIsAlreadyValidated=Invoice is already validated NoLinesToBill=No lines to bill +CustomReceipt=Custom Receipt +ReceiptName=Receipt Name diff --git a/htdocs/takepos/admin/receipt.php b/htdocs/takepos/admin/receipt.php new file mode 100644 index 00000000000..92333394edc --- /dev/null +++ b/htdocs/takepos/admin/receipt.php @@ -0,0 +1,153 @@ + + * Copyright (C) 2011-2017 Juanjo Menent + * Copyright (C) 2019 Andreu Bisquerra Gaya + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/takepos/admin/terminal.php + * \ingroup takepos + * \brief Setup page for TakePos module + */ + +require '../../main.inc.php'; // Load $user and permissions +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php"; + +// Security check +if (!$user->admin) accessforbidden(); + +$langs->loadLangs(array("admin", "cashdesk", "commercial")); + +/* + * Actions + */ + +if (GETPOST('action', 'alpha') == 'set') +{ + $db->begin(); + + $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_RECEIPT_NAME", GETPOST('TAKEPOS_RECEIPT_NAME', 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_SHOW_CUSTOMER", GETPOST('TAKEPOS_SHOW_CUSTOMER', 'alpha'), 'chaine', 0, '', $conf->entity); + + dol_syslog("admin/cashdesk: level ".GETPOST('level', 'alpha')); + + if (! $res > 0) $error++; + + if (! $error) + { + $db->commit(); + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } + else + { + $db->rollback(); + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + + +/* + * View + */ + +$form=new Form($db); +$formproduct=new FormProduct($db); + +llxHeader('', $langs->trans("CashDeskSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup'); +$head = takepos_prepare_head(); +dol_fiche_head($head, 'receipt', 'TakePOS', -1); +print '
'; + + +// Mode +print '
'; +print ''; +print ''; + +print ''; +print ''; +print ''; +print "\n"; + +$substitutionarray=pdf_getSubstitutionArray($langs, null, null, 2); +$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation"); +$htmltext = ''.$langs->trans("AvailableVariables").':
'; +foreach($substitutionarray as $key => $val) $htmltext.=$key.'
'; +$htmltext.='
'; + +print '\n"; + +print '\n"; + +print ''; + +// Customer information +print '\n"; + +print '
'.$langs->trans("Parameters").''.$langs->trans("Value").'
'; +print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices")." - ".$langs->trans("Header"), $htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'
'; +print '
'; +$variablename='TAKEPOS_HEADER'; +if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) +{ + print ''; +} +else +{ + include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes'); + print $doleditor->Create(); +} +print "
'; +print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices")." - ".$langs->trans("Footer"), $htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'
'; +print '
'; +$variablename='TAKEPOS_FOOTER'; +if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) +{ + print ''; +} +else +{ + include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes'); + print $doleditor->Create(); +} +print "
'; +print ''; +print '
'; +print $langs->trans('ShowCustomer'); +print ''; +print $form->selectyesno("TAKEPOS_SHOW_CUSTOMER", $conf->global->TAKEPOS_SHOW_CUSTOMER, 1); +print "
'; + +print '
'; + +print '
'; + +print "
\n"; + +print '
'; + +llxFooter(); +$db->close(); diff --git a/htdocs/takepos/admin/setup.php b/htdocs/takepos/admin/setup.php index 23e6eb05c48..5d7d2057ca1 100644 --- a/htdocs/takepos/admin/setup.php +++ b/htdocs/takepos/admin/setup.php @@ -75,11 +75,10 @@ if (GETPOST('action', 'alpha') == 'set') $res = dolibarr_set_const($db, "TAKEPOS_ORDER_NOTES", GETPOST('TAKEPOS_ORDER_NOTES', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_PHONE_BASIC_LAYOUT", GETPOST('TAKEPOS_PHONE_BASIC_LAYOUT', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_AUTO_PRINT_TICKETS", GETPOST('TAKEPOS_AUTO_PRINT_TICKETS', 'int'), 'int', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'alpha'), 'chaine', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUMPAD", GETPOST('TAKEPOS_NUMPAD', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUM_TERMINALS", GETPOST('TAKEPOS_NUM_TERMINALS', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_DIRECT_PAYMENT", GETPOST('TAKEPOS_DIRECT_PAYMENT', 'int'), 'int', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_CUSTOM_RECEIPT", GETPOST('TAKEPOS_CUSTOM_RECEIPT', 'int'), 'int', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_EMAIL_TEMPLATE_INVOICE", GETPOST('TAKEPOS_EMAIL_TEMPLATE_INVOICE', 'alpha'), 'chaine', 0, '', $conf->entity); if ($conf->global->TAKEPOS_ORDER_NOTES==1) @@ -232,6 +231,13 @@ print ''; print $form->selectyesno("TAKEPOS_DIRECT_PAYMENT", $conf->global->TAKEPOS_DIRECT_PAYMENT, 1); print "\n"; +// Custom Receipt +print ''; +print $langs->trans('CustomReceipt'); +print ''; +print $form->selectyesno("TAKEPOS_CUSTOM RECEIPT", $conf->global->TAKEPOS_CUSTOM_RECEIPT, 1); +print "\n"; + // Email template for send invoice print ''; print $langs->trans('EmailTemplate'); @@ -256,44 +262,6 @@ if (is_array($formmail->lines_model)) print $form->selectarray('TAKEPOS_EMAIL_TEMPLATE_INVOICE', $arrayofmessagename, $conf->global->TAKEPOS_EMAIL_TEMPLATE_INVOICE, 'None', 1, 0, '', 0, 0, 0, '', '', 1); print "\n"; -$substitutionarray=pdf_getSubstitutionArray($langs, null, null, 2); -$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation"); -$htmltext = ''.$langs->trans("AvailableVariables").':
'; -foreach($substitutionarray as $key => $val) $htmltext.=$key.'
'; -$htmltext.='
'; - -print ''; -print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices")." - ".$langs->trans("Header"), $htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'
'; -print ''; -$variablename='TAKEPOS_HEADER'; -if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) -{ - print ''; -} -else -{ - include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes'); - print $doleditor->Create(); -} -print "\n"; - -print ''; -print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices")." - ".$langs->trans("Footer"), $htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'
'; -print ''; -$variablename='TAKEPOS_FOOTER'; -if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) -{ - print ''; -} -else -{ - include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes'); - print $doleditor->Create(); -} -print "\n"; - print ''; print '
'; diff --git a/htdocs/takepos/receipt.php b/htdocs/takepos/receipt.php index 5905592607c..90d5fb9059c 100644 --- a/htdocs/takepos/receipt.php +++ b/htdocs/takepos/receipt.php @@ -28,7 +28,7 @@ require '../main.inc.php'; // Load $user and permissions include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; -$langs->loadLangs(array("main", "cashdesk")); +$langs->loadLangs(array("main", "cashdesk", "companies")); $place = (GETPOST('place', 'int') > 0 ? GETPOST('place', 'int') : 0); // $place is id of table for Ba or Restaurant @@ -54,6 +54,14 @@ if ($place > 0) $object=new Facture($db); $object->fetch($facid); +// Call to external receipt modules if exist +$hookmanager->initHooks(array('takeposfrontend'), $facid); +$reshook=$hookmanager->executeHooks('TakeposReceipt', $parameters, $object); +if (!empty($hookmanager->resPrint)) { + print $hookmanager->resPrint; + exit; +} + // IMPORTANT: This file is sended to 'Takepos Printing' application. Keep basic file. No external files as css, js... If you need images use absolute path. ?> @@ -77,19 +85,34 @@ $object->fetch($facid);

global->TAKEPOS_HEADER)) +if ($conf->global->TAKEPOS_CUSTOM_RECEIPT) { - $newfreetext=make_substitutions($conf->global->TAKEPOS_HEADER, $substitutionarray); - echo $newfreetext; + $substitutionarray=getCommonSubstitutionArray($langs); + if (! empty($conf->global->TAKEPOS_HEADER)) + { + $newfreetext=make_substitutions($conf->global->TAKEPOS_HEADER, $substitutionarray); + echo $newfreetext; + } } ?>

trans('Date')." ".dol_print_date($object->date, 'day').'
'; -if ($mysoc->country_code == 'ES') print "Factura simplificada "; +if ($conf->global->TAKEPOS_CUSTOM_RECEIPT) print $conf->global->TAKEPOS_RECEIPT_NAME." "; print $object->ref; +if ($conf->global->TAKEPOS_CUSTOM_RECEIPT && $conf->global->TAKEPOS_SHOW_CUSTOMER) +{ + $soc = new Societe($db); + $soc->fetch($invoice->socid); + if ($invoice->socid != $conf->global->{'CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"]}) + { + $soc = new Societe($db); + if ($invoice->socid > 0) $soc->fetch($invoice->socid); + else $soc->fetch($conf->global->{'CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"]}); + print "
".$langs->trans("Customer").': '.$soc->name; + } +} ?>


@@ -160,11 +183,14 @@ print $object->ref;

global->TAKEPOS_FOOTER)) +if ($conf->global->TAKEPOS_CUSTOM_RECEIPT) { - $newfreetext=make_substitutions($conf->global->TAKEPOS_FOOTER, $substitutionarray); - echo $newfreetext; + $substitutionarray=getCommonSubstitutionArray($langs); + if (! empty($conf->global->TAKEPOS_FOOTER)){ + $newfreetext=make_substitutions($conf->global->TAKEPOS_FOOTER, $substitutionarray); + echo $newfreetext; + + } } ?> From 741447d990f67b20b3293d56111d53612f5623bf Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Sun, 29 Sep 2019 21:30:06 +0200 Subject: [PATCH 22/44] Fix Travis errors --- htdocs/takepos/receipt.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/takepos/receipt.php b/htdocs/takepos/receipt.php index 90d5fb9059c..35e3bd7f836 100644 --- a/htdocs/takepos/receipt.php +++ b/htdocs/takepos/receipt.php @@ -60,7 +60,7 @@ $reshook=$hookmanager->executeHooks('TakeposReceipt', $parameters, $object); if (!empty($hookmanager->resPrint)) { print $hookmanager->resPrint; exit; -} +} // IMPORTANT: This file is sended to 'Takepos Printing' application. Keep basic file. No external files as css, js... If you need images use absolute path. ?> @@ -189,7 +189,6 @@ if ($conf->global->TAKEPOS_CUSTOM_RECEIPT) if (! empty($conf->global->TAKEPOS_FOOTER)){ $newfreetext=make_substitutions($conf->global->TAKEPOS_FOOTER, $substitutionarray); echo $newfreetext; - } } ?> From 4a305ec95c7e13990d238d7b8d0e821edb4de3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 30 Sep 2019 15:59:05 +0200 Subject: [PATCH 23/44] Add hook beforeAgenda in comm/action/index.php --- htdocs/comm/action/index.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php index a2328dd9ca4..403c563c30b 100644 --- a/htdocs/comm/action/index.php +++ b/htdocs/comm/action/index.php @@ -174,6 +174,26 @@ if ($action =='delete_action') /* * View */ +$parameters = array( + 'socid' => $socid, + 'status' => $status, + 'year' => $year, + 'month' => $month, + 'day' => $day, + 'type' => $type, + 'maxprint' => $maxprint, + 'filter' => $filter, + 'filtert' => $filtert, + 'showbirthday' => $showbirthday, + 'canedit' => $canedit, + 'optioncss' => $optioncss, + 'actioncode' => $actioncode, + 'pid' => $pid, + 'resourceid' => $resourceid, + 'usergroup' => $usergroup, +); +$reshook = $hookmanager->executeHooks('beforeAgenda', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); $help_url='EN:Module_Agenda_En|FR:Module_Agenda|ES:Módulo_Agenda'; llxHeader('', $langs->trans("Agenda"), $help_url); From ce7e8c83a359238676997ac7e4695188a5fdef2a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 17:08:57 +0200 Subject: [PATCH 24/44] Use a dedicated css imgforviewmode for button used to switch view --- htdocs/comm/action/card.php | 38 +++++---- htdocs/core/lib/functions.lib.php | 128 ++++++++++++------------------ htdocs/core/lib/ticket.lib.php | 12 +++ htdocs/projet/ganttview.php | 2 +- htdocs/projet/tasks.php | 2 +- htdocs/theme/eldy/btn.inc.php | 20 ++++- htdocs/ticket/agenda.php | 6 +- htdocs/ticket/messaging.php | 17 +--- 8 files changed, 110 insertions(+), 115 deletions(-) diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php index 9d17127aebe..37ef69c24d0 100644 --- a/htdocs/comm/action/card.php +++ b/htdocs/comm/action/card.php @@ -1546,24 +1546,28 @@ if ($id > 0) print $formconfirm; } - $linkback =img_picto($langs->trans("BackToList"), 'object_list', 'class="hideonsmartphone pictoactionview"'); - $linkback.= ''.$langs->trans("BackToList").''; - + $linkback=''; // Link to other agenda views - $out=''; - $out.=''; - $out.='
  • '.img_picto($langs->trans("ViewCal"), 'object_calendar', 'class="hideonsmartphone pictoactionview"'); - $out.=''.$langs->trans("ViewCal").''; - $out.='
  • '; - $out.='
  • '.img_picto($langs->trans("ViewWeek"), 'object_calendarweek', 'class="hideonsmartphone pictoactionview"'); - $out.=''.$langs->trans("ViewWeek").''; - $out.='
  • '; - $out.='
  • '.img_picto($langs->trans("ViewDay"), 'object_calendarday', 'class="hideonsmartphone pictoactionview"'); - $out.=''.$langs->trans("ViewDay").''; - $out.='
  • '; - $out.='
  • '.img_picto($langs->trans("ViewPerUser"), 'object_calendarperuser', 'class="hideonsmartphone pictoactionview"'); - $out.=''.$langs->trans("ViewPerUser").''; - $linkback.=$out; + $linkback.=img_picto($langs->trans("BackToList"), 'object_list', 'class="hideonsmartphone pictoactionview"'); + $linkback.=''.$langs->trans("BackToList").''; + $linkback.='
  • '; + $linkback.='
  • '; + $linkback.=img_picto($langs->trans("ViewCal"), 'object_calendar', 'class="hideonsmartphone pictoactionview"'); + $linkback.=''.$langs->trans("ViewCal").''; + $linkback.='
  • '; + $linkback.='
  • '; + $linkback.=img_picto($langs->trans("ViewWeek"), 'object_calendarweek', 'class="hideonsmartphone pictoactionview"'); + $linkback.=''.$langs->trans("ViewWeek").''; + $linkback.='
  • '; + $linkback.='
  • '; + $linkback.=img_picto($langs->trans("ViewDay"), 'object_calendarday', 'class="hideonsmartphone pictoactionview"'); + $linkback.=''.$langs->trans("ViewDay").''; + $linkback.='
  • '; + $linkback.='
  • '; + $linkback.=img_picto($langs->trans("ViewPerUser"), 'object_calendarperuser', 'class="hideonsmartphone pictoactionview"'); + $linkback.=''.$langs->trans("ViewPerUser").''; + + //$linkback.=$out; $morehtmlref='
    '; // Thirdparty diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 7aca989a0e8..fd947beda41 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3010,66 +3010,41 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt); } } else { - $pictowithoutext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto); + $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto); //if (in_array($picto, array('switch_off', 'switch_on', 'off', 'on'))) - if (empty($srconly) && in_array($pictowithoutext, array( - 'bank', 'close_title', 'delete', 'edit', 'ellipsis-h', 'filter', 'grip', 'grip_title', 'list', 'listlight', 'note', 'off', 'on', 'play', 'playdisabled', 'printer', 'resize', + if (empty($srconly) && in_array($pictowithouttext, array( + 'bank', 'close_title', 'delete', 'edit', 'ellipsis-h', 'filter', 'grip', 'grip_title', 'list', 'listlight', 'note', + 'object_list','object_calendar', 'object_calendarweek', 'object_calendarmonth', 'object_calendarday', 'object_calendarperuser', + 'off', 'on', 'play', 'playdisabled', 'printer', 'resize', 'note', 'setup', 'sign-out', 'split', 'switch_off', 'switch_on', 'tools', 'unlink', 'uparrow', '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected', 'jabber','skype','twitter','facebook','linkedin', 'chevron-left','chevron-right','chevron-down','chevron-top', 'home', 'companies', 'products', 'commercial', 'invoicing', 'accountancy', 'project', 'hrm', 'members', 'ticket', 'generic' ) )) { - $fa='fa'; + $fa='fa'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fa='fas'; - $fakey = $pictowithoutext; - $facolor = ''; $fasize = ''; + $fakey = $pictowithouttext; + $facolor = ''; $fasize = ''; - if ($pictowithoutext == 'setup') { - $fakey = 'fa-cog'; - } - elseif ($pictowithoutext == 'companies') { - $fakey = 'fa-building'; - } - elseif ($pictowithoutext == 'products') { - $fakey = 'fa-box-open'; - } - elseif ($pictowithoutext == 'commercial') { - $fakey = 'fa-user-tie'; - } - elseif ($pictowithoutext == 'invoicing') { - $fakey = 'fa-file-invoice'; - } - elseif ($pictowithoutext == 'accountancy') { - $fakey = 'fa-coins'; - } - elseif ($pictowithoutext == 'project') { - $fakey = 'fa-project-diagram'; - } - elseif ($pictowithoutext == 'hrm') { - $fakey = 'fa-umbrella-beach'; - } - elseif ($pictowithoutext == 'members') { - $fakey = 'fa-user-friends'; - } - elseif ($pictowithoutext == 'ticket') { - $fakey = 'fa-sticky-note'; - } - elseif ($pictowithoutext == 'generic') { - $fakey = 'fa-folder-open'; - } - elseif ($pictowithoutext == 'switch_off') { - $fakey = 'fa-toggle-off'; + $arrayconvpictotofa = array( + 'setup'=>'cog', 'companies'=>'building', 'products'=>'box_open', 'commercial'=>'box-tie', 'invoicing'=>'file-invoice', 'accountancy'=>'coins', 'project'=>'project-diagram', + 'hrm'=>'umbrella-beach', 'members'=>'user-friends', 'ticket'=>'sticky-note', 'generic'=>'folder-open', + 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', + 'bank'=>'bank', 'close_title'=>'window-close', 'delete'=>'trash', 'edit'=>'pencil', 'filter'=>'filter', 'split'=>'code-fork', + 'object_list'=>'list-alt','object_calendar'=>'calendar-alt', 'object_calendarweek'=>'calendar-week', 'object_calendarmonth'=>'calendar-alt', 'object_calendarday'=>'calendar-day', 'object_calendarperuser'=>'table' + ); + + if ($pictowithouttext == 'switch_off') { $facolor = '#999'; $fasize = '2em'; } - elseif ($pictowithoutext == 'switch_on') { - $fakey = 'fa-toggle-on'; + elseif ($pictowithouttext == 'switch_on') { $facolor = '#227722'; $fasize = '2em'; } - elseif ($pictowithoutext == 'off') { + elseif ($pictowithouttext == 'off') { $fakey = 'fa-square-o'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) { @@ -3078,7 +3053,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ } $fasize = '1.3em'; } - elseif ($pictowithoutext == 'on') { + elseif ($pictowithouttext == 'on') { $fakey = 'fa-check-square-o'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) { @@ -3087,44 +3062,35 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ } $fasize = '1.3em'; } - elseif ($pictowithoutext == 'bank') { - $fakey = 'fa-bank'; + elseif ($pictowithouttext == 'bank') { $facolor = '#444'; } - elseif ($pictowithoutext == 'close_title') { - $fakey = 'fa-window-close'; - } - elseif ($pictowithoutext == 'delete') { - $fakey = 'fa-trash'; + elseif ($pictowithouttext == 'delete') { $facolor = '#444'; } - elseif ($pictowithoutext == 'edit') { - $fakey = 'fa-pencil'; + elseif ($pictowithouttext == 'edit') { $facolor = '#444'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fakey = 'fa-pencil-alt'; } - elseif ($pictowithoutext == 'filter') { - $fakey = 'fa-'.$pictowithoutext; - } - elseif ($pictowithoutext == 'grip_title' || $pictowithoutext == 'grip') { + elseif ($pictowithouttext == 'grip_title' || $pictowithouttext == 'grip') { $fakey = 'fa-arrows'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fakey = 'fa-arrows-alt'; } - elseif ($pictowithoutext == 'listlight') { + elseif ($pictowithouttext == 'listlight') { $fakey = 'fa-download'; $facolor = '#999'; $marginleftonlyshort=1; } - elseif ($pictowithoutext == 'printer') { + elseif ($pictowithouttext == 'printer') { $fakey = 'fa-print'; $fasize = '1.2em'; $facolor = '#444'; } - elseif ($pictowithoutext == 'resize') { + elseif ($pictowithouttext == 'resize') { $fakey = 'fa-crop'; $facolor = '#444'; } - elseif ($pictowithoutext == 'note') { + elseif ($pictowithouttext == 'note') { $fakey = 'fa-sticky-note-o'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) { @@ -3133,45 +3099,53 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ $facolor = '#999'; $marginleftonlyshort=1; } - elseif ($pictowithoutext == 'uparrow') { + elseif ($pictowithouttext == 'uparrow') { $fakey = 'fa-mail-forward'; $facolor = '#555'; } - elseif (in_array($pictowithoutext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) { + elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) { $convertarray=array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right'); - $fakey = 'fa-'.$convertarray[$pictowithoutext]; - if (preg_match('/selected/', $pictowithoutext)) $facolor = '#888'; + $fakey = 'fa-'.$convertarray[$pictowithouttext]; + if (preg_match('/selected/', $pictowithouttext)) $facolor = '#888'; $marginleftonlyshort = 1; } - elseif ($pictowithoutext == 'sign-out') { + elseif ($pictowithouttext == 'sign-out') { $fakey = 'fa-sign-out'; $marginleftonlyshort=0; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fakey = 'fa-sign-out-alt'; } - elseif ($pictowithoutext == 'unlink') { + elseif ($pictowithouttext == 'unlink') { $fakey = 'fa-chain-broken'; $facolor = '#555'; } - elseif ($pictowithoutext == 'playdisabled') { + elseif ($pictowithouttext == 'playdisabled') { $fakey = 'fa-play'; $facolor = '#ccc'; } - elseif ($pictowithoutext == 'play') { + elseif ($pictowithouttext == 'play') { $fakey = 'fa-play'; $facolor = '#444'; } - elseif ($pictowithoutext == 'jabber') { + elseif ($pictowithouttext == 'jabber') { $fakey = 'fa-comment-o'; } - elseif (in_array($pictowithoutext, array('skype', 'twitter', 'facebook', 'linkedin'))) { - $fakey = 'fa-'.$pictowithoutext; + elseif (in_array($pictowithouttext, array('skype', 'twitter', 'facebook', 'linkedin'))) { + $fakey = 'fa-'.$pictowithouttext; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fa = 'fab'; } - elseif ($pictowithoutext == 'split') { - $fakey = 'fa-code-fork'; + // Img for type of views + elseif (in_array($pictowithouttext, array('object_list', 'object_calendar', 'object_calendarweek', 'object_calendarmonth', 'object_calendarday', 'object_calendarperuser'))) { + $fakey = 'imgforviewmode fa-'.$arrayconvpictotofa[$pictowithouttext]; + $marginleftonlyshort=0; + } + elseif (! empty($arrayconvpictotofa[$pictowithouttext])) + { + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; + $facolor = '#444'; + $marginleftonlyshort=0; } else { - $fakey = 'fa-'.$pictowithoutext; + $fakey = 'fa-'.$pictowithouttext; $facolor = '#444'; $marginleftonlyshort=0; } @@ -3189,7 +3163,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ $moreatt=trim($moreatt); $enabledisablehtml = ''; + $enabledisablehtml .= ' ' . ($morecss ? ' ' . $morecss : '') . '" style="' . ($fasize ? ('font-size: ' . $fasize . ';') : '') . ($facolor ? (' color: ' . $facolor . ';') : '') . ($morestyle ? ' ' . $morestyle : '') . '"' . (($notitle || empty($titlealt)) ? '' : ' title="' . dol_escape_htmltag($titlealt) . '"') . ($moreatt ? ' ' . $moreatt : '') . '>'; if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $enabledisablehtml.= $titlealt; } diff --git a/htdocs/core/lib/ticket.lib.php b/htdocs/core/lib/ticket.lib.php index 21761286131..0b27e003b5f 100644 --- a/htdocs/core/lib/ticket.lib.php +++ b/htdocs/core/lib/ticket.lib.php @@ -505,6 +505,18 @@ function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $no $out.=''; $out.=''; + + $out.=''; + $out.=''; if ($donetodo) { diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index 4e788a2b991..8d1027d5cf4 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -234,7 +234,7 @@ if ($user->rights->projet->all->creer || $user->rights->projet->creer) { $linktocreatetask = dolGetButtonTitle($langs->trans('AddTask'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id.'&action=create'.$param.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id), '', $linktocreatetaskUserRight, $linktocreatetaskParam); -$linktolist = dolGetButtonTitle($langs->trans('GoToListOfTasks'), '', 'fa fa-tasks paddingleft', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id); +$linktolist = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktolist.'   '.$linktocreatetask, 'generic'); diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index bfc775ff94f..a2785274bbd 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -669,7 +669,7 @@ elseif ($id > 0 || ! empty($ref)) print ''; $title=$langs->trans("ListOfTasks"); - $linktotasks = dolGetButtonTitle($langs->trans('GoToGanttView'), '', 'fa fa-calendar-minus-o paddingleft', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1'); + $linktotasks = dolGetButtonTitle($langs->trans('GanttView'), '', 'fa fa-calendar-minus-o paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1'); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); diff --git a/htdocs/theme/eldy/btn.inc.php b/htdocs/theme/eldy/btn.inc.php index 28355e7ea3a..a3000715712 100644 --- a/htdocs/theme/eldy/btn.inc.php +++ b/htdocs/theme/eldy/btn.inc.php @@ -68,19 +68,29 @@ span.butActionNewRefused>span.fa-plus-circle, span.butActionNewRefused>span.fa-p a.butActionNew>span.fa-list-alt, a.butActionNew>span.fa-list-alt:hover, span.butActionNew>span.fa-list-alt, span.butActionNew>span.fa-list-alt:hover, a.butActionNewRefused>span.fa-list-alt, a.butActionNewRefused>span.fa-list-alt:hover, -span.butActionNewRefused>span.fa-list-alt, span.butActionNewRefused>span.fa-list-alt:hover { +span.butActionNewRefused>span.fa-list-alt, span.butActionNewRefused>span.fa-list-alt:hover +{ font-size: 1em; padding-left: 0px; } -a.butActionNew>span.fa-plus-circle, a.butActionNew>span.fa-plus-circle:hover, +/*a.butActionNew>span.fa-plus-circle, a.butActionNew>span.fa-plus-circle:hover, span.butActionNew>span.fa-plus-circle, span.butActionNew>span.fa-plus-circle:hover, a.butActionNewRefused>span.fa-plus-circle, a.butActionNewRefused>span.fa-plus-circle:hover, span.butActionNewRefused>span.fa-plus-circle, span.butActionNewRefused>span.fa-plus-circle:hover, a.butActionNew>span.fa-list-alt, a.butActionNew>span.fa-list-alt:hover, span.butActionNew>span.fa-list-alt, span.butActionNew>span.fa-list-alt:hover, a.butActionNewRefused>span.fa-list-alt, a.butActionNewRefused>span.fa-list-alt:hover, -span.butActionNewRefused>span.fa-list-alt, span.butActionNewRefused>span.fa-list-alt:hover { +span.butActionNewRefused>span.fa-list-alt, span.butActionNewRefused>span.fa-list-alt:hover, +a.butActionNew>span.fa-comment-dots, a.butActionNew>span.fa-comment-dots:hover, +span.butActionNew>span.fa-comment-dots, span.butActionNew>span.fa-comment-dots:hover, +a.butActionNewRefused>span.fa-comment-dots, a.butActionNewRefused>span.fa-comment-dots:hover, +span.butActionNewRefused>span.fa-comment-dots, span.butActionNewRefused>span.fa-comment-dots:hover,*/ +a.butActionNew>span.fa, a.butActionNew>span.fa:hover, +span.butActionNew>span.fa, span.butActionNew>span.fa:hover, +a.butActionNewRefused>span.fa, a.butActionNewRefused>span.fa:hover, +span.butActionNewRefused>span.fa, span.butActionNewRefused>span.fa:hover +{ padding-: 6px; font-size: 1.5em; border: none; @@ -229,6 +239,10 @@ div.pagination li:first-child a.btnTitle{ } +.imgforviewmode { + color: #aaa; +} + global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (! $user->admin)) { ?> .butActionRefused, .butActionNewRefused, .btnTitle.refused { diff --git a/htdocs/ticket/agenda.php b/htdocs/ticket/agenda.php index 3d1c41b711c..44df1d8f6f7 100644 --- a/htdocs/ticket/agenda.php +++ b/htdocs/ticket/agenda.php @@ -234,17 +234,17 @@ if (!empty($object->id)) $morehtmlright = ''; $messagingUrl = DOL_URL_ROOT.'/ticket/messaging.php?track_id=' . $object->track_id; - $morehtmlright .= dolGetButtonTitle($langs->trans('MessagingViewType'), '', 'fa fa-comments', $messagingUrl, $id = '', $status = 1); + $morehtmlright .= dolGetButtonTitle($langs->trans('MessagingViewType'), '', 'fa fa-comments imgforviewmode', $messagingUrl, '', 1); // Show link to add a message (if read and not closed) $btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; $url = 'card.php?track_id=' . $object->track_id . '&action=presend_addmessage&mode=init'; - $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-title-button', $btnstatus); + $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-comment-dots', $url, 'add-new-ticket-title-button', $btnstatus); // Show link to add event (if read and not closed) $btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; $url = dol_buildpath('/comm/action/card.php', 1).'?action=create&datep='.date('YmdHi').'&origin=ticket&originid='.$object->id.'&projectid='.$object->fk_project.'&backtopage='.urlencode($_SERVER["PHP_SELF"]); - $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-calendar-plus', $url, 'add-new-ticket-even-button', $btnstatus); + $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-even-button', $btnstatus); print_barre_liste($langs->trans("ActionsOnTicket"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 1); diff --git a/htdocs/ticket/messaging.php b/htdocs/ticket/messaging.php index 5966973d4ca..2c76285437d 100644 --- a/htdocs/ticket/messaging.php +++ b/htdocs/ticket/messaging.php @@ -16,7 +16,7 @@ */ /** - * \file htdocs/ticket/agenda.php + * \file htdocs/ticket/messaging.php * \ingroup ticket * \brief Page with events on ticket */ @@ -233,27 +233,18 @@ if (!empty($object->id)) $morehtmlright = ''; - if($sortorder === 'desc') { - $sortUrl = $_SERVER["PHP_SELF"] . '?sortfield=a.datep&sortorder=asc' . $param; - $morehtmlright .= dolGetButtonTitle($langs->trans('Date'), $langs->trans('OrderByDateAsc'), 'fa fa-sort-numeric-down', $sortUrl, $id = '', $status = 1); - } - else{ - $sortUrl = $_SERVER["PHP_SELF"] . '?sortfield=a.datep&sortorder=desc' . $param; - $morehtmlright .= dolGetButtonTitle($langs->trans('Date'), $langs->trans('OrderByDateDesc'), 'fa fa-sort-numeric-down-alt', $sortUrl, $id = '', $status = 1); - } - $messagingUrl = DOL_URL_ROOT.'/ticket/agenda.php?track_id=' . $object->track_id; - $morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-tasks', $messagingUrl, $id = '', $status = 1); + $morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-list-alt imgforviewmode', $messagingUrl, '', 1); // Show link to add a message (if read and not closed) $btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; $url = 'card.php?track_id=' . $object->track_id . '&action=presend_addmessage&mode=init'; - $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-title-button', $btnstatus); + $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-comment-dots', $url, 'add-new-ticket-title-button', $btnstatus); // Show link to add event (if read and not closed) $btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; $url = dol_buildpath('/comm/action/card.php', 1).'?action=create&datep='.date('YmdHi').'&origin=ticket&originid='.$object->id.'&projectid='.$object->fk_project.'&backtopage='.urlencode($_SERVER["PHP_SELF"]); - $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-calendar-plus', $url, 'add-new-ticket-even-button', $btnstatus); + $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-even-button', $btnstatus); print_barre_liste($langs->trans("ActionsOnTicket"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 1); From 48fc1650269f55c9e5756086954caf9a81da6bdc Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 17:15:05 +0200 Subject: [PATCH 25/44] Trans --- htdocs/langs/en_US/projects.lang | 4 ++-- htdocs/projet/ganttview.php | 2 +- htdocs/projet/tasks.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index 8d3297b6587..39cbe6ce6a9 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -86,8 +86,8 @@ WhichIamLinkedToProject=which I'm linked to project Time=Time ListOfTasks=List of tasks GoToListOfTimeConsumed=Go to list of time consumed -GoToListOfTasks=Go to list of tasks -GoToGanttView=Go to Gantt view +GoToListOfTasks=Show as list +GoToGanttView=show as Gantt GanttView=Gantt View ListProposalsAssociatedProject=List of the commercial proposals related to the project ListOrdersAssociatedProject=List of sales orders related to the project diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index 8d1027d5cf4..a736e6e3107 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -234,7 +234,7 @@ if ($user->rights->projet->all->creer || $user->rights->projet->creer) { $linktocreatetask = dolGetButtonTitle($langs->trans('AddTask'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id.'&action=create'.$param.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id), '', $linktocreatetaskUserRight, $linktocreatetaskParam); -$linktolist = dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-list-alt paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id); +$linktolist = dolGetButtonTitle($langs->trans('GoToListOfTasks'), '', 'fa fa-list-alt paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktolist.'   '.$linktocreatetask, 'generic'); diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index a2785274bbd..0d6e8af15f0 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -669,7 +669,7 @@ elseif ($id > 0 || ! empty($ref)) print ''; $title=$langs->trans("ListOfTasks"); - $linktotasks = dolGetButtonTitle($langs->trans('GanttView'), '', 'fa fa-calendar-minus-o paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1'); + $linktotasks = dolGetButtonTitle($langs->trans('GoToGanttView'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1'); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); From b390cff172a9e41ff490a7f8d6d9a0039b1e0dd9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 17:22:22 +0200 Subject: [PATCH 26/44] Fix css --- htdocs/core/class/html.formticket.class.php | 2 +- htdocs/core/lib/company.lib.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index a7797f91833..577430592cf 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -981,7 +981,7 @@ class FormTicket include_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php'; $uselocalbrowser = true; - $doleditor = new DolEditor('mail_intro', $mail_intro, '100%', 140, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_2, 70); + $doleditor = new DolEditor('mail_intro', $mail_intro, '100%', 90, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_SOCIETE, ROWS_2, 70); $doleditor->Create(); print ''; // Author of event - $out.=''; + // Bill time + if (empty($conf->global->PROJECT_HIDE_TASKS) && ! empty($conf->global->PROJECT_BILL_TIME_SPENT)) + { + print ''; + } + // Categories if($conf->categorie->enabled) { print '
    '; + if($sortorder === 'desc') { + $sortUrl = $_SERVER["PHP_SELF"] . '?sortfield=a.datep&sortorder=asc' . $param; + $out .= dolGetButtonTitle($langs->trans('Date'), $langs->trans('OrderByDateAsc'), 'fa fa-sort-numeric-down', $sortUrl, '', 1); + } + else{ + $sortUrl = $_SERVER["PHP_SELF"] . '?sortfield=a.datep&sortorder=desc' . $param; + $out .= dolGetButtonTitle($langs->trans('Date'), $langs->trans('OrderByDateDesc'), 'fa fa-sort-numeric-down-alt', $sortUrl, '', 1); + } + $out.=''.$langs->trans("Search").' : '; diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index da7b2918ec7..230c98a1d3c 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -1568,7 +1568,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon = '', $noprin $out.=''; + $out.=''; //$userstatic->id=$histo[$key]['userid']; //$userstatic->login=$histo[$key]['login']; //$out.=$userstatic->getLoginUrl(1); From dc7ad61940eac7c3adea8c87731bf7712e29f1a3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 17:46:53 +0200 Subject: [PATCH 27/44] Add class reposition on button that switch the view mode --- htdocs/core/lib/functions.lib.php | 12 ++++++------ htdocs/core/menus/standard/eldy.lib.php | 2 +- htdocs/projet/ganttview.php | 10 +++++++++- htdocs/projet/tasks.php | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index fd947beda41..a3ee9d79324 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8239,7 +8239,7 @@ function dolGetButtonAction($label, $html = '', $actionType = 'default', $url = * * @param string $label label of button * @param string $helpText optional : content for help tooltip - * @param string $iconClass class for icon element + * @param string $iconClass class for icon element (Example: 'fa fa-file') * @param string $url the url for link * @param string $id attribute id of button * @param int $status 0 no user rights, 1 active, -1 Feature Disabled, -2 disable Other reason use helpText as tooltip @@ -8255,12 +8255,12 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u return ''; } - $class = 'btnTitle' ; - + $class = 'btnTitle'; // hidden conf keep during button transition TODO: remove this block - if(empty($conf->global->MAIN_USE_NEW_TITLE_BUTTON)){ + if (empty($conf->global->MAIN_USE_NEW_TITLE_BUTTON)) { $class = 'butActionNew'; } + if (! empty($params['morecss'])) $class.=' '.$params['morecss']; $attr=array( 'class' => $class @@ -8326,9 +8326,9 @@ function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $u $TCompiledAttr[] = $key.'="'.$value.'"'; } - $compiledAttributes = !empty($TCompiledAttr)?implode(' ', $TCompiledAttr):''; + $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr)); - $tag = !empty($attr['href'])?'a':'span'; + $tag = (empty($attr['href']) ? 'span' : 'a'); $button ='<'.$tag.' '.$compiledAttributes.' >'; diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 758f12b3f5e..51f2da2262c 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -205,7 +205,7 @@ function print_eldy_menu($db, $atarget, $type_user, &$tabMenu, &$menu, $noout = 'link' => '/projet/index.php?mainmenu=project&leftmenu=', 'title' => (empty($conf->global->PROJECT_USE_OPPORTUNITIES) || $conf->global->PROJECT_USE_OPPORTUNITIES == 2 ) ? (($conf->global->PROJECT_USE_OPPORTUNITIES == 2)?"Leads":"Projects") - : "LeadsOrProjects", + : "Projects", 'level' => 0, 'enabled' => $showmode = isVisibleToUserType($type_user, $tmpentry, $listofmodulesforexternal), 'target' => $atarget, diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index a736e6e3107..64772a34d5a 100644 --- a/htdocs/projet/ganttview.php +++ b/htdocs/projet/ganttview.php @@ -201,6 +201,14 @@ if (($id > 0 && is_numeric($id)) || ! empty($ref)) print nl2br($object->description); print '
    '.$langs->trans("BillTime").''; + print yn($object->usage_bill_time); + print '
    '.$langs->trans("Categories").''; @@ -234,7 +242,7 @@ if ($user->rights->projet->all->creer || $user->rights->projet->creer) { $linktocreatetask = dolGetButtonTitle($langs->trans('AddTask'), '', 'fa fa-plus-circle paddingleft', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id.'&action=create'.$param.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$object->id), '', $linktocreatetaskUserRight, $linktocreatetaskParam); -$linktolist = dolGetButtonTitle($langs->trans('GoToListOfTasks'), '', 'fa fa-list-alt paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id); +$linktolist = dolGetButtonTitle($langs->trans('GoToListOfTasks'), '', 'fa fa-list-alt paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/tasks.php?id='.$object->id, '', 1, array('morecss'=>'reposition')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktolist.'   '.$linktocreatetask, 'generic'); diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index 0d6e8af15f0..fef42957bab 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -669,7 +669,7 @@ elseif ($id > 0 || ! empty($ref)) print ''; $title=$langs->trans("ListOfTasks"); - $linktotasks = dolGetButtonTitle($langs->trans('GoToGanttView'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1'); + $linktotasks = dolGetButtonTitle($langs->trans('GoToGanttView'), '', 'fa fa-stream paddingleft imgforviewmode', DOL_URL_ROOT.'/projet/ganttview.php?id='.$object->id.'&withproject=1', '', 1, array('morecss'=>'reposition')); //print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $linktotasks, $num, $totalnboflines, 'generic', 0, '', '', 0, 1); print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'generic'); From ecc2e8df67bd54b67e97bfac2746eabe2f6b8614 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 17:58:31 +0200 Subject: [PATCH 28/44] Fix restore lost images --- htdocs/core/lib/functions.lib.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index a3ee9d79324..287623c6c55 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3039,10 +3039,12 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ if ($pictowithouttext == 'switch_off') { $facolor = '#999'; $fasize = '2em'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; } elseif ($pictowithouttext == 'switch_on') { $facolor = '#227722'; $fasize = '2em'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; } elseif ($pictowithouttext == 'off') { $fakey = 'fa-square-o'; @@ -3063,13 +3065,16 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ $fasize = '1.3em'; } elseif ($pictowithouttext == 'bank') { + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; $facolor = '#444'; } elseif ($pictowithouttext == 'delete') { + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; $facolor = '#444'; } elseif ($pictowithouttext == 'edit') { $facolor = '#444'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) $fakey = 'fa-pencil-alt'; } elseif ($pictowithouttext == 'grip_title' || $pictowithouttext == 'grip') { @@ -3163,7 +3168,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ $moreatt=trim($moreatt); $enabledisablehtml = ''; + $enabledisablehtml .= ' valignmiddle' . ($morecss ? ' ' . $morecss : '') . '" style="' . ($fasize ? ('font-size: ' . $fasize . ';') : '') . ($facolor ? (' color: ' . $facolor . ';') : '') . ($morestyle ? ' ' . $morestyle : '') . '"' . (($notitle || empty($titlealt)) ? '' : ' title="' . dol_escape_htmltag($titlealt) . '"') . ($moreatt ? ' ' . $moreatt : '') . '>'; if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $enabledisablehtml.= $titlealt; } From ac4d72bb74b17307445e283014b33911ce68da36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 30 Sep 2019 18:12:56 +0200 Subject: [PATCH 29/44] typo --- htdocs/main.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index ce8b1d6027e..a4e9560053b 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1463,7 +1463,7 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr if ($conf->browser->layout == 'phone') $enablebrowsernotif=false; if ($enablebrowsernotif) { - print ''."\n"; + print ''."\n"; print ''."\n"; } } From 506b1e8ecc77a4f1175009d22c9f1d59c751880d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 30 Sep 2019 18:17:29 +0200 Subject: [PATCH 30/44] typo --- test/phpunit/CoreTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/phpunit/CoreTest.php b/test/phpunit/CoreTest.php index 4720df9014c..eb6e90dc41a 100644 --- a/test/phpunit/CoreTest.php +++ b/test/phpunit/CoreTest.php @@ -374,7 +374,7 @@ class CoreTest extends PHPUnit\Framework\TestCase $result=testSqlAndScriptInject($test, 0); $this->assertGreaterThanOrEqual($expectedresult, $result, 'Error on testSqlAndScriptInject eee'); - $test=""; // Is locked by some brwoser like chrome because the default directive no-referrer-when-downgrade is sent when requesting the SRC and then refused because of browser protection on img src load without referrer. + $test=""; // Is locked by some browser like chrome because the default directive no-referrer-when-downgrade is sent when requesting the SRC and then refused because of browser protection on img src load without referrer. $test=""; // Same $test=''; From a5fce6cca8879166f9af29eda8821d4e57dabf57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 30 Sep 2019 18:25:54 +0200 Subject: [PATCH 31/44] Update CMailFile.class.php --- htdocs/core/class/CMailFile.class.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index b9f428d9f43..da5e1ebc1a3 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -136,12 +136,25 @@ class CMailFile { global $conf, $dolibarr_main_data_root; + $this->subject = $subject; + $this->addr_to = $to; + $this->addr_from = $from; + $this->msg = $msg; + $this->filename_list = $filename_list; + $this->mimetype_list = $mimetype_list; + $this->mimefilename_list = $mimefilename_list; + $this->addr_cc = $addr_cc; + $this->addr_bcc = $addr_bcc; + $this->deliveryreceipt = $deliveryreceipt; + if (empty($replyto)) $replyto = $from; + $this->reply_to = $replyto; + $this->errors_to = $errors_to; + $this->trackid = $trackid; $this->sendcontext = $sendcontext; $this->filename_list = $filename_list; $this->mimetype_list = $mimetype_list; $this->mimefilename_list = $mimefilename_list; - if (empty($replyto)) $replyto=$from; // Define this->sendmode $this->sendmode = ''; @@ -262,16 +275,6 @@ class CMailFile $files_encoded = ""; // Define smtp_headers - $this->subject = $subject; - $this->addr_from = $from; - $this->reply_to = $replyto; - $this->errors_to = $errors_to; - $this->addr_to = $to; - $this->addr_cc = $addr_cc; - $this->addr_bcc = $addr_bcc; - $this->deliveryreceipt = $deliveryreceipt; - $this->trackid = $trackid; - $smtp_headers = $this->write_smtpheaders(); if (! empty($moreinheader)) $smtp_headers.=$moreinheader; // $moreinheader contains the \r\n From cff8f582e78f6f5ea0fd608a867a6342503435f0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 18:47:18 +0200 Subject: [PATCH 32/44] Update bonprelevement.class.php --- htdocs/compta/prelevement/class/bonprelevement.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 5014923e12b..7fca836a651 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -1119,7 +1119,7 @@ class BonPrelevement extends CommonObject if (! $error && ! $notrigger) { // Call trigger - $result=$this->call_trigger('BON_PRELEVEMENT_CREATE', $user); + $result=$this->call_trigger('DIRECT_DEBIT_ORDER_CREATE', $user); if ($result < 0) $error++; // End call triggers } From a56b9e1ca92c204077753c079341e14646051641 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 18:50:23 +0200 Subject: [PATCH 33/44] The trigger BON_PRELEVEMENT has been renamed into DIRECT_DEBIT_ORDER_CREATE. --- ChangeLog | 1 + htdocs/compta/prelevement/class/bonprelevement.class.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b8a3fea2ce9..91b0de3466f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ Following changes may create regressions for some external modules, but were nec * Removed deprecated method actioncomm->add(), use create() instead * If you have developed your own emailing target selector and used parent::add_to_target(...), you must now use parent::addToTargets(...) * Removed function dol_micro_time. Use native PHP microtime instead. +* The trigger BON_PRELEVEMENT has been renamed into DIRECT_DEBIT_ORDER_CREATE. ***** ChangeLog for 10.0.2 compared to 10.0.1 ***** diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 9f9435a986c..1285a20117b 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -1149,7 +1149,7 @@ class BonPrelevement extends CommonObject if (! $notrigger) { // Call trigger - $result=$this->call_trigger('BON_PRELEVEMENT_DELETE', $user); + $result=$this->call_trigger('DIRECT_DEBIT_ORDER_DELETE', $user); if ($result < 0) $error++; // End call triggers } From fe735d4e677809c7fb8e0b6f1b0b4e9b58514506 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 18:51:28 +0200 Subject: [PATCH 34/44] Changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 91b0de3466f..0f4d3c30ddf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,7 +22,7 @@ Following changes may create regressions for some external modules, but were nec * Removed deprecated method actioncomm->add(), use create() instead * If you have developed your own emailing target selector and used parent::add_to_target(...), you must now use parent::addToTargets(...) * Removed function dol_micro_time. Use native PHP microtime instead. -* The trigger BON_PRELEVEMENT has been renamed into DIRECT_DEBIT_ORDER_CREATE. +* The trigger BON_PRELEVEMENT_CREATE has been renamed into DIRECT_DEBIT_ORDER_CREATE. ***** ChangeLog for 10.0.2 compared to 10.0.1 ***** From d9e9364ddf9356d58b5c80a1e428c573dabbea17 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 19:00:19 +0200 Subject: [PATCH 35/44] Close #11689 Close #11696 --- htdocs/product/stock/card.php | 236 +++++++++++++++++----------------- 1 file changed, 121 insertions(+), 115 deletions(-) diff --git a/htdocs/product/stock/card.php b/htdocs/product/stock/card.php index c085bff8082..4fef23ad1c5 100644 --- a/htdocs/product/stock/card.php +++ b/htdocs/product/stock/card.php @@ -87,81 +87,17 @@ $usercanread = (($user->rights->stock->lire)); $usercancreate = (($user->rights->stock->creer)); $usercandelete = (($user->rights->stock->supprimer)); -// Ajout entrepot -if ($action == 'add' && $user->rights->stock->creer) +$parameters=array('id'=>$id, 'ref'=>$ref); +$reshook=$hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); +if (empty($reshook)) { - $object->ref = GETPOST("ref"); - $object->fk_parent = GETPOST("fk_parent"); - $object->libelle = GETPOST("libelle"); - $object->description = GETPOST("desc"); - $object->statut = GETPOST("statut"); - $object->lieu = GETPOST("lieu"); - $object->address = GETPOST("address"); - $object->zip = GETPOST("zipcode"); - $object->town = GETPOST("town"); - $object->country_id = GETPOST("country_id"); - - if (! empty($object->libelle)) + // Ajout entrepot + if ($action == 'add' && $user->rights->stock->creer) { - // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost($extralabels, $object); - if ($ret < 0) { - $error++; - $action = 'create'; - } - - if (! $error) { - $id = $object->create($user); - if ($id > 0) { - setEventMessages($langs->trans("RecordSaved"), null, 'mesgs'); - - $categories = GETPOST('categories', 'array'); - $object->setCategories($categories); - if (!empty($backtopage)) { - header("Location: " . $backtopage); - exit; - } else { - header("Location: card.php?id=" . $id); - exit; - } - } else { - $action = 'create'; - setEventMessages($object->error, $object->errors, 'errors'); - } - } - } - else - { - setEventMessages($langs->trans("ErrorWarehouseRefRequired"), null, 'errors'); - $action="create"; // Force retour sur page creation - } -} - -// Delete warehouse -if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->stock->supprimer) -{ - $object->fetch(GETPOST('id', 'int')); - $result=$object->delete($user); - if ($result > 0) - { - setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs'); - header("Location: ".DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1'); - exit; - } - else - { - setEventMessages($object->error, $object->errors, 'errors'); - $action=''; - } -} - -// Modification entrepot -if ($action == 'update' && $cancel <> $langs->trans("Cancel")) -{ - if ($object->fetch($id)) - { - $object->libelle = GETPOST("libelle"); + $object->ref = GETPOST("ref"); $object->fk_parent = GETPOST("fk_parent"); + $object->libelle = GETPOST("libelle"); $object->description = GETPOST("desc"); $object->statut = GETPOST("statut"); $object->lieu = GETPOST("lieu"); @@ -170,57 +106,127 @@ if ($action == 'update' && $cancel <> $langs->trans("Cancel")) $object->town = GETPOST("town"); $object->country_id = GETPOST("country_id"); - // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost($extralabels, $object); - if ($ret < 0) $error++; + if (! empty($object->libelle)) + { + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) { + $error++; + $action = 'create'; + } - if (! $error) { - $ret = $object->update($id, $user); - if ($ret < 0) $error++; - } + if (! $error) { + $id = $object->create($user); + if ($id > 0) { + setEventMessages($langs->trans("RecordSaved"), null, 'mesgs'); - if ($error) { + $categories = GETPOST('categories', 'array'); + $object->setCategories($categories); + if (!empty($backtopage)) { + header("Location: " . $backtopage); + exit; + } else { + header("Location: card.php?id=" . $id); + exit; + } + } else { + $action = 'create'; + setEventMessages($object->error, $object->errors, 'errors'); + } + } + } + else + { + setEventMessages($langs->trans("ErrorWarehouseRefRequired"), null, 'errors'); + $action="create"; // Force retour sur page creation + } + } + + // Delete warehouse + if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->stock->supprimer) + { + $object->fetch(GETPOST('id', 'int')); + $result=$object->delete($user); + if ($result > 0) + { + setEventMessages($langs->trans("RecordDeleted"), null, 'mesgs'); + header("Location: ".DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1'); + exit; + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + $action=''; + } + } + + // Modification entrepot + if ($action == 'update' && $cancel <> $langs->trans("Cancel")) + { + if ($object->fetch($id)) + { + $object->libelle = GETPOST("libelle"); + $object->fk_parent = GETPOST("fk_parent"); + $object->description = GETPOST("desc"); + $object->statut = GETPOST("statut"); + $object->lieu = GETPOST("lieu"); + $object->address = GETPOST("address"); + $object->zip = GETPOST("zipcode"); + $object->town = GETPOST("town"); + $object->country_id = GETPOST("country_id"); + + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) $error++; + + if (! $error) { + $ret = $object->update($id, $user); + if ($ret < 0) $error++; + } + + if ($error) { + $action = 'edit'; + setEventMessages($object->error, $object->errors, 'errors'); + } else { + $categories = GETPOST('categories', 'array'); + $object->setCategories($categories); + $action = ''; + } + } + else + { $action = 'edit'; setEventMessages($object->error, $object->errors, 'errors'); - } else { - $categories = GETPOST('categories', 'array'); - $object->setCategories($categories); - $action = ''; - } + } } - else + elseif ($action == 'update_extras') { + $object->oldcopy = dol_clone($object); + + // Fill array 'array_options' with data from update form + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute', 'none')); + if ($ret < 0) $error++; + if (! $error) { + $result = $object->insertExtraFields(); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + if ($error) $action = 'edit_extras'; + } + + if ($cancel == $langs->trans("Cancel")) { - $action = 'edit'; - setEventMessages($object->error, $object->errors, 'errors'); + $action = ''; } + + + // Actions to build doc + $upload_dir = $conf->stock->dir_output; + $permissioncreate = $user->rights->stock->creer; + include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; } -elseif ($action == 'update_extras') { - $object->oldcopy = dol_clone($object); - - // Fill array 'array_options' with data from update form - $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); - $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute', 'none')); - if ($ret < 0) $error++; - if (! $error) { - $result = $object->insertExtraFields(); - if ($result < 0) { - setEventMessages($object->error, $object->errors, 'errors'); - $error++; - } - } - if ($error) $action = 'edit_extras'; -} - -if ($cancel == $langs->trans("Cancel")) -{ - $action = ''; -} - - -// Actions to build doc -$upload_dir = $conf->stock->dir_output; -$permissioncreate = $user->rights->stock->creer; -include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; /* From 33908afb66a36509169859b7548c7e63a579cb30 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 19:30:31 +0200 Subject: [PATCH 36/44] Update zapier logo --- htdocs/core/modules/modZapier.class.php | 4 ++-- htdocs/theme/eldy/img/object_zapier.png | Bin 0 -> 716 bytes htdocs/theme/md/img/object_zapier.png | Bin 0 -> 716 bytes 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 htdocs/theme/eldy/img/object_zapier.png create mode 100644 htdocs/theme/md/img/object_zapier.png diff --git a/htdocs/core/modules/modZapier.class.php b/htdocs/core/modules/modZapier.class.php index da6a8aa1547..ed628110044 100644 --- a/htdocs/core/modules/modZapier.class.php +++ b/htdocs/core/modules/modZapier.class.php @@ -19,7 +19,7 @@ * \defgroup zapier Module Zapier * \brief Zapier module descriptor. * - * \file htdocs/zapier/core/modules/modZapier.class.php + * \file htdocs/core/modules/modZapier.class.php * \ingroup zapier * \brief Description and activation file for module Zapier */ @@ -67,7 +67,7 @@ class modZapier extends DolibarrModules // Name of image file used for this module. // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' - $this->picto = 'zapier@zapier'; + $this->picto = 'zapier'; // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) $this->module_parts = array( // Set this to 1 if module has its own trigger directory (core/triggers) diff --git a/htdocs/theme/eldy/img/object_zapier.png b/htdocs/theme/eldy/img/object_zapier.png new file mode 100644 index 0000000000000000000000000000000000000000..4ffd34184affcdc0e807513378af999db135c7cc GIT binary patch literal 716 zcmV;-0yF)IP) z8T~YYKHDjvrzyt|~%-e zWH``aiQxb=t+ADMT8MR)>e?zQM>2E`)k@uUorQA%hdBUnkK)%6%0KI`><+QI1IK_x zKy8{2F5`EDAtm%G0NCshjisM)i1*)26sTvjlcB396)}2=9!KcPbpV|B%I}ttOJQ(W ztnOMn2mE}Ba|eI<44VQeDfEn{!u3hrxC33|*DqmHkUs1P;wT*WRBkEBix_OtsXIq9!MdS{6Z<}u4GxYbip(q%+ zh{55O^z*9qO@8P_rHpeU^yq1=P@If&>%)*^aW8+*d)gCNlo&Gxh|A0Sh`Tk=y2?(nI0000 z8T~YYKHDjvrzyt|~%-e zWH``aiQxb=t+ADMT8MR)>e?zQM>2E`)k@uUorQA%hdBUnkK)%6%0KI`><+QI1IK_x zKy8{2F5`EDAtm%G0NCshjisM)i1*)26sTvjlcB396)}2=9!KcPbpV|B%I}ttOJQ(W ztnOMn2mE}Ba|eI<44VQeDfEn{!u3hrxC33|*DqmHkUs1P;wT*WRBkEBix_OtsXIq9!MdS{6Z<}u4GxYbip(q%+ zh{55O^z*9qO@8P_rHpeU^yq1=P@If&>%)*^aW8+*d)gCNlo&Gxh|A0Sh`Tk=y2?(nI0000 Date: Mon, 30 Sep 2019 20:44:56 +0200 Subject: [PATCH 37/44] FIX : action com redirect --- htdocs/ticket/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/ticket/messaging.php b/htdocs/ticket/messaging.php index 2c76285437d..b56758c9493 100644 --- a/htdocs/ticket/messaging.php +++ b/htdocs/ticket/messaging.php @@ -243,7 +243,7 @@ if (!empty($object->id)) // Show link to add event (if read and not closed) $btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage"; - $url = dol_buildpath('/comm/action/card.php', 1).'?action=create&datep='.date('YmdHi').'&origin=ticket&originid='.$object->id.'&projectid='.$object->fk_project.'&backtopage='.urlencode($_SERVER["PHP_SELF"]); + $url = dol_buildpath('/comm/action/card.php', 1).'?action=create&datep='.date('YmdHi').'&origin=ticket&originid='.$object->id.'&projectid='.$object->fk_project.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?track_id=' . $object->track_id); $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-even-button', $btnstatus); From 91b7e810852d8f75b7b2fbec950a1decca363235 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 21:51:42 +0200 Subject: [PATCH 38/44] Fix warnings --- htdocs/install/inc.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/htdocs/install/inc.php b/htdocs/install/inc.php index c8dc7fd4382..bcca012eeac 100644 --- a/htdocs/install/inc.php +++ b/htdocs/install/inc.php @@ -544,12 +544,16 @@ function detect_dolibarr_main_url_root() $dolibarr_main_url_root = $_SERVER["SERVER_URL"] . $_SERVER["DOCUMENT_URI"]; } // If SCRIPT_URI, SERVER_URL, DOCUMENT_URI not defined (Ie: Apache 2.0.44 for Windows) else { - $proto = ( (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') || $_SERVER['SERVER_PORT'] == 443) ? 'https' : 'http'; + $proto = ((!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') || (! empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443)) ? 'https' : 'http'; if (!empty($_SERVER["HTTP_HOST"])) { $serverport = $_SERVER["HTTP_HOST"]; - } else { + } + elseif (!empty($_SERVER["SERVER_NAME"])) { $serverport = $_SERVER["SERVER_NAME"]; } + else { + $serverport = 'localhost'; + } $dolibarr_main_url_root = $proto . "://" . $serverport . $_SERVER["SCRIPT_NAME"]; } // Clean proposed URL From af3bee6fcf4db75f1b240da14ae00cd727164340 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 21:59:42 +0200 Subject: [PATCH 39/44] Remove warning --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index de9e7e00947..50f8fb08a24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -222,6 +222,7 @@ before_script: echo '$'dolibarr_main_db_host=\'127.0.0.1\'';' >> $CONF_FILE echo '$'dolibarr_main_db_name=\'travis\'';' >> $CONF_FILE echo '$'dolibarr_main_db_user=\'travis\'';' >> $CONF_FILE + echo '$'dolibarr_main_instance_unique_id=\'travis1234567890\'';' >> $CONF_FILE if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ]; then echo '$'dolibarr_main_db_type=\'mysqli\'';' >> $CONF_FILE echo '$'dolibarr_main_db_port=\'3306\'';' >> $CONF_FILE From edf1c74519d5ea3ac2142ad95abf58144c8f2cad Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 22:04:32 +0200 Subject: [PATCH 40/44] Add log of errors --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 50f8fb08a24..aa1807133a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -335,6 +335,7 @@ script: php step2.php set >> $TRAVIS_BUILD_DIR/install.log if [ "$?" -ne "0" ]; then echo "SORRY, AN ERROR OCCURED DURING INSTALLATION PROCESS" + tail -n 100 $TRAVIS_BUILD_DIR/install.log exit 1 fi cd ../.. From ebc79cf5eafe900b49648d190b770b8319363fd8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 22:13:21 +0200 Subject: [PATCH 41/44] Clean travis file --- .travis.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index aa1807133a1..9701edfc0a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -300,13 +300,9 @@ script: set +e echo -# TODO: Check Javascript (jshint?) - -# TODO: Check CSS (csslint?) - - | export INSTALL_FORCED_FILE=htdocs/install/install.forced.php - echo "Setting up Dolibarr $INSTALL_FORCED_FILE" + echo "Setting up Dolibarr $INSTALL_FORCED_FILE to test installation" # Ensure we catch errors set +e echo ' $INSTALL_FORCED_FILE @@ -327,9 +323,10 @@ script: echo '$'force_install_createuser=false';' >> $INSTALL_FORCED_FILE echo '$'force_install_mainforcehttps=false';' >> $INSTALL_FORCED_FILE echo '$'force_install_main_data_root=\'$TRAVIS_BUILD_DIR/htdocs\'';' >> $INSTALL_FORCED_FILE - # TODO: SQLite #cat $INSTALL_FORCED_FILE - echo "Installation test" + +- | + echo "Installing Dolibarr" cd htdocs/install php step1.php $TRAVIS_BUILD_DIR/htdocs > $TRAVIS_BUILD_DIR/install.log php step2.php set >> $TRAVIS_BUILD_DIR/install.log @@ -344,7 +341,7 @@ script: set +e echo - - | +- | echo "Setting up database to test migrations" if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ] || [ "$DB" = 'postgresql' ]; then echo "MySQL" @@ -359,7 +356,6 @@ script: #pgloader mysql://root:pass@127.0.0.1/base postgresql://dolibarrowner@127.0.0.1/dolibarr pgloader mysql://root@127.0.0.1/travis postgresql:///travis fi - # TODO: SQLite echo - | From 83ddf5ac8d6a0835ec1e3c4901c134b18c683316 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 30 Sep 2019 22:50:48 +0200 Subject: [PATCH 42/44] Disable test of pgsql installation --- .travis.yml | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9701edfc0a2..9b639c95bd8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -209,7 +209,6 @@ before_script: #echo 'select * from information_schema.table_constraints;' | psql travis #echo 'ALTER TABLE "llx_accounting_account" DROP CONSTRAINT "idx_16390_primary"' | psql travis fi - # TODO: SQLite echo - | @@ -325,22 +324,22 @@ script: echo '$'force_install_main_data_root=\'$TRAVIS_BUILD_DIR/htdocs\'';' >> $INSTALL_FORCED_FILE #cat $INSTALL_FORCED_FILE -- | - echo "Installing Dolibarr" - cd htdocs/install - php step1.php $TRAVIS_BUILD_DIR/htdocs > $TRAVIS_BUILD_DIR/install.log - php step2.php set >> $TRAVIS_BUILD_DIR/install.log - if [ "$?" -ne "0" ]; then - echo "SORRY, AN ERROR OCCURED DURING INSTALLATION PROCESS" - tail -n 100 $TRAVIS_BUILD_DIR/install.log - exit 1 - fi - cd ../.. - rm $INSTALL_FORCED_FILE - #cat $TRAVIS_BUILD_DIR/install.log - set +e - echo - +#- | +# echo "Installing Dolibarr" +# cd htdocs/install +# php step1.php $TRAVIS_BUILD_DIR/htdocs > $TRAVIS_BUILD_DIR/install.log +# php step2.php set >> $TRAVIS_BUILD_DIR/install.log +# if [ "$?" -ne "0" ]; then +# echo "SORRY, AN ERROR OCCURED DURING INSTALLATION PROCESS" +# cat $TRAVIS_BUILD_DIR/install.log +# exit 1 +# fi +# cd ../.. +# rm $INSTALL_FORCED_FILE +# #cat $TRAVIS_BUILD_DIR/install.log +# set +e +# echo + - | echo "Setting up database to test migrations" if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ] || [ "$DB" = 'postgresql' ]; then From bd76c1da115ae255c9b97b40d20633347f2e1c0b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Oct 2019 01:35:11 +0200 Subject: [PATCH 43/44] Look and feel v10 --- htdocs/admin/facture.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 765f2e6f995..e21dc942284 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -808,36 +808,39 @@ print '
    '; print '
    '; print load_fiche_titre($langs->trans("PathToDocuments"), '', ''); -print ''."\n"; +print '
    '; +print '
    '."\n"; print ''."\n"; print ''."\n"; print ''."\n"; print "\n"; -print ''."\n"; +print ''."\n"; print ''."\n"; print ''."\n"; print ''."\n"; print "
    '.$langs->trans("Name").''.$langs->trans("Value").'
    '.$langs->trans("PathDirectory").''.$conf->facture->dir_output.'
    \n"; - +print "
    \n"; /* * Notifications */ print '
    '; print load_fiche_titre($langs->trans("Notifications"), '', ''); -print ''; + +print '
    '; +print '
    '; print ''; print ''; print ''; print ''; print "\n"; - print '\n"; - print '
    '.$langs->trans("Parameter").' 
    '; print $langs->trans("YouMayFindNotificationsFeaturesIntoModuleNotification").'
    '; print '
    '; print "
    '; +print "\n"; + dol_fiche_end(); From 41bfc89544e456f3db6ecdef4f96f62f20862145 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 1 Oct 2019 01:42:08 +0200 Subject: [PATCH 44/44] Fix travis for pgsql --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9b639c95bd8..d5583ef6ff2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -200,6 +200,7 @@ before_script: mysql -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql fi if [ "$DB" = 'postgresql' ]; then + #pgsql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql #pgloader mysql://root:pass@127.0.0.1/dolibarr_9 postgresql://dolibarrowner:dolibarrownerpass@127.0.0.1/dolibarr_dev echo pgloader mysql://root@127.0.0.1/travis postgresql:///travis pgloader mysql://root@127.0.0.1/travis postgresql:///travis @@ -230,7 +231,6 @@ before_script: echo '$'dolibarr_main_db_type=\'pgsql\'';' >> $CONF_FILE echo '$'dolibarr_main_db_port=\'5432\'';' >> $CONF_FILE fi - # TODO: SQLite echo '$'dolibarr_main_authentication=\'dolibarr\'';' >> $CONF_FILE cat $CONF_FILE echo @@ -353,7 +353,13 @@ script: if [ "$DB" = 'postgresql' ]; then #pgsql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql #pgloader mysql://root:pass@127.0.0.1/base postgresql://dolibarrowner@127.0.0.1/dolibarr + echo pgloader mysql://root@127.0.0.1/travis postgresql:///travis pgloader mysql://root@127.0.0.1/travis postgresql:///travis + echo 'ALTER SEQUENCE llx_accountingaccount_rowid_seq RENAME TO llx_accounting_account_rowid_seq' | psql travis + echo 'ALTER SEQUENCE llx_accounting_account_rowid_seq RESTART WITH 1000001;' | psql travis + #echo 'select * from INFORMATION_SCHEMA.COLUMNS where table_name = 'llx_accountingaccount' | psql travis + #echo 'select * from information_schema.table_constraints;' | psql travis + #echo 'ALTER TABLE "llx_accounting_account" DROP CONSTRAINT "idx_16390_primary"' | psql travis fi echo