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/ChangeLog b/ChangeLog index b8a3fea2ce9..0f4d3c30ddf 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_CREATE has been renamed into DIRECT_DEBIT_ORDER_CREATE. ***** ChangeLog for 10.0.2 compared to 10.0.1 ***** 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..1c95c76f9c2 --- /dev/null +++ b/dev/examples/zapier/authentication.js @@ -0,0 +1,77 @@ +/*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 + // 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..82cc39f8fab --- /dev/null +++ b/dev/examples/zapier/creates/thirdparty.js @@ -0,0 +1,90 @@ +/*jshint esversion: 6 */ +// 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, + 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, + 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'} + ] + } +}; diff --git a/dev/examples/zapier/index.js b/dev/examples/zapier/index.js new file mode 100644 index 00000000000..fc452a196e6 --- /dev/null +++ b/dev/examples/zapier/index.js @@ -0,0 +1,73 @@ +/*jshint esversion: 6 */ +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..8fbd203f962 --- /dev/null +++ b/dev/examples/zapier/package.json @@ -0,0 +1,24 @@ +{ + "name": "Dolibarr", + "version": "1.0.0", + "description": "An app for connecting Dolibarr to the Zapier platform.", + "repository": "Dolibarr/dolibarr", + "homepage": "https://www.dolibarr.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/accountancy/index.php b/htdocs/accountancy/index.php index 0bede00d86d..0d20ae9027d 100644 --- a/htdocs/accountancy/index.php +++ b/htdocs/accountancy/index.php @@ -50,7 +50,7 @@ $hookmanager->initHooks(array('accountancyindex')); llxHeader('', $langs->trans("AccountancyArea")); -print load_fiche_titre($langs->trans("AccountancyArea"), '', 'title_accountancy'); +print load_fiche_titre($langs->trans("AccountancyArea"), '', 'accountancy'); //dol_fiche_head(); $step = 0; diff --git a/htdocs/adherents/index.php b/htdocs/adherents/index.php index 3e26ae1ce3a..2fd2cf22940 100644 --- a/htdocs/adherents/index.php +++ b/htdocs/adherents/index.php @@ -52,7 +52,7 @@ $staticmember=new Adherent($db); $statictype=new AdherentType($db); $subscriptionstatic=new Subscription($db); -print load_fiche_titre($langs->trans("MembersArea")); +print load_fiche_titre($langs->trans("MembersArea"), '', 'members'); $Adherents=array(); $AdherentsAValider=array(); diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index e85b5143257..90ce0ba932d 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -419,7 +419,7 @@ print ''; print ''; print ''; -print_barre_liste($titre, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); +print_barre_liste($titre, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $topicmail="Information"; $modelmail="member"; @@ -956,7 +956,7 @@ print "\n"; print ""; print ''; -if ($num > $limit || $page) print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic.png', 0, '', '', $limit, 1); +if ($num > $limit || $page) print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, '', '', $limit, 1); // End of page llxFooter(); diff --git a/htdocs/adherents/subscription/list.php b/htdocs/adherents/subscription/list.php index 48d1ffde363..268ebbce58c 100644 --- a/htdocs/adherents/subscription/list.php +++ b/htdocs/adherents/subscription/list.php @@ -262,7 +262,7 @@ print ''; print ''; print ''; -print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $topicmail="Information"; $modelmail="subscription"; diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 352a4dc6130..fd8e6e46643 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -248,7 +248,7 @@ if (! $rowid && $action != 'create' && $action != 'edit') print ''; print ''; - print_barre_liste($langs->trans("MembersTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); + print_barre_liste($langs->trans("MembersTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $moreforfilter = ''; diff --git a/htdocs/admin/index.php b/htdocs/admin/index.php index a6336d11d8e..c7d5e5b8912 100644 --- a/htdocs/admin/index.php +++ b/htdocs/admin/index.php @@ -45,7 +45,6 @@ llxHeader('', $langs->trans("Setup"), $wikihelp); print load_fiche_titre($langs->trans("SetupArea"), '', 'tools'); - if (! empty($conf->global->MAIN_MOTD_SETUPPAGE)) { $conf->global->MAIN_MOTD_SETUPPAGE=preg_replace('//i', '
', $conf->global->MAIN_MOTD_SETUPPAGE); diff --git a/htdocs/asset/type.php b/htdocs/asset/type.php index 1357d397709..1c27e8909a7 100644 --- a/htdocs/asset/type.php +++ b/htdocs/asset/type.php @@ -237,7 +237,7 @@ if (! $rowid && $action != 'create' && $action != 'edit') print ''; print ''; - print_barre_liste($langs->trans("AssetsTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); + print_barre_liste($langs->trans("AssetsTypes"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $moreforfilter = ''; diff --git a/htdocs/bookmarks/list.php b/htdocs/bookmarks/list.php index 844443244cd..cc79a08f0cd 100644 --- a/htdocs/bookmarks/list.php +++ b/htdocs/bookmarks/list.php @@ -85,7 +85,7 @@ $newcardbutton=''; $newcardbutton.= dolGetButtonTitle($langs->trans('NewBookmark'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/bookmarks/card.php?action=create', '', !empty($user->rights->bookmark->creer)); -print_barre_liste($langs->trans("ListOfBookmarks"), $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', -1, '', 'title_generic.png', 0, $newcardbutton); +print_barre_liste($langs->trans("ListOfBookmarks"), $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, '', -1, '', 'generic', 0, $newcardbutton); $sql = "SELECT b.rowid, b.dateb, b.fk_user, b.url, b.target, b.title, b.favicon, b.position,"; $sql.= " u.login, u.lastname, u.firstname"; 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/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 3c138043d26..4bba10a939a 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 3f21e94f53d..a51281d96c8 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); @@ -271,7 +274,7 @@ 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); @@ -282,7 +285,7 @@ class AgendaEvents extends DolibarrApi } 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/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); diff --git a/htdocs/comm/action/peruser.php b/htdocs/comm/action/peruser.php index d4020f4df92..4204224faa5 100644 --- a/htdocs/comm/action/peruser.php +++ b/htdocs/comm/action/peruser.php @@ -109,6 +109,7 @@ if ($dateselect > 0) } $tmp=empty($conf->global->MAIN_DEFAULT_WORKING_HOURS)?'9-18':$conf->global->MAIN_DEFAULT_WORKING_HOURS; +$tmp=str_replace(' ', '', $tmp); // FIX 7533 $tmparray=explode('-', $tmp); $begin_h = GETPOST('begin_h', 'int')!=''?GETPOST('begin_h', 'int'):($tmparray[0] != '' ? $tmparray[0] : 9); $end_h = GETPOST('end_h', 'int')?GETPOST('end_h', 'int'):($tmparray[1] != '' ? $tmparray[1] : 18); @@ -117,6 +118,7 @@ if ($end_h < 1 || $end_h > 24) $end_h = 18; if ($end_h <= $begin_h) $end_h = $begin_h + 1; $tmp=empty($conf->global->MAIN_DEFAULT_WORKING_DAYS)?'1-5':$conf->global->MAIN_DEFAULT_WORKING_DAYS; +$tmp=str_replace(' ', '', $tmp); // FIX 7533 $tmparray=explode('-', $tmp); $begin_d = GETPOST('begin_d', 'int')?GETPOST('begin_d', 'int'):($tmparray[0] != '' ? $tmparray[0] : 1); $end_d = GETPOST('end_d', 'int')?GETPOST('end_d', 'int'):($tmparray[1] != '' ? $tmparray[1] : 5); diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 285ed03e7c3..8811b2bbcfc 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -86,6 +86,7 @@ $extralabels=$extrafields->fetch_name_optionals_label($object->table_element); $hookmanager->initHooks(array('thirdpartycomm','globalcard')); + /* * Actions */ diff --git a/htdocs/comm/index.php b/htdocs/comm/index.php index 15e4e226587..ef9091a9638 100644 --- a/htdocs/comm/index.php +++ b/htdocs/comm/index.php @@ -79,7 +79,7 @@ if (! empty($conf->fournisseur->enabled)) $supplierorderstatic=new CommandeFourn llxHeader("", $langs->trans("CommercialArea")); -print load_fiche_titre($langs->trans("CommercialArea"), '', 'title_commercial.png'); +print load_fiche_titre($langs->trans("CommercialArea"), '', 'commercial'); print '
    '; diff --git a/htdocs/comm/mailing/card.php b/htdocs/comm/mailing/card.php index e8d1d8c7599..fb19de42d5b 100644 --- a/htdocs/comm/mailing/card.php +++ b/htdocs/comm/mailing/card.php @@ -742,7 +742,7 @@ if ($action == 'create') // Print mail form - print load_fiche_titre($langs->trans("NewMailing"), $availablelink, 'title_generic'); + print load_fiche_titre($langs->trans("NewMailing"), $availablelink, 'generic'); dol_fiche_head(); @@ -1117,7 +1117,7 @@ else $htmltext.=''; // Print mail content - print load_fiche_titre($langs->trans("EMail"), $form->textwithpicto(''.$langs->trans("AvailableVariables").'', $htmltext, 1, 'help', '', 0, 2, 'emailsubstitionhelp'), 'title_generic'); + print load_fiche_titre($langs->trans("EMail"), $form->textwithpicto(''.$langs->trans("AvailableVariables").'', $htmltext, 1, 'help', '', 0, 2, 'emailsubstitionhelp'), 'generic'); dol_fiche_head('', '', '', -1); @@ -1262,7 +1262,7 @@ else $htmltext.=''; // Print mail content - print load_fiche_titre($langs->trans("EMail"), $form->textwithpicto($langs->trans("AvailableVariables"), $htmltext, 1, 'help', '', 0, 2, 'emailsubstitionhelp'), 'title_generic'); + print load_fiche_titre($langs->trans("EMail"), $form->textwithpicto($langs->trans("AvailableVariables"), $htmltext, 1, 'help', '', 0, 2, 'emailsubstitionhelp'), 'generic'); dol_fiche_head(null, '', '', -1); diff --git a/htdocs/comm/mailing/cibles.php b/htdocs/comm/mailing/cibles.php index fb3ce1ece70..cb1ff16f74f 100644 --- a/htdocs/comm/mailing/cibles.php +++ b/htdocs/comm/mailing/cibles.php @@ -250,7 +250,7 @@ if ($object->fetch($id) >= 0) // Show email selectors if ($allowaddtarget && $user->rights->mailing->creer) { - print load_fiche_titre($langs->trans("ToAddRecipientsChooseHere"), ($user->admin?info_admin($langs->trans("YouCanAddYourOwnPredefindedListHere"), 1):''), 'title_generic'); + print load_fiche_titre($langs->trans("ToAddRecipientsChooseHere"), ($user->admin?info_admin($langs->trans("YouCanAddYourOwnPredefindedListHere"), 1):''), 'generic'); //print ''; print '
    '; @@ -453,7 +453,7 @@ if ($object->fetch($id) >= 0) if ($allowaddtarget) { $cleartext=$langs->trans("ToClearAllRecipientsClickHere").' '.'id.'" class="button reposition">'.$langs->trans("TargetsReset").''; } - print_barre_liste($langs->trans("MailSelectedRecipients"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $cleartext, $num, $nbtotalofrecords, 'title_generic', 0, '', '', $limit); + print_barre_liste($langs->trans("MailSelectedRecipients"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $cleartext, $num, $nbtotalofrecords, 'generic', 0, '', '', $limit); print ''; diff --git a/htdocs/comm/mailing/list.php b/htdocs/comm/mailing/list.php index 0986050a146..7db503b4675 100644 --- a/htdocs/comm/mailing/list.php +++ b/htdocs/comm/mailing/list.php @@ -173,7 +173,7 @@ if ($result) print ''; print ''; - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', $num, '', 'title_generic.png', 0, $newcardbutton); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', $num, '', 'generic', 0, $newcardbutton); $moreforfilter = ''; diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index 609cfc49d43..52b745f089b 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -462,7 +462,7 @@ if ($resql) print ''; print ''; - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="SendPropalRef"; $modelmail="proposal_send"; diff --git a/htdocs/comm/propal/stats/index.php b/htdocs/comm/propal/stats/index.php index 13b7b5fa2d2..eb397f1fce3 100644 --- a/htdocs/comm/propal/stats/index.php +++ b/htdocs/comm/propal/stats/index.php @@ -80,7 +80,7 @@ if ($mode == 'supplier') llxHeader('', $title); -print load_fiche_titre($title, '', 'title_commercial.png'); +print load_fiche_titre($title, '', 'commercial'); dol_mkdir($dir); diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index c7db3c560af..f65bb0118a7 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1485,7 +1485,7 @@ if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } // Mode creation if ($action == 'create' && $usercancreate) { - print load_fiche_titre($langs->trans('CreateOrder'), '', 'title_commercial.png'); + print load_fiche_titre($langs->trans('CreateOrder'), '', 'commercial'); $soc = new Societe($db); if ($socid > 0) diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 59922a02c01..723053eebaa 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -464,7 +464,7 @@ if ($resql) print ''; - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="SendOrderRef"; $modelmail="order_send"; diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index 1d2936263b8..00bdd3d7f4f 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -79,7 +79,7 @@ if ($mode == 'supplier') llxHeader('', $title); -print load_fiche_titre($title, '', 'title_commercial.png'); +print load_fiche_titre($title, '', 'commercial'); dol_mkdir($dir); diff --git a/htdocs/compta/index.php b/htdocs/compta/index.php index e2c0180dc3b..48c6d8664b1 100644 --- a/htdocs/compta/index.php +++ b/htdocs/compta/index.php @@ -87,7 +87,7 @@ $thirdpartystatic = new Societe($db); llxHeader("", $langs->trans("AccountancyTreasuryArea")); -print load_fiche_titre($langs->trans("AccountancyTreasuryArea"), '', 'title_accountancy.png'); +print load_fiche_titre($langs->trans("AccountancyTreasuryArea"), '', 'invoicing'); print '
    '; diff --git a/htdocs/compta/prelevement/bons.php b/htdocs/compta/prelevement/bons.php index 2b67b73c95b..31df49ddaf3 100644 --- a/htdocs/compta/prelevement/bons.php +++ b/htdocs/compta/prelevement/bons.php @@ -122,7 +122,7 @@ if ($result) print ''; print ''; - print_barre_liste($langs->trans("WithdrawalsReceipts"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic', 0, $newcardbutton, '', $limit); + print_barre_liste($langs->trans("WithdrawalsReceipts"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $moreforfilter=''; diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 9f9435a986c..773511458f3 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -772,17 +772,18 @@ class BonPrelevement extends CommonObject * Create a withdraw * TODO delete params banque and agence when not necesary * - * @param int $banque dolibarr mysoc bank - * @param int $agence dolibarr mysoc bank office (guichet) + * @param int $banque dolibarr mysoc bank + * @param int $agence dolibarr mysoc bank office (guichet) * @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 string $executiondate Date to execute the transfer + * @param int $notrigger Disable triggers * @return int <0 if KO, nbre of invoice withdrawed if OK */ - public function Create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '') + public 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->context['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('DIRECT_DEBIT_ORDER_CREATE', $user); + if ($result < 0) $error++; + // End call triggers + } + if (!$error) { $this->db->commit(); @@ -1149,7 +1159,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 } diff --git a/htdocs/compta/prelevement/demandes.php b/htdocs/compta/prelevement/demandes.php index 6c1ea278430..e338a2a6bd7 100644 --- a/htdocs/compta/prelevement/demandes.php +++ b/htdocs/compta/prelevement/demandes.php @@ -140,7 +140,7 @@ else $newcardbutton = ''.$langs->trans("Back").''; -print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic', 0, $newcardbutton, '', $limit); +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); print '
    '; if ($optioncss != '') print ''; diff --git a/htdocs/compta/prelevement/list.php b/htdocs/compta/prelevement/list.php index dd53988d2ec..d7fb75462a1 100644 --- a/htdocs/compta/prelevement/list.php +++ b/htdocs/compta/prelevement/list.php @@ -131,7 +131,7 @@ if ($result) print"\n\n"; print ''; - print_barre_liste($langs->trans("WithdrawalsLines"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic', 0, '', '', $limit); + print_barre_liste($langs->trans("WithdrawalsLines"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, '', '', $limit); $moreforfilter=''; diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index 89848b8fcae..a3e026c37f5 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -1372,7 +1372,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() { @@ -1411,6 +1411,7 @@ class Contact extends CommonObject $this->socid = $socid; $this->statut=1; + return 1; } /** diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 629fe589e56..a0286e5a0e2 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -1112,7 +1112,7 @@ if ($result > 0) // Create if ($action == 'create') { - print load_fiche_titre($langs->trans('AddContract'), '', 'title_commercial.png'); + print load_fiche_titre($langs->trans('AddContract'), '', 'commercial'); $soc = new Societe($db); if ($socid>0) $soc->fetch($socid); 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/contrat/index.php b/htdocs/contrat/index.php index 85538fe9ea8..d5b817d05c3 100644 --- a/htdocs/contrat/index.php +++ b/htdocs/contrat/index.php @@ -70,7 +70,7 @@ $now = dol_now(); llxHeader(); -print load_fiche_titre($langs->trans("ContractsArea"), '', 'title_commercial.png'); +print load_fiche_titre($langs->trans("ContractsArea"), '', 'commercial'); //print '
    '; diff --git a/htdocs/contrat/list.php b/htdocs/contrat/list.php index 5fea2cee66f..cb09745b24f 100644 --- a/htdocs/contrat/list.php +++ b/htdocs/contrat/list.php @@ -380,7 +380,7 @@ print ''; print ''; print ''; -print_barre_liste($langs->trans("ListOfContracts"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $totalnboflines, 'title_commercial.png', 0, $newcardbutton, '', $limit); +print_barre_liste($langs->trans("ListOfContracts"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $totalnboflines, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="SendContractRef"; $modelmail="contract"; diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index 9371a9ea835..f26b11c6b08 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -336,7 +336,7 @@ if ($mode == "0") $title=$langs->trans("ListOfInactiveServices"); // Must use == if ($mode == "4" && $filter != "expired") $title=$langs->trans("ListOfRunningServices"); if ($mode == "4" && $filter == "expired") $title=$langs->trans("ListOfExpiredServices"); if ($mode == "5") $title=$langs->trans("ListOfClosedServices"); -print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, '', '', $limit); +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, '', '', $limit); if ($sall) { diff --git a/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php b/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php index bba7e6557de..326a9297ce8 100644 --- a/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php +++ b/htdocs/core/boxes/box_supplier_orders_awaiting_reception.php @@ -69,22 +69,22 @@ class box_supplier_orders_awaiting_reception extends ModeleBoxes */ public function loadBox($max = 5) { - global $conf, $user, $langs, $db; - $langs->loadLangs(array("boxes", "sendings")); + global $conf, $user, $langs; + $langs->loadLangs(array("boxes", "sendings", "orders")); $this->max = $max; include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; - $supplierorderstatic=new CommandeFournisseur($db); + $supplierorderstatic=new CommandeFournisseur($this->db); include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php'; - $thirdpartytmp = new Fournisseur($db); + $thirdpartytmp = new Fournisseur($this->db); $this->info_box_head = array('text' => $langs->trans("BoxTitleSupplierOrdersAwaitingReception", $max)); if ($user->rights->fournisseur->commande->lire) { $sql = "SELECT s.nom as name, s.rowid as socid,"; - $sql.= " s.code_client, s.code_fournisseur,"; + $sql.= " s.code_client, s.code_fournisseur, s.email,"; $sql.= " s.logo,"; $sql.= " c.rowid, c.ref, c.tms, c.date_commande, c.date_livraison, "; $sql.= " c.total_ht,"; @@ -102,19 +102,19 @@ class box_supplier_orders_awaiting_reception extends ModeleBoxes if ($user->socid) $sql.= " AND s.rowid = ".$user->socid; if ($conf->global->MAIN_LASTBOX_ON_OBJECT_DATE) $sql.= " ORDER BY c.date_commande DESC, c.ref DESC "; else $sql.= " ORDER BY c.date_livraison ASC, c.fk_statut ASC "; - $sql.= $db->plimit($max, 0); + $sql.= $this->db->plimit($max, 0); - $result = $db->query($sql); + $result = $this->db->query($sql); if ($result) { - $num = $db->num_rows($result); + $num = $this->db->num_rows($result); $line = 0; while ($line < $num) { - $objp = $db->fetch_object($result); - $date=$db->jdate($objp->date_commande); - $date_livraison=$db->jdate($objp->date_livraison); - $datem=$db->jdate($objp->tms); + $objp = $this->db->fetch_object($result); + $date=$this->db->jdate($objp->date_commande); + $date_livraison=$this->db->jdate($objp->date_livraison); + $datem=$this->db->jdate($objp->tms); $supplierorderstatic->date_livraison = $date_livraison; $supplierorderstatic->statut = $objp->fk_statut; @@ -124,6 +124,7 @@ class box_supplier_orders_awaiting_reception extends ModeleBoxes $thirdpartytmp->id = $objp->socid; $thirdpartytmp->name = $objp->name; + $thirdpartytmp->email = $objp->email; $thirdpartytmp->fournisseur = 1; $thirdpartytmp->code_fournisseur = $objp->code_fournisseur; $thirdpartytmp->logo = $objp->logo; @@ -165,12 +166,12 @@ class box_supplier_orders_awaiting_reception extends ModeleBoxes 'text' => $langs->trans("NoSupplierOrder"), ); - $db->free($result); + $this->db->free($result); } else { $this->info_box_contents[0][] = array( 'td' => '', 'maxlength'=>500, - 'text' => ($db->error().' sql='.$sql), + 'text' => ($this->db->error().' sql='.$sql), ); } } diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 864f2869b82..da5e1ebc1a3 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -129,19 +129,32 @@ class CMailFile * @param string $css Css option * @param string $trackid Tracking string (contains type and id of related element) * @param string $moreinheader More in header. $moreinheader must contains the "\r\n" (TODO not supported for other MAIL_SEND_MODE different than 'phpmail' and 'smtps' for the moment) - * @param string $sendcontext 'standard', 'emailing', ... (used to define with sending mode and parameters to use) + * @param string $sendcontext 'standard', 'emailing', ... (used to define which sending mode and parameters to use) * @param string $replyto Reply-to email (will be set to same value than From by default if not provided) */ public function __construct($subject, $to, $from, $msg, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = 0, $errors_to = '', $css = '', $trackid = '', $moreinheader = '', $sendcontext = 'standard', $replyto = '') { 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 diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 8a28a46680b..ab80d512ebf 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -6595,10 +6595,19 @@ abstract class CommonObject $out .= ''; $html_id = !empty($this->id) ? $this->element.'_extras_'.$key.'_'.$this->id : ''; diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 8b6998bdb22..39ff11f83a2 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1555,7 +1555,7 @@ class ExtraFields { $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' $showempty=(($required && $default != '')?0:1); - $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty); + $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss); } elseif ($type == 'password') { diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index df7753501e4..cd227de0f2c 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -7509,7 +7509,7 @@ class Form */ public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0) { - $out.=$this->showFilterButtons(); + $out=$this->showFilterButtons(); if ($addcheckuncheckall) { $out.=$this->showCheckAddButtons($cssclass, $calljsfunction); 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.=''; 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..9d24af321e7 --- /dev/null +++ b/htdocs/core/triggers/interface_99_modZapier_ZapierTriggers.class.php @@ -0,0 +1,530 @@ + + * + * 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 = "technic"; + $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'; + $sql .= ' WHERE 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': + // 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': + + // 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': + // 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': + + // 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': + // 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': + + // 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': + // case 'SHIPPING_DELETE': + } + 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/don/list.php b/htdocs/don/list.php index 1af11afca24..2bd6b676016 100644 --- a/htdocs/don/list.php +++ b/htdocs/don/list.php @@ -154,7 +154,7 @@ if ($resql) print ''; print ''; - print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton); + print_barre_liste($langs->trans("Donations"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton); if ($search_all) { diff --git a/htdocs/expensereport/list.php b/htdocs/expensereport/list.php index fd53e8af1d1..e70e8d34d78 100644 --- a/htdocs/expensereport/list.php +++ b/htdocs/expensereport/list.php @@ -473,7 +473,7 @@ if ($resql) $newcardbutton.= dolGetButtonTitle($langs->trans('NewTrip'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/expensereport/card.php?action=create'); } - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); } $topicmail="SendExpenseReport"; diff --git a/htdocs/fichinter/card-rec.php b/htdocs/fichinter/card-rec.php index 63183c73d1d..59d02502dad 100644 --- a/htdocs/fichinter/card-rec.php +++ b/htdocs/fichinter/card-rec.php @@ -248,7 +248,7 @@ $today = dol_mktime( * Create mode */ if ($action == 'create') { - print load_fiche_titre($langs->trans("CreateRepeatableIntervention"), '', 'title_commercial.png'); + print load_fiche_titre($langs->trans("CreateRepeatableIntervention"), '', 'commercial'); $object = new Fichinter($db); // Source invoice //$object = new Managementfichinter($db); // Source invoice @@ -439,7 +439,7 @@ $date_next_execution = (GETPOST('remonth') ? dol_mktime( else dol_print_error('', "Error, no invoice ".$object->id); } elseif ($action == 'selsocforcreatefrommodel') { - print load_fiche_titre($langs->trans("CreateRepeatableIntervention"), '', 'title_commercial.png'); + print load_fiche_titre($langs->trans("CreateRepeatableIntervention"), '', 'commercial'); dol_fiche_head(''); print '
    '; @@ -810,7 +810,7 @@ $date_next_execution = (GETPOST('remonth') ? dol_mktime( '', $num, '', - 'title_commercial.png' + 'commercial' ); print $langs->trans("ToCreateAPredefinedInterventional").'

    '; diff --git a/htdocs/fichinter/list.php b/htdocs/fichinter/list.php index e54aa7940d3..da249d1f0cd 100644 --- a/htdocs/fichinter/list.php +++ b/htdocs/fichinter/list.php @@ -327,7 +327,7 @@ if ($resql) print ''; print ''; - print_barre_liste($title, $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER['PHP_SELF'], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="Information"; $modelmail="intervention"; diff --git a/htdocs/fichinter/stats/index.php b/htdocs/fichinter/stats/index.php index 096584d8936..ecde4ba5c72 100644 --- a/htdocs/fichinter/stats/index.php +++ b/htdocs/fichinter/stats/index.php @@ -65,7 +65,7 @@ $dir=$conf->ficheinter->dir_temp; llxHeader('', $title); -print load_fiche_titre($title, '', 'title_commercial.png'); +print load_fiche_titre($title, '', 'commercial'); dol_mkdir($dir); diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 7af71f7a344..2583873185d 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -649,7 +649,7 @@ if ($resql) print ''; print ''; print ''; - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="SendOrderRef"; $modelmail="order_supplier_send"; diff --git a/htdocs/hrm/index.php b/htdocs/hrm/index.php index ece34cf12b5..a6ef15c6908 100644 --- a/htdocs/hrm/index.php +++ b/htdocs/hrm/index.php @@ -77,7 +77,7 @@ $childids[]=$user->id; llxHeader('', $langs->trans('HRMArea')); -print load_fiche_titre($langs->trans("HRMArea"), '', 'title_hrm.png'); +print load_fiche_titre($langs->trans("HRMArea"), '', 'hrm'); if (! empty($setupcompanynotcomplete)) diff --git a/htdocs/index.php b/htdocs/index.php index 70acfc62bab..a375c005676 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -80,7 +80,7 @@ llxHeader('', $title); $resultboxes=FormOther::getBoxesArea($user, "0"); // Load $resultboxes (selectboxlist + boxactivated + boxlista + boxlistb) -print load_fiche_titre($langs->trans("HomeArea"), $resultboxes['selectboxlist'], 'title_home'); +print load_fiche_titre($langs->trans("HomeArea"), $resultboxes['selectboxlist'], 'home'); if (! empty($conf->global->MAIN_MOTD)) { diff --git a/htdocs/install/mysql/tables/llx_zapier_hook.key.sql b/htdocs/install/mysql/tables/llx_zapier_hook.key.sql new file mode 100644 index 00000000000..4bce26ae0ea --- /dev/null +++ b/htdocs/install/mysql/tables/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_zapier_hook ADD INDEX idx_fieldobject (fieldobject); + +--ALTER TABLE llx_zapier_hook ADD UNIQUE INDEX uk_zapier_hook_fieldxy(fieldx, fieldy); + +--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/install/mysql/tables/llx_zapier_hook.sql b/htdocs/install/mysql/tables/llx_zapier_hook.sql new file mode 100644 index 00000000000..27d56352bff --- /dev/null +++ b/htdocs/install/mysql/tables/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_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; diff --git a/htdocs/install/mysql/tables/llx_zapier_hook_extrafields.sql b/htdocs/install/mysql/tables/llx_zapier_hook_extrafields.sql new file mode 100644 index 00000000000..09fef4cc399 --- /dev/null +++ b/htdocs/install/mysql/tables/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_zapier_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/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/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index 96efb3be55f..29bb88a80a4 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -4,6 +4,7 @@ LatestBOMModified=Latest %s Bills of materials modified BillOfMaterials=Bill of Material BOMsSetup=Setup of module BOM ListOfBOMs=List of bills of material - BOM +ListOfManufacturingOrders=List of Manufacturing Orders NewBOM=New bill of material ProductBOMHelp=Product to create with this BOM BOMsNumberingModules=BOM numbering templates @@ -16,4 +17,8 @@ ValueOfMeansLoss=Value of 0.95 means an average of 5%% of loss during the produc DeleteBillOfMaterials=Delete Bill Of Materials ConfirmDeleteBillOfMaterials=Are you sure you want to delete this Bill Of Material? MenuMRP=Manufacturing Orders -NewMO=New Manufacturing Order \ No newline at end of file +NewMO=New Manufacturing Order +QtyToProduce=Qty to produce +DateStartPlannedMo=Date start planned +DateEndPlannedMo=Date end planned +KeepEmptyForAsap=Empty means 'As Soon As Possible' \ No newline at end of file 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/langs/en_US/ticket.lang b/htdocs/langs/en_US/ticket.lang index 70bd8220af0..6dbc13ec306 100644 --- a/htdocs/langs/en_US/ticket.lang +++ b/htdocs/langs/en_US/ticket.lang @@ -137,6 +137,10 @@ NoUnreadTicketsFound=No unread ticket found TicketViewAllTickets=View all tickets TicketViewNonClosedOnly=View only open tickets TicketStatByStatus=Tickets by status +OrderByDateAsc=Sort by ascending date +OrderByDateDesc=Sort by descending date +MessagingViewType=Show as messaging list +MessageListViewType=Show as table list # # Ticket card 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/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"; } } diff --git a/htdocs/modulebuilder/template/myobject_card.php b/htdocs/modulebuilder/template/myobject_card.php index 72bc424c53c..21615af7ddc 100644 --- a/htdocs/modulebuilder/template/myobject_card.php +++ b/htdocs/modulebuilder/template/myobject_card.php @@ -190,7 +190,7 @@ if ($action == 'create') dol_fiche_head(array(), ''); - print '
    attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired'; - $out .= '">'; - if (! empty($extrafields->attributes[$this->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$this->table_element]['help'][$key]); - else $out .= $labeltoshow; + // BUG #11554 : For public page, use red dot for required fields, instead of bold label + $context = isset($params["context"]) ? $params["context"] : "none"; + if ($context=="public") { // Public page : red dot instead of bold ble characters + $out .= '">'; + if (! empty($extrafields->attributes[$this->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$this->table_element]['help'][$key]); + else $out .= $labeltoshow; + if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' *'; + } else { + if ($mode != 'view' && ! empty($extrafields->attributes[$this->table_element]['required'][$key])) $out .= ' fieldrequired'; + $out .= '">'; + if (! empty($extrafields->attributes[$this->table_element]['help'][$key])) $out .= $form->textwithpicto($labeltoshow, $extrafields->attributes[$this->table_element]['help'][$key]); + else $out .= $labeltoshow; + } $out .= ''; diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 27d087b2fde..104247bf1c5 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -541,7 +541,12 @@ class Notify '', '', 0, - -1 + -1, + '', + '', + '', + '', + 'notification' ); if ($mailfile->sendfile()) @@ -769,7 +774,12 @@ class Notify '', '', 0, - 1 + 1, + '', + '', + '', + '', + 'notification' ); if ($mailfile->sendfile()) 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); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9ac07936b65..811ac2e22f1 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3036,36 +3036,43 @@ 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', - 'note', 'setup', 'sign-out', 'split', 'switch_off', 'switch_on', 'tools', 'unlink', 'uparrow', '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected', + 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', 'instagram', 'snapchat', 'youtube', 'google-plus-g','whatsapp', - 'chevron-left','chevron-right','chevron-down','chevron-top' + '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'; - $fasize = '1.4em'; - } - 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'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; } - elseif ($pictowithoutext == 'switch_on') { - $fakey = 'fa-toggle-on'; + elseif ($pictowithouttext == 'switch_on') { $facolor = '#227722'; $fasize = '2em'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; } - elseif ($pictowithoutext == 'off') { + elseif ($pictowithouttext == 'off') { $fakey = 'fa-square-o'; if (empty($conf->global->MAIN_DISABLE_FONT_AWESOME_5)) { @@ -3074,7 +3081,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)) { @@ -3083,44 +3090,38 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $ } $fasize = '1.3em'; } - elseif ($pictowithoutext == 'bank') { - $fakey = 'fa-bank'; + elseif ($pictowithouttext == 'bank') { + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; $facolor = '#444'; } - elseif ($pictowithoutext == 'close_title') { - $fakey = 'fa-window-close'; - } - elseif ($pictowithoutext == 'delete') { - $fakey = 'fa-trash'; + elseif ($pictowithouttext == 'delete') { + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; $facolor = '#444'; } - elseif ($pictowithoutext == 'edit') { - $fakey = 'fa-pencil'; + elseif ($pictowithouttext == 'edit') { $facolor = '#444'; + $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext]; 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)) { @@ -3129,45 +3130,58 @@ 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'; } +<<<<<<< HEAD elseif (in_array($pictowithoutext, array('skype', 'twitter', 'facebook', 'linkedin', 'instagram','snapchat','youtube','google-plus-g','whatsapp'))) { $fakey = 'fa-'.$pictowithoutext; +======= + elseif (in_array($pictowithouttext, array('skype', 'twitter', 'facebook', 'linkedin'))) { + $fakey = 'fa-'.$pictowithouttext; +>>>>>>> upstream/develop 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; } @@ -4099,7 +4113,7 @@ function print_titre($title) * @return void * @deprecated Use print load_fiche_titre instead */ -function print_fiche_titre($title, $mesg = '', $picto = 'title_generic.png', $pictoisfullpath = 0, $id = '') +function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '') { print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id); } @@ -4117,13 +4131,13 @@ function print_fiche_titre($title, $mesg = '', $picto = 'title_generic.png', $pi * @return string * @see print_barre_liste() */ -function load_fiche_titre($titre, $morehtmlright = '', $picto = 'title_generic.png', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '') +function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '') { global $conf; $return=''; - if ($picto == 'setup') $picto='title_generic.png'; + if ($picto == 'setup') $picto='generic'; $return.= "\n"; $return.= ''; // maring bottom must be same than into print_barre_list @@ -4165,7 +4179,7 @@ function load_fiche_titre($titre, $morehtmlright = '', $picto = 'title_generic.p * @param int $hidenavigation Force to hide all navigation tools * @return void */ -function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'title_generic.png', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0) +function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0) { global $conf,$langs; @@ -4174,7 +4188,7 @@ function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $totalnboflines=abs($totalnboflines); if ($picto == 'setup') $picto='title_setup.png'; - if (($conf->browser->name == 'ie') && $picto=='title_generic.png') $picto='title.gif'; + if (($conf->browser->name == 'ie') && $picto=='generic') $picto='title.gif'; if ($limit < 0) $limit = $conf->liste_limit; if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) { @@ -8261,7 +8275,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 @@ -8277,12 +8291,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 @@ -8348,9 +8362,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/lib/ticket.lib.php b/htdocs/core/lib/ticket.lib.php index c1d42bf25b7..0b27e003b5f 100644 --- a/htdocs/core/lib/ticket.lib.php +++ b/htdocs/core/lib/ticket.lib.php @@ -108,7 +108,21 @@ function ticket_prepare_head($object) // History - $head[$h][0] = DOL_URL_ROOT.'/ticket/agenda.php?track_id=' . $object->track_id; + $ticketViewType = "messaging"; + if(empty($_SESSION['ticket-view-type'])){ + $_SESSION['ticket-view-type'] = $ticketViewType; + } + else{ + $ticketViewType = $_SESSION['ticket-view-type']; + } + + if($ticketViewType == "messaging"){ + $head[$h][0] = DOL_URL_ROOT.'/ticket/messaging.php?track_id=' . $object->track_id; + } + else{ + // $ticketViewType == "list" + $head[$h][0] = DOL_URL_ROOT.'/ticket/agenda.php?track_id=' . $object->track_id; + } $head[$h][1] = $langs->trans('Events'); if (! empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read) )) { @@ -187,3 +201,612 @@ function llxHeaderTicket($title, $head = "", $disablejs = 0, $disablehead = 0, $ print '
    '; } + + + +/** + * Show html area with actions for ticket messaging. + * Note: Global parameter $param must be defined. + * + * @param Conf $conf Object conf + * @param Translate $langs Object langs + * @param DoliDB $db Object db + * @param mixed $filterobj Filter on object Adherent|Societe|Project|Product|CommandeFournisseur|Dolresource|Ticket|... to list events linked to an object + * @param Contact $objcon Filter on object contact to filter events on a contact + * @param int $noprint Return string but does not output it + * @param string $actioncode Filter on actioncode + * @param string $donetodo Filter on event 'done' or 'todo' or ''=nofilter (all). + * @param array $filters Filter on other fields + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @return string|void Return html part or void if noprint is 1 + */ +function show_ticket_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC') +{ + global $user, $conf; + global $form; + + global $param, $massactionbutton; + + dol_include_once('/comm/action/class/actioncomm.class.php'); + + // Check parameters + if (! is_object($filterobj) && ! is_object($objcon)) dol_print_error('', 'BadParameter'); + + $out=''; + $histo=array(); + $numaction = 0 ; + $now=dol_now('tzuser'); + + // Open DSI -- Fix order by -- Begin + $sortfield_list = explode(',', $sortfield); + $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent'); + $sortfield_new_list = array(); + foreach ($sortfield_list as $sortfield_value) { + $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)]; + } + $sortfield_new = implode(',', $sortfield_new_list); + + if (! empty($conf->agenda->enabled)) + { + // Recherche histo sur actioncomm + if (is_object($objcon) && $objcon->id > 0) { + $sql = "SELECT DISTINCT a.id, a.label as label,"; + } + else + { + $sql = "SELECT a.id, a.label as label,"; + } + $sql.= " a.datep as dp,"; + $sql.= " a.note as message,"; + $sql.= " a.datep2 as dp2,"; + $sql.= " a.percent as percent, 'action' as type,"; + $sql.= " a.fk_element, a.elementtype,"; + $sql.= " a.fk_contact,"; + $sql.= " c.code as acode, c.libelle as alabel, c.picto as apicto,"; + $sql.= " u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname"; + if (is_object($filterobj) && get_class($filterobj) == 'Societe') $sql.= ", sp.lastname, sp.firstname"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') $sql.= ", m.lastname, m.firstname"; + elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') $sql.= ", o.ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Product') $sql.= ", o.ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') $sql.= ", o.ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') $sql.= ", o.ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') $sql.= ", o.ref"; + $sql.= " FROM ".MAIN_DB_PREFIX."actioncomm as a"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id"; + + $force_filter_contact = false; + if (is_object($objcon) && $objcon->id > 0) { + $force_filter_contact = true; + $sql.= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm"; + $sql.= " AND r.element_type = '" . $db->escape($objcon->table_element) . "' AND r.fk_element = " . $objcon->id; + } + + if (is_object($filterobj) && get_class($filterobj) == 'Societe') $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') { + $sql.= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er"; + $sql.= " ON er.resource_type = 'dolresource'"; + $sql.= " AND er.element_id = a.id"; + $sql.= " AND er.resource_id = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') $sql.= ", ".MAIN_DB_PREFIX."adherent as m"; + elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') $sql.= ", ".MAIN_DB_PREFIX."commande_fournisseur as o"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Product') $sql.= ", ".MAIN_DB_PREFIX."product as o"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') $sql.= ", ".MAIN_DB_PREFIX."ticket as o"; + elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') $sql.= ", ".MAIN_DB_PREFIX."bom_bom as o"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') $sql.= ", ".MAIN_DB_PREFIX."contrat as o"; + + $sql.= " WHERE a.entity IN (".getEntity('agenda').")"; + if ($force_filter_contact === false) { + if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) $sql.= " AND a.fk_soc = ".$filterobj->id; + elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) $sql.= " AND a.fk_project = ".$filterobj->id; + elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') + { + $sql.= " AND a.fk_element = m.rowid AND a.elementtype = 'member'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') + { + $sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'Product') + { + $sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'product'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') + { + $sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') + { + $sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') + { + $sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'"; + if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id; + } + } + + // Condition on actioncode + if (! empty($actioncode)) + { + if (empty($conf->global->AGENDA_USE_EVENT_TYPE)) + { + if ($actioncode == 'AC_NON_AUTO') $sql.= " AND c.type != 'systemauto'"; + elseif ($actioncode == 'AC_ALL_AUTO') $sql.= " AND c.type = 'systemauto'"; + else + { + if ($actioncode == 'AC_OTH') $sql.= " AND c.type != 'systemauto'"; + elseif ($actioncode == 'AC_OTH_AUTO') $sql.= " AND c.type = 'systemauto'"; + } + } + else + { + if ($actioncode == 'AC_NON_AUTO') $sql.= " AND c.type != 'systemauto'"; + elseif ($actioncode == 'AC_ALL_AUTO') $sql.= " AND c.type = 'systemauto'"; + else $sql.= " AND c.code = '".$db->escape($actioncode)."'"; + } + } + if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))"; + elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))"; + if (is_array($filters) && $filters['search_agenda_label']) $sql.= natural_search('a.label', $filters['search_agenda_label']); + } + + // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing. + if (! empty($conf->mailing->enabled) && ! empty($objcon->email) + && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) + { + $langs->load("mails"); + + $sql2 = "SELECT m.rowid as id, m.titre as label, mc.date_envoi as dp, mc.date_envoi as dp2, '100' as percent, 'mailing' as type"; + $sql2.= ", '' as fk_element, '' as elementtype, '' as contact_id"; + $sql2.= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto"; + $sql2.= ", u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname"; // User that valid action + if (is_object($filterobj) && get_class($filterobj) == 'Societe') $sql2.= ", '' as lastname, '' as firstname"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') $sql2.= ", '' as lastname, '' as firstname"; + elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') $sql2.= ", '' as ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Product') $sql2.= ", '' as ref"; + elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') $sql2.= ", '' as ref"; + $sql2.= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u"; + $sql2.= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email. + $sql2.= " AND mc.statut = 1"; + $sql2.= " AND u.rowid = m.fk_user_valid"; + $sql2.= " AND mc.fk_mailing=m.rowid"; + } + + if (!empty($sql) && !empty($sql2)) { + $sql = $sql . " UNION " . $sql2; + } elseif (empty($sql) && !empty($sql2)) { + $sql = $sql2; + } + + //TODO Add limit in nb of results + $sql.= $db->order($sortfield_new, $sortorder); + dol_syslog("company.lib::show_actions_done", LOG_DEBUG); + $resql=$db->query($sql); + if ($resql) + { + $i = 0 ; + $num = $db->num_rows($resql); + + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + if ($obj->type == 'action') { + $contactaction = new ActionComm($db); + $contactaction->id=$obj->id; + $result = $contactaction->fetchResources(); + if ($result<0) { + dol_print_error($db); + setEventMessage("company.lib::show_actions_done Error fetch ressource", 'errors'); + } + + //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))"; + //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))"; + $tododone=''; + if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->datep > $now)) $tododone='todo'; + + $histo[$numaction]=array( + 'type'=>$obj->type, + 'tododone'=>$tododone, + 'id'=>$obj->id, + 'datestart'=>$db->jdate($obj->dp), + 'dateend'=>$db->jdate($obj->dp2), + 'note'=>$obj->label, + 'message'=>$obj->message, + 'percent'=>$obj->percent, + + 'userid'=>$obj->user_id, + 'login'=>$obj->user_login, + 'userfirstname'=>$obj->user_firstname, + 'userlastname'=>$obj->user_lastname, + 'userphoto'=>$obj->user_photo, + + 'contact_id'=>$obj->fk_contact, + 'socpeopleassigned' => $contactaction->socpeopleassigned, + 'lastname'=>$obj->lastname, + 'firstname'=>$obj->firstname, + 'fk_element'=>$obj->fk_element, + 'elementtype'=>$obj->elementtype, + // Type of event + 'acode'=>$obj->acode, + 'alabel'=>$obj->alabel, + 'libelle'=>$obj->alabel, // deprecated + 'apicto'=>$obj->apicto + ); + } else { + $histo[$numaction]=array( + 'type'=>$obj->type, + 'tododone'=>'done', + 'id'=>$obj->id, + 'datestart'=>$db->jdate($obj->dp), + 'dateend'=>$db->jdate($obj->dp2), + 'note'=>$obj->label, + 'message'=>$obj->message, + 'percent'=>$obj->percent, + 'acode'=>$obj->acode, + + 'userid'=>$obj->user_id, + 'login'=>$obj->user_login, + 'userfirstname'=>$obj->user_firstname, + 'userlastname'=>$obj->user_lastname, + 'userphoto'=>$obj->user_photo + ); + } + + $numaction++; + $i++; + } + } + else + { + dol_print_error($db); + } + + if (! empty($conf->agenda->enabled) || (! empty($conf->mailing->enabled) && ! empty($objcon->email))) + { + $delay_warning=$conf->global->MAIN_DELAY_ACTIONS_TODO*24*60*60; + + require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; + require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; + + $formactions=new FormActions($db); + + $actionstatic=new ActionComm($db); + $userstatic=new User($db); + $contactstatic = new Contact($db); + $userGetNomUrlCache = array(); + + $out.='
    '; + $out.=''; + if ($objcon && get_class($objcon) == 'Contact' && + (is_null($filterobj) || get_class($filterobj) == 'Societe')) + { + $out.=''; + } + else + { + $out.=''; + } + if ($filterobj && get_class($filterobj) == 'Societe') $out.=''; + + $out.="\n"; + + $out.='
    '; + $out.='
    '; + + $out.=''; + + $out.=''; + + $out.=''; + if ($donetodo) + { + $out.=''; + } + $out.=''; + $out.=''; + + $out.=''; + $out.=''; + + + $out.='
    '; + 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").' : '.$langs->trans("Type").' '; + $out.=$formactions->select_type_actions($actioncode, "actioncode", '', empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:-1, 0, 0, 1); + $out.=''; + $out.=$langs->trans("Label").' '; + $out.=''; + $out.=''; + $searchpicto=$form->showFilterAndCheckAddButtons($massactionbutton?1:0, 'checkforselect', 1); + $out.=$searchpicto; + $out.='
    '; + + $out.=''; + $out.=''; + + $out.="\n"; + + $out.='\n"; + } + + + if ($noprint) return $out; + else print $out; +} 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/core/modules/modZapier.class.php b/htdocs/core/modules/modZapier.class.php new file mode 100644 index 00000000000..ed628110044 --- /dev/null +++ b/htdocs/core/modules/modZapier.class.php @@ -0,0 +1,377 @@ + + * 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/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 = '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) + '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"); + // 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/tools.php b/htdocs/core/tools.php index cd65ace73bf..49b17c20520 100644 --- a/htdocs/core/tools.php +++ b/htdocs/core/tools.php @@ -43,7 +43,7 @@ llxHeader("", $langs->trans("Tools"), ""); $text=$langs->trans("Tools"); -print load_fiche_titre($text); +print load_fiche_titre($text, '', 'generic'); // Show description of content print '
    '.$langs->trans("ToolsDesc").'


    '; diff --git a/htdocs/core/tpl/extrafields_add.tpl.php b/htdocs/core/tpl/extrafields_add.tpl.php index f4f74d35428..7e146b63fe0 100644 --- a/htdocs/core/tpl/extrafields_add.tpl.php +++ b/htdocs/core/tpl/extrafields_add.tpl.php @@ -41,7 +41,8 @@ $parameters = array(); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; if (empty($reshook)) { - print $object->showOptionals($extrafields, 'edit'); + $params = isset($tpl_context) ? array('context' => $tpl_context) : array(); // BUG #11554 : Add context in params + print $object->showOptionals($extrafields, 'edit', $params); // BUG #11554 : Add context in params } ?> diff --git a/htdocs/core/tpl/extrafields_list_search_input.tpl.php b/htdocs/core/tpl/extrafields_list_search_input.tpl.php index 0b9a048f28a..9ee4bd9ce37 100644 --- a/htdocs/core/tpl/extrafields_list_search_input.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_input.tpl.php @@ -41,7 +41,7 @@ if (! empty($extrafieldsobjectkey)) // $extrafieldsobject is the $object->table_ { // for the type as 'checkbox', 'chkbxlst', 'sellist' we should use code instead of id (example: I declare a 'chkbxlst' to have a link with dictionnairy, I have to extend it with the 'code' instead 'rowid') $morecss=''; - if ($typeofextrafield == 'sellist') $morecss='maxwidth200'; + if (in_array($typeofextrafield, array('link', 'sellist'))) $morecss='maxwidth200'; echo $extrafields->showInputField($key, $search_array_options[$search_options_pattern.$tmpkey], '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); } print '
    '."\n"; + print '
    '."\n"; // Common attributes include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; diff --git a/htdocs/opensurvey/list.php b/htdocs/opensurvey/list.php index 025f7099577..8685b6982c3 100644 --- a/htdocs/opensurvey/list.php +++ b/htdocs/opensurvey/list.php @@ -245,7 +245,7 @@ print ''; $newcardbutton=''; $newcardbutton.= dolGetButtonTitle($langs->trans('NewSurvey'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/opensurvey/wizard/index.php', '', $user->rights->opensurvey->write); -print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); // Add code for pre mass action (confirmation or email presend form) $topicmail="SendOpenSurveyRef"; diff --git a/htdocs/product/index.php b/htdocs/product/index.php index 5b74ef07f80..157f613ef03 100644 --- a/htdocs/product/index.php +++ b/htdocs/product/index.php @@ -77,7 +77,7 @@ if ((isset($_GET["type"]) && $_GET["type"] == 1) || empty($conf->product->enable llxHeader("", $langs->trans("ProductsAndServices"), $helpurl); $linkback=""; -print load_fiche_titre($transAreaType, $linkback, 'title_products.png'); +print load_fiche_titre($transAreaType, $linkback, 'products'); print '
    '; 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'; /* diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index 9426d2041b0..633dc48d36c 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -184,7 +184,7 @@ if ($result) print ''; print ''; - print_barre_liste($langs->trans("ListOfWarehouses"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $totalnboflines, 'title_generic.png', 0, $newcardbutton, '', $limit); + print_barre_liste($langs->trans("ListOfWarehouses"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $totalnboflines, 'generic', 0, $newcardbutton, '', $limit); if ($sall) { diff --git a/htdocs/product/stock/movement_card.php b/htdocs/product/stock/movement_card.php index 291dcc6e456..36d28392dad 100644 --- a/htdocs/product/stock/movement_card.php +++ b/htdocs/product/stock/movement_card.php @@ -728,7 +728,7 @@ if ($resql) if ($id > 0) print ''; if ($id > 0) print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, '', 0, '', '', $limit); - else print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic', 0, '', '', $limit); + else print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, '', '', $limit); if ($sall) { diff --git a/htdocs/product/stock/movement_list.php b/htdocs/product/stock/movement_list.php index 71e4d95f6c7..17b63ed8989 100644 --- a/htdocs/product/stock/movement_list.php +++ b/htdocs/product/stock/movement_list.php @@ -706,7 +706,7 @@ if ($resql) if ($id > 0) print ''; if ($id > 0) print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, '', 0, '', '', $limit); - else print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic', 0, '', '', $limit); + else print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, '', '', $limit); if ($sall) { diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index b9799865e20..92d82ea0d72 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -438,7 +438,7 @@ $head[1][1] = $langs->trans("ReplenishmentOrders"); $head[1][2] = 'replenishorders'; -print load_fiche_titre($langs->trans('Replenishment'), '', 'title_generic.png'); +print load_fiche_titre($langs->trans('Replenishment'), '', 'generic'); dol_fiche_head($head, 'replenish', '', -1, ''); diff --git a/htdocs/product/stock/replenishorders.php b/htdocs/product/stock/replenishorders.php index 59f436cb487..f38b1b6bd8e 100644 --- a/htdocs/product/stock/replenishorders.php +++ b/htdocs/product/stock/replenishorders.php @@ -93,7 +93,7 @@ $texte = $langs->trans('ReplenishmentOrders'); llxHeader('', $texte, $helpurl, ''); -print load_fiche_titre($langs->trans('Replenishment'), '', 'title_generic.png'); +print load_fiche_titre($langs->trans('Replenishment'), '', 'generic'); $head = array(); $head[0][0] = DOL_URL_ROOT.'/product/stock/replenish.php'; diff --git a/htdocs/product/stock/tpl/stockcorrection.tpl.php b/htdocs/product/stock/tpl/stockcorrection.tpl.php index f5989fb46c1..ae9c49c6e95 100644 --- a/htdocs/product/stock/tpl/stockcorrection.tpl.php +++ b/htdocs/product/stock/tpl/stockcorrection.tpl.php @@ -53,7 +53,7 @@ if (empty($conf) || ! is_object($conf)) { '; - print load_fiche_titre($langs->trans("StockCorrection"), '', 'title_generic.png'); + print load_fiche_titre($langs->trans("StockCorrection"), '', 'generic'); print ''."\n"; diff --git a/htdocs/product/stock/tpl/stocktransfer.tpl.php b/htdocs/product/stock/tpl/stocktransfer.tpl.php index 787083f0940..4ed59d88002 100644 --- a/htdocs/product/stock/tpl/stocktransfer.tpl.php +++ b/htdocs/product/stock/tpl/stocktransfer.tpl.php @@ -53,7 +53,7 @@ if (empty($conf) || ! is_object($conf)) { } } - print load_fiche_titre($langs->trans("StockTransfer"), '', 'title_generic.png'); + print load_fiche_titre($langs->trans("StockTransfer"), '', 'generic'); print ''."\n"; diff --git a/htdocs/projet/ganttview.php b/htdocs/projet/ganttview.php index 87920f2a977..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 ''; + // Bill time + if (empty($conf->global->PROJECT_HIDE_TASKS) && ! empty($conf->global->PROJECT_BILL_TIME_SPENT)) + { + print '
    '; + } + // Categories if($conf->categorie->enabled) { print ''."\n"; // Other attributes +$tpl_context = 'public'; //BUG #11554 : define templae context to public include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; // Comments print ''; diff --git a/htdocs/resource/card.php b/htdocs/resource/card.php index 4ec52539188..02f9fbc1073 100644 --- a/htdocs/resource/card.php +++ b/htdocs/resource/card.php @@ -226,7 +226,7 @@ if ($action == 'create' || $object->fetch($id) > 0) { if ($action == 'create') { - print load_fiche_titre($title, '', 'title_generic'); + print load_fiche_titre($title, '', 'generic'); dol_fiche_head(''); } else diff --git a/htdocs/resource/list.php b/htdocs/resource/list.php index d9547ad441b..8151cebf05f 100644 --- a/htdocs/resource/list.php +++ b/htdocs/resource/list.php @@ -199,7 +199,7 @@ if($ret == -1) { $newcardbutton.= dolGetButtonTitle($langs->trans('MenuResourceAdd'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/resource/card.php?action=create'); } - print_barre_liste($pagetitle, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $ret+1, $nbtotalofrecords, 'title_generic.png', 0, $newcardbutton, '', $limit); + print_barre_liste($pagetitle, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $ret+1, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); } $moreforfilter = ''; diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index cdc1af37d4e..f10da8279ae 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1546,7 +1546,7 @@ else print ''; print ''; 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 1e764edbdb6..5b173707b74 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -3586,7 +3586,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() { @@ -3639,6 +3639,7 @@ class Societe extends CommonObject $this->idprof4='idprof4'; $this->idprof5='idprof5'; $this->idprof6='idprof6'; + return 1; } /** diff --git a/htdocs/societe/index.php b/htdocs/societe/index.php index 2010edeb217..acfd42a064d 100644 --- a/htdocs/societe/index.php +++ b/htdocs/societe/index.php @@ -55,7 +55,7 @@ $helpurl='EN:Module_Third_Parties|FR:Module_Tiers|ES:Módulo_Terceros'; llxHeader("", $langs->trans("ThirdParties"), $helpurl); $linkback=''; -print load_fiche_titre($transAreaType, $linkback, 'title_companies.png'); +print load_fiche_titre($transAreaType, $linkback, 'companies'); //print '
    '.$langs->trans("BillTime").''; + print yn($object->usage_bill_time); + print '
    '.$langs->trans("Categories").''; @@ -234,10 +242,10 @@ 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('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, 'title_generic.png', 0, '', '', 0, 1); -print load_fiche_titre($title, $linktolist.'   '.$linktocreatetask, 'title_generic.png'); +//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'); // Get list of tasks in tasksarray and taskarrayfiltered diff --git a/htdocs/projet/index.php b/htdocs/projet/index.php index 6b9247530fd..ba15aef57cf 100644 --- a/htdocs/projet/index.php +++ b/htdocs/projet/index.php @@ -88,7 +88,7 @@ $morehtml.=''; $morehtml.=''; $morehtml.=''; -print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, -1, 'title_project.png', 0, $morehtml); +print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', '', '', '', 0, -1, 'project', 0, $morehtml); // Show description of content print '
    '; diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index dd29a401bf7..fef42957bab 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -669,10 +669,10 @@ 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('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, 'title_generic.png', 0, '', '', 0, 1); - print load_fiche_titre($title, $linktotasks.'   '.$linktocreatetask, 'title_generic.png'); + //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'); // Get list of tasks in tasksarray and taskarrayfiltered // We need all tasks (even not limited to a user because a task to user can have a parent that is not affected to him). diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index d4c4a6d8473..9e8e71f5b32 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -941,7 +941,7 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0) $title=$langs->trans("ListTaskTimeUserProject"); - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic', 0, $linktocreatetime, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $linktocreatetime, '', $limit); } else { @@ -949,7 +949,7 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0) $title=$langs->trans("ListTaskTimeForTask"); - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_generic', 0, $linktocreatetime, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, $linktocreatetime, '', $limit); } $i = 0; diff --git a/htdocs/public/members/new.php b/htdocs/public/members/new.php index 81f46897cc6..151f8486577 100644 --- a/htdocs/public/members/new.php +++ b/htdocs/public/members/new.php @@ -645,6 +645,7 @@ print '
    '.$langs->trans("URLPhoto").'
    '.$form->editfieldkey('AllocateCommercial', 'commercial_id', '', $object, 0).''; $userlist = $form->select_dolusers('', '', 0, null, 0, '', '', 0, 0, 0, '', 0, '', '', 0, 1); - // Note: If user has no right to "see all thirdparties", we for selection of sale representative to him, so after creation he can see the record. + // Note: If user has no right to "see all thirdparties", we force selection of sale representative to him, so after creation he can see the record. $selected = (count(GETPOST('commercial', 'array')) > 0 ? GETPOST('commercial', 'array') : (GETPOST('commercial', 'int') > 0 ? array(GETPOST('commercial', 'int')) : (empty($user->rights->societe->client->voir)?array($user->id):array()))); print $form->multiselectarray('commercial', $userlist, $selected, null, null, null, null, "90%"); print '
    '; diff --git a/htdocs/supplier_proposal/list.php b/htdocs/supplier_proposal/list.php index 0c65ae5150f..dd678b51605 100644 --- a/htdocs/supplier_proposal/list.php +++ b/htdocs/supplier_proposal/list.php @@ -403,7 +403,7 @@ if ($resql) print ''; print ''; - print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit); + print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'commercial', 0, $newcardbutton, '', $limit); $topicmail="SendSupplierProposalRef"; $modelmail="supplier_proposal_send"; 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..35e3bd7f836 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,13 @@ 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; + } } ?> diff --git a/htdocs/theme/eldy/btn.inc.php b/htdocs/theme/eldy/btn.inc.php index 2e42d42acaa..a3000715712 100644 --- a/htdocs/theme/eldy/btn.inc.php +++ b/htdocs/theme/eldy/btn.inc.php @@ -60,15 +60,41 @@ span.butAction, span.butActionDelete { /* text-align: center; New button are on right of screen */ cursor: pointer; } -a.butActionNew>span.fa-plus-circle, a.butActionNew>span.fa-plus-circle:hover, + +.tableforfieldcreate 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 { - padding-: 6px; font-size: 1.5em; border: none; box-shadow: none; webkit-box-shadow: none; +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, +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, +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; + box-shadow: none; webkit-box-shadow: none; } .butAction:hover { @@ -208,8 +234,14 @@ TITLE BUTTON display: block; } +div.pagination li:first-child a.btnTitle{ + margin-left: 10px; +} +.imgforviewmode { + color: #aaa; +} global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (! $user->admin)) { ?> diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 561da969cdd..7e1a52bf59b 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -249,8 +249,9 @@ select.flat, form.flat select { select:invalid { color: gray; } -input:disabled { - background:#ddd; +input:disabled, textarea:disabled, select[disabled='disabled'] +{ + background:#eee; } input.liste_titre { @@ -261,9 +262,6 @@ input.removedfile { border: 0px !important; vertical-align: text-bottom; } -textarea:disabled { - background:#ddd; -} input[type=file ] { background-color: transparent; border-top: none; border-left: none; border-right: none; box-shadow: none; } input[type=checkbox] { background-color: transparent; border: none; box-shadow: none; } input[type=radio] { background-color: transparent; border: none; box-shadow: none; } @@ -5861,3 +5859,4 @@ div.tabsElem a.tab { include dol_buildpath($path.'/theme/'.$theme.'/dropdown.inc.php', 0); include dol_buildpath($path.'/theme/'.$theme.'/info-box.inc.php', 0); include dol_buildpath($path.'/theme/'.$theme.'/progress.inc.php', 0); +include dol_buildpath($path.'/theme/'.$theme.'/timeline.inc.php', 0); diff --git a/htdocs/theme/eldy/img/object_zapier.png b/htdocs/theme/eldy/img/object_zapier.png new file mode 100644 index 00000000000..4ffd34184af Binary files /dev/null and b/htdocs/theme/eldy/img/object_zapier.png differ diff --git a/htdocs/theme/eldy/timeline.inc.php b/htdocs/theme/eldy/timeline.inc.php new file mode 100644 index 00000000000..2cb3461d713 --- /dev/null +++ b/htdocs/theme/eldy/timeline.inc.php @@ -0,0 +1,197 @@ + + * License: Open source - MIT + * Please visit http://opensource.org/licenses/MIT for more information + */ + +if (! defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet'); ?> +/*