From f1294a1adcf3e495efe6fc794001bb71c4fba11a Mon Sep 17 00:00:00 2001 From: Myddleware Date: Fri, 12 May 2023 11:41:17 +0200 Subject: [PATCH] Release 3.3.1e (#1015) ** Bugfix * Bugfix : no filter on delete document * Bugfix : change order to validate values * Bugfix : DocIdRef was not returned * Bugfix : add missing setter method for manual parameter * Bugfix : change value formula to manage parentheses * Bugfix : We don't send output for the API and Myddleware UI * Bugfix : change the way to get the environment * Bugfix : enhance function changeValue and changeMultiValue * Bugfix : dateref value * Bugfix : Manage space into formula changeValue and changeMultiValue * Bugfix : Rename function checkParentDocument to checkParentDocuments for rule and job classes * Bugfix : Add http-client library * Bugfix : Myddleware 3.3 : Change dockerfile * Bugfix : clearSendData (manage fields 'source_date_modified', 'id_doc_myddleware', 'Myddleware_element_id' ) * Bugfix : output management * Bugfix : manage return null value for check methods * Bugfix : change the type attribute from private to protected * Bugfix : init $emailAddresses attribute ** Connector * SugarCRM : deletion management * SugarCRM : a duplicate field on email address module * Moodle : imporve error management * Moodle : manage create only fields * Moodle : fix issue on new custom field function * Salesforce : add rule mode Update only (U) * Airtable : fix bug on reference date * Airtable : fix ref date field name --- .env | 2 +- Dockerfile | 85 +++---------- composer.json | 1 + composer.lock | 169 ++++++++++++++++++++++++- src/Command/SynchroCommand.php | 2 +- src/Manager/DocumentManager.php | 25 +++- src/Manager/FormulaFunctionManager.php | 10 +- src/Manager/JobManager.php | 7 +- src/Manager/NotificationManager.php | 2 +- src/Manager/RuleManager.php | 18 +-- src/Solutions/airtable.php | 10 +- src/Solutions/erpnext.php | 14 +- src/Solutions/moodle.php | 48 +++++-- src/Solutions/salesforce.php | 16 +-- src/Solutions/solution.php | 21 ++- src/Solutions/sugarcrm.php | 19 ++- src/Solutions/vtigercrm.php | 2 +- templates/Flux/view/view.html.twig | 4 +- 18 files changed, 314 insertions(+), 141 deletions(-) diff --git a/.env b/.env index cbaecb321..734ceeaef 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -MYDDLEWARE_VERSION=3.3.1d +MYDDLEWARE_VERSION=3.3.2a APP_SECRET=Thissecretisnotsosecretchangeit APP_ENV=prod diff --git a/Dockerfile b/Dockerfile index 28c171333..e21386d7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,95 +1,42 @@ -FROM --platform=linux/amd64 php:7.4.26-apache -LABEL maintainer="Francesco Bianco " +FROM --platform=linux/amd64 php:8.1.17-apache ## Configure PHP RUN apt-get update && apt-get upgrade -y && \ - apt-get -y install -qq --force-yes rsync mariadb-client libzip-dev libicu-dev git zlib1g-dev libc-client-dev libkrb5-dev cron rsyslog unzip libssh2-1-dev gnupg2 alien libaio1 nano vim net-tools iputils-ping telnet && \ + apt-get -y install -qq --force-yes mariadb-client libzip-dev libicu-dev zlib1g-dev libc-client-dev libkrb5-dev gnupg2 libaio1 && \ docker-php-ext-configure intl && docker-php-ext-configure imap --with-kerberos --with-imap-ssl && \ docker-php-ext-install imap exif mysqli pdo pdo_mysql zip intl && \ echo "short_open_tag=off" >> /usr/local/etc/php/conf.d/syntax.ini && \ echo "memory_limit=-1" >> /usr/local/etc/php/conf.d/memory_limit.ini && \ echo "display_errors=0" >> /usr/local/etc/php/conf.d/errors.ini && \ sed -e 's!DocumentRoot /var/www/html!DocumentRoot /var/www/html/public!' -ri /etc/apache2/sites-available/000-default.conf && \ - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer && \ apt-get clean && rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer #RUN pecl install -f ssh2-1.1.2 && docker-php-ext-enable ssh2 -## Install PHP Accelerators -RUN pecl install apcu \ - && pecl install apcu_bc-1.0.3 \ - && docker-php-ext-enable apcu --ini-name 10-docker-php-ext-apcu.ini \ - && docker-php-ext-enable apc --ini-name 20-docker-php-ext-apc.ini +COPY composer.json ./composer.json +COPY composer.lock ./composer.lock +RUN composer install ## Intall NodeJS RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ apt-get update && apt-get install -y nodejs build-essential && npm install -g npm yarn && \ apt-get clean && rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* -## Install Xdebug -RUN pecl install -f xdebug && \ - docker-php-ext-enable xdebug && \ - echo "xdebug.remote_enable = 1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_autostart = 0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_connect_back = 0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_port = 9000" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_handler = 'dbgp'" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \ - echo "xdebug.remote_mode = req" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini - -## Install MS Database -#RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ -# curl https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list && \ -# apt-get update && \ -# apt-get install --no-install-recommends -y msodbcsql17 unixodbc-dev && \ -# pecl install -f sqlsrv pdo_sqlsrv && \ -# docker-php-ext-enable sqlsrv pdo_sqlsrv && \ -# sed -i 's,^\(MinProtocol[ ]*=\).*,\1'TLSv1.0',g' /etc/ssl/openssl.cnf && \ -# sed -i 's,^\(CipherString[ ]*=\).*,\1'DEFAULT@SECLEVEL=1',g' /etc/ssl/openssl.cnf - -## Install Oracle Database -RUN curl "https://download.oracle.com/otn_software/linux/instantclient/195000/oracle-instantclient19.5-sqlplus-19.5.0.0.0-1.x86_64.rpm" -o "/mnt/oracle-instant-sqlplus.rpm" && \ - curl "https://download.oracle.com/otn_software/linux/instantclient/195000/oracle-instantclient19.5-basic-19.5.0.0.0-1.x86_64.rpm" -o "/mnt/oracle-instant-basic.rpm" && \ - curl "https://download.oracle.com/otn_software/linux/instantclient/195000/oracle-instantclient19.5-devel-19.5.0.0.0-1.x86_64.rpm" -o "/mnt/oracle-instant-devel.rpm" && \ - curl "https://download.oracle.com/otn_software/linux/instantclient/195000/oracle-instantclient19.5-odbc-19.5.0.0.0-1.x86_64.rpm" -o "/mnt/oracle-instant-odbc.rpm" && \ - curl "https://download.oracle.com/otn_software/linux/instantclient/195000/oracle-instantclient19.5-tools-19.5.0.0.0-1.x86_64.rpm" -o "/mnt/oracle-instant-tools.rpm" && \ - alien -i /mnt/oracle-instant-sqlplus.rpm && \ - alien -i /mnt/oracle-instant-basic.rpm && \ - alien -i /mnt/oracle-instant-devel.rpm && \ - alien -i /mnt/oracle-instant-odbc.rpm && \ - alien -i /mnt/oracle-instant-tools.rpm && \ - ln -s /usr/lib/oracle/19.5/client64/lib/libsqora.so.19.1 /usr/lib/libsqora.so && \ - rm /mnt/* && \ - export LD_LIBRARY_PATH=/usr/lib/oracle/19.5/client64/lib && \ - export ORACLE_HOME=/usr/lib/oracle/19.5/client64 && \ - export C_INCLUDE_PATH=/usr/include/oracle/19.5/client64 && \ - docker-php-ext-install oci8 pdo_oci +COPY --chown=www-data:www-data . . -## Install Platform tool -RUN curl -sS https://platform.sh/cli/installer | php && \ - ln -s /root/.platformsh/bin/platform /usr/local/bin/platform +# Build packages with yarn +RUN yarn install +RUN yarn run build ## Setup Cronjob -RUN echo "cron.* /var/log/cron.log" >> /etc/rsyslog.conf && rm -fr /etc/cron.* && mkdir /etc/cron.d -COPY docker/etc/crontab /etc/ -RUN chmod 600 /etc/crontab - -## Install DBLIB -#RUN apt-get update && \ -# apt-get install -y freetds-bin freetds-dev freetds-common libct4 libsybdb5 tdsodbc libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev zlib1g-dev libicu-dev g++ libc-client-dev && \ -# docker-php-ext-configure pdo_dblib --with-libdir=/lib/x86_64-linux-gnu && \ -# docker-php-ext-configure intl && \ -# docker-php-ext-install pdo_dblib && \ -# docker-php-ext-install intl && \ -# docker-php-ext-install mbstring && \ -# docker-php-ext-enable intl mbstring pdo_dblib - -## Sysadmin tools -RUN apt-get update && apt-get upgrade -y && \ - apt-get -y install -qq --force-yes nano vim net-tools iputils-ping telnet +# RUN echo "cron.* /var/log/cron.log" >> /etc/rsyslog.conf && rm -fr /etc/cron.* && mkdir /etc/cron.d +# COPY docker/etc/crontab /etc/ +# RUN chmod 600 /etc/crontab ## Entrypoint and scripts -COPY ./docker/script/myddleware-cron.sh /usr/local/bin/myddleware-cron.sh COPY ./docker/script/myddleware-foreground.sh /usr/local/bin/myddleware-foreground.sh -COPY ./docker/script/myddleware-monitor.sh /usr/local/bin/myddleware-monitor.sh +COPY ./docker/script/myddleware-cron.sh /usr/local/bin/myddleware-cron.sh + RUN chmod +x /usr/local/bin/myddleware-*.sh CMD ["myddleware-foreground.sh"] diff --git a/composer.json b/composer.json index e3ac11f8c..0443660aa 100644 --- a/composer.json +++ b/composer.json @@ -65,6 +65,7 @@ "symfony/flex": "^1.3.1", "symfony/form": "5.4.*", "symfony/framework-bundle": "5.4.*", + "symfony/http-client": "5.4.*", "symfony/http-foundation": "5.4.*", "symfony/mailer": "5.4.*", "symfony/monolog-bundle": "3.8.*", diff --git a/composer.lock b/composer.lock index 081bc91d1..a7d45d190 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2364746f914f74c3813b0187e13c5393", + "content-hash": "b5f2f49aa6d7eaf23a64023c53ae99a6", "packages": [ { "name": "api-platform/core", @@ -7855,6 +7855,171 @@ ], "time": "2023-01-10T17:40:25+00:00" }, + { + "name": "symfony/http-client", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "0dabec4e3898d3e00451dd47b5ef839168f9bbf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/0dabec4e3898d3e00451dd47b5ef839168f9bbf5", + "reference": "0dabec4e3898d3e00451dd47b5ef839168f9bbf5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-client-contracts": "^2.4", + "symfony/polyfill-php73": "^1.11", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.0|^2|^3" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "2.4" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4.13|^5.1.5|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-client/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T16:02:29+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/1a4f708e4e87f335d1b1be6148060739152f0bd5", + "reference": "1a4f708e4e87f335d1b1be6148060739152f0bd5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-13T20:07:29+00:00" + }, { "name": "symfony/http-foundation", "version": "v5.4.20", @@ -14338,5 +14503,5 @@ "ext-simplexml": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.1.0" } diff --git a/src/Command/SynchroCommand.php b/src/Command/SynchroCommand.php index 5c976bc60..2650b2f39 100644 --- a/src/Command/SynchroCommand.php +++ b/src/Command/SynchroCommand.php @@ -129,7 +129,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->jobManager->checkPredecessorDocuments(); // Permet de valider qu'au moins un document parent(relation père) est existant - $this->jobManager->checkParentDocument(); + $this->jobManager->checkParentDocuments(); // Permet de transformer les docuement avant d'être envoyés à la cible $this->jobManager->transformDocuments(); diff --git a/src/Manager/DocumentManager.php b/src/Manager/DocumentManager.php index cb46ceaab..29206c67a 100644 --- a/src/Manager/DocumentManager.php +++ b/src/Manager/DocumentManager.php @@ -68,6 +68,7 @@ class documentcore protected $jobId; protected $key; protected $docIdRefError; + protected $env; protected bool $transformError = false; protected ?ToolsManager $tools; protected $api; // Specify if the class is called by the API @@ -122,6 +123,7 @@ public function __construct( $this->tools = $tools; $this->formulaManager = $formulaManager; $this->solutionManager = $solutionManager; + $this->env = $_SERVER['APP_ENV']; } public static function lstGblStatus(): array @@ -361,8 +363,12 @@ public function filterDocument($ruleFilters) } try { $filterOK = true; - // Si des filtres sont présents - if (!empty($ruleFilters)) { + // Only if there is a least one filter + // No filter on delete document as they will be filter after is Myddleware never sent the data + if ( + !empty($ruleFilters) + AND $this->documentType != 'D' + ) { // Boucle sur les filtres foreach ($ruleFilters as $ruleFilter) { if (!$this->checkFilter($this->sourceData[$ruleFilter['target']], $ruleFilter['type'], $ruleFilter['value'])) { @@ -689,7 +695,7 @@ public function checkPredecessorDocument(): bool return true; } catch (\Exception $e) { // Reference document id is used to show which document is blocking the current document in Myddleware - $this->docIdRefError = (is_array($result) and !empty($result['id']) ? $result['id'] : ''); + $this->docIdRefError = ((is_array($result) and !empty($result['id'])) ? $result['id'] : ''); $this->message .= 'Failed to check document predecessor : '.$e->getMessage().' '.$e->getFile().' Line : ( '.$e->getLine().' )'; $this->typeError = 'E'; $this->updateStatus('Predecessor_KO'); @@ -1922,7 +1928,11 @@ public function updateStatus($new_status) WHERE id = :id '; - if (!$this->api) { + // We don't send output for the API and Myddleware UI + if ( + !$this->api + AND $this->env == 'background' + ) { echo 'status '.$new_status.' id = '.$this->id.' '.$now.chr(10); } // Suppression de la dernière virgule @@ -1962,7 +1972,11 @@ public function updateDeleteFlag($deleted) WHERE id = :id '; - if (!$this->api) { + // We don't send output for the API and Myddleware UI + if ( + !$this->api + AND $this->env != 'prod' + ) { echo(!empty($deleted) ? 'Remove' : 'Restore').' document id = '.$this->id.' '.$now.chr(10); } $stmt = $this->connection->prepare($query); @@ -2180,6 +2194,7 @@ protected function getTargetId($ruleRelationship, $record_id) { try { $direction = $this->getRelationshipDirection($ruleRelationship); + // En fonction du sens de la relation, la recherche du parent id peut-être inversée (recherchée en source ou en cible) // Search all documents with target ID not empty in status close or no_send (document canceled but it is a real document) if ('-1' == $direction) { diff --git a/src/Manager/FormulaFunctionManager.php b/src/Manager/FormulaFunctionManager.php index 74c08dfd1..699a06ead 100644 --- a/src/Manager/FormulaFunctionManager.php +++ b/src/Manager/FormulaFunctionManager.php @@ -81,7 +81,9 @@ public static function changeFormatDate($dateToChange, $oldFormat, $newFormat) public static function changeValue($var, $arrayKeyToValue, $acceptNull = null) { // Transform string into an array - $arrayKeyToValue = json_decode(str_replace(['(', ')', '\''], ['{', '}', '"'], $arrayKeyToValue), true); + // Change first and last characters (parentheses) by accolades + // Replace ' before and after , and : by " (manage space before , and :) + $arrayKeyToValue = json_decode('{"'.str_replace([ ':\'', '\':', ': \'', '\' :', ',\'', '\',', ', \'', '\' ,'], [ ':"', '":', ':"', '":', ',"', '",', ',"', '",'], substr($arrayKeyToValue,2,-2)).'"}', true); if (in_array($var, array_keys($arrayKeyToValue))) { return $arrayKeyToValue[$var]; } @@ -92,11 +94,13 @@ public static function changeValue($var, $arrayKeyToValue, $acceptNull = null) public static function changeMultiValue($var, $arrayKeyToValue, $delimiter) { - // Transform $var into array + // Transform string into an array + // Change first and last characters (parentheses) by accolades + // Replace ' before and after , and : by " (manage space before , and :) $return = ''; $arrayVar = explode($delimiter, $var); if (!empty($arrayVar)) { - $arrayKeyToValue = json_decode(str_replace(['(', ')', '\''], ['{', '}', '"'], $arrayKeyToValue), true); + $arrayKeyToValue = json_decode('{"'.str_replace([ ':\'', '\':', ': \'', '\' :', ',\'', '\',', ', \'', '\' ,'], [ ':"', '":', ':"', '":', ',"', '",', ',"', '",'], substr($arrayKeyToValue,2,-2)).'"}', true); foreach ($arrayVar as $varValue) { // Transform string into an array if (!empty($arrayKeyToValue[$varValue])) { diff --git a/src/Manager/JobManager.php b/src/Manager/JobManager.php index 6780c1f1a..76c0637e7 100644 --- a/src/Manager/JobManager.php +++ b/src/Manager/JobManager.php @@ -234,9 +234,9 @@ public function filterDocuments() } // Permet de contrôler si un docuement a une relation mais n'a pas de correspondance d'ID pour cette relation dans Myddleware - public function checkParentDocument() + public function checkParentDocuments() { - $this->ruleManager->checkParentDocument(); + $this->ruleManager->checkParentDocuments(); } // Permet de trasformer les documents @@ -287,6 +287,7 @@ public function runError($limit, $attempt) foreach ($documentsError as $documentError) { $this->ruleManager->setRule($documentError['rule_id']); $this->ruleManager->setJobId($this->id); + $this->ruleManager->setManual($this->manual); $this->ruleManager->setApi($this->api); $errorActionDocument = $this->ruleManager->actionDocument($documentError['id'], 'rerun'); if (!empty($errorActionDocument)) { @@ -501,6 +502,7 @@ public function massAction($action, $dataType, $ids, $forceAll, $fromStatus, $to if ($param['ruleId'] != $document['rule_id']) { $this->ruleManager->setApi($this->api); $this->ruleManager->setJobId($this->id); + $this->ruleManager->setManual($this->manual); $this->ruleManager->setRule($document['rule_id']); } $this->ruleManager->actionDocument($document['id'], $action, $toStatus); @@ -544,6 +546,7 @@ public function readRecord($ruleId, $filterQuery, $filterValues, $usesDocumentId // We instanciate the rule $this->ruleManager->setRule($ruleId); $this->ruleManager->setJobId($this->id); + $this->ruleManager->setManual($this->manual); $this->ruleManager->setApi($this->api); // We create an array that will match the initial structure of the function diff --git a/src/Manager/NotificationManager.php b/src/Manager/NotificationManager.php index ea4791b2c..e87341944 100644 --- a/src/Manager/NotificationManager.php +++ b/src/Manager/NotificationManager.php @@ -51,7 +51,7 @@ class NotificationManager { protected EntityManagerInterface $entityManager; - protected $emailAddresses; + protected $emailAddresses = array(); protected $configParams; protected ToolsManager $tools; private LoggerInterface $logger; diff --git a/src/Manager/RuleManager.php b/src/Manager/RuleManager.php index 22a282b49..8b26cba60 100644 --- a/src/Manager/RuleManager.php +++ b/src/Manager/RuleManager.php @@ -560,7 +560,7 @@ protected function validateReadDataSource() // Order data in the date_modified order $modified = array_column($dataSourceValues, 'date_modified'); - array_multisort($modified, SORT_ASC, $dataSourceValues); + array_multisort($modified, SORT_DESC, $dataSourceValues); foreach ($dataSourceValues as $value) { // Check if the previous record has the same date_modified than the current record // Check only if offset isn't managed into the source application connector @@ -698,7 +698,7 @@ public function checkPredecessorDocuments($documents = null): array * * @throws \Doctrine\DBAL\Exception */ - public function checkParentDocument($documents = null): array + public function checkParentDocuments($documents = null): array { // include_once 'document.php'; // Permet de charger dans la classe toutes les relations de la règle @@ -1270,7 +1270,7 @@ protected function rerun($id_document): array $status = $this->documentManager->getStatus(); } if (in_array($status, ['Predecessor_OK', 'Relate_KO'])) { - $response = $this->checkParentDocument([['id' => $id_document]]); + $response = $this->checkParentDocuments([['id' => $id_document]]); if (true === $response[$id_document]) { $msg_success[] = 'Transfer id '.$id_document.' : Status change => Relate_OK'; } else { @@ -1413,7 +1413,7 @@ protected function massIdRerun(string $documentIds) } } if (in_array($status, ['Predecessor_OK', 'Relate_KO'])) { - $response = $this->checkParentDocument($arrayIdDocument); + $response = $this->checkParentDocuments($arrayIdDocument); if (true === $this->verifyMultiIdResponse($response)) { // Update status if an action has been executed $status = 'Relate_OK'; @@ -1510,15 +1510,15 @@ protected function clearSendData($sendData) if (!empty($sendData)) { foreach ($sendData as $key => $value) { if (isset($value['source_date_modified'])) { - unset($sendData->{$key}['source_date_modified']); + unset($sendData[$key]['source_date_modified']); } if (isset($value['id_doc_myddleware'])) { - unset($sendData->{$key}['id_doc_myddleware']); + unset($sendData[$key]['id_doc_myddleware']); } - + if (isset($value['Myddleware_element_id'])) { + unset($sendData[$key]['Myddleware_element_id']); + } } - - return $sendData; } } diff --git a/src/Solutions/airtable.php b/src/Solutions/airtable.php index 54a77b0cd..57c3d7d31 100644 --- a/src/Solutions/airtable.php +++ b/src/Solutions/airtable.php @@ -196,6 +196,7 @@ public function readData($param): array $param['fields'][] = $dateRefField; } } + $stop = false; $page = 1; $offset = ''; @@ -285,7 +286,10 @@ public function readData($param): array } // Get the reference date - if (!empty($record['fields'][$dateRefField])) { + if ( + !empty($dateRefField) + AND !empty($record['fields'][$dateRefField]) + ) { $dateModified = $record['fields'][$dateRefField]; // createdTime not allowed for reading action, only to get an history or a duplicate field } elseif ( @@ -399,10 +403,6 @@ public function upsert(string $method, array $param): array ++$i; continue; } - // Myddleware_element_id is a field only used by Myddleware. Not sent to the target application - if (!empty($data['Myddleware_element_id'])) { - unset($data['Myddleware_element_id']); - } $body['records'][$i]['fields'] = $data; diff --git a/src/Solutions/erpnext.php b/src/Solutions/erpnext.php index ff6ebf327..67259cffe 100644 --- a/src/Solutions/erpnext.php +++ b/src/Solutions/erpnext.php @@ -327,14 +327,12 @@ public function createUpdate($method, $param): array try { foreach ($data as $key => $value) { // We don't send Myddleware fields - if (in_array($key, ['target_id', 'Myddleware_element_id'])) { - if ( - 'target_id' == $key - and !empty($value) - ) { - $url = $this->paramConnexion['url'].'/api/resource/'.rawurlencode($param['module']).'/'.rawurlencode($value); - } - unset($data[$key]); + if ( + 'target_id' == $key + and !empty($value) + ) { + $url = $this->paramConnexion['url'].'/api/resource/'.rawurlencode($param['module']).'/'.rawurlencode($value); + unset($data[$key]); // if the data is a link } elseif ('link_doctype' == $key) { $data['links'] = [['link_doctype' => $data[$key], 'link_name' => $data['link_name']]]; diff --git a/src/Solutions/moodle.php b/src/Solutions/moodle.php index aa2fa2d6b..9615b99d4 100644 --- a/src/Solutions/moodle.php +++ b/src/Solutions/moodle.php @@ -48,6 +48,10 @@ class moodlecore extends solution 'courses' => ['shortname', 'idnumber'], ]; + protected array $createOnlyFields = [ + 'courses' => ['lang'], + ]; + protected string $delaySearch = '-1 year'; public function login($paramConnexion) @@ -191,14 +195,14 @@ public function read($param): array $functionName = $this->getFunctionName($param); // Get the custom fields set in the connector $customFieldList = $this->getCustomFields($param); - // Init the attribute name and value for custom fields - $attributeName = ($param['module'] == 'courses' ? 'shortname' : 'name'); + // Init the attribute value for custom fields depending on the module $attributeValue = ($param['module'] == 'courses' ? 'valueraw' : 'value'); // Call to Moodle $serverurl = $this->paramConnexion['url'].'/webservice/rest/server.php'.'?wstoken='.$this->paramConnexion['token'].'&wsfunction='.$functionName; $response = $this->moodleClient->post($serverurl, $parameters); $xml = $this->formatResponse('read', $response, $param); + if (!empty($xml->ERRORCODE)) { throw new \Exception("Error $xml->ERRORCODE : $xml->MESSAGE"); } @@ -229,7 +233,7 @@ public function read($param): array $customFieldValue = ''; $customFieldName = ''; foreach($customField->KEY as $customFieldValues) { - if ($customFieldValues->attributes()->__toString() == $attributeName) { + if ($customFieldValues->attributes()->__toString() == 'shortname') { $customFieldName = $customFieldValues->VALUE->__toString(); } elseif ($customFieldValues->attributes()->__toString() == $attributeValue) { $customFieldValue = $customFieldValues->VALUE->__toString(); @@ -273,10 +277,6 @@ public function createData($param): array $dataSugar = []; $obj = new \stdClass(); foreach ($data as $key => $value) { - // We don't send Myddleware_element_id field to Moodle - if (in_array($key, array('Myddleware_element_id', 'source_date_modified', 'id_doc_myddleware'))) { - continue; - } if (!empty($value)) { // if $value belongs to $this->paramConnexion[user_custom_fields] then we add it to $obj->customfields if (in_array($key, $customFieldList)) { @@ -336,7 +336,17 @@ public function createData($param): array $serverurl = $this->paramConnexion['url'].'/webservice/rest/server.php'.'?wstoken='.$this->paramConnexion['token'].'&wsfunction='.$functionname; $response = $this->moodleClient->post($serverurl, $params); $xml = simplexml_load_string($response); + + // Check if there is a warning + if ( + !empty($xml->SINGLE) + AND $xml->SINGLE->KEY->attributes()->__toString() == 'warnings' + AND !empty($xml->SINGLE->KEY->MULTIPLE->SINGLE->KEY[3]) + ) { + throw new \Exception('ERROR : '.$xml->SINGLE->KEY->MULTIPLE->SINGLE->KEY[3]->VALUE.chr(10)); + } + // Réponse standard pour les modules avec retours if ( !empty($xml->MULTIPLE->SINGLE->KEY->VALUE) @@ -404,10 +414,7 @@ public function updateData($param): array foreach ($data as $key => $value) { if ('target_id' == $key) { continue; - // We don't send Myddleware_element_id field to Moodle - } elseif (in_array($key, array('Myddleware_element_id','source_date_modified','id_doc_myddleware'))) { - continue; - } + } if (!empty($value)) { // if $value belongs to $this->paramConnexion[user_custom_fields] then we add it to $obj->customfields if (in_array($key, $customFieldList)) { @@ -466,6 +473,15 @@ public function updateData($param): array $serverurl = $this->paramConnexion['url'].'/webservice/rest/server.php'.'?wstoken='.$this->paramConnexion['token'].'&wsfunction='.$functionname; $response = $this->moodleClient->post($serverurl, $params); $xml = simplexml_load_string($response); + + // Check if there is a warning + if ( + !empty($xml) + AND $xml->SINGLE->KEY->attributes()->__toString() == 'warnings' + AND !empty($xml->SINGLE->KEY->MULTIPLE->SINGLE->KEY[3]) + ) { + throw new \Exception('ERROR : '.$xml->SINGLE->KEY->MULTIPLE->SINGLE->KEY[3]->VALUE.chr(10)); + } // Réponse standard pour les modules avec retours if (!empty($xml->ERRORCODE)) { @@ -513,6 +529,14 @@ protected function checkDataBeforeUpdate($param, $data, $idDoc=null) ) { unset($data['createpassword']); } + // Rempove create only field + if (!empty($this->createOnlyFields[$param['module']])) { + foreach($this->createOnlyFields[$param['module']] as $createOnlyField) { + if (isset($data[$createOnlyField])) { + unset($data[$createOnlyField]); + } + } + } return parent::checkDataBeforeUpdate($param, $data, $idDoc); } @@ -670,7 +694,7 @@ protected function getCustomFields ($param) { ) { return explode(',',$this->paramConnexion['course_custom_fields']); } - return null; + return array(); } // Function to add custom fields for course and user modules. diff --git a/src/Solutions/salesforce.php b/src/Solutions/salesforce.php index f7abad779..bc0181cf4 100644 --- a/src/Solutions/salesforce.php +++ b/src/Solutions/salesforce.php @@ -489,11 +489,7 @@ public function createData($param): array $parameter = array(); $parameter['attributes'] = array('type' => $param['module'], 'referenceId' => 'Ref'.$i); foreach ($data as $key => $value) { - // On n'envoie jamais le champ Myddleware_element_id à Salesforce - if (in_array($key, array('Myddleware_element_id','id_doc_myddleware','source_date_modified'))) { - continue; - } - elseif ($key == 'target_id') { + if ($key == 'target_id') { continue; } elseif($key == 'Birthdate') { @@ -604,11 +600,7 @@ public function updateData($param): array // Instanciation de l'URL d'appel $query_url = $this->instance_url."/services/data/".$this->versionApi."/sobjects/" . $param['module'] . '/'; foreach ($data as $key => $value) { - // On n'envoie jamais le champ Myddleware_element_id à Salesforce - if (in_array($key, array('Myddleware_element_id','id_doc_myddleware','source_date_modified'))) { - continue; - } - elseif ($key == 'target_id') { + if ($key == 'target_id') { $target_id = $value; // Ajout de l'ID à l'URL pour la modification $query_url .= $value . '/'; @@ -775,12 +767,12 @@ public function getRuleMode($module,$type): array */ public function getRefFieldName($param): string { - if(in_array($param['ruleParams']['mode'],array("0","S"))) { + if(in_array($param['ruleParams']['mode'],array("0","S","U"))) { return "LastModifiedDate"; } else if ($param['ruleParams']['mode'] == "C"){ return "CreatedDate"; } else { - throw new \Exception ("$param[ruleParams][mode] is not a correct Rule mode."); + throw new \Exception ($param['ruleParams']['mode']." is not a correct Rule mode."); } return ""; } diff --git a/src/Solutions/solution.php b/src/Solutions/solution.php index e3ac41687..145ba7670 100644 --- a/src/Solutions/solution.php +++ b/src/Solutions/solution.php @@ -78,9 +78,9 @@ class solutioncore protected Connection $connection; protected ParameterBagInterface $parameterBagInterface; protected EntityManagerInterface $entityManager; - private DocumentRepository $documentRepository; - private RuleRelationShipRepository $ruleRelationshipsRepository; - private FormulaManager $formulaManager; + protected DocumentRepository $documentRepository; + protected RuleRelationShipRepository $ruleRelationshipsRepository; + protected FormulaManager $formulaManager; public function __construct( LoggerInterface $logger, @@ -397,6 +397,7 @@ public function read($param) public function createData($param): array { try { + $result = array(); // For every document foreach ($param['data'] as $idDoc => $record) { try { @@ -405,6 +406,10 @@ public function createData($param): array // Check control before create $record = $this->checkDataBeforeCreate($param, $record, $idDoc); + // No action if null is returned + if ($record === null) { + continue; + } // Call create method $recordId = $this->create($param, $record, $idDoc); @@ -481,6 +486,7 @@ protected function create($param, $record, $idDoc = null) public function updateData($param): array { try { + $result = array(); // For every document foreach ($param['data'] as $idDoc => $record) { try { @@ -492,6 +498,10 @@ public function updateData($param): array } // Check control before create $record = $this->checkDataBeforeUpdate($param, $record, $idDoc); + // No action if null is returned + if ($record === null) { + continue; + } // Call create methode $recordId = $this->update($param, $record, $idDoc); @@ -535,6 +545,7 @@ protected function update($param, $data, $idDoc = null) public function deleteData($param): array { try { + $result = array(); // For every document foreach ($param['data'] as $idDoc => $record) { try { @@ -543,6 +554,10 @@ public function deleteData($param): array } // Check control before delete $record = $this->checkDataBeforeDelete($param, $record); + // No action if null is returned + if ($record === null) { + continue; + } // Call delete methode $recordId = $this->delete($param, $record); diff --git a/src/Solutions/sugarcrm.php b/src/Solutions/sugarcrm.php index 3be93e029..534da49ac 100644 --- a/src/Solutions/sugarcrm.php +++ b/src/Solutions/sugarcrm.php @@ -43,14 +43,17 @@ class sugarcrmcore extends solution protected array $required_fields = ['default' => ['id', 'date_modified']]; - protected array $FieldsDuplicate = ['Contacts' => ['email1', 'last_name'], + protected array $FieldsDuplicate = + [ + 'default' => ['name'], + 'Contacts' => ['email1', 'last_name'], 'Accounts' => ['email1', 'name'], 'Users' => ['email1', 'last_name'], 'Leads' => ['email1', 'last_name'], 'Prospects' => ['email1', 'name'], - 'default' => ['name'], + 'EmailAddresses' => ['email_address'], ]; - + public function getFieldsLogin(): array { return [ @@ -363,12 +366,18 @@ public function read($param) $result[$record->id]['date_modified'] = end($records)->date_modified; } } + // Error if only deletion records read if ($onlyDeletion) { - throw new \Exception('Only deletion records read. It is not possible to determine the reference date with only deletion. Please increase the rule limit to include non deletion records.'); + if (count($result) >= $param['limit']) { + throw new \Exception('Only deletion records read. It is not possible to determine the reference date with only deletion. Please increase the rule limit to include non deletion records.'); + } else { + // If only deletion without new or modified record, we send no result. We wait for new or modified record. + // Otherwise we will read the deleted record until a new or modified record is read because Sugar doesn't return modified date for deleted record. + return array(); + } } } - return $result; } diff --git a/src/Solutions/vtigercrm.php b/src/Solutions/vtigercrm.php index a2689ec02..d60b3a732 100644 --- a/src/Solutions/vtigercrm.php +++ b/src/Solutions/vtigercrm.php @@ -701,7 +701,7 @@ public function deleteData($param): array // Clean a record by removing all Myddleware fields protected function cleanRecord($param, $data) { - $myddlewareFields = ['target_id', 'source_date_modified', 'id_doc_myddleware', 'Myddleware_element_id']; + $myddlewareFields = ['target_id']; foreach ($myddlewareFields as $myddlewareField) { if (array_key_exists($myddlewareField, $data)) { unset($data[$myddlewareField]); diff --git a/templates/Flux/view/view.html.twig b/templates/Flux/view/view.html.twig index 014513c30..4b00709dd 100644 --- a/templates/Flux/view/view.html.twig +++ b/templates/Flux/view/view.html.twig @@ -340,7 +340,7 @@ {{'list_flux.tab.name'|trans}} {{'list_flux.tab.source_id'|trans}} {{'list_flux.tab.target_id'|trans}} - {{'list_flux.tab.date_modified'|trans}} + {{'list_flux.tab.dateref'|trans}} {{'list_flux.tab.type'|trans}} {{'list_flux.tab.statut'|trans}} @@ -363,7 +363,7 @@ {{ flux.source }} {{ flux.target }} - {{ flux.dateModified|date("d/m/Y H:i:s", timezone) }} + {{ flux.sourceDateModified|date("d/m/Y H:i:s", timezone) }} {{ flux.type }}
{{ flux.status }}