From e9aad0c975b291ab3c0b5efd14f59732e4712c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 15:13:24 +0200 Subject: [PATCH 1/6] feat: phpcs and pre commit --- .phpcs.xml.dist | 369 ++-------------------- composer.json | 7 +- composer.lock | 47 ++- dev/tools/phpcs/dolibarr-ruleset.dtd | 18 ++ dev/tools/phpcs/dolibarr-ruleset.xml | 447 +++++++++++++++++++++++++++ 5 files changed, 531 insertions(+), 357 deletions(-) create mode 100644 dev/tools/phpcs/dolibarr-ruleset.dtd create mode 100644 dev/tools/phpcs/dolibarr-ruleset.xml diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 63d2dfc..2868170 100755 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -1,349 +1,24 @@ - - The PSR-12 coding standard. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - error - Method name "%s" must not be prefixed with an underscore to indicate visibility - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - - - - - - - - - - - - - - - 0 - - - 0 - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + ./admin + ./ajax + ./class + ./core + ./css + ./js + ./lib + + + + + + + + diff --git a/composer.json b/composer.json index 7a72258..2ab597b 100755 --- a/composer.json +++ b/composer.json @@ -6,6 +6,11 @@ }, "require-dev": { "caprel/dolibarr-stubs": "^18.0", - "squizlabs/php_codesniffer": "^3.13" + "squizlabs/php_codesniffer": "^3.13", + "26b/php-pre-commit": "^0.2.1" + }, + "scripts": { + "post-install-cmd": "php-pre-commit", + "post-update-cmd": "php-pre-commit" } } diff --git a/composer.lock b/composer.lock index e518333..ff50a7b 100755 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,38 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e07207189027c776f16ff1e06816e456", + "content-hash": "7e1c1884b1fe05c7452f97b75c4f087e", "packages": [], "packages-dev": [ + { + "name": "26b/php-pre-commit", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/26B/php-pre-commit.git", + "reference": "a253fb1898c9a4152cc112c83b924e1d93888094" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/26B/php-pre-commit/zipball/a253fb1898c9a4152cc112c83b924e1d93888094", + "reference": "a253fb1898c9a4152cc112c83b924e1d93888094", + "shasum": "" + }, + "bin": [ + "php-pre-commit" + ], + "type": "scripts", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Pre-commit git hook for enforcing php standards.", + "support": { + "issues": "https://github.com/26B/php-pre-commit/issues", + "source": "https://github.com/26B/php-pre-commit/tree/0.2.1" + }, + "time": "2022-08-11T16:23:46+00:00" + }, { "name": "caprel/dolibarr-stubs", "version": "v18.0", @@ -34,16 +63,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.5", + "version": "3.13.6", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" + "reference": "4c378e1a528ea066890fc2397cbdd2f94eb2fc91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/4c378e1a528ea066890fc2397cbdd2f94eb2fc91", + "reference": "4c378e1a528ea066890fc2397cbdd2f94eb2fc91", "shasum": "" }, "require": { @@ -109,17 +138,17 @@ "type": "thanks_dev" } ], - "time": "2025-11-04T16:30:35+00:00" + "time": "2026-08-06T00:17:32+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=8.0" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/dev/tools/phpcs/dolibarr-ruleset.dtd b/dev/tools/phpcs/dolibarr-ruleset.dtd new file mode 100644 index 0000000..24aa329 --- /dev/null +++ b/dev/tools/phpcs/dolibarr-ruleset.dtd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/dev/tools/phpcs/dolibarr-ruleset.xml b/dev/tools/phpcs/dolibarr-ruleset.xml new file mode 100644 index 0000000..c94cc66 --- /dev/null +++ b/dev/tools/phpcs/dolibarr-ruleset.xml @@ -0,0 +1,447 @@ + + + + Dolibarr coding standard. + + + + + + /\.git/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 4 + + + 4 + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 0 + + + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + 0 + + + + + 0 + + + + 0 + + + + + 0 + + + + + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + + + + + + + 0 + + + + + 0 + + + + 0 + + + + + + + + 0 + + + 0 + + + + 0 + + + + + + + + 0 + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + From c2350f5f1ad842c3be3d407890da83b430e153ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 15:15:27 +0200 Subject: [PATCH 2/6] feat: apply dolibarr coding standardfs --- admin/about.php | 12 +- admin/autodeclaration.php | 94 +- admin/setup.php | 238 +- ajax/dismiss_notice.php | 20 +- class/actions_autoverifactu.class.php | 1134 ++++--- class/verifactuqueue.class.php | 98 +- .../facture/doc/pdf_Autoverifactu.modules.php | 137 +- core/modules/modAutoverifactu.class.php | 1270 +++---- ...actu_AutoverifactuFreezeInvoices.class.php | 676 ++-- css/admin.css.php | 50 +- css/selector_status.css.php | 84 +- js/autoverifactu.js.php | 212 +- lib/autoverifactu.lib.php | 378 +-- lib/setup.lib.php | 58 +- lib/validation.lib.php | 1101 ++++--- lib/verifactu.lib.php | 2922 ++++++++--------- 16 files changed, 4224 insertions(+), 4260 deletions(-) diff --git a/admin/about.php b/admin/about.php index f760406..be51f6e 100755 --- a/admin/about.php +++ b/admin/about.php @@ -34,7 +34,7 @@ // Access control if (!$user->admin) { - accessforbidden(); + accessforbidden(); } // Parameters @@ -66,11 +66,11 @@ $head = autoverifactuAdminPrepareHead(); echo dol_get_fiche_head( - $head, - 'about', - $langs->trans($title), - 0, - 'autoverifactu@autoverifactu' + $head, + 'about', + $langs->trans($title), + 0, + 'autoverifactu@autoverifactu' ); // About page goes here diff --git a/admin/autodeclaration.php b/admin/autodeclaration.php index d83f4e9..18bc535 100644 --- a/admin/autodeclaration.php +++ b/admin/autodeclaration.php @@ -33,7 +33,7 @@ // Access control if (!$user->admin) { - accessforbidden(); + accessforbidden(); } // Translations @@ -52,21 +52,21 @@ * Actions */ if ($action === 'create') { - autoverifactu_set_const('AUTOVERIFACTU_RESPONSABILITY', $autodeclaration); - header('Location: ' . $_SERVER['PHP_SELF']); + autoverifactu_set_const('AUTOVERIFACTU_RESPONSABILITY', $autodeclaration); + header('Location: ' . $_SERVER['PHP_SELF']); } elseif ($action === 'delete') { - autoverifactu_set_const('AUTOVERIFACTU_RESPONSABILITY', ''); - autoverifactu_set_const('AUTOVERIFACTU_ENABLED', false); - header('Location: ' . $_SERVER['PHP_SELF']); + autoverifactu_set_const('AUTOVERIFACTU_RESPONSABILITY', ''); + autoverifactu_set_const('AUTOVERIFACTU_ENABLED', false); + header('Location: ' . $_SERVER['PHP_SELF']); } elseif ($action === 'download') { - ob_clean(); - header('Content-Type: text/html'); - header('Content-Disposition: attachment; filename="autodeclaracion.html"'); - echo $autodeclaration; - die(); + ob_clean(); + header('Content-Type: text/html'); + header('Content-Disposition: attachment; filename="autodeclaracion.html"'); + echo $autodeclaration; + die(); } elseif ($action) { - header('Location: ' . $_SERVER['PHP_SELF']); - die(); + header('Location: ' . $_SERVER['PHP_SELF']); + die(); } $action = null; @@ -91,11 +91,11 @@ $head = autoverifactuAdminPrepareHead(); echo dol_get_fiche_head( - $head, - 'autodeclaration', - $langs->trans($title), - 0, - 'autoverifactu@autoverifactu' + $head, + 'autodeclaration', + $langs->trans($title), + 0, + 'autoverifactu@autoverifactu' ); // Autodeclaration page goes here @@ -105,47 +105,47 @@ ?>
-
- -
+
+ +
-
- -
+
+ +
-
- -
- - - - - - -
-
+
+ +
+ + + + + + +
+
admin) { - accessforbidden(); + accessforbidden(); } // Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only $useFormSetup = 1; if (!class_exists('FormSetup')) { - require_once DOL_DOCUMENT_ROOT . '/core/class/html.formsetup.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formsetup.class.php'; } if (!class_exists('FormFile')) { - require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php'; } $formSetup = new FormSetup($db); @@ -85,28 +85,28 @@ ob_start(); ?>
- - - - - - - + + + + + + +
fieldAttr['type'] = 'password'; $pass_field->fieldAttr['required'] = 1; $pass_field->fieldAttr['error'] = !autoverifactuPkcs12Check( - DOL_DATA_ROOT . '/' . $cert_field->fieldValue, - getDolGlobalString('AUTOVERIFACTU_PASSWORD') + DOL_DATA_ROOT . '/' . $cert_field->fieldValue, + getDolGlobalString('AUTOVERIFACTU_PASSWORD') ); $invalid = $invalid || $pass_field->fieldAttr['error']; $formSetup->newItem('FISCAL_SECTION_TITLE')->setAsTitle(); $taxes = array( - '01' => 'IVA', - '02' => 'IPSI', - '03' => 'IGIC', - '05' => $langs->trans('Others'), + '01' => 'IVA', + '02' => 'IPSI', + '03' => 'IGIC', + '05' => $langs->trans('Others'), ); $taxField = $formSetup->newItem('AUTOVERIFACTU_TAX')->setAsSelect($taxes); @@ -164,23 +164,23 @@ class="valignmiddle inline-block linkobject hideobject" $taxField->defaultFieldValue = '01'; $regimes = array( - '01' => $langs->trans('VerifactuDetailsRegimeType01'), - '02' => $langs->trans('VerifactuDetailsRegimeType02'), - '03' => $langs->trans('VerifactuDetailsRegimeType03'), - '04' => $langs->trans('VerifactuDetailsRegimeType04'), - '05' => $langs->trans('VerifactuDetailsRegimeType05'), - '06' => $langs->trans('VerifactuDetailsRegimeType06'), - '07' => $langs->trans('VerifactuDetailsRegimeType07'), - '08' => $langs->trans('VerifactuDetailsRegimeType08'), - '09' => $langs->trans('VerifactuDetailsRegimeType09'), - '10' => $langs->trans('VerifactuDetailsRegimeType10'), - '11' => $langs->trans('VerifactuDetailsRegimeType11'), - '14' => $langs->trans('VerifactuDetailsRegimeType14'), - '15' => $langs->trans('VerifactuDetailsRegimeType15'), - '17' => $langs->trans('VerifactuDetailsRegimeType17'), - '18' => $langs->trans('VerifactuDetailsRegimeType18'), - '19' => $langs->trans('VerifactuDetailsRegimeType19'), - '20' => $langs->trans('VerifactuDetailsRegimeType20'), + '01' => $langs->trans('VerifactuDetailsRegimeType01'), + '02' => $langs->trans('VerifactuDetailsRegimeType02'), + '03' => $langs->trans('VerifactuDetailsRegimeType03'), + '04' => $langs->trans('VerifactuDetailsRegimeType04'), + '05' => $langs->trans('VerifactuDetailsRegimeType05'), + '06' => $langs->trans('VerifactuDetailsRegimeType06'), + '07' => $langs->trans('VerifactuDetailsRegimeType07'), + '08' => $langs->trans('VerifactuDetailsRegimeType08'), + '09' => $langs->trans('VerifactuDetailsRegimeType09'), + '10' => $langs->trans('VerifactuDetailsRegimeType10'), + '11' => $langs->trans('VerifactuDetailsRegimeType11'), + '14' => $langs->trans('VerifactuDetailsRegimeType14'), + '15' => $langs->trans('VerifactuDetailsRegimeType15'), + '17' => $langs->trans('VerifactuDetailsRegimeType17'), + '18' => $langs->trans('VerifactuDetailsRegimeType18'), + '19' => $langs->trans('VerifactuDetailsRegimeType19'), + '20' => $langs->trans('VerifactuDetailsRegimeType20'), ); $regimeField = $formSetup->newItem('AUTOVERIFACTU_DEFAULT_REGIME')->setAsSelect($regimes); @@ -204,24 +204,24 @@ class="valignmiddle inline-block linkobject hideobject" $invalid = $invalid || $blocklog_field->fieldAttr['error']; if ($invalid) { - $toggle->fieldAttr['disabled'] = true; - $toggle->fieldAttr['error'] = true; - - ob_start(); - - ?> -
- - - - - - - -
- fieldOverride = ob_get_clean(); + $toggle->fieldAttr['disabled'] = true; + $toggle->fieldAttr['error'] = true; + + ob_start(); + + ?> +
+ + + + + + + +
+ fieldOverride = ob_get_clean(); } $formSetup->newItem('ADVANCED_SECTION_TITLE')->setAsTitle(); @@ -234,31 +234,31 @@ class="valignmiddle inline-block linkobject hideobject" */ if ($action === 'update' && !empty($user->admin)) { - autoverifactuSetupPost(); + autoverifactuSetupPost(); - header('Location: ' . $_SERVER['PHP_SELF']); + header('Location: ' . $_SERVER['PHP_SELF']); } elseif ($action === 'upload' && !empty($user->admin)) { - $filepath = autoverifactuUploadCert(); - - if ($filepath) { - $filepath = str_replace(DOL_DATA_ROOT . '/', '', $filepath); - autoverifactu_set_const('AUTOVERIFACTU_CERT', $filepath); - $cert_field->fieldValue = $filepath; - header('Location: ' . $_SERVER['PHP_SELF']); - } else { - dol_syslog('Unable to upload the user cert file', LOG_ERR); - autoverifactu_set_const('AUTOVERIFACTU_CERT', null); - - http_response_code(400); - header('Location: ' . $_SERVER['PHP_SELF'] . '?uploaderror=1'); - } + $filepath = autoverifactuUploadCert(); + + if ($filepath) { + $filepath = str_replace(DOL_DATA_ROOT . '/', '', $filepath); + autoverifactu_set_const('AUTOVERIFACTU_CERT', $filepath); + $cert_field->fieldValue = $filepath; + header('Location: ' . $_SERVER['PHP_SELF']); + } else { + dol_syslog('Unable to upload the user cert file', LOG_ERR); + autoverifactu_set_const('AUTOVERIFACTU_CERT', null); + + http_response_code(400); + header('Location: ' . $_SERVER['PHP_SELF'] . '?uploaderror=1'); + } } $certpath = getDolGlobalString('AUTOVERIFACTU_CERT'); if (!is_file(DOL_DATA_ROOT . '/' . $certpath)) { - autoverifactu_set_const('AUTOVERIFACTU_CERT', ''); - $cert_field->fieldValue = ''; - $cert_field->fieldAttr['error'] = true; + autoverifactu_set_const('AUTOVERIFACTU_CERT', ''); + $cert_field->fieldValue = ''; + $cert_field->fieldAttr['error'] = true; } $action = 'edit'; @@ -283,58 +283,58 @@ class="valignmiddle inline-block linkobject hideobject" $head = autoverifactuAdminPrepareHead(); echo dol_get_fiche_head( - $head, - 'settings', - $langs->trans($title), - -1, - 'autoverifactu@autoverifactu', + $head, + 'settings', + $langs->trans($title), + -1, + 'autoverifactu@autoverifactu', ); // Setup page goes here echo '' . $langs->trans('AutoverifactuSetupPage') . '

'; if (!empty($formSetup->items)) { - echo '
'; - echo $formSetup->generateOutput(true); - echo '
'; + echo '
'; + echo $formSetup->generateOutput(true); + echo '
'; } if (empty($setupnotempty)) { - echo '
'.$langs->trans('NothingToSetup'); + echo '
'.$langs->trans('NothingToSetup'); } $formfile->form_attach_new_file( - $_SERVER["PHP_SELF"] . '?action=upload', - $langs->trans('UploadCertificate'), - 0, - 0, - 1, - 50, - null, - '', - 1, - '', - 0, - 'autoverifactu-certupload', - '.p12', - '', - 0, - 0, - 1, - 0 + $_SERVER["PHP_SELF"] . '?action=upload', + $langs->trans('UploadCertificate'), + 0, + 0, + 1, + 50, + null, + '', + 1, + '', + 0, + 'autoverifactu-certupload', + '.p12', + '', + 0, + 0, + 1, + 0 ); // Page end echo dol_get_fiche_end(); ?> - + close(); diff --git a/ajax/dismiss_notice.php b/ajax/dismiss_notice.php index 19d88e5..be7923c 100644 --- a/ajax/dismiss_notice.php +++ b/ajax/dismiss_notice.php @@ -23,25 +23,25 @@ */ if (!defined('NOTOKENRENEWAL')) { - define('NOTOKENRENEWAL', 1); // Disables token renewal + define('NOTOKENRENEWAL', 1); // Disables token renewal } if (!defined('NOREQUIREMENU')) { - define('NOREQUIREMENU', '1'); + define('NOREQUIREMENU', '1'); } if (!defined('NOREQUIREHTML')) { - define('NOREQUIREHTML', '1'); + define('NOREQUIREHTML', '1'); } if (!defined('NOREQUIREAJAX')) { - define('NOREQUIREAJAX', '1'); + define('NOREQUIREAJAX', '1'); } // if (!defined('NOREQUIRESOC')) { // define('NOREQUIRESOC', '1'); // } if (!defined('NOCSRFCHECK')) { - define('NOCSRFCHECK', '1'); + define('NOCSRFCHECK', '1'); } if (!defined('NOREQUIREHTML')) { - define('NOREQUIREHTML', '1'); + define('NOREQUIREHTML', '1'); } @@ -62,7 +62,7 @@ // Security check if (!$user->admin) { - accessforbidden(); + accessforbidden(); } /* @@ -73,12 +73,12 @@ $dismissed = getDolGlobalString('AUTOVERIFACTU_DISMISSED_NOTICES', ''); $dismissed = array_filter(array_map('trim', explode(',', $dismissed)), function ($t) use ($tag) { - return $t && $t !== $tag; + return $t && $t !== $tag; }); if (!in_array($tag, $dismissed, true)) { - $dismissed[] = $tag; - autoverifactu_set_const('AUTOVERIFACTU_DISMISSED_NOTICES', implode(',', $dismissed), $entity); + $dismissed[] = $tag; + autoverifactu_set_const('AUTOVERIFACTU_DISMISSED_NOTICES', implode(',', $dismissed), $entity); } $db->close(); diff --git a/class/actions_autoverifactu.class.php b/class/actions_autoverifactu.class.php index c426f8d..3a744f8 100644 --- a/class/actions_autoverifactu.class.php +++ b/class/actions_autoverifactu.class.php @@ -36,535 +36,532 @@ */ class ActionsAutoverifactu extends CommonHookActions { - /** - * @var DoliDB Database handler. - */ - public $db; - - /** - * @var string Error code (or message) - */ - public $error = ''; - - /** - * @var string[] Errors. - */ - public $errors = array(); - - - /** - * @var mixed[] Hook results. Propagated to $hookmanager->resArray for later reuse. - */ - public $results = array(); - - /** - * @var ?string String displayed by executeHook() immediately after return. - */ - public $resprints; - - /** - * @var int Priority of hook (50 is used if value is not defined). - */ - public $priority; - - - /** - * Constructor - * - * @param DoliDB $db Database handler. - */ - public function __construct($db) - { - $this->db = $db; - - } - - /** - * Overload the doActions function : replacing the parent's function with the one below - * - * @param array $parameters Hook metadata (context, etc...) - * @param CommonObject $object The object to process (an invoice if you are - * in invoice module, a propale in propale's module, etc...) - * @param ?string $action Current action (if set). Generally create or edit or null - * - * @return int Return integer < 0 on error, 0 on success, 1 to replace - * standard code - */ - public function doActions($parameters, &$object, &$action) - { - - global $langs, $mysoc, $dolibarr_main_url_root; - - - if($parameters['currentcontext'] ==='invoicelist'){ - //añade estilo a los estados de verifactu. - echo ''; - } - - if ($parameters['currentcontext'] === 'invoicecard') { - switch ($action) { - case 'verifactu': - //verificacion de factura enviada a verifactu - $result = autoverifactuIntegrityCheck($object); - if (!$result) { - $this->errors[] = $langs->trans('BlockedLogNotFound'); - } elseif ($result < 0) { - $this->errors[] = $langs->trans('InconsistentInvoiceData'); - } - // url de verificacion en caso de test o production. - $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); - $base_url = $testMode ? VERIFACTU_TEST_COLLATION_BASE_URL : VERIFACTU_COLLATION_BASE_URL; - $endpoint = '/wlpl/TIKE-CONT/ValidarQR'; - //en caso de tener IRPF hay que quitarselo ya que en verifactu no hay que tenerlo en cuenta - // por ello le sumo el irpf al total - $query = http_build_query(array( - 'nif' => $mysoc->idprof1, - 'numserie' => $object->ref, - 'fecha' => date('d-m-Y', $object->date), - 'importe' => number_format($object->total_ttc - $object->total_localtax2 , 2, '.', ''), - 'formato' => 'json', - )); - $ch = curl_init(); - echo $base_url . $endpoint . '?' . $query; - curl_setopt($ch, CURLOPT_URL, $base_url . $endpoint . '?' . $query); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); - curl_setopt($ch, CURLOPT_FAILONERROR, 1); - curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12'); - $certPath = DOL_DATA_ROOT . '/' . getDolGlobalString('AUTOVERIFACTU_CERT'); - curl_setopt($ch, CURLOPT_SSLCERT, $certPath); - $certPass = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); - curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $certPass); - - $res = curl_exec($ch); - - if ($res === false) { - $this->errors[] = $langs->trans('CollationRequestError'); - } else { - $data = json_decode($res); - - if ($data->status !== 'OK') { - $this->errors[] = $langs->trans('CollationResponseError'); - - if ($data->mensaje) { - $this->errors[] = $data->mensaje; - } - } elseif (!in_array($data->mensaje, array('Factura encontrada', 'Encontrada'), true)) { - $this->errors[] = $langs->trans('NotPubliclyRegistered'); - } - } - - if (empty($this->errors)) { - $this->results[] = $langs->trans('IntegrityCheckOK'); - } - break; - case 'edit_extras': - $attribute=GETPOST("attribute","alpha"); - //evito que se editen estos campos - if( - $attribute==="verifactu_status" || - $attribute==="verifactu_hash" || - $attribute === "verifactu_error" || - $attribute === "verifactu_error_code" || - $attribute ==="verifactu_pdfLegalText" || - $attribute==="VerifactuTimeStamp" - ){ - $this->errors[] = $langs->trans('NotEdit'); - $action = ''; - - } - break; - case 'add': - if(in_array($object->type,array(Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE),true)){ - $rectificationType=GETPOST("options_verifactu_rectification_type","alpha"); - - if(empty($rectificationType)){ - $this->errors[] = $langs->trans('RectificationTypeRequired'); - header('Location: '.$_SERVER['PHP_SELF'].'?action=create'); - } - } - - break; - case 'verifactuResend': - //esta accion se da cuando una factura ha tenido un error y se quiere reenviar unavez subsanado el error - $now=new DateTimeImmutable('now',new DateTimeZone('Europe/Madrid')); - //compruebo que el a pasado el tiempo de espera par la proxima peticion de la api - if($now->getTimestamp()load('autoverifactu@autoverifactu'); - $this->errors[] = $langs->trans('notToDoList',getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); - return 0; - }else if(in_array($object->array_options['options_verifactu_status'],array("2","4","5"),true)){ - //en caso de poder enviarla lo envio - $result = autoverifactuRegisterInvoice($object, $action); - if ($result <= 0) { - if (!empty($object->errors)) { - $this->errors = array_merge($this->errors, (array) $object->errors); - }else{ - $this->errors[] = $langs->trans('RecordCreationFail'); - } - } - return $result; - } - break; - } - } elseif ($parameters['currentcontext'] === 'admincompany') { - if ($action === 'update' && autoverifactuEnabled()) { - $forbidden = $mysoc->nom !== GETPOST('name') - || $mysoc->idprof1 !== GETPOST('siren'); - if ($forbidden) { - $_POST['name'] = $mysoc->nom; - $_POST['siren'] = $mysoc->idprof1; - $this->errors[] = $langs->trans('UpdateDisabledBy'); - $action = 'skip'; - } - } - } - if (count($this->errors)) { - return -1; - } elseif (count($this->results)) { - setEventMessages($this->resprints ?? '', $this->results, 'mesgs'); - return 1; - } - } - - /** - * Execute action before PDF (document) creation - * - * @param array $parameters Array of parameters. - * @param CommonObject $object Object output on PDF. - * @param string $action 'add', 'update', 'view'. - * - * @return int Return integer <0 if KO, - * =0 if OK but we want to process standard actions too, - * >0 if OK and we want to replace standard actions. - */ - public function beforePDFCreation($parameters, &$object, &$action) - { - //?No entiendo por que regeneras el archivo xml. Una vez enviado y guardado es mejor no volver a generar. - - /* if ( - $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - ) { - $result = autoverifactuCheckInvoiceImmutableXML($object, 'alta'); - - if ($result < 0) { - return $result; - } - - if ($object->status >= Facture::STATUS_CLOSED) { - $result = autoverifactuCheckInvoiceImmutableXML($object, 'anulacion'); - - if (!$result < 0) { - return $result; - } - } - }*/ - - return 0; - } - - /** - * Execute action after PDF (document) header creation. Writes the QR code before the - * invoice body is opened. - * - * @param array $parameters Array of parameters. - * @param PDFCT &$pdfhandler Object output on PDF. - * @param string $action 'add', 'update', 'view'. - * - * @return int Return always 0. - * Overwrites the hookmanager results array - */ - public function printUnderHeaderPDFline($parameters, &$pdfhandler) - { - global $mysoc; - $object = $parameters['object']; - $modelpdf = $object->model_pdf; - if ( - $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - && $modelpdf !== "Autoverifactu" //en caso de que no tenga la plantilla autoverifactu que ya incluye el QR - ) { - $pdf = &$parameters['pdf']; - - // url de verificacion en caso de test o production. - $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); - $base_url = $testMode ? VERIFACTU_TEST_COLLATION_BASE_URL : VERIFACTU_COLLATION_BASE_URL; - $endpoint = '/wlpl/TIKE-CONT/ValidarQR'; - $query = http_build_query(array( - 'nif' => $mysoc->idprof1, - 'numserie' => $object->ref, - 'fecha' => date('d-m-Y', $object->date), - 'importe' => number_format($object->total_ttc - $object->total_localtax2, 2, '.', ''), - )); - //El código «QR» deberá tener un tamaño entre 30x30 y 40x40 milímetros y seguir las especificaciones de la norma ISO/IEC 18004:2015 - //A este respecto, se deben mantener como mínimo 2 milímetros de espacio vacío (en blanco) alrededor de los cuatro lados del código «QR», recomendándose que sean 6 milímetros. - //La presentación del código «QR» incluirá también un texto que siempre deberá ir precediéndolo: «QR tributario:», y que se situará encima del propio código «QR» - // (preferiblemente centrado con respecto a este), de manera que sirva para identificarlo y distinguirlo de otros posibles códigos «QR» que pudiera contener la factura para otros cometidos. - $pdf->setTopMargin($pdfhandler->tab_top -5); - $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); - - $pdf->write2DBarcode( - $base_url . $endpoint . '?' . $query, - 'QRCODE,M', - $pdfhandler->marge_gauche, - $pdfhandler->tab_top-1 , - 32, - 32, - array( - 'border' => false, - 'padding' => 2, - 'fgcolor' => array(25, 25, 25), - 'bgcolor' => array(255, 255, 255), //margen color blanco con padding 2mm - 'module_width' => 1, - 'module_height' => 1, - ), - 30, - ); - $pdf->setTopMargin($pdfhandler->tab_top + 32); - $pdf->MultiCell(30, 10, 'VERI*FACTU', 0, 'C', 0, 1); - $this->results = array('extra_under_address_shift' => 40); - } - - return 0; - } - - - /** - * Execute action on card page buttons render. If it is a facture page, - * it adds a "verifactu" button to the row. - * - * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of the page. - * @param string $action Global action. - * - * @return null Empty response. The button - * html is echoed to the output - * buffer. - */ - public function addMoreActionsButtons($parameters, &$object, $action) - { - global $langs; - if ( - $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - && $object->array_options['options_verifactu_status'] === '1' - ) { - echo dolGetButtonAction( - $langs->trans('CheckIntegrity'), - 'Veri*Factu', - 'default', - $_SERVER['PHP_SELF'] . '?action=verifactu&token=' . newToken() . '&id=' . $object->id, - '', - 1, - array( - 'attr' => array( - 'class' => 'classfortooltip', - 'title' => '' - ), - ) - ); - } - //Boton para mostrar los errores de factura - if( $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - && $object->array_options['options_verifactu_status'] === '4' - ){ - echo dolGetButtonAction( - $langs->trans('fixErrors'), - $langs->trans('fixErrors'), - 'default', - $_SERVER['PHP_SELF'] . '?action=fixErrors&token=' . newToken() . '&id=' . $object->id, - '', - 1, - array( - 'attr' => array( - 'class' => 'classfortooltip', - 'title' => '' - ), - ) - ); - } - //permitir reenviar la facturas con errores - if( $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - && in_array($object->array_options['options_verifactu_status'], array("2","4","5"),true) - ){ - echo dolGetButtonAction( - $langs->trans('VerifactuResend'), - $langs->trans('VerifactuResend'), - 'default', - $_SERVER['PHP_SELF'] . '?action=verifactuResend&token=' . newToken() . '&id=' . $object->id, - '', - 1, - array( - 'attr' => array( - 'class' => 'classfortooltip', - 'title' => '' - ), - ) - ); - } - } - - /** - * Execute action on each card page buttons render. If it is a facture page, - * then check userRights for each button based on the button action and - * the state of the invoice. - * - * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of - * the page. - * @param string $action Global action. - * - * @return int<0,1> 1 if button has been overwrited, - * 0 otherwise. - */ - public function dolGetButtonAction(&$parameters, $object, $action) - { - global $langs; - - if ( - $object->element === 'facture' - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - ) { - $url = parse_url($parameters['url']); - parse_str($url['query'] ?? '', $query); - - $action = $query['action'] ?? null; - - if ( - $object->status > Facture::STATUS_DRAFT - && in_array($action, array('modif', 'reopen', 'delete'), true) - && !empty($parameters['userRight']) - ) { - - $label = $langs->trans('DisabledBy'); - - $button = dolGetButtonAction( - $label, - $parameters['html'], - $parameters['actionType'], - '', - $parameters['id'], - 0, - $parameters['params'] - ); - - $this->resprints = $button; - return 1; - } elseif ($object->status == Facture::STATUS_DRAFT && $action === 'valid') { - $object->fetch_thirdparty(); - $thirdparty = $object->thirdparty; - $valid_id = $thirdparty->idprof1 && $thirdparty->id_prof_check(1, $thirdparty); - - if ( - !$valid_id - && !$thirdparty->tva_intra - && !autoverifactuIsPosInvoice($object) - && !empty($parameters['userRight']) - ) { - $label = $langs->trans('ThirdpartyIdProfRequired'); - - $button = dolGetButtonAction( - $label, - $parameters['html'], - $parameters['actionType'], - '', - $parameters['id'], - 0, - $parameters['params'] - ); - - $this->resprints = $button; - return 1; - } - - //$object->fetch_lines(); - - /* Lo que limita es el numero de diferentes tipos de taxas - las lineas con las mismas tipos de taxas se deben de sumar - - if (count($object->lines) > 12 && !empty($parameters['userRight'])) { - $label = $langs->trans('MaxInvoiceLines'); - $button = dolGetButtonAction( - $label, - $parameters['html'], - $parameters['actionType'], - '', - $parameters['id'], - 0, - $parameters['params'] - ); - - $this->resprints = $button; - return 1; - } */ - } - } - } - - public function formObjectOptions($parameters, $object, $action) - { - - global $extrafields, $langs, $db ; - - - if ($parameters['currentcontext'] !== 'invoicecard' || $object->element !== 'facture') { - return; - } - - if($parameters['currentcontext'] === 'invoicecard' && $action==="fixErrors" && $object->id>0) { - //accion de mostrar los erroes y una explicacion - require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php'; - $langs->load('autoverifactu@autoverifactu'); - $form = new Form($db); - $formquestion; - - if($object->array_options['options_verifactu_error_code'] === "2001" ){ - //El NIF del bloque Destinatarios no está identificado en el censo de la AEAT. - $message = $langs->trans("Errorcode2001",$object->thirdparty->idprof1 ) ; - $parametros = $_GET; - $parametros['id'] = $object->id; - $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; - $this->formAlert($message,$url); - }else{ - //los demas errores en teoria no deberian producirse porque la aplicación - //daria error y no enviaria la petición - $message= $langs->trans("ErrorCodeErrorAplication"); - $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; - $this->formAlert($message,$url); - } - return 0; - } - - if ( - !in_array( - $object->type, - array( - Facture::TYPE_REPLACEMENT, - Facture::TYPE_CREDIT_NOTE - ), - true - ) && $object->id !== null // never hide the field for invoice creation forms - // && $action === 'edit_extras' - ) { - //$extrafields->attributes['facture']['list']['verifactu_rectification_type'] = '0'; - } - //css para ocultar de los campos adjuntos el icono de editar - print ' + /** + * @var DoliDB Database handler. + */ + public $db; + + /** + * @var string Error code (or message) + */ + public $error = ''; + + /** + * @var string[] Errors. + */ + public $errors = array(); + + + /** + * @var mixed[] Hook results. Propagated to $hookmanager->resArray for later reuse. + */ + public $results = array(); + + /** + * @var ?string String displayed by executeHook() immediately after return. + */ + public $resprints; + + /** + * @var int Priority of hook (50 is used if value is not defined). + */ + public $priority; + + + /** + * Constructor + * + * @param DoliDB $db Database handler. + */ + public function __construct($db) + { + $this->db = $db; + } + + /** + * Overload the doActions function : replacing the parent's function with the one below + * + * @param array $parameters Hook metadata (context, etc...) + * @param CommonObject $object The object to process (an invoice if you are + * in invoice module, a propale in propale's module, etc...) + * @param ?string $action Current action (if set). Generally create or edit or null + * + * @return int Return integer < 0 on error, 0 on success, 1 to replace + * standard code + */ + public function doActions($parameters, &$object, &$action) + { + + global $langs, $mysoc, $dolibarr_main_url_root; + + + if ($parameters['currentcontext'] ==='invoicelist') { + //añade estilo a los estados de verifactu. + echo ''; + } + + if ($parameters['currentcontext'] === 'invoicecard') { + switch ($action) { + case 'verifactu': + //verificacion de factura enviada a verifactu + $result = autoverifactuIntegrityCheck($object); + if (!$result) { + $this->errors[] = $langs->trans('BlockedLogNotFound'); + } elseif ($result < 0) { + $this->errors[] = $langs->trans('InconsistentInvoiceData'); + } + // url de verificacion en caso de test o production. + $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); + $base_url = $testMode ? VERIFACTU_TEST_COLLATION_BASE_URL : VERIFACTU_COLLATION_BASE_URL; + $endpoint = '/wlpl/TIKE-CONT/ValidarQR'; + //en caso de tener IRPF hay que quitarselo ya que en verifactu no hay que tenerlo en cuenta + // por ello le sumo el irpf al total + $query = http_build_query(array( + 'nif' => $mysoc->idprof1, + 'numserie' => $object->ref, + 'fecha' => date('d-m-Y', $object->date), + 'importe' => number_format($object->total_ttc - $object->total_localtax2, 2, '.', ''), + 'formato' => 'json', + )); + $ch = curl_init(); + echo $base_url . $endpoint . '?' . $query; + curl_setopt($ch, CURLOPT_URL, $base_url . $endpoint . '?' . $query); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_FAILONERROR, 1); + curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12'); + $certPath = DOL_DATA_ROOT . '/' . getDolGlobalString('AUTOVERIFACTU_CERT'); + curl_setopt($ch, CURLOPT_SSLCERT, $certPath); + $certPass = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); + curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $certPass); + + $res = curl_exec($ch); + + if ($res === false) { + $this->errors[] = $langs->trans('CollationRequestError'); + } else { + $data = json_decode($res); + + if ($data->status !== 'OK') { + $this->errors[] = $langs->trans('CollationResponseError'); + + if ($data->mensaje) { + $this->errors[] = $data->mensaje; + } + } elseif (!in_array($data->mensaje, array('Factura encontrada', 'Encontrada'), true)) { + $this->errors[] = $langs->trans('NotPubliclyRegistered'); + } + } + + if (empty($this->errors)) { + $this->results[] = $langs->trans('IntegrityCheckOK'); + } + break; + case 'edit_extras': + $attribute=GETPOST("attribute", "alpha"); + //evito que se editen estos campos + if ( + $attribute==="verifactu_status" || + $attribute==="verifactu_hash" || + $attribute === "verifactu_error" || + $attribute === "verifactu_error_code" || + $attribute ==="verifactu_pdfLegalText" || + $attribute==="VerifactuTimeStamp" + ) { + $this->errors[] = $langs->trans('NotEdit'); + $action = ''; + } + break; + case 'add': + if (in_array($object->type, array(Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE), true)) { + $rectificationType=GETPOST("options_verifactu_rectification_type", "alpha"); + + if (empty($rectificationType)) { + $this->errors[] = $langs->trans('RectificationTypeRequired'); + header('Location: '.$_SERVER['PHP_SELF'].'?action=create'); + } + } + + break; + case 'verifactuResend': + //esta accion se da cuando una factura ha tenido un error y se quiere reenviar unavez subsanado el error + $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + //compruebo que el a pasado el tiempo de espera par la proxima peticion de la api + if ($now->getTimestamp()load('autoverifactu@autoverifactu'); + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + return 0; + } elseif (in_array($object->array_options['options_verifactu_status'], array("2","4","5"), true)) { + //en caso de poder enviarla lo envio + $result = autoverifactuRegisterInvoice($object, $action); + if ($result <= 0) { + if (!empty($object->errors)) { + $this->errors = array_merge($this->errors, (array) $object->errors); + } else { + $this->errors[] = $langs->trans('RecordCreationFail'); + } + } + return $result; + } + break; + } + } elseif ($parameters['currentcontext'] === 'admincompany') { + if ($action === 'update' && autoverifactuEnabled()) { + $forbidden = $mysoc->nom !== GETPOST('name') + || $mysoc->idprof1 !== GETPOST('siren'); + if ($forbidden) { + $_POST['name'] = $mysoc->nom; + $_POST['siren'] = $mysoc->idprof1; + $this->errors[] = $langs->trans('UpdateDisabledBy'); + $action = 'skip'; + } + } + } + if (count($this->errors)) { + return -1; + } elseif (count($this->results)) { + setEventMessages($this->resprints ?? '', $this->results, 'mesgs'); + return 1; + } + } + + /** + * Execute action before PDF (document) creation + * + * @param array $parameters Array of parameters. + * @param CommonObject $object Object output on PDF. + * @param string $action 'add', 'update', 'view'. + * + * @return int Return integer <0 if KO, + * =0 if OK but we want to process standard actions too, + * >0 if OK and we want to replace standard actions. + */ + public function beforePDFCreation($parameters, &$object, &$action) + { + //?No entiendo por que regeneras el archivo xml. Una vez enviado y guardado es mejor no volver a generar. + + /* if ( + $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + ) { + $result = autoverifactuCheckInvoiceImmutableXML($object, 'alta'); + + if ($result < 0) { + return $result; + } + + if ($object->status >= Facture::STATUS_CLOSED) { + $result = autoverifactuCheckInvoiceImmutableXML($object, 'anulacion'); + + if (!$result < 0) { + return $result; + } + } + }*/ + + return 0; + } + + /** + * Execute action after PDF (document) header creation. Writes the QR code before the + * invoice body is opened. + * + * @param array $parameters Array of parameters. + * @param PDFCT &$pdfhandler Object output on PDF. + * @param string $action 'add', 'update', 'view'. + * + * @return int Return always 0. + * Overwrites the hookmanager results array + */ + public function printUnderHeaderPDFline($parameters, &$pdfhandler) + { + global $mysoc; + $object = $parameters['object']; + $modelpdf = $object->model_pdf; + if ( + $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + && $modelpdf !== "Autoverifactu" //en caso de que no tenga la plantilla autoverifactu que ya incluye el QR + ) { + $pdf = &$parameters['pdf']; + + // url de verificacion en caso de test o production. + $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); + $base_url = $testMode ? VERIFACTU_TEST_COLLATION_BASE_URL : VERIFACTU_COLLATION_BASE_URL; + $endpoint = '/wlpl/TIKE-CONT/ValidarQR'; + $query = http_build_query(array( + 'nif' => $mysoc->idprof1, + 'numserie' => $object->ref, + 'fecha' => date('d-m-Y', $object->date), + 'importe' => number_format($object->total_ttc - $object->total_localtax2, 2, '.', ''), + )); + //El código «QR» deberá tener un tamaño entre 30x30 y 40x40 milímetros y seguir las especificaciones de la norma ISO/IEC 18004:2015 + //A este respecto, se deben mantener como mínimo 2 milímetros de espacio vacío (en blanco) alrededor de los cuatro lados del código «QR», recomendándose que sean 6 milímetros. + //La presentación del código «QR» incluirá también un texto que siempre deberá ir precediéndolo: «QR tributario:», y que se situará encima del propio código «QR» + // (preferiblemente centrado con respecto a este), de manera que sirva para identificarlo y distinguirlo de otros posibles códigos «QR» que pudiera contener la factura para otros cometidos. + $pdf->setTopMargin($pdfhandler->tab_top -5); + $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); + + $pdf->write2DBarcode( + $base_url . $endpoint . '?' . $query, + 'QRCODE,M', + $pdfhandler->marge_gauche, + $pdfhandler->tab_top-1, + 32, + 32, + array( + 'border' => false, + 'padding' => 2, + 'fgcolor' => array(25, 25, 25), + 'bgcolor' => array(255, 255, 255), //margen color blanco con padding 2mm + 'module_width' => 1, + 'module_height' => 1, + ), + 30, + ); + $pdf->setTopMargin($pdfhandler->tab_top + 32); + $pdf->MultiCell(30, 10, 'VERI*FACTU', 0, 'C', 0, 1); + $this->results = array('extra_under_address_shift' => 40); + } + + return 0; + } + + + /** + * Execute action on card page buttons render. If it is a facture page, + * it adds a "verifactu" button to the row. + * + * @param array $parameters Array of parameters. + * @param CommonObect &$object Instance of the owner object of the page. + * @param string $action Global action. + * + * @return null Empty response. The button + * html is echoed to the output + * buffer. + */ + public function addMoreActionsButtons($parameters, &$object, $action) + { + global $langs; + if ( + $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + && $object->array_options['options_verifactu_status'] === '1' + ) { + echo dolGetButtonAction( + $langs->trans('CheckIntegrity'), + 'Veri*Factu', + 'default', + $_SERVER['PHP_SELF'] . '?action=verifactu&token=' . newToken() . '&id=' . $object->id, + '', + 1, + array( + 'attr' => array( + 'class' => 'classfortooltip', + 'title' => '' + ), + ) + ); + } + //Boton para mostrar los errores de factura + if ( $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + && $object->array_options['options_verifactu_status'] === '4' + ) { + echo dolGetButtonAction( + $langs->trans('fixErrors'), + $langs->trans('fixErrors'), + 'default', + $_SERVER['PHP_SELF'] . '?action=fixErrors&token=' . newToken() . '&id=' . $object->id, + '', + 1, + array( + 'attr' => array( + 'class' => 'classfortooltip', + 'title' => '' + ), + ) + ); + } + //permitir reenviar la facturas con errores + if ( $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + && in_array($object->array_options['options_verifactu_status'], array("2","4","5"), true) + ) { + echo dolGetButtonAction( + $langs->trans('VerifactuResend'), + $langs->trans('VerifactuResend'), + 'default', + $_SERVER['PHP_SELF'] . '?action=verifactuResend&token=' . newToken() . '&id=' . $object->id, + '', + 1, + array( + 'attr' => array( + 'class' => 'classfortooltip', + 'title' => '' + ), + ) + ); + } + } + + /** + * Execute action on each card page buttons render. If it is a facture page, + * then check userRights for each button based on the button action and + * the state of the invoice. + * + * @param array $parameters Array of parameters. + * @param CommonObect &$object Instance of the owner object of + * the page. + * @param string $action Global action. + * + * @return int<0,1> 1 if button has been overwrited, + * 0 otherwise. + */ + public function dolGetButtonAction(&$parameters, $object, $action) + { + global $langs; + + if ( + $object->element === 'facture' + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + ) { + $url = parse_url($parameters['url']); + parse_str($url['query'] ?? '', $query); + + $action = $query['action'] ?? null; + + if ( + $object->status > Facture::STATUS_DRAFT + && in_array($action, array('modif', 'reopen', 'delete'), true) + && !empty($parameters['userRight']) + ) { + $label = $langs->trans('DisabledBy'); + + $button = dolGetButtonAction( + $label, + $parameters['html'], + $parameters['actionType'], + '', + $parameters['id'], + 0, + $parameters['params'] + ); + + $this->resprints = $button; + return 1; + } elseif ($object->status == Facture::STATUS_DRAFT && $action === 'valid') { + $object->fetch_thirdparty(); + $thirdparty = $object->thirdparty; + $valid_id = $thirdparty->idprof1 && $thirdparty->id_prof_check(1, $thirdparty); + + if ( + !$valid_id + && !$thirdparty->tva_intra + && !autoverifactuIsPosInvoice($object) + && !empty($parameters['userRight']) + ) { + $label = $langs->trans('ThirdpartyIdProfRequired'); + + $button = dolGetButtonAction( + $label, + $parameters['html'], + $parameters['actionType'], + '', + $parameters['id'], + 0, + $parameters['params'] + ); + + $this->resprints = $button; + return 1; + } + + //$object->fetch_lines(); + + /* Lo que limita es el numero de diferentes tipos de taxas + las lineas con las mismas tipos de taxas se deben de sumar + + if (count($object->lines) > 12 && !empty($parameters['userRight'])) { + $label = $langs->trans('MaxInvoiceLines'); + $button = dolGetButtonAction( + $label, + $parameters['html'], + $parameters['actionType'], + '', + $parameters['id'], + 0, + $parameters['params'] + ); + + $this->resprints = $button; + return 1; + } */ + } + } + } + + public function formObjectOptions($parameters, $object, $action) + { + + global $extrafields, $langs, $db ; + + + if ($parameters['currentcontext'] !== 'invoicecard' || $object->element !== 'facture') { + return; + } + + if ($parameters['currentcontext'] === 'invoicecard' && $action==="fixErrors" && $object->id>0) { + //accion de mostrar los erroes y una explicacion + require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php'; + $langs->load('autoverifactu@autoverifactu'); + $form = new Form($db); + $formquestion; + + if ($object->array_options['options_verifactu_error_code'] === "2001" ) { + //El NIF del bloque Destinatarios no está identificado en el censo de la AEAT. + $message = $langs->trans("Errorcode2001", $object->thirdparty->idprof1); + $parametros = $_GET; + $parametros['id'] = $object->id; + $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $this->formAlert($message, $url); + } else { + //los demas errores en teoria no deberian producirse porque la aplicación + //daria error y no enviaria la petición + $message= $langs->trans("ErrorCodeErrorAplication"); + $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $this->formAlert($message, $url); + } + return 0; + } + + if ( + !in_array( + $object->type, + array( + Facture::TYPE_REPLACEMENT, + Facture::TYPE_CREDIT_NOTE + ), + true + ) && $object->id !== null // never hide the field for invoice creation forms + // && $action === 'edit_extras' + ) { + //$extrafields->attributes['facture']['list']['verifactu_rectification_type'] = '0'; + } + //css para ocultar de los campos adjuntos el icono de editar + print ' '; - - - } - - //funcion que genera una ventana emergente con el mensaje parado por parametro con un btn de aceptar, - // que te lleva a la url pasada por parametro. - private function formAlert($message,$url){ - ?> - - - + + + db = $db; - } + public function __construct($db) + { + $this->db = $db; + } - /* - Funcion para obtener las facturas con el estado en cola (3) cuando se pueda enviar - a la api una peticion porque el tiempo de espera ya a pasado. - */ - public function processMassiveQueue() - { - global $conf, $langs; - $langs->load('autoverifactu@autoverifactu'); - $now=new DateTimeImmutable('now',new DateTimeZone('Europe/Madrid')); - if($now->getTimestamp()db->query($sql); - if ($resql && $this->db->num_rows($resql) > 0) { - //en caso de existir facturas en cola genero un array con las facturas - $listInvoice = array(); - while ($obj = $this->db->fetch_object($resql)) { - $invoice = new Facture($this->db); - if ($invoice->fetch($obj->fk_object) > 0) { - $invoice->fetch_optionals(); - $listInvoice[] = $invoice; - } - - } - //genero el xml y las envio - $result = autoverifactuRegisterInvoiceList($listInvoice); - if ($result < 0) { - if (!empty($object->errors)) { - $this->errors = array_merge($this->errors, (array) $object->errors); - }else{ - $this->errors[] = $langs->trans('RecordCreationFail'); - } - } - return $result; - } - return 0; - } - - } -} \ No newline at end of file + /* + Funcion para obtener las facturas con el estado en cola (3) cuando se pueda enviar + a la api una peticion porque el tiempo de espera ya a pasado. + */ + public function processMassiveQueue() + { + global $conf, $langs; + $langs->load('autoverifactu@autoverifactu'); + $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + if ($now->getTimestamp()db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + //en caso de existir facturas en cola genero un array con las facturas + $listInvoice = array(); + while ($obj = $this->db->fetch_object($resql)) { + $invoice = new Facture($this->db); + if ($invoice->fetch($obj->fk_object) > 0) { + $invoice->fetch_optionals(); + $listInvoice[] = $invoice; + } + } + //genero el xml y las envio + $result = autoverifactuRegisterInvoiceList($listInvoice); + if ($result < 0) { + if (!empty($object->errors)) { + $this->errors = array_merge($this->errors, (array) $object->errors); + } else { + $this->errors[] = $langs->trans('RecordCreationFail'); + } + } + return $result; + } + return 0; + } + } +} diff --git a/core/modules/facture/doc/pdf_Autoverifactu.modules.php b/core/modules/facture/doc/pdf_Autoverifactu.modules.php index ff0cadf..7a6fc40 100644 --- a/core/modules/facture/doc/pdf_Autoverifactu.modules.php +++ b/core/modules/facture/doc/pdf_Autoverifactu.modules.php @@ -40,11 +40,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; -require_once dirname(__DIR__ , 4). '/lib/validation.lib.php'; -require_once dirname(__DIR__,4) . '/lib/autoverifactu.lib.php'; +require_once dirname(__DIR__, 4). '/lib/validation.lib.php'; +require_once dirname(__DIR__, 4) . '/lib/autoverifactu.lib.php'; -//!importante +//!importante /* @@ -135,7 +135,7 @@ public function __construct($db) $langs->loadLangs(array("main", "bills")); - + $this->db = $db; $this->name = "Autoverifactu"; $this->description = "Factura PDF plantilla Autoverifactu. Una plantilla compatible con el QR de Verifactu"; @@ -241,7 +241,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede // Load translation files required by the page $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); - + // Show Draft Watermark if ($object->statut == $object::STATUS_DRAFT && (getDolGlobalString('FACTURE_DRAFT_WATERMARK'))) { $this->watermark = getDolGlobalString('FACTURE_DRAFT_WATERMARK'); @@ -567,31 +567,31 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede } } } - + //echo "
";
-				
+
 				//verifactu_pdfLegalText
-				
 
-				if(isset($object->array_options["options_verifactu_pdfLegalText"] )){
+
+				if (isset($object->array_options["options_verifactu_pdfLegalText"])) {
 					$langs->load("autoverifactu@autoverifactu");
 					$LegalText="Texto Legal ";
 					$LegalText .= '
'.$object->array_options["options_verifactu_pdfLegalTextUser"] ; $LegalTextArray = explode(',', $object->array_options["options_verifactu_pdfLegalText"]); foreach ($LegalTextArray as $value) { - $LegalText .= '
'.$langs->trans( $value) ; + $LegalText .= '
'.$langs->trans($value); } $LegalText .= "

"; - $notetoshow = dol_concatdesc($notetoshow, $LegalText,false,true); + $notetoshow = dol_concatdesc($notetoshow, $LegalText, false, true); } // Extrafields in noteº $extranote = $this->getExtrafieldsInHtml($object, $outputlangs); - + if (!empty($extranote)) { $notetoshow = dol_concatdesc($notetoshow, $extranote); } - + if ($notetoshow) { $tab_top -= 2; @@ -1893,18 +1893,18 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output - + /* 7. Ubicación del QR en la factura - + Si se utiliza un formato de orientación vertical para organizar y disponer el contenido de la factura, el código «QR» se situará arriba de esta, próximo al margen superior, preferiblemente centrado respecto a los márgenes izquierdo y - derecho de la factura.La presentación del código «QR» incluirá también un texto que siempre deberá ir precediéndolo: - «QR tributario:», y que se situará encima del propio código «QR» (preferiblemente centrado con respecto a este), - de manera que sirva para identificarlo y distinguirlo de otros posibles códigos «QR» que pudiera contener + derecho de la factura.La presentación del código «QR» incluirá también un texto que siempre deberá ir precediéndolo: + «QR tributario:», y que se situará encima del propio código «QR» (preferiblemente centrado con respecto a este), + de manera que sirva para identificarlo y distinguirlo de otros posibles códigos «QR» que pudiera contener la factura para otros cometidos. - Además, en el caso de facturas expedidas por sistemas que emiten facturas verificables, - justo debajo del código «QR» deberá aparecer la frase «Factura verificable en la sede electrónica de la AEAT» + Además, en el caso de facturas expedidas por sistemas que emiten facturas verificables, + justo debajo del código «QR» deberá aparecer la frase «Factura verificable en la sede electrónica de la AEAT» o «VERI*FACTU», preferiblemente centrada con respecto al código «QR». Si no cabe toda la frase en una sola línea, podrán utilizarse varias líneas hasta completarla.Tanto el texto que siempre debe preceder al código «QR», como, en su caso, la frase que habrán de incluir los sistemas «VERI*FACTU» deberán tener un tipo de letra y tamaño legibles, siempre iguales o @@ -1914,62 +1914,62 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output 1. El código «QR» deberá tener un tamaño entre 30x30 y 40x40 milímetros y seguir las especificaciones de la norma ISO/IEC 18004:2015.Este rango asegura que el QR pueda ser escaneado correctamente por cualquier dispositivo. - + A este respecto, se deben mantener como mínimo 2 milímetros de espacio vacío (en blanco) alrededor de los cuatro lados - del código «QR», recomendándose que sean 6 milímetros.La presentación del código «QR» incluirá también un texto que - siempre deberá ir precediéndolo: «QR tributario:»,Además, en el caso de facturas expedidas por sistemas que emiten - facturas verificables, justo debajo del código «QR» deberá aparecer la frase «Factura verificable en la sede + del código «QR», recomendándose que sean 6 milímetros.La presentación del código «QR» incluirá también un texto que + siempre deberá ir precediéndolo: «QR tributario:»,Además, en el caso de facturas expedidas por sistemas que emiten + facturas verificables, justo debajo del código «QR» deberá aparecer la frase «Factura verificable en la sede electrónica de la AEAT» o «VERI*FACTU», preferiblemente centrada con respecto al código «QR». */ if ( - $object->element === 'facture' - && $object->status > Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - && autoverifactuEnabled() - ) { + $object->element === 'facture' + && $object->status > Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + && autoverifactuEnabled() + ) { global $mysoc; - $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); + $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); $base_url = $testMode ? VERIFACTU_TEST_COLLATION_BASE_URL : VERIFACTU_COLLATION_BASE_URL; $endpoint = '/wlpl/TIKE-CONT/ValidarQR'; - + $query = http_build_query(array( - 'nif' => $mysoc->idprof1, - 'numserie' => $object->ref, - 'fecha' => date('d-m-Y', $object->date), - 'importe' => number_format($object->total_ttc - $object->total_localtax2, 2, '.', ''), - )); - + 'nif' => $mysoc->idprof1, + 'numserie' => $object->ref, + 'fecha' => date('d-m-Y', $object->date), + 'importe' => number_format($object->total_ttc - $object->total_localtax2, 2, '.', ''), + )); + $qr_width = 36; $qr_x = ($this->page_largeur - $qr_width) / 2; $qr_y = 8; - - $pdf->SetXY($qr_x+1,3); - $pdf->SetFont('', '', $default_font_size ); - $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); + $pdf->SetXY($qr_x+1, 3); + $pdf->SetFont('', '', $default_font_size); + + $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); $pdf->write2DBarcode( - $base_url . $endpoint . '?' . $query, - 'QRCODE,M', - $qr_x, - $qr_y, - $qr_width, - $qr_width, - array( - 'border' => false, - 'padding' => 6, - 'fgcolor' => array(25, 25, 25), - 'bgcolor' => array(255, 255, 255), - 'module_width' => 1, - 'module_height' => 1, - ), - 25, - ); - - $pdf->SetXY($qr_x+1, $qr_y + $qr_width ); - $pdf->MultiCell(30, 10, 'VERI*FACTU', 0, 'C', 0, 1); - } + $base_url . $endpoint . '?' . $query, + 'QRCODE,M', + $qr_x, + $qr_y, + $qr_width, + $qr_width, + array( + 'border' => false, + 'padding' => 6, + 'fgcolor' => array(25, 25, 25), + 'bgcolor' => array(255, 255, 255), + 'module_width' => 1, + 'module_height' => 1, + ), + 25, + ); + + $pdf->SetXY($qr_x+1, $qr_y + $qr_width); + $pdf->MultiCell(30, 10, 'VERI*FACTU', 0, 'C', 0, 1); + } $pdf->SetTextColor(0, 0, 60); $pdf->SetFont('', 'B', $default_font_size + 2); @@ -1994,7 +1994,6 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $logo = $logodir.'/logos/'.$this->emetteur->logo; } if (is_readable($logo)) { - $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) } else { $pdf->SetTextColor(200, 0, 0); @@ -2048,11 +2047,11 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output } } - - - - + + + + @@ -2360,11 +2359,11 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output */ protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0, $heightforqrinvoice = 0) { - - $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0); + + $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0); - $text="En cumplimiento de la normativa de Protección de Datos le informamos que el RESPONSABLE del tratamiento de los mismos es OYR SOLUTIONS S.L. + $text="En cumplimiento de la normativa de Protección de Datos le informamos que el RESPONSABLE del tratamiento de los mismos es OYR SOLUTIONS S.L. gestionados con la FINALIDAD de expedir un presupuesto o la correspondiente factura por la compra de un presto o la prestación de alguno de nuestros servicios. La LEGITIMACIÓN se basa en la existencia de una relación comercial de compra de productos o contractual para la prestación de un servicio. Serán DESTINATARIOS de sus datos aquellas organizaciones o entidades directamente relacionadas con el Responsable, así como las Administraciones Públicas con competencia en la materia. El plazo de CONSERVACIÓN de sus datos será hasta el fin de la prestación del servicio, y una vez finalizado, hasta que se solicite su supresión por parte del interesado. Entre sus DERECHOS se encuentra el de acceder, rectificar y suprimir, así como el de oposición, limitación y portabilidad. Si tiene alguna pregunta relacionada con el cumplimiento del RGPD o la protección de datos, póngase en contacto con nuestro Responsable de Protección de Datos en el correo security@oyr.es"; diff --git a/core/modules/modAutoverifactu.class.php b/core/modules/modAutoverifactu.class.php index 32783c9..7f593c8 100644 --- a/core/modules/modAutoverifactu.class.php +++ b/core/modules/modAutoverifactu.class.php @@ -36,639 +36,639 @@ */ class modAutoverifactu extends DolibarrModules { - /** - * Constructor. Define names, constants, directories, boxes, permissions. - * - * @param DoliDB $db Database handler. - */ - public function __construct($db) - { - global $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 = 409904; - - // Key text used to identify module (for permissions, menus, etc...) - $this->rights_class = 'autoverifactu'; - - // 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 = 'financial'; - - // Module position in the family on 2 digits ('01', '10', '20', ...) - $this->module_position = '90'; - - // 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 'ModuleAutoverifactuName' not found (Autoverifactu is name of module). - $this->name = preg_replace('/^mod/i', '', get_class($this)); - - // DESCRIPTION_FLAG - // Module description, used if translation string 'ModuleAutoverifactuDesc' not found (Autoverifactu is name of module). - $this->description = 'Bridge Dolibarr bills to the vVeri*Factu system'; - // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = 'With this module activated, each validated bill will be immediatly sent to the verifactu system and freezed'; - - // Author - $this->editor_name = 'Còdec'; - $this->editor_url = 'https://www.codeccoop.org'; // Must be an external online web site - $this->editor_squarred_logo = 'logo-codec.png@autoverifactu'; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@autoverifactu' - - // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' - $this->version = '0.0.12'; - // 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 AUTOVERIFACTU 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' - // To use a supported fa-xxx css style of font awesome, use this->picto='xxx' - $this->picto = 'fa-receipt'; - - // 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' => 1, - // Set this to 1 if module has its own printing directory (core/modules/printing) - 'printing' => 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( - '/autoverifactu/css/admin.css.php', - ), - // Set this to relative path of js file if module must load a js on all pages - 'js' => array( - '/autoverifactu/js/autoverifactu.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 to 'all' - /* BEGIN MODULEBUILDER HOOKSCONTEXTS */ - 'hooks' => array( - 'admincompany', - 'invoicecard', - 'propalcard', - 'ordercard', - 'contractcard', - 'interventioncard', - 'expeditioncard', - 'pdfgeneration', - 'invoicelist', //para añadir estilos al listado de facturas - ), - /* END MODULEBUILDER HOOKSCONTEXTS */ - // Set this to 1 if features of module are opened to external users - 'moduleforexternal' => 0, - // Set this to 1 if the module provides a website template into doctemplates/websites/website_template-mytemplate - 'websitetemplates' => 0, - // Set this to 1 if the module provides a captcha driver - 'captcha' => 0 - ); - - // Data directories to create when module is enabled. - // Example: this->dirs = array("/autoverifactu/temp","/autoverifactu/subdir"); - $this->dirs = array('/autoverifactu/temp'); - - // Config pages. Put here list of php page, stored into autoverifactu/admin directory, to use to setup module. - $this->config_page_url = array('setup.php@autoverifactu'); - - // Dependencies - // A condition to hide module - $this->hidden = getDolGlobalInt('MODULE_AUTOVERIFACTU_DISABLED'); // A condition to disable module; - // List of module class names that must be enabled if this module is enabled. Example: array('always'=>array('modModuleToEnable1','modModuleToEnable2'), 'FR'=>array('modModuleToEnableFR')...) - $this->depends = array('modFacture', 'modBlockedLog'); - // List of module class names to disable if this one is disabled. Example: array('modModuleToDisable1', ...) - $this->requiredby = array(); - // List of module class names this module is in conflict with. Example: array('modModuleToDisable1', ...) - $this->conflictwith = array(); - - // The language file dedicated to your module - $this->langfiles = array('autoverifactu@autoverifactu'); - - // Prerequisites - $this->phpmin = array(8, 0); // Minimum version of PHP required by module - // $this->phpmax = array(8, 0); // Maximum version of PHP required by module - $this->need_dolibarr_version = array(20, -3); // Minimum version of Dolibarr required by module - // $this->max_dolibarr_version = array(19, -3); // Maximum version of Dolibarr required by module - $this->need_javascript_ajax = 1; - - // Messages at activation - $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','MX'='textmx'...) - $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','MX'='textmx'...) - $this->warnings_unactivation = array(); // array('ES' => 'BlockedLogAreRequiredByYourCountryLegislation'); - - // $this->automatic_activation = array('ES'=>'AutoverifactuWasAutomaticallyActivatedBecauseOfYourCountryChoice'); - - // $this->always_enabled = (isModEnabled('autoverifactu') - // && getDolGlobalString('AUTOVERIFACTU_DISABLE_NOT_ALLOWED_FOR_COUNTRY') - // && in_array((empty($mysoc->country_code) ? '' : $mysoc->country_code), explode(',', getDolGlobalString('AUTOVERIFACTU_DISABLE_NOT_ALLOWED_FOR_COUNTRY'))) - // && $this->alreadyUsed()); - - /* Constants */ - // List of particular constants to add when module is enabled (key, 'chaine', - // value, desc, visible, 'current' or 'allentities', deleteonunactive). - - - // 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 (!isModEnabled('autoverifactu')) { - $conf->autoverifactu = new stdClass(); - $conf->autoverifactu->enabled = 0; - } - - // Array to add new pages in new tabs - /* BEGIN MODULEBUILDER TABS */ - // Don't forget to deactivate/reactivate your module to test your changes - $this->tabs = array(); - - $this->dictionaries = array(); - - // Boxes/Widgets - // Add here list of php file(s) stored in autoverifactu/core/boxes that contains a class to show a widget. - $this->boxes = array(); - - - // creo crontab para ejecutar las facturas en cola - $this->cronjobs = array( - array( - 'label' => 'Procesar cola de envíos VERI*FACTU', - 'jobtype' => 'method', - 'class' => '/autoverifactu/class/verifactuqueue.class.php', - 'objectname' => 'VerifactuQueue', - 'method' => 'processMassiveQueue', - 'parameters' => '', - 'comment' => 'Revisa las facturas en cola y las envía agrupadas respetando los tiempos de la AEAT', - 'frequency' => 1, - 'unitfrequency' => 60, - 'status' => 1, - 'test' => 'isModEnabled("autoverifactu")', - 'priority' => 1, - ) - ); - - // Permissions provided by this module - $this->rights = array(); - - // Main menu entries to add - $this->menu = array(); - // $r = 0; - // Add here entries to declare new menus - // $this->menu[$r++] = array( - // 'fk_menu' => '', // Will be stored into mainmenu + leftmenu. Use '' 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' => 'Autoverifactu', - // 'prefix' => img_picto('', $this->picto, 'class="pictofixedwidth valignmiddle"'), - // 'mainmenu' => 'autoverifactu', - // 'leftmenu' => '', - // 'url' => '/autoverifactu/autoverifactuindex.php', - // 'langs' => 'autoverifactu@autoverifactu', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - // 'position' => 1000 + $r, - // 'enabled' => 'isModEnabled("autoverifactu")', // Define condition to show or hide menu entry. Use 'isModEnabled("autoverifactu")' if entry must be visible if module is enabled. - // 'perms' => '1', // Use 'perms'=>'$user->hasRight("autoverifactu", "myobject", "read")' if you want your menu with a permission rules - // 'target' => '', - // 'user' => 0, // 0=Menu for internal users, 1=external users, 2=both - // ); - } - - /** - * 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,1> 1 if OK, <=0 if KO. - */ - public function init($options = '') - { - global $db, $langs; // , $conf; - $langs->loadLangs(array('autoverifactu@autoverifactu')); - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); - dolibarr_set_const($db, 'FAC_FORCE_DATE_VALIDATION', '1', 'chaine', 0, '', 0); - dolibarr_set_const($db, 'VERIFACTU_NEXT_DELIVERY_ALLOWED', $now->getTimestamp(), 'chaine', 0, '', 0); - - // Create tables of module at module activation - // $result = $this->_load_tables('/autoverifactu/sql/'); - // if ($result < 0) { - // // Do not activate module if error 'not allowed' returned when loading module SQL queries - // // (the _load_table run sql with run_sql with the error allowed parameter set to 'default'). - // return -1; - // } - - // Create extrafields during init - include_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; - $extrafields = new ExtraFields($this->db); - //----------------------------------------Invoice ---------------------------------------- - // Tipo de rectificación en caso de que la factura sea rectificativa. - $extrafields->addExtraField( - 'verifactu_rectification_type', - 'VerifactuRectificationType', - 'select', - 1, - 2, - 'facture', - 0, - 0, - '', - array( - 'options' => array( - 'R1' => $langs->trans('VerifactuRectificationTypeR1'), - 'R2' => $langs->trans('VerifactuRectificationTypeR2'), - 'R3' => $langs->trans('VerifactuRectificationTypeR3'), - 'R4' => $langs->trans('VerifactuRectificationTypeR4'), - // 'R5' => $langs->trans('VerifactuRectificationTypeR5') - ), - ), - 0, - '', - '3', - $langs->trans('VerifactuRectificationTypeDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Fecha de operación - $extrafields->addExtraField( - 'verifactu_date_operation', - 'VerifactuDateOperation', - 'date', - 2, - 2, - 'facture', - 0, - 0, - '', - '', - 0, - '', - '3', - $langs->trans('VerifactuDateOperiationDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Campo para el almacenamiento de los textos legales para el pdf - // de la factura por el usuario. - $extrafields->addExtraField( - 'verifactu_pdfLegalTextUser', - 'pdfLegalTextUser', - 'text', - 3, - 1500, - 'facture', - 0, - 0, - '', - '', - 1, - '', - 3, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Estado de los envios a verifactu en funcion de si esta permitio o no hacer una peticion a la API - $extrafields->addExtraField( - 'verifactu_status', - 'Estado VERI*FACTU', - 'select', - 4, - 1, - 'facture', - 0, - 0, - '0', - array( - 'options' => array( - '0' => $langs->trans('verifactuStatusSelect0'), - '1' => $langs->trans('verifactuStatusSelect1'), - '2' => $langs->trans('verifactuStatusSelect2'), - '3' => $langs->trans('verifactuStatusSelect3'), - '4' => $langs->trans('verifactuStatusSelect4'), - '5' => $langs->trans('verifactuStatusSelect5'), - '6' => $langs->trans('verifactuStatusSelect6'), - '7' => $langs->trans('verifactuStatusSelect7'), - - ), - ), - 0, - '', - '1', - $langs->trans('verifactuStatusDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // campo para el almacenamiento de errores de validación de la factura. - $extrafields->addExtraField( - 'verifactu_error', - 'VerifactuError', - 'text', - 5, - 510, - 'facture', - 0, - 0, - '', - '', - 0, - '', - 3, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - //campo para el almacenamiento de los codigos de errores de validación de la factura. - $extrafields->addExtraField( - 'verifactu_error_code', - 'VerifactuErrorcode', - 'varchar', - 6, - 4, - 'facture', - 0, - 0, - '', - '', - 0, - '', - 0, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // hash verifactu - $extrafields->addExtraField( - 'verifactu_hash', - 'VerifactuHash', - 'varchar', - 10, - 255, - 'facture', - 0, - 0, - '', - '', - 0, - '', - 0, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Campo para el almacenamiento de los textos legales para el pdf de la factura. - $extrafields->addExtraField( - 'verifactu_pdfLegalText', - 'pdfLegalText', - 'text', - 11, - 1500, - 'facture', - 0, - 0, - '', - '', - 0, - '', - 0, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Timestamp de validación de la factura. - $extrafields->addExtraField( - 'verifactu_tms', - 'VerifactuTimeStamp', - 'int', - 12, - 15, - 'facture', - 0, - 0, - '0', - '', - 0, - '', - 0, - '', - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); -//----------------------------------------line ---------------------------------------- - // regimen de facturación de la línea de factura - $extrafields->addExtraField( - 'verifactu_regime_type', - 'VerifactuDetailsRegimeType', - 'select', - 1, - 2, - 'facturedet', - 0, - 0, - '01', - array( - 'options' => array( - '01' => $langs->trans('VerifactuDetailsRegimeType01'), - '02' => $langs->trans('VerifactuDetailsRegimeType02'), - '03' => $langs->trans('VerifactuDetailsRegimeType03'), - '04' => $langs->trans('VerifactuDetailsRegimeType04'), - '05' => $langs->trans('VerifactuDetailsRegimeType05'), - '06' => $langs->trans('VerifactuDetailsRegimeType06'), - '07' => $langs->trans('VerifactuDetailsRegimeType07'), - '08' => $langs->trans('VerifactuDetailsRegimeType08'), - '09' => $langs->trans('VerifactuDetailsRegimeType09'), - '10' => $langs->trans('VerifactuDetailsRegimeType10'), - '11' => $langs->trans('VerifactuDetailsRegimeType11'), - '14' => $langs->trans('VerifactuDetailsRegimeType14'), - '15' => $langs->trans('VerifactuDetailsRegimeType15'), - '17' => $langs->trans('VerifactuDetailsRegimeType17'), - '18' => $langs->trans('VerifactuDetailsRegimeType18'), - '19' => $langs->trans('VerifactuDetailsRegimeType19'), - '20' => $langs->trans('VerifactuDetailsRegimeType20'), - ), - ), - 0, - '', - '3', - $langs->trans('VerifactuDetailsRegimeTypeDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - //type of tax of the line of invoice - $extrafields->addExtraField( - 'Verifactu_Tax', - 'VerifactuTax', - 'select', - 2, - 2, - 'facturedet', - 0, - 0, - '01', - array( - 'options' => array( - '01' => $langs->trans('VerifactuTax01'), - '02' => $langs->trans('VerifactuTax02'), - '03' => $langs->trans('VerifactuTax03'), - '05' => $langs->trans('VerifactuTax05'), - ), - ), - 0, - '', - '3', - $langs->trans('VerifactuTaxDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // tipo de operación de la línea de factura - $extrafields->addExtraField( - 'verifactu_operation_type', - 'VerifactuDetailsOperationType', - 'select', - 3, - 2, - 'facturedet', - 0, - 0, - 'S1', - array( - 'options' => array( - 'S1' => $langs->trans('VerifactuDetailsOperationTypeS1'), - 'S2' => $langs->trans('VerifactuDetailsOperationTypeS2'), - 'N1' => $langs->trans('VerifactuDetailsOperationTypeN1'), - 'N2' => $langs->trans('VerifactuDetailsOperationTypeN2'), - ), - ), - 0, - '', - '3', - $langs->trans('VerifactuDetailsOperationTypeDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Tipos de excepción - $extrafields->addExtraField( - 'verifactu_tax_excemption', - 'VerifactuDetailsTaxExcemption', - 'select', - 4, - 2, - 'facturedet', - 0, - 0, - '', - array( - 'options' => array( - 'E1' => $langs->trans('VerifactuDetailsTaxExcemptionE1'), - 'E2' => $langs->trans('VerifactuDetailsTaxExcemptionE2'), - 'E3' => $langs->trans('VerifactuDetailsTaxExcemptionE3'), - 'E4' => $langs->trans('VerifactuDetailsTaxExcemptionE4'), - 'E5' => $langs->trans('VerifactuDetailsTaxExcemptionE5'), - 'E6' => $langs->trans('VerifactuDetailsTaxExcemptionE6'), - ), - ), - 0, - '', - '3', - $langs->trans('VerifactuDetailsTaxExcemptionDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); -//----------------------------------------thirdparty---------------------------------------- - // tipo de identificacion fiscal del tercero - $extrafields->addExtraField( - 'verifactu_identification_thirdparty', - 'VerifactuIdentificationThirdparty', - 'select', - 1, - 2, - 'societe', - 0, - 0, - '02', - array( - 'options' => array( - '02' => $langs->trans('VerifactuIdentificationThirdparty02'), - '03' => $langs->trans('VerifactuIdentificationThirdparty03'), - '04' => $langs->trans('VerifactuIdentificationThirdparty04'), - '05' => $langs->trans('VerifactuIdentificationThirdparty05'), - '06' => $langs->trans('VerifactuIdentificationThirdparty06'), - '07' => $langs->trans('VerifactuIdentificationThirdparty07'), - ), - ), - 1, - '', - '3', - $langs->trans('VerifactuIdentificationThirdpartyDescription'), - '', - '', - 'autoverifactu@autoverifactu', - 'isModEnabled("autoverifactu")', - ); - // Permissions - $this->remove($options); - $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,1> 1 if OK, <=0 if KO - */ - public function remove($options = '') - { - $sql = array(); - return $this->_remove($sql, $options); - } + /** + * Constructor. Define names, constants, directories, boxes, permissions. + * + * @param DoliDB $db Database handler. + */ + public function __construct($db) + { + global $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 = 409904; + + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'autoverifactu'; + + // 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 = 'financial'; + + // Module position in the family on 2 digits ('01', '10', '20', ...) + $this->module_position = '90'; + + // 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 'ModuleAutoverifactuName' not found (Autoverifactu is name of module). + $this->name = preg_replace('/^mod/i', '', get_class($this)); + + // DESCRIPTION_FLAG + // Module description, used if translation string 'ModuleAutoverifactuDesc' not found (Autoverifactu is name of module). + $this->description = 'Bridge Dolibarr bills to the vVeri*Factu system'; + // Used only if file README.md and README-LL.md not found. + $this->descriptionlong = 'With this module activated, each validated bill will be immediatly sent to the verifactu system and freezed'; + + // Author + $this->editor_name = 'Còdec'; + $this->editor_url = 'https://www.codeccoop.org'; // Must be an external online web site + $this->editor_squarred_logo = 'logo-codec.png@autoverifactu'; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@autoverifactu' + + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' + $this->version = '0.0.12'; + // 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 AUTOVERIFACTU 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' + // To use a supported fa-xxx css style of font awesome, use this->picto='xxx' + $this->picto = 'fa-receipt'; + + // 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' => 1, + // Set this to 1 if module has its own printing directory (core/modules/printing) + 'printing' => 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( + '/autoverifactu/css/admin.css.php', + ), + // Set this to relative path of js file if module must load a js on all pages + 'js' => array( + '/autoverifactu/js/autoverifactu.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 to 'all' + /* BEGIN MODULEBUILDER HOOKSCONTEXTS */ + 'hooks' => array( + 'admincompany', + 'invoicecard', + 'propalcard', + 'ordercard', + 'contractcard', + 'interventioncard', + 'expeditioncard', + 'pdfgeneration', + 'invoicelist', //para añadir estilos al listado de facturas + ), + /* END MODULEBUILDER HOOKSCONTEXTS */ + // Set this to 1 if features of module are opened to external users + 'moduleforexternal' => 0, + // Set this to 1 if the module provides a website template into doctemplates/websites/website_template-mytemplate + 'websitetemplates' => 0, + // Set this to 1 if the module provides a captcha driver + 'captcha' => 0 + ); + + // Data directories to create when module is enabled. + // Example: this->dirs = array("/autoverifactu/temp","/autoverifactu/subdir"); + $this->dirs = array('/autoverifactu/temp'); + + // Config pages. Put here list of php page, stored into autoverifactu/admin directory, to use to setup module. + $this->config_page_url = array('setup.php@autoverifactu'); + + // Dependencies + // A condition to hide module + $this->hidden = getDolGlobalInt('MODULE_AUTOVERIFACTU_DISABLED'); // A condition to disable module; + // List of module class names that must be enabled if this module is enabled. Example: array('always'=>array('modModuleToEnable1','modModuleToEnable2'), 'FR'=>array('modModuleToEnableFR')...) + $this->depends = array('modFacture', 'modBlockedLog'); + // List of module class names to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->requiredby = array(); + // List of module class names this module is in conflict with. Example: array('modModuleToDisable1', ...) + $this->conflictwith = array(); + + // The language file dedicated to your module + $this->langfiles = array('autoverifactu@autoverifactu'); + + // Prerequisites + $this->phpmin = array(8, 0); // Minimum version of PHP required by module + // $this->phpmax = array(8, 0); // Maximum version of PHP required by module + $this->need_dolibarr_version = array(20, -3); // Minimum version of Dolibarr required by module + // $this->max_dolibarr_version = array(19, -3); // Maximum version of Dolibarr required by module + $this->need_javascript_ajax = 1; + + // Messages at activation + $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','MX'='textmx'...) + $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','MX'='textmx'...) + $this->warnings_unactivation = array(); // array('ES' => 'BlockedLogAreRequiredByYourCountryLegislation'); + + // $this->automatic_activation = array('ES'=>'AutoverifactuWasAutomaticallyActivatedBecauseOfYourCountryChoice'); + + // $this->always_enabled = (isModEnabled('autoverifactu') + // && getDolGlobalString('AUTOVERIFACTU_DISABLE_NOT_ALLOWED_FOR_COUNTRY') + // && in_array((empty($mysoc->country_code) ? '' : $mysoc->country_code), explode(',', getDolGlobalString('AUTOVERIFACTU_DISABLE_NOT_ALLOWED_FOR_COUNTRY'))) + // && $this->alreadyUsed()); + + /* Constants */ + // List of particular constants to add when module is enabled (key, 'chaine', + // value, desc, visible, 'current' or 'allentities', deleteonunactive). + + + // 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 (!isModEnabled('autoverifactu')) { + $conf->autoverifactu = new stdClass(); + $conf->autoverifactu->enabled = 0; + } + + // Array to add new pages in new tabs + /* BEGIN MODULEBUILDER TABS */ + // Don't forget to deactivate/reactivate your module to test your changes + $this->tabs = array(); + + $this->dictionaries = array(); + + // Boxes/Widgets + // Add here list of php file(s) stored in autoverifactu/core/boxes that contains a class to show a widget. + $this->boxes = array(); + + + // creo crontab para ejecutar las facturas en cola + $this->cronjobs = array( + array( + 'label' => 'Procesar cola de envíos VERI*FACTU', + 'jobtype' => 'method', + 'class' => '/autoverifactu/class/verifactuqueue.class.php', + 'objectname' => 'VerifactuQueue', + 'method' => 'processMassiveQueue', + 'parameters' => '', + 'comment' => 'Revisa las facturas en cola y las envía agrupadas respetando los tiempos de la AEAT', + 'frequency' => 1, + 'unitfrequency' => 60, + 'status' => 1, + 'test' => 'isModEnabled("autoverifactu")', + 'priority' => 1, + ) + ); + + // Permissions provided by this module + $this->rights = array(); + + // Main menu entries to add + $this->menu = array(); + // $r = 0; + // Add here entries to declare new menus + // $this->menu[$r++] = array( + // 'fk_menu' => '', // Will be stored into mainmenu + leftmenu. Use '' 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' => 'Autoverifactu', + // 'prefix' => img_picto('', $this->picto, 'class="pictofixedwidth valignmiddle"'), + // 'mainmenu' => 'autoverifactu', + // 'leftmenu' => '', + // 'url' => '/autoverifactu/autoverifactuindex.php', + // 'langs' => 'autoverifactu@autoverifactu', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + // 'position' => 1000 + $r, + // 'enabled' => 'isModEnabled("autoverifactu")', // Define condition to show or hide menu entry. Use 'isModEnabled("autoverifactu")' if entry must be visible if module is enabled. + // 'perms' => '1', // Use 'perms'=>'$user->hasRight("autoverifactu", "myobject", "read")' if you want your menu with a permission rules + // 'target' => '', + // 'user' => 0, // 0=Menu for internal users, 1=external users, 2=both + // ); + } + + /** + * 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,1> 1 if OK, <=0 if KO. + */ + public function init($options = '') + { + global $db, $langs; // , $conf; + $langs->loadLangs(array('autoverifactu@autoverifactu')); + $now=new DateTimeImmutable( + 'now', + new DateTimeZone('Europe/Madrid'), + ); + dolibarr_set_const($db, 'FAC_FORCE_DATE_VALIDATION', '1', 'chaine', 0, '', 0); + dolibarr_set_const($db, 'VERIFACTU_NEXT_DELIVERY_ALLOWED', $now->getTimestamp(), 'chaine', 0, '', 0); + + // Create tables of module at module activation + // $result = $this->_load_tables('/autoverifactu/sql/'); + // if ($result < 0) { + // // Do not activate module if error 'not allowed' returned when loading module SQL queries + // // (the _load_table run sql with run_sql with the error allowed parameter set to 'default'). + // return -1; + // } + + // Create extrafields during init + include_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + //----------------------------------------Invoice ---------------------------------------- + // Tipo de rectificación en caso de que la factura sea rectificativa. + $extrafields->addExtraField( + 'verifactu_rectification_type', + 'VerifactuRectificationType', + 'select', + 1, + 2, + 'facture', + 0, + 0, + '', + array( + 'options' => array( + 'R1' => $langs->trans('VerifactuRectificationTypeR1'), + 'R2' => $langs->trans('VerifactuRectificationTypeR2'), + 'R3' => $langs->trans('VerifactuRectificationTypeR3'), + 'R4' => $langs->trans('VerifactuRectificationTypeR4'), + // 'R5' => $langs->trans('VerifactuRectificationTypeR5') + ), + ), + 0, + '', + '3', + $langs->trans('VerifactuRectificationTypeDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Fecha de operación + $extrafields->addExtraField( + 'verifactu_date_operation', + 'VerifactuDateOperation', + 'date', + 2, + 2, + 'facture', + 0, + 0, + '', + '', + 0, + '', + '3', + $langs->trans('VerifactuDateOperiationDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Campo para el almacenamiento de los textos legales para el pdf + // de la factura por el usuario. + $extrafields->addExtraField( + 'verifactu_pdfLegalTextUser', + 'pdfLegalTextUser', + 'text', + 3, + 1500, + 'facture', + 0, + 0, + '', + '', + 1, + '', + 3, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Estado de los envios a verifactu en funcion de si esta permitio o no hacer una peticion a la API + $extrafields->addExtraField( + 'verifactu_status', + 'Estado VERI*FACTU', + 'select', + 4, + 1, + 'facture', + 0, + 0, + '0', + array( + 'options' => array( + '0' => $langs->trans('verifactuStatusSelect0'), + '1' => $langs->trans('verifactuStatusSelect1'), + '2' => $langs->trans('verifactuStatusSelect2'), + '3' => $langs->trans('verifactuStatusSelect3'), + '4' => $langs->trans('verifactuStatusSelect4'), + '5' => $langs->trans('verifactuStatusSelect5'), + '6' => $langs->trans('verifactuStatusSelect6'), + '7' => $langs->trans('verifactuStatusSelect7'), + + ), + ), + 0, + '', + '1', + $langs->trans('verifactuStatusDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // campo para el almacenamiento de errores de validación de la factura. + $extrafields->addExtraField( + 'verifactu_error', + 'VerifactuError', + 'text', + 5, + 510, + 'facture', + 0, + 0, + '', + '', + 0, + '', + 3, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + //campo para el almacenamiento de los codigos de errores de validación de la factura. + $extrafields->addExtraField( + 'verifactu_error_code', + 'VerifactuErrorcode', + 'varchar', + 6, + 4, + 'facture', + 0, + 0, + '', + '', + 0, + '', + 0, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // hash verifactu + $extrafields->addExtraField( + 'verifactu_hash', + 'VerifactuHash', + 'varchar', + 10, + 255, + 'facture', + 0, + 0, + '', + '', + 0, + '', + 0, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Campo para el almacenamiento de los textos legales para el pdf de la factura. + $extrafields->addExtraField( + 'verifactu_pdfLegalText', + 'pdfLegalText', + 'text', + 11, + 1500, + 'facture', + 0, + 0, + '', + '', + 0, + '', + 0, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Timestamp de validación de la factura. + $extrafields->addExtraField( + 'verifactu_tms', + 'VerifactuTimeStamp', + 'int', + 12, + 15, + 'facture', + 0, + 0, + '0', + '', + 0, + '', + 0, + '', + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + //----------------------------------------line ---------------------------------------- + // regimen de facturación de la línea de factura + $extrafields->addExtraField( + 'verifactu_regime_type', + 'VerifactuDetailsRegimeType', + 'select', + 1, + 2, + 'facturedet', + 0, + 0, + '01', + array( + 'options' => array( + '01' => $langs->trans('VerifactuDetailsRegimeType01'), + '02' => $langs->trans('VerifactuDetailsRegimeType02'), + '03' => $langs->trans('VerifactuDetailsRegimeType03'), + '04' => $langs->trans('VerifactuDetailsRegimeType04'), + '05' => $langs->trans('VerifactuDetailsRegimeType05'), + '06' => $langs->trans('VerifactuDetailsRegimeType06'), + '07' => $langs->trans('VerifactuDetailsRegimeType07'), + '08' => $langs->trans('VerifactuDetailsRegimeType08'), + '09' => $langs->trans('VerifactuDetailsRegimeType09'), + '10' => $langs->trans('VerifactuDetailsRegimeType10'), + '11' => $langs->trans('VerifactuDetailsRegimeType11'), + '14' => $langs->trans('VerifactuDetailsRegimeType14'), + '15' => $langs->trans('VerifactuDetailsRegimeType15'), + '17' => $langs->trans('VerifactuDetailsRegimeType17'), + '18' => $langs->trans('VerifactuDetailsRegimeType18'), + '19' => $langs->trans('VerifactuDetailsRegimeType19'), + '20' => $langs->trans('VerifactuDetailsRegimeType20'), + ), + ), + 0, + '', + '3', + $langs->trans('VerifactuDetailsRegimeTypeDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + //type of tax of the line of invoice + $extrafields->addExtraField( + 'Verifactu_Tax', + 'VerifactuTax', + 'select', + 2, + 2, + 'facturedet', + 0, + 0, + '01', + array( + 'options' => array( + '01' => $langs->trans('VerifactuTax01'), + '02' => $langs->trans('VerifactuTax02'), + '03' => $langs->trans('VerifactuTax03'), + '05' => $langs->trans('VerifactuTax05'), + ), + ), + 0, + '', + '3', + $langs->trans('VerifactuTaxDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // tipo de operación de la línea de factura + $extrafields->addExtraField( + 'verifactu_operation_type', + 'VerifactuDetailsOperationType', + 'select', + 3, + 2, + 'facturedet', + 0, + 0, + 'S1', + array( + 'options' => array( + 'S1' => $langs->trans('VerifactuDetailsOperationTypeS1'), + 'S2' => $langs->trans('VerifactuDetailsOperationTypeS2'), + 'N1' => $langs->trans('VerifactuDetailsOperationTypeN1'), + 'N2' => $langs->trans('VerifactuDetailsOperationTypeN2'), + ), + ), + 0, + '', + '3', + $langs->trans('VerifactuDetailsOperationTypeDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Tipos de excepción + $extrafields->addExtraField( + 'verifactu_tax_excemption', + 'VerifactuDetailsTaxExcemption', + 'select', + 4, + 2, + 'facturedet', + 0, + 0, + '', + array( + 'options' => array( + 'E1' => $langs->trans('VerifactuDetailsTaxExcemptionE1'), + 'E2' => $langs->trans('VerifactuDetailsTaxExcemptionE2'), + 'E3' => $langs->trans('VerifactuDetailsTaxExcemptionE3'), + 'E4' => $langs->trans('VerifactuDetailsTaxExcemptionE4'), + 'E5' => $langs->trans('VerifactuDetailsTaxExcemptionE5'), + 'E6' => $langs->trans('VerifactuDetailsTaxExcemptionE6'), + ), + ), + 0, + '', + '3', + $langs->trans('VerifactuDetailsTaxExcemptionDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + //----------------------------------------thirdparty---------------------------------------- + // tipo de identificacion fiscal del tercero + $extrafields->addExtraField( + 'verifactu_identification_thirdparty', + 'VerifactuIdentificationThirdparty', + 'select', + 1, + 2, + 'societe', + 0, + 0, + '02', + array( + 'options' => array( + '02' => $langs->trans('VerifactuIdentificationThirdparty02'), + '03' => $langs->trans('VerifactuIdentificationThirdparty03'), + '04' => $langs->trans('VerifactuIdentificationThirdparty04'), + '05' => $langs->trans('VerifactuIdentificationThirdparty05'), + '06' => $langs->trans('VerifactuIdentificationThirdparty06'), + '07' => $langs->trans('VerifactuIdentificationThirdparty07'), + ), + ), + 1, + '', + '3', + $langs->trans('VerifactuIdentificationThirdpartyDescription'), + '', + '', + 'autoverifactu@autoverifactu', + 'isModEnabled("autoverifactu")', + ); + // Permissions + $this->remove($options); + $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,1> 1 if OK, <=0 if KO + */ + public function remove($options = '') + { + $sql = array(); + return $this->_remove($sql, $options); + } } diff --git a/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php b/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php index 9ccff98..fc93e73 100644 --- a/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php +++ b/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php @@ -43,343 +43,341 @@ */ class InterfaceAutoverifactuFreezeInvoices extends DolibarrTriggers { - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - parent::__construct($db); - $this->family = 'financial'; - $this->description = 'Auto-Veri*Factu triggers'; - $this->version = self::VERSIONS['dev']; - $this->picto = 'autoverifactu@autoverifactu'; - } - - /** - * Function called when a Dolibarr business event is done. - * All functions "runTrigger" are triggered if the file is inside the 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 Return integer <0 if KO, 0 if no triggered ran, >0 if OK - */ - public function runTrigger($action, $object, $user, $langs, $conf) - { - - if (!autoverifactuEnabled() && $action !== 'USER_LOGOUT') { - return 0; - } - - static $context; - $langs->load('autoverifactu@autoverifactu'); - /** - * Tracked invoices types: - * 0: Default ✓ - * 1: Replacement ✓ - * 2: Credit note ✓ - * 3: Down payment ✓ - * 4: Proforma ✕ - * 5: Situation ✕ - * - * Invoice status: - * 0: Draft - * 1: Validated - * 2: Closed - * 3: Abandoned - */ - - // TODO: Handle donations. - // As far as i know, they have to be declared as invoices to the AEAT, it isn't? - switch ($action) { - case 'BILL_CREATE': - - if (isset($object->context['createfromclone'])) { - $object->array_options['options_verifactu_tms'] = null; - $object->array_options['options_verifactu_hash'] = null; - $object->array_options['options_verifactu_error'] = null; - $object->array_options['options_verifactu_pdfLegalText'] = null; - $object->array_options['options_verifactu_status'] = 0; - $result = $object->insertExtraFields(); - if ($result < 0) { - return $result; - } - } - - if (!$context) { - $context = new stdClass; - $context->invoice = $object; - } - - if ( - $object->origin - && $object->origin_id - && getDolGlobalInt('AUTOVERIFACTU_SPLIT_INVOICES') - ) { - global $db, $user; - - if (isset($context->origin) && $context->origin->element === $object->origin) { - return; - } - - if ($object->origin === 'propal') { - dol_include_once('/comm/propal/class/propal.class.php'); - $sourceObject = new Propal($db); - } elseif ($object->origin_type === 'order' || $object->origin_type === 'commande') { - dol_include_once('/commande/class/commande.class.php'); - $sourceObject = new Commande($db); - } elseif ($object->origin_type === 'contrat' || $object->origin_type === 'contract') { - dol_include_once('/contrat/class/contrat.class.php'); - $sourceObject = new Contrat($db); - } elseif ($object->origin_type === 'shipping') { - dol_include_once('/expedition/class/expedition.class.php'); - $sourceObject = new Expedition($db); - } elseif ($object->origin_type === 'fichinter') { - dol_include_once('/fichinter/class/fichinter.class.php'); - $sourceObject = new Fichinter($db); - } - - if (!isset($sourceObject)) { - return; - } - - $sourceObject->fetch($object->origin_id); - $sourceObject->fetch_lines(); - - $context->origin = $sourceObject; - - $sourceLines = count($sourceObject->lines); - if ($sourceLines > 12) { - $context->splitInvoice = true; - - $sourceLines -= 12; - - while ($sourceLines >= 0) { - $siblingId = $object->createFromCurrent($user); - if ($siblingId < 0) { - dol_syslog('Unable to create a copy of the invoice in the split invoices loop', LOG_ERR); - $this->errors[] = $langs->trans('SplitInvoiceError'); - return $siblingId; - } - - $result = $object->add_object_linked('facture', $siblingId); - if ($result < 0) { - dol_syslog('Unable to link the partial invoice to the source invoice', LOG_ERR); - $this->errors[] = $langs->trans('SplitInvoiceError'); - return $result; - } - - $result = $sourceObject->add_object_linked('facture', $siblingId); - if ($result < 0) { - dol_syslog('Unable to link the partial invoice to the source entity', LOG_ERR); - $this->errors[] = $langs->trans('SplitInvoiceError'); - return $result; - } - - $sourceLines -= 12; - } - } - } - - - //al crear una factura tipo rectificativa tenemos que borrar el hash y los demas campos - if($object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_CREDIT_NOTE){ - $object->array_options['options_verifactu_tms'] = null; - $object->array_options['options_verifactu_hash'] = null; - $object->array_options['options_verifactu_error'] = null; - $object->array_options['options_verifactu_status'] = 0; - $result = $object->insertExtraFields(); - if ($result < 0) { - return $result; - } - } - - - break; - case 'BILL_CANCEL': - //esto - $trigger = $_GET['action'] ?? ''; - $facid = $_GET['facid'] ?? INF; - //?quizas hay que excluir las anulaciones por morosos, esta debe de acerse por una factura ¿Rectificativa? - // If it's triggered by a replacment invoice, skip the cancel record registration. - if ($trigger === 'confirm_valid' && $facid > $object->id) { - return 0; - } - //creación de facturas de anulacion - $now=new DateTimeImmutable('now',new DateTimeZone('Europe/Madrid')); - //Verifactu obliga a enviar peticiones a la api con unos tiempos de espera determinados enviados en la última respuesta - //en caso de que el tiempo del proximo envio no haya pasado - if($now->getTimestamp()array_options['options_verifactu_status'],array("7"), true)){ - $this->errors[] = $langs->trans('notToDoList',getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); - return -1; - - } - }else{ - //en caso que el tiempo de envio a pasado - $result = autoverifactuRegisterInvoice($object, $action); - if ($result < 0) { - dol_syslog('Error while sending a cancel record to the Veri*Factu API', LOG_ERR); - $this->errors[] = $langs->trans('CancelRecordFail'); - } - } - return $result; - case 'BILL_VALIDATE': - - // case 'DON_VALIDATE': - /* $object->fetch_lines(); - if (is_array($object->lines) && count($object->lines) > 12) { - dol_syslog('Veri*Factu bans invoices with more than 12 lines', LOG_INFO); - $this->errors[] = $langs->trans('MaxInvoiceLinesError'); - return -1; - } */ - //verificamos que el tiempo de espera a pasado - // y si no lo incluimos en la lista de pendientes de envio - - $now=new DateTimeImmutable('now',new DateTimeZone('Europe/Madrid')); - - if($now->getTimestamp()array_options['options_verifactu_status'],array("2","4","5"), true)){ - //en caso de eser facturas con errores, - //no las enviamos a la lista de espera ya que no sabemos si han sido arregladas o no - $this->errors[] = $langs->trans('notToDoList',getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); - return -1; - } - /*Para incluir la facturas anuladas en las acciones lista temporal habria que modificar - la funcion autoverifactuRegisterInvoiceList y obtener de alguna forma la un identificador del tipo de factura de alta o anulacion */ - $object->array_options['options_verifactu_status'] = '3'; - $object->insertExtraFields(); - dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); - return 1; - }else{ - //en caso de que el tiempo de espera haya pasado enviamos la factura - $result = autoverifactuRegisterInvoice($object, $action); - if ($result < 0) { - if (!empty($object->errors)) { - //si hay errores los enviamos - $this->errors = array_merge($this->errors, (array) $object->errors); - }else{ - $this->errors[] = $langs->trans('RecordCreationFail'); - } - } - return $result; - } - - case 'BILL_UNVALIDATE': - case 'BILL_UNPAYED': - if ($object->type <= Facture::TYPE_DEPOSIT) { - dol_syslog('Veri*Factu disables invoice unvalidations', LOG_INFO); - $this->errors[] = $langs->trans('ValidatedNotEditable'); - return -1; - } - break; - case 'BILL_DELETE': - // case 'DON_DELETE': - if ( - $object->status != Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - ) { - dol_syslog('Veri*Factu disables validated invoices removals', LOG_INFO); - $this->errors[] = $langs->trans('ValidatedNotDeletable'); - return -1; - } - - break; - // TODO: Handle subsanaciones - // NOTE: El protocolo contempla la subsanación de facturas en los casos en los que no - // sea necesaria una emisión rectificativa. - case 'BILL_MODIFY': - // case 'DON_MODIFY': - if ( - $object->status != Facture::STATUS_DRAFT - && $object->type <= Facture::TYPE_DEPOSIT - ) { - dol_syslog('Veri*Factu disables validated invoices edits', LOG_INFO); - $this->errors[] = $langs->trans('ValidatedNotModifiable'); - return -1; - } - - break; - case 'LINEBILL_INSERT': - global $db, $mysoc; - - $facture = $context->invoice ?? null; - - if (!$facture) { - $facture = new Facture($db); - $facture->fetch($object->fk_facture); - } - - $facture->fetch_lines(); - - if (count($facture->lines) > 12) { - if (isset($context->splitInvoice) && $context->splitInvoice) { - $result = $facture->fetchObjectLinked(); - if ($result < 0) { - dol_syslog('Error while loading partial invoices relations', LOG_ERR); - $this->errors[] = $langs->trans('FetchSplitInvoicesError'); - return $result; - } - - $linkedInvoices = $facture->linkedObjects['facture'] ?? array(); - foreach ($linkedInvoices as $candidate) { - $candidate->fetch_lines(); - - if (count($candidate->lines) < 12) { - $linkedInvoice = $candidate; - } - } - - if (!isset($linkedInvoice)) { - dol_syslog('Error while loading partial invoices relations', LOG_ERR); - $this->errors[] = $langs->trans('MaxInvoiceLinesError'); - return -1; - } - - $result = $object->delete(null, 1); - if ($result < 0) { - dol_syslog('Error while shifting lines from split partial invoice', LOG_ERR); - $this->errors[] = $langs->trans('SplitInvoiceLinesError'); - return -1; - } - - $object->fk_facture = $linkedInvoice->id; - $result = $object->insert($user, 1); - if ($result < 0) { - dol_syslog('Error while shifting lines from a split partial invoice', LOG_ERR); - $this->errors[] = $langs->trans('SplitInvoiceLinesError'); - return -1; - } - - $linkedInvoice->update_price(1, 'auto', 0, $mysoc); - } else { - dol_syslog('Veri*Factu bans invoices with more than 12 lines', LOG_INFO); - setEventMessage($langs->trans('MaxInvoiceLinesWarn'), 'warnings'); - } - } - - break; - case 'LINEPROPAL_INSERT': - case 'LINEORDER_INSERT': - case 'LINECONTRACT_INSERT': - case 'LINEFICHINTER_CREATE': - case 'LINESHIPPING_INSERT': - if (!getDolGlobalInt('AUTOVERIFACTU_SPLIT_INVOICES')) { - setEventMessage($langs->trans('MaxEntityLinesWarn'), 'warnings'); - } - - break; - case 'USER_LOGOUT': - autoverifactu_set_const('AUTOVERIFACTU_DISMISSED_NOTICES', ''); - break; - } - - return 0; - } + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + parent::__construct($db); + $this->family = 'financial'; + $this->description = 'Auto-Veri*Factu triggers'; + $this->version = self::VERSIONS['dev']; + $this->picto = 'autoverifactu@autoverifactu'; + } + + /** + * Function called when a Dolibarr business event is done. + * All functions "runTrigger" are triggered if the file is inside the 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 Return integer <0 if KO, 0 if no triggered ran, >0 if OK + */ + public function runTrigger($action, $object, $user, $langs, $conf) + { + + if (!autoverifactuEnabled() && $action !== 'USER_LOGOUT') { + return 0; + } + + static $context; + $langs->load('autoverifactu@autoverifactu'); + /** + * Tracked invoices types: + * 0: Default ✓ + * 1: Replacement ✓ + * 2: Credit note ✓ + * 3: Down payment ✓ + * 4: Proforma ✕ + * 5: Situation ✕ + * + * Invoice status: + * 0: Draft + * 1: Validated + * 2: Closed + * 3: Abandoned + */ + + // TODO: Handle donations. + // As far as i know, they have to be declared as invoices to the AEAT, it isn't? + switch ($action) { + case 'BILL_CREATE': + + if (isset($object->context['createfromclone'])) { + $object->array_options['options_verifactu_tms'] = null; + $object->array_options['options_verifactu_hash'] = null; + $object->array_options['options_verifactu_error'] = null; + $object->array_options['options_verifactu_pdfLegalText'] = null; + $object->array_options['options_verifactu_status'] = 0; + $result = $object->insertExtraFields(); + if ($result < 0) { + return $result; + } + } + + if (!$context) { + $context = new stdClass; + $context->invoice = $object; + } + + if ( + $object->origin + && $object->origin_id + && getDolGlobalInt('AUTOVERIFACTU_SPLIT_INVOICES') + ) { + global $db, $user; + + if (isset($context->origin) && $context->origin->element === $object->origin) { + return; + } + + if ($object->origin === 'propal') { + dol_include_once('/comm/propal/class/propal.class.php'); + $sourceObject = new Propal($db); + } elseif ($object->origin_type === 'order' || $object->origin_type === 'commande') { + dol_include_once('/commande/class/commande.class.php'); + $sourceObject = new Commande($db); + } elseif ($object->origin_type === 'contrat' || $object->origin_type === 'contract') { + dol_include_once('/contrat/class/contrat.class.php'); + $sourceObject = new Contrat($db); + } elseif ($object->origin_type === 'shipping') { + dol_include_once('/expedition/class/expedition.class.php'); + $sourceObject = new Expedition($db); + } elseif ($object->origin_type === 'fichinter') { + dol_include_once('/fichinter/class/fichinter.class.php'); + $sourceObject = new Fichinter($db); + } + + if (!isset($sourceObject)) { + return; + } + + $sourceObject->fetch($object->origin_id); + $sourceObject->fetch_lines(); + + $context->origin = $sourceObject; + + $sourceLines = count($sourceObject->lines); + if ($sourceLines > 12) { + $context->splitInvoice = true; + + $sourceLines -= 12; + + while ($sourceLines >= 0) { + $siblingId = $object->createFromCurrent($user); + if ($siblingId < 0) { + dol_syslog('Unable to create a copy of the invoice in the split invoices loop', LOG_ERR); + $this->errors[] = $langs->trans('SplitInvoiceError'); + return $siblingId; + } + + $result = $object->add_object_linked('facture', $siblingId); + if ($result < 0) { + dol_syslog('Unable to link the partial invoice to the source invoice', LOG_ERR); + $this->errors[] = $langs->trans('SplitInvoiceError'); + return $result; + } + + $result = $sourceObject->add_object_linked('facture', $siblingId); + if ($result < 0) { + dol_syslog('Unable to link the partial invoice to the source entity', LOG_ERR); + $this->errors[] = $langs->trans('SplitInvoiceError'); + return $result; + } + + $sourceLines -= 12; + } + } + } + + + //al crear una factura tipo rectificativa tenemos que borrar el hash y los demas campos + if ($object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_CREDIT_NOTE) { + $object->array_options['options_verifactu_tms'] = null; + $object->array_options['options_verifactu_hash'] = null; + $object->array_options['options_verifactu_error'] = null; + $object->array_options['options_verifactu_status'] = 0; + $result = $object->insertExtraFields(); + if ($result < 0) { + return $result; + } + } + + + break; + case 'BILL_CANCEL': + //esto + $trigger = $_GET['action'] ?? ''; + $facid = $_GET['facid'] ?? INF; + //?quizas hay que excluir las anulaciones por morosos, esta debe de acerse por una factura ¿Rectificativa? + // If it's triggered by a replacment invoice, skip the cancel record registration. + if ($trigger === 'confirm_valid' && $facid > $object->id) { + return 0; + } + //creación de facturas de anulacion + $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + //Verifactu obliga a enviar peticiones a la api con unos tiempos de espera determinados enviados en la última respuesta + //en caso de que el tiempo del proximo envio no haya pasado + if ($now->getTimestamp()array_options['options_verifactu_status'], array("7"), true)) { + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + return -1; + } + } else { + //en caso que el tiempo de envio a pasado + $result = autoverifactuRegisterInvoice($object, $action); + if ($result < 0) { + dol_syslog('Error while sending a cancel record to the Veri*Factu API', LOG_ERR); + $this->errors[] = $langs->trans('CancelRecordFail'); + } + } + return $result; + case 'BILL_VALIDATE': + + // case 'DON_VALIDATE': + /* $object->fetch_lines(); + if (is_array($object->lines) && count($object->lines) > 12) { + dol_syslog('Veri*Factu bans invoices with more than 12 lines', LOG_INFO); + $this->errors[] = $langs->trans('MaxInvoiceLinesError'); + return -1; + } */ + //verificamos que el tiempo de espera a pasado + // y si no lo incluimos en la lista de pendientes de envio + + $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + + if ($now->getTimestamp()array_options['options_verifactu_status'], array("2","4","5"), true)) { + //en caso de eser facturas con errores, + //no las enviamos a la lista de espera ya que no sabemos si han sido arregladas o no + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + return -1; + } + /*Para incluir la facturas anuladas en las acciones lista temporal habria que modificar + la funcion autoverifactuRegisterInvoiceList y obtener de alguna forma la un identificador del tipo de factura de alta o anulacion */ + $object->array_options['options_verifactu_status'] = '3'; + $object->insertExtraFields(); + dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); + return 1; + } else { + //en caso de que el tiempo de espera haya pasado enviamos la factura + $result = autoverifactuRegisterInvoice($object, $action); + if ($result < 0) { + if (!empty($object->errors)) { + //si hay errores los enviamos + $this->errors = array_merge($this->errors, (array) $object->errors); + } else { + $this->errors[] = $langs->trans('RecordCreationFail'); + } + } + return $result; + } + + case 'BILL_UNVALIDATE': + case 'BILL_UNPAYED': + if ($object->type <= Facture::TYPE_DEPOSIT) { + dol_syslog('Veri*Factu disables invoice unvalidations', LOG_INFO); + $this->errors[] = $langs->trans('ValidatedNotEditable'); + return -1; + } + break; + case 'BILL_DELETE': + // case 'DON_DELETE': + if ( + $object->status != Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + ) { + dol_syslog('Veri*Factu disables validated invoices removals', LOG_INFO); + $this->errors[] = $langs->trans('ValidatedNotDeletable'); + return -1; + } + + break; + // TODO: Handle subsanaciones + // NOTE: El protocolo contempla la subsanación de facturas en los casos en los que no + // sea necesaria una emisión rectificativa. + case 'BILL_MODIFY': + // case 'DON_MODIFY': + if ( + $object->status != Facture::STATUS_DRAFT + && $object->type <= Facture::TYPE_DEPOSIT + ) { + dol_syslog('Veri*Factu disables validated invoices edits', LOG_INFO); + $this->errors[] = $langs->trans('ValidatedNotModifiable'); + return -1; + } + + break; + case 'LINEBILL_INSERT': + global $db, $mysoc; + + $facture = $context->invoice ?? null; + + if (!$facture) { + $facture = new Facture($db); + $facture->fetch($object->fk_facture); + } + + $facture->fetch_lines(); + + if (count($facture->lines) > 12) { + if (isset($context->splitInvoice) && $context->splitInvoice) { + $result = $facture->fetchObjectLinked(); + if ($result < 0) { + dol_syslog('Error while loading partial invoices relations', LOG_ERR); + $this->errors[] = $langs->trans('FetchSplitInvoicesError'); + return $result; + } + + $linkedInvoices = $facture->linkedObjects['facture'] ?? array(); + foreach ($linkedInvoices as $candidate) { + $candidate->fetch_lines(); + + if (count($candidate->lines) < 12) { + $linkedInvoice = $candidate; + } + } + + if (!isset($linkedInvoice)) { + dol_syslog('Error while loading partial invoices relations', LOG_ERR); + $this->errors[] = $langs->trans('MaxInvoiceLinesError'); + return -1; + } + + $result = $object->delete(null, 1); + if ($result < 0) { + dol_syslog('Error while shifting lines from split partial invoice', LOG_ERR); + $this->errors[] = $langs->trans('SplitInvoiceLinesError'); + return -1; + } + + $object->fk_facture = $linkedInvoice->id; + $result = $object->insert($user, 1); + if ($result < 0) { + dol_syslog('Error while shifting lines from a split partial invoice', LOG_ERR); + $this->errors[] = $langs->trans('SplitInvoiceLinesError'); + return -1; + } + + $linkedInvoice->update_price(1, 'auto', 0, $mysoc); + } else { + dol_syslog('Veri*Factu bans invoices with more than 12 lines', LOG_INFO); + setEventMessage($langs->trans('MaxInvoiceLinesWarn'), 'warnings'); + } + } + + break; + case 'LINEPROPAL_INSERT': + case 'LINEORDER_INSERT': + case 'LINECONTRACT_INSERT': + case 'LINEFICHINTER_CREATE': + case 'LINESHIPPING_INSERT': + if (!getDolGlobalInt('AUTOVERIFACTU_SPLIT_INVOICES')) { + setEventMessage($langs->trans('MaxEntityLinesWarn'), 'warnings'); + } + + break; + case 'USER_LOGOUT': + autoverifactu_set_const('AUTOVERIFACTU_DISMISSED_NOTICES', ''); + break; + } + + return 0; + } } diff --git a/css/admin.css.php b/css/admin.css.php index 93f7a62..428b665 100644 --- a/css/admin.css.php +++ b/css/admin.css.php @@ -22,23 +22,23 @@ */ if (!defined('NOREQUIRESOC')) { - define('NOREQUIRESOC', '1'); + define('NOREQUIRESOC', '1'); } if (!defined('NOTOKENRENEWAL')) { - define('NOTOKENRENEWAL', 1); + define('NOTOKENRENEWAL', 1); } if (!defined('NOLOGIN')) { - define('NOLOGIN', 1); + define('NOLOGIN', 1); } if (!defined('NOREQUIREHTML')) { - define('NOREQUIREHTML', 1); + define('NOREQUIREHTML', 1); } if (!defined('NOREQUIREAJAX')) { - define('NOREQUIREAJAX', '1'); + define('NOREQUIREAJAX', '1'); } /** @@ -52,9 +52,9 @@ header('Content-type: text/css'); if (empty($dolibarr_nocache)) { - header('Cache-Control: max-age=10800, public, must-revalidate'); + header('Cache-Control: max-age=10800, public, must-revalidate'); } else { - header('Cache-Control: no-cache'); + header('Cache-Control: no-cache'); } ?> @@ -65,36 +65,36 @@ } .autodeclaration-preview { - position: relative; - max-width: 65rem; - padding: 6rem 4.5rem 4.5rem; - border: 1px solid; - box-sizing: border-box; + position: relative; + max-width: 65rem; + padding: 6rem 4.5rem 4.5rem; + border: 1px solid; + box-sizing: border-box; } .autodeclaration-preview h1, .autodeclaration-preview h2 { - line-height: 1.2; + line-height: 1.2; } .autodeclaration-preview h1 { - margin-bottom: 1.5em; + margin-bottom: 1.5em; } .autodeclaration-preview ol, .autodeclaration-preview ul { - padding-left: 1rem; + padding-left: 1rem; } .autodeclaration-watermark { - position: absolute; - z-index: 10; - font-weight: 800; - font-size: 8rem; - color: red; - top: 15%; - left: 50%; - transform: translate(-50%, -50%) rotate(45deg); - opacity: 0.3; - text-transform: uppercase; + position: absolute; + z-index: 10; + font-weight: 800; + font-size: 8rem; + color: red; + top: 15%; + left: 50%; + transform: translate(-50%, -50%) rotate(45deg); + opacity: 0.3; + text-transform: uppercase; } diff --git a/css/selector_status.css.php b/css/selector_status.css.php index 0727004..94ec817 100644 --- a/css/selector_status.css.php +++ b/css/selector_status.css.php @@ -1,37 +1,37 @@ load("autoverifactu@autoverifactu"); @@ -39,50 +39,50 @@ ?> td[data-key="facture.verifactu_status"] { - font-family: sans-serif; - font-size: 0.85em; - font-weight: bold !important; - display: inline-flex !important; - align-items: center; - justify-content: center; - padding: 6px 12px; - margin: 5px; - min-height: 28px; - box-sizing: border-box; - border-radius: 4px; - color: #ffffff !important; - height: auto !important; + font-family: sans-serif; + font-size: 0.85em; + font-weight: bold !important; + display: inline-flex !important; + align-items: center; + justify-content: center; + padding: 6px 12px; + margin: 5px; + min-height: 28px; + box-sizing: border-box; + border-radius: 4px; + color: #ffffff !important; + height: auto !important; } /* --- VARIACIONES DE COLOR SEGÚN EL ESTADO DE VERI*FACTU --- */ /* Pendiente de envío */ td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect0"), ENT_QUOTES, 'UTF-8');?>"] { - background-color: #2b82a4 !important; - border-color: #1f617a !important; - color: #ffffff !important; + background-color: #2b82a4 !important; + border-color: #1f617a !important; + color: #ffffff !important; } /* Registrado Correctamente */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect1"),ENT_QUOTES, 'UTF-8');?>"] { - background-color: #28a745 !important; - border-color: #1e7e34 !important; - color: #ffffff !important; +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect1"), ENT_QUOTES, 'UTF-8');?>"] { + background-color: #28a745 !important; + border-color: #1e7e34 !important; + color: #ffffff !important; } /* Rechazado */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect2"),ENT_QUOTES, 'UTF-8');?>"] { - background-color: #dc3545 !important; - border-color: #bd2130 !important; - color: #ffffff !important; +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect2"), ENT_QUOTES, 'UTF-8');?>"] { + background-color: #dc3545 !important; + border-color: #bd2130 !important; + color: #ffffff !important; } /* En cola (Espera Temporal) */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect3"),ENT_QUOTES, 'UTF-8');?>"] { - background-color: #ffc107 !important; - border-color: #d39e00 !important; - color: #212529 !important; +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect3"), ENT_QUOTES, 'UTF-8');?>"] { + background-color: #ffc107 !important; + border-color: #d39e00 !important; + color: #212529 !important; } /* Registrado Correctamente pero con Errores */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect4"),ENT_QUOTES, 'UTF-8');?>"] { - background-color: #fd7e14 !important; - /* Naranja corporativo de advertencia */ - border-color: #cf6206 !important; - color: #ffffff !important; +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect4"), ENT_QUOTES, 'UTF-8');?>"] { + background-color: #fd7e14 !important; + /* Naranja corporativo de advertencia */ + border-color: #cf6206 !important; + color: #ffffff !important; } \ No newline at end of file diff --git a/js/autoverifactu.js.php b/js/autoverifactu.js.php index 7044382..105b7aa 100644 --- a/js/autoverifactu.js.php +++ b/js/autoverifactu.js.php @@ -30,22 +30,22 @@ // define('NOREQUIRETRAN', 0); // } if (!defined('NOCSRFCHECK')) { - define('NOCSRFCHECK', 1); + define('NOCSRFCHECK', 1); } if (!defined('NOTOKENRENEWAL')) { - define('NOTOKENRENEWAL', 1); + define('NOTOKENRENEWAL', 1); } // if (!defined('NOLOGIN')) { // define('NOLOGIN', 1); // } if (!defined('NOREQUIREMENU')) { - define('NOREQUIREMENU', 1); + define('NOREQUIREMENU', 1); } if (!defined('NOREQUIREHTML')) { - define('NOREQUIREHTML', 1); + define('NOREQUIREHTML', 1); } if (!defined('NOREQUIREAJAX')) { - define('NOREQUIREAJAX', '1'); + define('NOREQUIREAJAX', '1'); } @@ -62,9 +62,9 @@ // Important: Following code is to cache this file to avoid page request by browser at each Dolibarr page access. // You can use CTRL+F5 to refresh your browser cache. if (empty($dolibarr_nocache)) { - header('Cache-Control: max-age=3600, public, must-revalidate'); + header('Cache-Control: max-age=3600, public, must-revalidate'); } else { - header('Cache-Control: no-cache'); + header('Cache-Control: no-cache'); } require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php'; @@ -82,23 +82,23 @@ $drop = array(); if ($enabled && ($index = array_search('DISABLED', $dismissed, true)) !== false) { - $drop = array_merge($drop, array_splice($dismissed, $index, 1)); + $drop = array_merge($drop, array_splice($dismissed, $index, 1)); } if (!$testMode && ($index = array_search('TESTMODE', $dismissed, true)) !== false) { - $drop = array_merge($drop, array_splice($dismissed, $index, 1)); + $drop = array_merge($drop, array_splice($dismissed, $index, 1)); } if (count($drop)) { - $dismissed = array_filter($dismissed, function ($tag) use ($drop) { - return !in_array($tag, $drop, true); - }); - - autoverifactu_set_const( - 'AUTOVERIFACTU_DISMISSED_NOTICES', - implode(',', array_filter(array_map('trim', $dismissed))), - $mysoc->entity, - ); + $dismissed = array_filter($dismissed, function ($tag) use ($drop) { + return !in_array($tag, $drop, true); + }); + + autoverifactu_set_const( + 'AUTOVERIFACTU_DISMISSED_NOTICES', + implode(',', array_filter(array_map('trim', $dismissed))), + $mysoc->entity, + ); } $messages = array(); @@ -106,106 +106,106 @@ $is_admin = $user->admin; if ($is_admin && !$enabled && !in_array('DISABLED', $dismissed, true)) { - $messages[] = array( - 'warning', - '' . $langs->trans('AutoVerifactuNotEnabled') . ', ' - . $langs->trans('InvoicesNotSent') . '.', - true, - 'DISABLED', - ); + $messages[] = array( + 'warning', + '' . $langs->trans('AutoVerifactuNotEnabled') . ', ' + . $langs->trans('InvoicesNotSent') . '.', + true, + 'DISABLED', + ); } if ($is_admin && $testMode && !in_array('TESTMODE', $dismissed, true)) { - $messages[] = array( - 'info', - $langs->trans('AutoVerifactuInTestMode'), - true, - 'TESTMODE' - ); + $messages[] = array( + 'info', + $langs->trans('AutoVerifactuInTestMode'), + true, + 'TESTMODE' + ); } ?> /* Javascript library of module Auto-Veri*Factu */ document.addEventListener("DOMContentLoaded", function () { - // handle ui messages - const entity = entity ?: 1 ?>; - const messages = ; - messages.forEach(function (msg) { - const [type, message, sticky, tag] = msg; - $.jnotify(message, { - type, - sticky, - beforeRemove: () => { - fetch("/custom/autoverifactu/ajax/dismiss_notice.php", { - method: "POST", - headers: { "Content-Type": "application/x-www-form-urlencoded" }, - body: `tag=${tag}&entity=${+entity}`, - }); - } - }); - }); - - autoverifactuHandleInvoiceCardReactivity(); - autoverifactuHandleInvoiceDetailsReactivity(); + // handle ui messages + const entity = entity ?: 1 ?>; + const messages = ; + messages.forEach(function (msg) { + const [type, message, sticky, tag] = msg; + $.jnotify(message, { + type, + sticky, + beforeRemove: () => { + fetch("/custom/autoverifactu/ajax/dismiss_notice.php", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: `tag=${tag}&entity=${+entity}`, + }); + } + }); + }); + + autoverifactuHandleInvoiceCardReactivity(); + autoverifactuHandleInvoiceDetailsReactivity(); }); function autoverifactuHandleInvoiceCardReactivity() { - const form = document.querySelector("#formtocreate"); - if (!form) return; - - const rectificationTypeField = form.querySelector(".field_options_verifactu_rectification_type"); - if (!rectificationTypeField) return; - - let invoiceType = "0"; - function setInvoiceType(value) { - invoiceType = value; - - // 0 = 'Factura estándard' - // 1 = 'Factura rectificativa' - // 2 = 'Abono' - if (value === "1" || value === "2") { - rectificationTypeField.style.display = "table-row"; - } else { - rectificationTypeField.style.display = "none"; - rectificationTypeField.querySelector("select").value = ""; - } - } - - const radioButtons = form.querySelectorAll('input[type="radio"]'); - radioButtons.forEach((input) => { - if (input.checked) { - setInvoiceType(input.value); - } - - input.addEventListener("change", () => { - if (input.checked) { - setInvoiceType(input.value); - } - }); - }); + const form = document.querySelector("#formtocreate"); + if (!form) return; + + const rectificationTypeField = form.querySelector(".field_options_verifactu_rectification_type"); + if (!rectificationTypeField) return; + + let invoiceType = "0"; + function setInvoiceType(value) { + invoiceType = value; + + // 0 = 'Factura estándard' + // 1 = 'Factura rectificativa' + // 2 = 'Abono' + if (value === "1" || value === "2") { + rectificationTypeField.style.display = "table-row"; + } else { + rectificationTypeField.style.display = "none"; + rectificationTypeField.querySelector("select").value = ""; + } + } + + const radioButtons = form.querySelectorAll('input[type="radio"]'); + radioButtons.forEach((input) => { + if (input.checked) { + setInvoiceType(input.value); + } + + input.addEventListener("change", () => { + if (input.checked) { + setInvoiceType(input.value); + } + }); + }); } function autoverifactuHandleInvoiceDetailsReactivity() { - const form = document.querySelector("form#addproduct"); - if (!form) return; - - const regimeField = form.querySelector(".fieldline_options_verifactu_regime_type select"); - const optTypeField = form.querySelector(".fieldline_options_verifactu_operation_type select"); - const excemptionField = form.querySelector(".fieldline_options_verifactu_tax_excemption select"); - if (!(regimeField && optTypeField && excemptionField)) return; - - $(regimeField).val("").trigger("change"); - $(optTypeField).val("S1").trigger("change"); - - $(optTypeField).on("change", function () { - if (this.value) { - $(excemptionField).val("").trigger("change"); - } - }); - - $(excemptionField).on("change", function () { - if (this.value) { - $(optTypeField).val("").trigger("change"); - } - }); + const form = document.querySelector("form#addproduct"); + if (!form) return; + + const regimeField = form.querySelector(".fieldline_options_verifactu_regime_type select"); + const optTypeField = form.querySelector(".fieldline_options_verifactu_operation_type select"); + const excemptionField = form.querySelector(".fieldline_options_verifactu_tax_excemption select"); + if (!(regimeField && optTypeField && excemptionField)) return; + + $(regimeField).val("").trigger("change"); + $(optTypeField).val("S1").trigger("change"); + + $(optTypeField).on("change", function () { + if (this.value) { + $(excemptionField).val("").trigger("change"); + } + }); + + $(excemptionField).on("change", function () { + if (this.value) { + $(optTypeField).val("").trigger("change"); + } + }); } diff --git a/lib/autoverifactu.lib.php b/lib/autoverifactu.lib.php index 30037aa..ab37854 100644 --- a/lib/autoverifactu.lib.php +++ b/lib/autoverifactu.lib.php @@ -30,32 +30,32 @@ */ function autoverifactuAdminPrepareHead() { - global $langs, $conf; - $langs->load('autoverifactu@autoverifactu'); + global $langs, $conf; + $langs->load('autoverifactu@autoverifactu'); - $h = 0; - $head = array(); + $h = 0; + $head = array(); - $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/setup.php'; - $head[$h][1] = $langs->trans('Settings'); - $head[$h][2] = 'settings'; - $h++; + $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/setup.php'; + $head[$h][1] = $langs->trans('Settings'); + $head[$h][2] = 'settings'; + $h++; - $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/autodeclaration.php'; - $head[$h][1] = $langs->trans('Autodeclaration'); - $head[$h][2] = 'autodeclaration'; - $h++; + $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/autodeclaration.php'; + $head[$h][1] = $langs->trans('Autodeclaration'); + $head[$h][2] = 'autodeclaration'; + $h++; - $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/about.php'; - $head[$h][1] = $langs->trans('About'); - $head[$h][2] = 'about'; - $h++; + $head[$h][0] = DOL_URL_ROOT . '/custom/autoverifactu/admin/about.php'; + $head[$h][1] = $langs->trans('About'); + $head[$h][2] = 'about'; + $h++; - complete_head_from_modules($conf, $langs, null, $head, $h, 'autoverifactu@autoverifactu'); - complete_head_from_modules($conf, $langs, null, $head, $h, 'autoverifactu@autoverifactu', 'remove'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'autoverifactu@autoverifactu'); + complete_head_from_modules($conf, $langs, null, $head, $h, 'autoverifactu@autoverifactu', 'remove'); - return $head; + return $head; } /** @@ -69,10 +69,10 @@ function autoverifactuAdminPrepareHead() */ function autoverifactu_set_const($name, $value, $entity_id = null) { - require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php'; - global $db, $mysoc; - return dolibarr_set_const($db, $name, $value, 'chaine', 0, '', is_int($entity_id) ? $entity_id : $mysoc->entity); + global $db, $mysoc; + return dolibarr_set_const($db, $name, $value, 'chaine', 0, '', is_int($entity_id) ? $entity_id : $mysoc->entity); } /** @@ -82,174 +82,174 @@ function autoverifactu_set_const($name, $value, $entity_id = null) */ function autoverifactuDeclarationRenderedTemplate() { - global $mysoc, $langs; + global $mysoc, $langs; - ob_start(); - ?> + ob_start(); + ?>
-

trans('Draft') ?>

-

- trans('DeclarationTitle'); ?> -

-
    -
  1. -
      -
    1. -

      - trans('DeclarationSifNameLabel'); ?>: -

      -

      Auto-Veri*Factu

      -
    2. -
    3. -

      - trans('DeclarationSifCodeLabel'); ?>: -

      -

      AV

      -
    4. -
    5. -

      - trans('DeclarationSifVersionLabel'); ?>: -

      -

      1.0.0

      -
    6. -
    7. -

      - trans('DeclarationSoftwareDescriptionLabel'); ?>: -

      -

      - trans('DeclarationSoftwareDescription'); ?>: -

      -

      trans('DeclarationFeaturesListLabel') ?>:

      -
        -
      • - trans('DeclarationFeaturesList1'); ?> -
      • -
      • - trans('DeclarationFeaturesList2'); ?> -
      • -
      • - trans('DeclarationFeaturesList3'); ?> -
      • -
      • - trans('DeclarationFeaturesList4'); ?> -
      • -
      • - trans('DeclarationFeaturesList5'); ?> -
      • -
      • - trans('DeclarationFeaturesList6'); ?> -
      • -
      -

      - trans('DeclarationRequirements1'); ?> -

      -

      - trans('DeclarationRequirements2'); ?> -

      -
    8. -
    9. -

      - trans('DeclarationOnlyVerifactuLabel'); ?>: -

      -

      trans('DeclarationBoolYes'); ?>

      -
    10. -
    11. -

      - trans('DeclarationMultiCompanyLabel'); ?>: -

      -

      trans('DeclarationBoolNo'); ?>

      -
    12. -
    13. -

      - trans('DeclarationSignModeLabel'); ?>: -

      -

      - trans('DeclarationSignMode'); ?> -

      -
    14. -
    15. -

      - trans('DeclarationCompanyName') ?>: -

      -

      nom ?>

      -
    16. -
    17. -

      - trans('DeclarationTaxID'); ?>: -

      -

      idprof1 ?>

      -
    18. -
    19. -

      - trans('DeclarationAddress') ?>: -

      -

      - address ?>
      - zip ?> - town ?> (state ?>)
      - country ?> -

      -
    20. -
    21. -

      - trans('DeclarationCompliance'); ?> -

      -
    22. -
    23. -

      - trans('DeclarationSignDateLabel'); ?>: -

      -

      -

      - trans('DeclarationSignLocationLabel'); ?>: -

      -

      - town ?> (state ?>)
      - country ?> -

      -
    24. -
    -
  2. -

    trans('DeclarationAnnex'); ?>

    -
  3. -
      -
    1. -

      trans('DeclarationLinksLabel'); ?>

      - -

      - * - trans('DeclarationGPLNote'); ?> -

      -
    2. -
    3. -

      - trans('DeclarationSpecsLabel'); ?>: -

      -

      - trans('DeclarationSpecsListLabel'); ?>: -

      -
        -
      • - trans('DeclarationSpecs1'); ?> -
      • -
      • - trans('DeclarationSpecs2'); ?> -
      • -
      -

      - trans('DeclarationDischarge'); ?> -

      -
    4. -
    -
  4. -
+

trans('Draft') ?>

+

+ trans('DeclarationTitle'); ?> +

+
    +
  1. +
      +
    1. +

      + trans('DeclarationSifNameLabel'); ?>: +

      +

      Auto-Veri*Factu

      +
    2. +
    3. +

      + trans('DeclarationSifCodeLabel'); ?>: +

      +

      AV

      +
    4. +
    5. +

      + trans('DeclarationSifVersionLabel'); ?>: +

      +

      1.0.0

      +
    6. +
    7. +

      + trans('DeclarationSoftwareDescriptionLabel'); ?>: +

      +

      + trans('DeclarationSoftwareDescription'); ?>: +

      +

      trans('DeclarationFeaturesListLabel') ?>:

      +
        +
      • + trans('DeclarationFeaturesList1'); ?> +
      • +
      • + trans('DeclarationFeaturesList2'); ?> +
      • +
      • + trans('DeclarationFeaturesList3'); ?> +
      • +
      • + trans('DeclarationFeaturesList4'); ?> +
      • +
      • + trans('DeclarationFeaturesList5'); ?> +
      • +
      • + trans('DeclarationFeaturesList6'); ?> +
      • +
      +

      + trans('DeclarationRequirements1'); ?> +

      +

      + trans('DeclarationRequirements2'); ?> +

      +
    8. +
    9. +

      + trans('DeclarationOnlyVerifactuLabel'); ?>: +

      +

      trans('DeclarationBoolYes'); ?>

      +
    10. +
    11. +

      + trans('DeclarationMultiCompanyLabel'); ?>: +

      +

      trans('DeclarationBoolNo'); ?>

      +
    12. +
    13. +

      + trans('DeclarationSignModeLabel'); ?>: +

      +

      + trans('DeclarationSignMode'); ?> +

      +
    14. +
    15. +

      + trans('DeclarationCompanyName') ?>: +

      +

      nom ?>

      +
    16. +
    17. +

      + trans('DeclarationTaxID'); ?>: +

      +

      idprof1 ?>

      +
    18. +
    19. +

      + trans('DeclarationAddress') ?>: +

      +

      + address ?>
      + zip ?> - town ?> (state ?>)
      + country ?> +

      +
    20. +
    21. +

      + trans('DeclarationCompliance'); ?> +

      +
    22. +
    23. +

      + trans('DeclarationSignDateLabel'); ?>: +

      +

      +

      + trans('DeclarationSignLocationLabel'); ?>: +

      +

      + town ?> (state ?>)
      + country ?> +

      +
    24. +
    +
  2. +

    trans('DeclarationAnnex'); ?>

    +
  3. +
      +
    1. +

      trans('DeclarationLinksLabel'); ?>

      + +

      + * + trans('DeclarationGPLNote'); ?> +

      +
    2. +
    3. +

      + trans('DeclarationSpecsLabel'); ?>: +

      +

      + trans('DeclarationSpecsListLabel'); ?>: +

      +
        +
      • + trans('DeclarationSpecs1'); ?> +
      • +
      • + trans('DeclarationSpecs2'); ?> +
      • +
      +

      + trans('DeclarationDischarge'); ?> +

      +
    4. +
    +
  4. +
- autoverifactu->dir_output . '/'; + global $conf; + $upload_dir = $conf->autoverifactu->dir_output . '/'; - if (!is_dir($upload_dir)) { - dol_mkdir($upload_dir); - } + if (!is_dir($upload_dir)) { + dol_mkdir($upload_dir); + } - $dest = null; + $dest = null; - if (!empty($_FILES['userfile']['tmp_name'])) { - $file = $_FILES['userfile']; - $filename = dol_sanitizeFileName($file['name']); - $dest = $upload_dir . $filename; + if (!empty($_FILES['userfile']['tmp_name'])) { + $file = $_FILES['userfile']; + $filename = dol_sanitizeFileName($file['name']); + $dest = $upload_dir . $filename; - if (dol_move_uploaded_file($file['tmp_name'], $dest, 1, 0, $file['error'])) { - // $file_id = dol_add_file($dest, $filename, 'autoverifactu'); - } else { - return; - } - } + if (dol_move_uploaded_file($file['tmp_name'], $dest, 1, 0, $file['error'])) { + // $file_id = dol_add_file($dest, $filename, 'autoverifactu'); + } else { + return; + } + } - return $dest; + return $dest; } diff --git a/lib/validation.lib.php b/lib/validation.lib.php index 219289d..e52e7af 100644 --- a/lib/validation.lib.php +++ b/lib/validation.lib.php @@ -43,35 +43,35 @@ */ function autoverifactuIntegrityCheck($invoice) { - $blockedlog = autoverifactuFetchBlockedLog($invoice); - - if (!$blockedlog) { - return 0; - } - - $signatrueCheck = $blockedlog->checkSignature(); - if (!$signatrueCheck) { - return -1; - } - - $record = autoverifactuInvoiceToRecord($invoice); - - $immutable = autoverifactuRecordFromLog($blockedlog); - /* - echo "


"; - var_dump($record); - echo "
Inmutable
"; - var_dump($immutable);*/ - - if (!$record || !$immutable) { - return -1; - } - - $error = $record->hash !== $immutable->hash; - if ($error) { - return -1; - } - return 1; + $blockedlog = autoverifactuFetchBlockedLog($invoice); + + if (!$blockedlog) { + return 0; + } + + $signatrueCheck = $blockedlog->checkSignature(); + if (!$signatrueCheck) { + return -1; + } + + $record = autoverifactuInvoiceToRecord($invoice); + + $immutable = autoverifactuRecordFromLog($blockedlog); + /* + echo "


"; + var_dump($record); + echo "
Inmutable
"; + var_dump($immutable);*/ + + if (!$record || !$immutable) { + return -1; + } + + $error = $record->hash !== $immutable->hash; + if ($error) { + return -1; + } + return 1; } /** @@ -83,21 +83,21 @@ function autoverifactuIntegrityCheck($invoice) */ function autoverifactuFetchBlockedLog($invoice) { - global $db; - - $sql = 'SELECT rowid FROM ' . $db->prefix() . 'blockedlog'; - $sql .= ' WHERE element = \'facture\''; - // $sql .= ' AND entity = ' . $confg->entity; - $sql .= ' AND action = \'BILL_VALIDATE\''; - $sql .= ' AND fk_object = ' . $invoice->id; - - $resql = $db->query($sql); - if ($resql && $db->num_rows($resql)) { - $obj = $db->fetch_object($resql); - $blockedlog = new BlockedLog($db); - $blockedlog->fetch($obj->rowid); - return $blockedlog; - } + global $db; + + $sql = 'SELECT rowid FROM ' . $db->prefix() . 'blockedlog'; + $sql .= ' WHERE element = \'facture\''; + // $sql .= ' AND entity = ' . $confg->entity; + $sql .= ' AND action = \'BILL_VALIDATE\''; + $sql .= ' AND fk_object = ' . $invoice->id; + + $resql = $db->query($sql); + if ($resql && $db->num_rows($resql)) { + $obj = $db->fetch_object($resql); + $blockedlog = new BlockedLog($db); + $blockedlog->fetch($obj->rowid); + return $blockedlog; + } } /** @@ -110,58 +110,56 @@ function autoverifactuFetchBlockedLog($invoice) */ function autoverifactuCheckInvoiceImmutableXML($invoice, $type = 'alta') { - global $mysoc; + global $mysoc; - $result = 0; + $result = 0; - if (!autoverifactuValidateRecordType($type)) { + if (!autoverifactuValidateRecordType($type)) { + return $result; + } - return $result; - } + list($file, $hidden) = autoverifactuInvoiceImmutableXMLPath($invoice); - list($file, $hidden) = autoverifactuInvoiceImmutableXMLPath($invoice); + if (!is_file($hidden)) { + $blockedlog = autoverifactuFetchBlockedLog($invoice); - if (!is_file($hidden)) { - $blockedlog = autoverifactuFetchBlockedLog($invoice); + if (!$blockedlog) { + dol_syslog('Immutable log not found for invoice #' . $invoice->id, LOG_ERR); + return -1; + } - if (!$blockedlog) { - dol_syslog('Immutable log not found for invoice #' . $invoice->id, LOG_ERR); - return -1; - } + $record = autoverifactuRecordFromLog($blockedlog); - $record = autoverifactuRecordFromLog($blockedlog); + $xml = autoverifactuSoapEnvelope( + $record, + array( + 'name' => $mysoc->nom, + 'idprof1' => $mysoc->idprof1, + ), + ); - $xml = autoverifactuSoapEnvelope( - $record, - array( - 'name' => $mysoc->nom, - 'idprof1' => $mysoc->idprof1, - ), - ); + $bytes = file_put_contents($hidden, $xml); - $bytes = file_put_contents($hidden, $xml); + $result = intval($bytes > 0); - $result = intval($bytes > 0); + if (!$result) { + dol_syslog('Empty XML regeneration for invoice #' . $invoice->id, LOG_ERR); + return -1; + } + } - if (!$result) { - dol_syslog('Empty XML regeneration for invoice #' . $invoice->id, LOG_ERR); - return -1; - } - } + if (!is_file($file)) { + $bytes = file_put_contents($file, file_get_contents($hidden)); - if (!is_file($file)) { + $result = $result + intval($bytes > 0); - $bytes = file_put_contents($file, file_get_contents($hidden)); + if (!$result) { + dol_syslog('Empty XML regeneration for for invoice #' . $invoice->id, LOG_ERR); + return -1; + } + } - $result = $result + intval($bytes > 0); - - if (!$result) { - dol_syslog('Empty XML regeneration for for invoice #' . $invoice->id, LOG_ERR); - return -1; - } - } - - return $result; + return $result; } /** @@ -175,20 +173,20 @@ function autoverifactuCheckInvoiceImmutableXML($invoice, $type = 'alta') */ function autoverifactuInvoiceImmutableXMLPath($invoice, $type = 'alta') { - global $conf; - //genero el archivo xml con fecha para que no se sobrescriban y tener un historial - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); - - $invoiceref = dol_sanitizeFileName($invoice->ref); - $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; - - $file = $dir . '/' . $invoiceref . '-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; - - return array($file, $hidden); + global $conf; + //genero el archivo xml con fecha para que no se sobrescriban y tener un historial + $now=new DateTimeImmutable( + 'now', + new DateTimeZone('Europe/Madrid'), + ); + + $invoiceref = dol_sanitizeFileName($invoice->ref); + $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; + + $file = $dir . '/' . $invoiceref . '-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; + + return array($file, $hidden); } /** @@ -201,27 +199,27 @@ function autoverifactuInvoiceImmutableXMLPath($invoice, $type = 'alta') */ function autoverifactuGetPreviousValidInvoice($invoice, $tms = null) { - global $db; - - $timestamp = $invoice->array_options['options_verifactu_tms'] ?: $tms ?: time(); - - $sql = 'SELECT f.rowid FROM ' . $db->prefix() . 'facture f'; - $sql .= ' LEFT JOIN ' . $db->prefix() . 'facture_extrafields fx'; - $sql .= ' ON f.rowid = fx.fk_object'; - $sql .= ' WHERE f.fk_statut > 0 AND f.type <= 3'; - $sql .= ' AND fx.verifactu_hash IS NOT null'; - $sql .= ' AND fx.verifactu_tms < ' . $timestamp; - $sql .= ' AND fx.fk_object != ' . $invoice->id; - $sql .= ' ORDER BY fx.verifactu_tms DESC'; - - $result = $db->query($sql); - - if ($result && $db->num_rows($result)) { - $obj = $db->fetch_object($result); - $invoice = new Facture($db); - $invoice->fetch($obj->rowid); - return $invoice; - } + global $db; + + $timestamp = $invoice->array_options['options_verifactu_tms'] ?: $tms ?: time(); + + $sql = 'SELECT f.rowid FROM ' . $db->prefix() . 'facture f'; + $sql .= ' LEFT JOIN ' . $db->prefix() . 'facture_extrafields fx'; + $sql .= ' ON f.rowid = fx.fk_object'; + $sql .= ' WHERE f.fk_statut > 0 AND f.type <= 3'; + $sql .= ' AND fx.verifactu_hash IS NOT null'; + $sql .= ' AND fx.verifactu_tms < ' . $timestamp; + $sql .= ' AND fx.fk_object != ' . $invoice->id; + $sql .= ' ORDER BY fx.verifactu_tms DESC'; + + $result = $db->query($sql); + + if ($result && $db->num_rows($result)) { + $obj = $db->fetch_object($result); + $invoice = new Facture($db); + $invoice->fetch($obj->rowid); + return $invoice; + } } /** @@ -233,20 +231,20 @@ function autoverifactuGetPreviousValidInvoice($invoice, $tms = null) */ function autoverifactuGetSourceInvoice($invoice) { - $prev_id = $invoice->fk_facture_source; - if (!$prev_id) { - return; - } + $prev_id = $invoice->fk_facture_source; + if (!$prev_id) { + return; + } - global $db; - $invoice = new Facture($db); - $found = $invoice->fetch($prev_id); + global $db; + $invoice = new Facture($db); + $found = $invoice->fetch($prev_id); - if (!$found) { - return; - } + if (!$found) { + return; + } - return $invoice; + return $invoice; } /** @@ -259,47 +257,47 @@ function autoverifactuGetSourceInvoice($invoice) */ function autoverifactuRecordFromLog($blockedlog, $recordType = 'alta') { - global $db; - - $objectdata = $blockedlog->object_data; - - $blocked = new Facture($db); - $blocked->fetch($blockedlog->fk_object); - - $blocked->status = 1; - $blocked->type = $objectdata->type; - $blocked->ref = $objectdata->ref; - - $lines = array(); - - $extrafields = new ExtraFields($db); - $extralabels = $extrafields->fetch_name_optionals_label('facturedet'); - - foreach ($objectdata->invoiceline as $indice => $linedata) { - $line = new FactureLigne($db); - - $line->localtax2_tx = $linedata->localtax2_tx; - $line->localtax1_tx =$linedata->localtax1_tx; - $line->tva_tx = $linedata->tva_tx; - $line->total_localtax1 = $linedata->total_localtax1; - $line->total_localtax2 = $linedata->total_localtax2; - $line->total_ht = $linedata->total_ht; - $line->total_tva = $linedata->total_tva; - $line->product_type=$linedata->product_type; - $lines[] = $line; - } - $blocked->lines = $lines; - - if (isset($objectdata->thirdparty) && $objectdata->thirdparty) { - $blocked->thirdparty = new Societe($db); - $blocked->thirdparty->nom = $objectdata->thirdparty->name; - $blocked->thirdparty->idprof1 = $objectdata->thirdparty->idprof1u ?? null; - $blocked->thirdparty->country_code = $objectdata->thirdparty->country_code ?? null; - $blocked->thirdparty->code_client = $objectdata->thirdparty->code_client; - } else { - $blocked->thirdparty = null; - } - return autoverifactuInvoiceToRecord($blocked, $recordType); + global $db; + + $objectdata = $blockedlog->object_data; + + $blocked = new Facture($db); + $blocked->fetch($blockedlog->fk_object); + + $blocked->status = 1; + $blocked->type = $objectdata->type; + $blocked->ref = $objectdata->ref; + + $lines = array(); + + $extrafields = new ExtraFields($db); + $extralabels = $extrafields->fetch_name_optionals_label('facturedet'); + + foreach ($objectdata->invoiceline as $indice => $linedata) { + $line = new FactureLigne($db); + + $line->localtax2_tx = $linedata->localtax2_tx; + $line->localtax1_tx =$linedata->localtax1_tx; + $line->tva_tx = $linedata->tva_tx; + $line->total_localtax1 = $linedata->total_localtax1; + $line->total_localtax2 = $linedata->total_localtax2; + $line->total_ht = $linedata->total_ht; + $line->total_tva = $linedata->total_tva; + $line->product_type=$linedata->product_type; + $lines[] = $line; + } + $blocked->lines = $lines; + + if (isset($objectdata->thirdparty) && $objectdata->thirdparty) { + $blocked->thirdparty = new Societe($db); + $blocked->thirdparty->nom = $objectdata->thirdparty->name; + $blocked->thirdparty->idprof1 = $objectdata->thirdparty->idprof1u ?? null; + $blocked->thirdparty->country_code = $objectdata->thirdparty->country_code ?? null; + $blocked->thirdparty->code_client = $objectdata->thirdparty->code_client; + } else { + $blocked->thirdparty = null; + } + return autoverifactuInvoiceToRecord($blocked, $recordType); } /** @@ -312,19 +310,19 @@ function autoverifactuRecordFromLog($blockedlog, $recordType = 'alta') */ function autoverifactuPkcs12Check($certpath, $password) { - if (!is_file($certpath)) { - return 0; - } - $ext = strtolower(pathinfo($certpath)['extension'] ?? ''); - if (!in_array($ext, array('p12', 'pfx'), true)) { - return 0; - } - $password = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); - if (!$password) { - return 0; - } - $content = file_get_contents($certpath); - return (int) openssl_pkcs12_read($content, $_, $password); + if (!is_file($certpath)) { + return 0; + } + $ext = strtolower(pathinfo($certpath)['extension'] ?? ''); + if (!in_array($ext, array('p12', 'pfx'), true)) { + return 0; + } + $password = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); + if (!$password) { + return 0; + } + $content = file_get_contents($certpath); + return (int) openssl_pkcs12_read($content, $_, $password); } /** @@ -334,22 +332,22 @@ function autoverifactuPkcs12Check($certpath, $password) */ function autoverifactuSystemCheck() { - global $conf, $mysoc; - if (!function_exists('isValidTinForES')) { - require_once DOL_DOCUMENT_ROOT . '/core/lib/profid.lib.php'; - } - $certpath = DOL_DATA_ROOT . '/' . (getDolGlobalString('AUTOVERIFACTU_CERT') ?: 'nofile'); - if (!is_file($certpath)) { - return 0; - } - return intval( - $mysoc->nom && $mysoc->idprof1 - && isValidTinForES($mysoc->idprof1) - && !empty($conf->modules['blockedlog']) - && getDolGlobalInt('FAC_FORCE_DATE_VALIDATION') - && getDolGlobalString('AUTOVERIFACTU_RESPONSABILITY') - && autoverifactuPkcs12Check($certpath, getDolGlobalString('AUTOVERIFACTU_PASSWORD')) - ); + global $conf, $mysoc; + if (!function_exists('isValidTinForES')) { + require_once DOL_DOCUMENT_ROOT . '/core/lib/profid.lib.php'; + } + $certpath = DOL_DATA_ROOT . '/' . (getDolGlobalString('AUTOVERIFACTU_CERT') ?: 'nofile'); + if (!is_file($certpath)) { + return 0; + } + return intval( + $mysoc->nom && $mysoc->idprof1 + && isValidTinForES($mysoc->idprof1) + && !empty($conf->modules['blockedlog']) + && getDolGlobalInt('FAC_FORCE_DATE_VALIDATION') + && getDolGlobalString('AUTOVERIFACTU_RESPONSABILITY') + && autoverifactuPkcs12Check($certpath, getDolGlobalString('AUTOVERIFACTU_PASSWORD')) + ); } /** @@ -359,12 +357,12 @@ function autoverifactuSystemCheck() */ function autoverifactuEnabled() { - $check = autoverifactuSystemCheck(); - $enabled = getDolGlobalInt('AUTOVERIFACTU_ENABLED'); - if (!$check && $enabled) { - autoverifactu_set_const('AUTOVERIFACTU_ENABLED', false); - } - return $check && $enabled; + $check = autoverifactuSystemCheck(); + $enabled = getDolGlobalInt('AUTOVERIFACTU_ENABLED'); + if (!$check && $enabled) { + autoverifactu_set_const('AUTOVERIFACTU_ENABLED', false); + } + return $check && $enabled; } /** @@ -374,124 +372,124 @@ function autoverifactuEnabled() * @param array $error error array * @return int 0 if validatio fail, 1 if succeed */ -function autoverifactuValidateRecord($record,&$error) +function autoverifactuValidateRecord($record, &$error) { - $isValid = autoverifactuValidateRecordValues($record,$error); - - if (!$isValid) { - return 0; - } - - if (!isset($record->breakdown, $record->totalTaxAmount, $record->totalAmount)) { - $error[]='NotValueNull'; //añado error - return 0; - } - - if ( - in_array($record->invoiceType, array('F2', 'R5'), true) - && count($record->recipients) - ) { - // If is simplified, it should not have recipients. - $error[]='NotValidateTypeF2F5NotRecipients';//añado error - return 0; - } - - $isCorrective = preg_match('/R[0-5]/', $record->invoiceType); - if ($isCorrective && !$record->correctiveType) { - $error[]='InvoceMustBeCorrectiveType';//añado error - return 0; - } elseif (!$isCorrective && $record->correctiveType) { - $error[]='InvoceNotMustBeCorrectiveType';//añado error - return 0; - } elseif (!$isCorrective && count($record->correctedInvoices)) { - $error[]='InvoceNotMustBeCorrectiveType';//añado error - return 0; - } - - if ($record->correctiveType === 'S') { - // If its corrective by diferrence it should have base and tax amounts. - if (!$record->correctedBaseAmount || !$record->correctedTaxAmount) { - $error[]='CorrectiveTypeDiferrenceShouldHaveBaseTaxAmounts';//añado error - return 0; - } - } else { - // If is corrective by substitution, it shouldn't. - if ($record->correctedBaseAmount || $record->correctedTaxAmount) { - $error[]='CorrectiveTypeSubtitutionNotShouldHaveBaseTaxAmounts';//añado error - return 0; - } - } - - if ($record->invoiceType === 'F3' && count($record->replacedInvoices)) { - $error[]='NotValidateTypeF3RemplaceInvoice';//añado error - return 0; - } elseif ($record->invoiceType !== 'F3' && count($record->replacedInvoices)) { - $error[]='NotValidateTypeNotF3RemplaceInvoice';//añado error - return 0; - } - $expectedTax = 0; - $expectedBase = 0; - foreach ($record->breakdown as $details) { - if (!isset($details->taxAmount, $details->baseAmount, $details->taxRate)) { - $error[]='NotValueNull';//añado error - return 0; - } - $validTaxAmount = false; - $validTaxAmountEquivalenceSurcharge=false; - $expectedLineTax = (float) $details->baseAmount * $details->taxRate / 100; - if( isset( $details->equivalenceSurcharge)){ - if($record->regimeType !=='18'){ - $error[]="NotValidRegimeTypeEquivalenceSurcharge";//añado error - } - $expectedLineEquivalenceSurcharge= $details->baseAmount * $details->equivalenceSurcharge->type / 100; - for ($t = -0.02; $t <= 0.02; $t += 0.01) { - $taxAmount = number_format($expectedLineEquivalenceSurcharge + $t, 2, '.', ''); - /*var_dump($taxAmount); - echo "
"; - var_dump($details->equivalenceSurcharge->total); - echo "
"; - echo "
"; - echo "
";*/ - if ($details->equivalenceSurcharge->total === $taxAmount) { - $validTaxAmountEquivalenceSurcharge = true; - break; - } - } - if (!$validTaxAmountEquivalenceSurcharge) { - $error[]="NotValidTaxAmountEquivalenceSurcharge";//añado error - return 0; - } - $expectedTax += $details->equivalenceSurcharge->total; - } - for ($t = -0.02; $t <= 0.02; $t += 0.01) { - $taxAmount = number_format($expectedLineTax + $t, 2, '.', ''); - if ($details->taxAmount === $taxAmount) { - $validTaxAmount = true; - break; - } - } - if (!$validTaxAmount) { - $error[]="NotValidTaxAmount";//añado error - return 0; - } - $expectedTax += $details->taxAmount; - $expectedBase += $details->baseAmount; - } - $expectedTax = number_format($expectedTax, 2, '.', ''); - $expectedBase = number_format($expectedBase, 2, '.', ''); - $expectedTotal = number_format($expectedTax + $expectedBase, 2, '.', ''); - $isTotalValid = false; - for ($t = -0.02; $t <= 0.02; $t += 0.01) { - $total = number_format($expectedTotal + $t, 2, '.', ''); - if ($record->totalAmount === $total ) { - $isTotalValid = true; - break; - } - } - if((int)$isTotalValid){ - $error[]='NotValueTotal';//añado error - } - return (int) $isTotalValid; + $isValid = autoverifactuValidateRecordValues($record, $error); + + if (!$isValid) { + return 0; + } + + if (!isset($record->breakdown, $record->totalTaxAmount, $record->totalAmount)) { + $error[]='NotValueNull'; //añado error + return 0; + } + + if ( + in_array($record->invoiceType, array('F2', 'R5'), true) + && count($record->recipients) + ) { + // If is simplified, it should not have recipients. + $error[]='NotValidateTypeF2F5NotRecipients';//añado error + return 0; + } + + $isCorrective = preg_match('/R[0-5]/', $record->invoiceType); + if ($isCorrective && !$record->correctiveType) { + $error[]='InvoceMustBeCorrectiveType';//añado error + return 0; + } elseif (!$isCorrective && $record->correctiveType) { + $error[]='InvoceNotMustBeCorrectiveType';//añado error + return 0; + } elseif (!$isCorrective && count($record->correctedInvoices)) { + $error[]='InvoceNotMustBeCorrectiveType';//añado error + return 0; + } + + if ($record->correctiveType === 'S') { + // If its corrective by diferrence it should have base and tax amounts. + if (!$record->correctedBaseAmount || !$record->correctedTaxAmount) { + $error[]='CorrectiveTypeDiferrenceShouldHaveBaseTaxAmounts';//añado error + return 0; + } + } else { + // If is corrective by substitution, it shouldn't. + if ($record->correctedBaseAmount || $record->correctedTaxAmount) { + $error[]='CorrectiveTypeSubtitutionNotShouldHaveBaseTaxAmounts';//añado error + return 0; + } + } + + if ($record->invoiceType === 'F3' && count($record->replacedInvoices)) { + $error[]='NotValidateTypeF3RemplaceInvoice';//añado error + return 0; + } elseif ($record->invoiceType !== 'F3' && count($record->replacedInvoices)) { + $error[]='NotValidateTypeNotF3RemplaceInvoice';//añado error + return 0; + } + $expectedTax = 0; + $expectedBase = 0; + foreach ($record->breakdown as $details) { + if (!isset($details->taxAmount, $details->baseAmount, $details->taxRate)) { + $error[]='NotValueNull';//añado error + return 0; + } + $validTaxAmount = false; + $validTaxAmountEquivalenceSurcharge=false; + $expectedLineTax = (float) $details->baseAmount * $details->taxRate / 100; + if ( isset($details->equivalenceSurcharge)) { + if ($record->regimeType !=='18') { + $error[]="NotValidRegimeTypeEquivalenceSurcharge";//añado error + } + $expectedLineEquivalenceSurcharge= $details->baseAmount * $details->equivalenceSurcharge->type / 100; + for ($t = -0.02; $t <= 0.02; $t += 0.01) { + $taxAmount = number_format($expectedLineEquivalenceSurcharge + $t, 2, '.', ''); + /*var_dump($taxAmount); + echo "
"; + var_dump($details->equivalenceSurcharge->total); + echo "
"; + echo "
"; + echo "
";*/ + if ($details->equivalenceSurcharge->total === $taxAmount) { + $validTaxAmountEquivalenceSurcharge = true; + break; + } + } + if (!$validTaxAmountEquivalenceSurcharge) { + $error[]="NotValidTaxAmountEquivalenceSurcharge";//añado error + return 0; + } + $expectedTax += $details->equivalenceSurcharge->total; + } + for ($t = -0.02; $t <= 0.02; $t += 0.01) { + $taxAmount = number_format($expectedLineTax + $t, 2, '.', ''); + if ($details->taxAmount === $taxAmount) { + $validTaxAmount = true; + break; + } + } + if (!$validTaxAmount) { + $error[]="NotValidTaxAmount";//añado error + return 0; + } + $expectedTax += $details->taxAmount; + $expectedBase += $details->baseAmount; + } + $expectedTax = number_format($expectedTax, 2, '.', ''); + $expectedBase = number_format($expectedBase, 2, '.', ''); + $expectedTotal = number_format($expectedTax + $expectedBase, 2, '.', ''); + $isTotalValid = false; + for ($t = -0.02; $t <= 0.02; $t += 0.01) { + $total = number_format($expectedTotal + $t, 2, '.', ''); + if ($record->totalAmount === $total ) { + $isTotalValid = true; + break; + } + } + if ((int) $isTotalValid) { + $error[]='NotValueTotal';//añado error + } + return (int) $isTotalValid; } /** @@ -503,10 +501,10 @@ function autoverifactuValidateRecord($record,&$error) */ function autoverifactuIsInvoiceRecorded($invoice) { - $invoice->fetch_optionals(); - // return !!($invoice->array_options['options_verifactu_hash'] ?? false); - //ya pueden tener hash y tener que renviarlas en el caso de contener errores - return (!empty($invoice->array_options['options_verifactu_hash']) && !in_array( $invoice->array_options['options_verifactu_status'],array("2","4","5"), true)); + $invoice->fetch_optionals(); + // return !!($invoice->array_options['options_verifactu_hash'] ?? false); + //ya pueden tener hash y tener que renviarlas en el caso de contener errores + return (!empty($invoice->array_options['options_verifactu_hash']) && !in_array($invoice->array_options['options_verifactu_status'], array("2","4","5"), true)); } /** @@ -518,131 +516,129 @@ function autoverifactuIsInvoiceRecorded($invoice) */ function autoverifactuIsPosInvoice($invoice) { - $is_derived = in_array( - $invoice->type, - array( - Facture::TYPE_REPLACEMENT, - Facture::TYPE_CREDIT_NOTE - ) - ); - if ($is_derived && $invoice->fk_facture_source) { - global $db; - $source = new Facture($db); - $source->fetch($invoice->fk_facture_source); - - $invoice = $source; - } - return $invoice->module_source === 'takepos'; + $is_derived = in_array( + $invoice->type, + array( + Facture::TYPE_REPLACEMENT, + Facture::TYPE_CREDIT_NOTE + ) + ); + if ($is_derived && $invoice->fk_facture_source) { + global $db; + $source = new Facture($db); + $source->fetch($invoice->fk_facture_source); + + $invoice = $source; + } + return $invoice->module_source === 'takepos'; } /** * Performs validation checks to the record values. * * @param stdClass $record Invoice record object. - * @param array $error array de errores + * @param array $error array de errores * @return bool */ -function autoverifactuValidateRecordValues($record ,&$error) +function autoverifactuValidateRecordValues($record, &$error) { - if (!autoverifactuValidateRecordType($record->type)) { - $error[] = "NotRecordType";//añado error - return false; - } - - if (!autoverifactuValidateInvoiceType($record->invoiceType)) { - $error[] = "NotRecordInvoiceType";//añado error - return false; - } - - if (!autoverifactuValidateDate($record->dateOperation, false)) { - $error[] = "NotRecordDateOperation";//añado error - return false; - } - - if (!autoverifactuValidateAlphaNumber($record->description, 500)) { - $error[] = "NotValidRecordDescription";//añado error - return false; - } - - if (!autoverifactuValidateAlphaNumber($record->invoiceId->invoiceNumber, 60)) { - $error[] = "NotValidRecordInvoice";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->factureTotalAmount, 12, 2)) { - $error[] = "NotValidRecordFactureTTC";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->factureTtc, 12, 2)) { - $error[] = "NotValidRecordTTC";//añado error - return false; - } - - if ($record->factureTotalAmount !== $record->factureTtc) { - $error[] = "NotEqualRecordTTCAndRecordFactureTTC";//añado error - return false; - } - - if (!autoverifactuValidateCorrectiveType($record->correctiveType, false)) { - $error[] = "NotValidRecordcorrectiveType";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->correctedBaseAmount, 12, 2, false)) { - $error[] = "NotValidCorrectedBaseAmount";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->correctedTaxAmount, 12, 2, false)) { - $error[] = "NotValidCorrectedTaxAmount";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->totalTaxAmount, 12, 2)) { - $error[] = "NotValidRecordTotalTaxAmount";//añado error - return false; - } - - if (!autoverifactuValidateNumber($record->totalAmount, 12, 2)) { - $error[] = "NotValidRecordTotalAmount";//añado error - return false; - } - - if(!autoverifactuValidateTotalAndTotalTax($record,$error)){ - return false; - } - - foreach ($record->breakdown as $breakdownDetails) { - - if(!autoverifactuValidateTaxType($breakdownDetails->taxType)){ - $error[]="NotValidateTaxType";//añado error - return false; - } - if(!autoverifactuValidateRegimeType($breakdownDetails->regimeType)){ - $error[]="NotValidateRegimeType";//añado error - return false; - } - if(!autoverifactuValidateOperationType($breakdownDetails->operationType)){ - $error[]="NotValidateOperationType";//añado error - return false; - } - if( ! autoverifactuValidateNumber($breakdownDetails->taxRate, 4, 2)){ - $error[]="NotValidateTaxRate";//añado error - return false; - } - if( !autoverifactuValidateNumber($breakdownDetails->baseAmount, 12, 2)){ - $error[]="NotValidateBaseAmount";//añado error - return false; - } - if(!autoverifactuValidateExcemptionCode($breakdownDetails->excemptionCode, false)){ - $error[]="NotValidateExcemptionCode";//añado error - return false; - } - - } - - return true; + if (!autoverifactuValidateRecordType($record->type)) { + $error[] = "NotRecordType";//añado error + return false; + } + + if (!autoverifactuValidateInvoiceType($record->invoiceType)) { + $error[] = "NotRecordInvoiceType";//añado error + return false; + } + + if (!autoverifactuValidateDate($record->dateOperation, false)) { + $error[] = "NotRecordDateOperation";//añado error + return false; + } + + if (!autoverifactuValidateAlphaNumber($record->description, 500)) { + $error[] = "NotValidRecordDescription";//añado error + return false; + } + + if (!autoverifactuValidateAlphaNumber($record->invoiceId->invoiceNumber, 60)) { + $error[] = "NotValidRecordInvoice";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->factureTotalAmount, 12, 2)) { + $error[] = "NotValidRecordFactureTTC";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->factureTtc, 12, 2)) { + $error[] = "NotValidRecordTTC";//añado error + return false; + } + + if ($record->factureTotalAmount !== $record->factureTtc) { + $error[] = "NotEqualRecordTTCAndRecordFactureTTC";//añado error + return false; + } + + if (!autoverifactuValidateCorrectiveType($record->correctiveType, false)) { + $error[] = "NotValidRecordcorrectiveType";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->correctedBaseAmount, 12, 2, false)) { + $error[] = "NotValidCorrectedBaseAmount";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->correctedTaxAmount, 12, 2, false)) { + $error[] = "NotValidCorrectedTaxAmount";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->totalTaxAmount, 12, 2)) { + $error[] = "NotValidRecordTotalTaxAmount";//añado error + return false; + } + + if (!autoverifactuValidateNumber($record->totalAmount, 12, 2)) { + $error[] = "NotValidRecordTotalAmount";//añado error + return false; + } + + if (!autoverifactuValidateTotalAndTotalTax($record, $error)) { + return false; + } + + foreach ($record->breakdown as $breakdownDetails) { + if (!autoverifactuValidateTaxType($breakdownDetails->taxType)) { + $error[]="NotValidateTaxType";//añado error + return false; + } + if (!autoverifactuValidateRegimeType($breakdownDetails->regimeType)) { + $error[]="NotValidateRegimeType";//añado error + return false; + } + if (!autoverifactuValidateOperationType($breakdownDetails->operationType)) { + $error[]="NotValidateOperationType";//añado error + return false; + } + if ( ! autoverifactuValidateNumber($breakdownDetails->taxRate, 4, 2)) { + $error[]="NotValidateTaxRate";//añado error + return false; + } + if ( !autoverifactuValidateNumber($breakdownDetails->baseAmount, 12, 2)) { + $error[]="NotValidateBaseAmount";//añado error + return false; + } + if (!autoverifactuValidateExcemptionCode($breakdownDetails->excemptionCode, false)) { + $error[]="NotValidateExcemptionCode";//añado error + return false; + } + } + + return true; } /** @@ -656,8 +652,8 @@ function autoverifactuValidateRecordValues($record ,&$error) function autoverifactuValidateRecordType($value, $required = true) { - $options = array('alta', 'anulacion'); - return in_array($value, $options, true) || !$required && empty($value); + $options = array('alta', 'anulacion'); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -669,19 +665,19 @@ function autoverifactuValidateRecordType($value, $required = true) * @return bool */ function autoverifactuValidateDate($value, $required = true) -{ - - //Si está vacío y no es obligatorio, es válido - if (!$required && empty($value)) { - return true; - } - //Si ya es un objeto de fecha (DateTime o DateTimeImmutable), es válido - if ($value instanceof DateTimeInterface) { - return true; - } - - $d = DateTime::createFromFormat('d-m-y', $value); - return $d && $d->format('d-m-y') === $value || !$required && empty($value); +{ + + //Si está vacío y no es obligatorio, es válido + if (!$required && empty($value)) { + return true; + } + //Si ya es un objeto de fecha (DateTime o DateTimeImmutable), es válido + if ($value instanceof DateTimeInterface) { + return true; + } + + $d = DateTime::createFromFormat('d-m-y', $value); + return $d && $d->format('d-m-y') === $value || !$required && empty($value); } /** @@ -694,8 +690,8 @@ function autoverifactuValidateDate($value, $required = true) */ function autoverifactuValidateInvoiceType($value, $required = true) { - $options = array('F1', 'F2', 'F3', 'R1', 'R2', 'R3', 'R4', 'R5'); - return in_array($value, $options, true) || !$required && empty($value); + $options = array('F1', 'F2', 'F3', 'R1', 'R2', 'R3', 'R4', 'R5'); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -708,10 +704,10 @@ function autoverifactuValidateInvoiceType($value, $required = true) */ function autoverifactuValidateCorrectiveType($value, $required = true) { - //factura correctiva I o S (Diferencia o Sustitución ) - $options = array('I', 'S'); + //factura correctiva I o S (Diferencia o Sustitución ) + $options = array('I', 'S'); - return in_array($value, $options, true) || !$required && empty($value); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -725,16 +721,16 @@ function autoverifactuValidateCorrectiveType($value, $required = true) */ function autoverifactuValidateAlphaNumber($value, $length, $required = true) { - if (!$required && empty($value)) { - return true; - } + if (!$required && empty($value)) { + return true; + } // la variable $string no existe es $value - $actualLength = mb_strlen($value, 'UTF-8'); - if ($actualLength === 0 || $actualLength > intval($length)) { - return false; - } + $actualLength = mb_strlen($value, 'UTF-8'); + if ($actualLength === 0 || $actualLength > intval($length)) { + return false; + } - return htmlspecialchars($value) === $value; + return htmlspecialchars($value) === $value; } /** @@ -749,30 +745,30 @@ function autoverifactuValidateAlphaNumber($value, $length, $required = true) */ function autoverifactuValidateNumber($value, $digits = 12, $decimals = 2, $required = true) { - if (!$required && empty($value)) { - return true; - } - if (!is_numeric($value)) { - return false; - } - $abs = strval(abs($value)); - $parts = explode('.', $abs); - $integers = $parts[0]; - //en versiones de php más extrictas $parts[1] ?? ''; al realizar la resta de $digits - $decimals da error al no ser un valor numérico, por eso asigno 0 - $decimalPart = $parts[1] ?? ''; - $maxIntegers; - if ($decimalPart === '') { - $maxIntegers = $digits; - }else{ - $maxIntegers = $digits - $decimals; - } - $intCount = strlen($integers); - $decCount = strlen($decimalPart); - return ( - $intCount <= $maxIntegers - && $decCount <= intval($decimals) - && $intCount + $decCount <= $digits - ); + if (!$required && empty($value)) { + return true; + } + if (!is_numeric($value)) { + return false; + } + $abs = strval(abs($value)); + $parts = explode('.', $abs); + $integers = $parts[0]; + //en versiones de php más extrictas $parts[1] ?? ''; al realizar la resta de $digits - $decimals da error al no ser un valor numérico, por eso asigno 0 + $decimalPart = $parts[1] ?? ''; + $maxIntegers; + if ($decimalPart === '') { + $maxIntegers = $digits; + } else { + $maxIntegers = $digits - $decimals; + } + $intCount = strlen($integers); + $decCount = strlen($decimalPart); + return ( + $intCount <= $maxIntegers + && $decCount <= intval($decimals) + && $intCount + $decCount <= $digits + ); } @@ -786,8 +782,8 @@ function autoverifactuValidateNumber($value, $digits = 12, $decimals = 2, $requi */ function autoverifactuValidateTaxType($value, $required = true) { - $options = array('01', '02', '03', '05'); - return in_array($value, $options, true) || !$required && empty($value); + $options = array('01', '02', '03', '05'); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -800,27 +796,27 @@ function autoverifactuValidateTaxType($value, $required = true) */ function autoverifactuValidateRegimeType($value, $required = true) { - $options = array( - '01', - '02', - '03', - '04', - '05', - '06', - '07', - '08', - '09', - '10', - '11', - '14', - '15', - '17', - '18', - '19', - '20', - ); - - return in_array($value, $options, true) || !$required && empty($value); + $options = array( + '01', + '02', + '03', + '04', + '05', + '06', + '07', + '08', + '09', + '10', + '11', + '14', + '15', + '17', + '18', + '19', + '20', + ); + + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -833,9 +829,9 @@ function autoverifactuValidateRegimeType($value, $required = true) */ function autoverifactuValidateOperationType($value, $required = true) { - //hay que añadir la opcion de validate - $options = array('S1', 'S2', 'N1', 'N2'); - return in_array($value, $options, true) || !$required && empty($value); + //hay que añadir la opcion de validate + $options = array('S1', 'S2', 'N1', 'N2'); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -848,8 +844,8 @@ function autoverifactuValidateOperationType($value, $required = true) */ function autoverifactuValidateExcemptionCode($value, $required = true) { - $options = array('E1', 'E2', 'E3', 'E4', 'E5', 'E6'); - return in_array($value, $options, true) || !$required && empty($value); + $options = array('E1', 'E2', 'E3', 'E4', 'E5', 'E6'); + return in_array($value, $options, true) || !$required && empty($value); } /** @@ -857,35 +853,36 @@ function autoverifactuValidateExcemptionCode($value, $required = true) * @param stdClass $record Invoice record object. * * @return bool - * + * */ -function autoverifactuValidateTotalAndTotalTax($record,&$error){ - //valido que las taxas y las cuantias calculadas sean las mismas - $isTotalValid = false; - for ($t = -0.02; $t <= 0.02; $t += 0.01) { - $total = number_format($record->totalAmount + $t, 2, '.', ''); - var_dump( $record->factureTtc ); - var_dump($total); - if ( $record->factureTtc === $total ) { - $isTotalValid = true; - break; - } - } - if (!$isTotalValid) { - $error[] ="NotValidCalculatedTotal";//añado error - return false; - } - $isTotalTaxAmountValid = false; - for ($t = -0.02; $t <= 0.02; $t += 0.01) { - $total = number_format($record->totalTaxAmount + $t, 2, '.', ''); - if ( $record->factureTotalTaxAmount === $total ) { - $isTotalTaxAmountValid = true; - break; - } - } - if (!$isTotalTaxAmountValid) { - $error[] ="NotValidCalculatedRate";//añado error - return false; - } - return true; -} \ No newline at end of file +function autoverifactuValidateTotalAndTotalTax($record, &$error) +{ + //valido que las taxas y las cuantias calculadas sean las mismas + $isTotalValid = false; + for ($t = -0.02; $t <= 0.02; $t += 0.01) { + $total = number_format($record->totalAmount + $t, 2, '.', ''); + var_dump($record->factureTtc); + var_dump($total); + if ( $record->factureTtc === $total ) { + $isTotalValid = true; + break; + } + } + if (!$isTotalValid) { + $error[] ="NotValidCalculatedTotal";//añado error + return false; + } + $isTotalTaxAmountValid = false; + for ($t = -0.02; $t <= 0.02; $t += 0.01) { + $total = number_format($record->totalTaxAmount + $t, 2, '.', ''); + if ( $record->factureTotalTaxAmount === $total ) { + $isTotalTaxAmountValid = true; + break; + } + } + if (!$isTotalTaxAmountValid) { + $error[] ="NotValidCalculatedRate";//añado error + return false; + } + return true; +} diff --git a/lib/verifactu.lib.php b/lib/verifactu.lib.php index 1e7d9cc..43f920b 100644 --- a/lib/verifactu.lib.php +++ b/lib/verifactu.lib.php @@ -38,12 +38,12 @@ /* XML namespaces */ define('AUTOVERIFACTU_SOAPENV_NS', 'http://schemas.xmlsoap.org/soap/envelope/'); define( - 'AUTOVERIFACTU_SUM_NS', - 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', + 'AUTOVERIFACTU_SUM_NS', + 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroLR.xsd', ); define( - 'AUTOVERIFACTU_SUM1_NS', - 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd', + 'AUTOVERIFACTU_SUM1_NS', + 'https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SuministroInformacion.xsd', ); define('AUTOVERIFACTU_XD_NS', 'http://www.w3.org/2000/09/xmldsig'); @@ -51,190 +51,185 @@ * Verifactu invoice record registration. * * @param Facture $invoice Target invoice. Invoice should not be validated, or - * action should be BILL_CANCEL. + * action should be BILL_CANCEL. * @param string $action Current action. * * @return int Return <0 if KO, 0 if skipped, >0 if OK. */ function autoverifactuRegisterInvoice($invoice, $action) { - - - - global $db, $conf, $hookmanager; - - $error; - if ($invoice->type > Facture::TYPE_DEPOSIT) { - - // Skip non recordable invoice types. - return 0; - } - - - - if ( - $invoice->status == Facture::STATUS_DRAFT && - !in_array( - $action, - array( - 'BILL_VALIDATE', - // 'DON_VALIDATE', - // 'CASHCONTROL_VALIDATE', - ), - true, - ) - ) { - - return 0; - } elseif ( - $invoice->status == Facture::STATUS_VALIDATED && - $action !== 'BILL_CANCEL' - && - $action !== 'verifactuResend' //excluyo en caso de reenvio - ) { - - return 0; - } -; - if (empty($conf->facture->multidir_output[$conf->entity])) { - dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); - $invoice->error[]="NotExistInvoiceOutput"; //añado el error - return -1; - } - - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); - - $invoice->fetch_thirdparty(); - $thirdparty = $invoice->thirdparty; - $valid_id = $thirdparty->id_prof_check(1, $thirdparty); - - //las facturas simplificadas no tienen tercero y por tanto tienen que evitar esta validación - if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { - dol_syslog('Skip invoice verifactu record registration due to thirdparty without a vaid idprof1'); - $invoice->error[]="NotNIFThirdparty"; - return -1; - } - - $invoice->fetch_lines(); - if (!count($invoice->lines)) { - dol_syslog('Skip invoice verifactu record registration to an invoice without lines'); - $invoice->error[]="NotLinesFacure"; - return -1; - } - - $invoiceref = dol_sanitizeFileName($invoice->ref); - $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; - //he añadido la fecha para que no se sobreescriban los XML - //de esta forma se tiene un historial de todas los XML enviados - if ($action === 'BILL_VALIDATE') { - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - }else if($action === 'verifactuResend'){ - $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - }else { - $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - } - - if (!file_exists($dir)) { - if (dol_mkdir($dir) < 0) { - dol_syslog('Unable to create verifactu files directory ' . $dir, LOG_ERR); - $invoice->error[]="NotCreateDirectoryVerifactu"; - return -1; - } - } - - if (!is_object($hookmanager)) { - include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($db); - } - - $hookmanager->initHooks(array('autoverifactu')); - - $parameters = array( - 'file' => $file, - 'invoice' => $invoice, - 'action' => $action, - ); - - $reshook = $hookmanager->executeHooks( - 'beforeAutoverifactuRecord', - $parameters, - $invoice, - ); - - if ($reshook < 0) { - dol_syslog('Skip verfiactu record registry for invoice #' . $invoice->id); - return $reshook; - } elseif ($reshook) { - dol_syslog( - 'Verfiactu record registry interception on "beforeAutoverifactuRecord" for invoice #' - . $invoice->id - ); - - return $reshook; - } - - try { - - $record = autoverifactuSendInvoice($invoice, $action, $xml); - - - // Skip document generation if send does not succeed. - if (!$record) { - return 0; - } - - $result = file_put_contents($file, $xml); - $result = $result && file_put_contents($hidden, $xml); - - if (!$result) { - throw new Exception('Unable to store XML invoice record', 500); - } else { - // Store invoice verifactu extrafields after record registration - $invoice->array_options['options_verifactu_hash'] = $record->hash; - $invoice->array_options['options_verifactu_tms'] = $record->hashedAt->getTimestamp(); - - if ($error = $record->error ?? null) { - $invoice->array_options['options_verifactu_error'] = $error->message; - $invoice->array_options['options_verifactu_error_code'] = $error->code; - } - - - $result = $invoice->insertExtraFields(); - - if ($result <= 0) { - throw new Exception('Unable to update invoice extra fields', 500); - } - - $parameters['record'] = $record; - $parameters['xml'] = $xml; - - $reshook = $hookmanager->executeHooks( - 'afterAutoverifactuRecord', - $parameters, - $invoice, - ); - } - } catch (Error | Exception $e) { - - if (isset($xml) && $xml) { - file_put_contents($file, $xml); - } - - if (isset($record) && $record) { - autoverifactuSendInvoice($invoice, 'anulacion'); - } - - dol_syslog('Error on verifactu request ' . print_r($e, true), LOG_ERR); - return -1; - } - - return 1; + + + + global $db, $conf, $hookmanager; + + $error; + if ($invoice->type > Facture::TYPE_DEPOSIT) { + // Skip non recordable invoice types. + return 0; + } + + + + if ( + $invoice->status == Facture::STATUS_DRAFT && + !in_array( + $action, + array( + 'BILL_VALIDATE', + // 'DON_VALIDATE', + // 'CASHCONTROL_VALIDATE', + ), + true, + ) + ) { + return 0; + } elseif ( + $invoice->status == Facture::STATUS_VALIDATED && + $action !== 'BILL_CANCEL' + && + $action !== 'verifactuResend' //excluyo en caso de reenvio + ) { + return 0; + } + ; + if (empty($conf->facture->multidir_output[$conf->entity])) { + dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); + $invoice->error[]="NotExistInvoiceOutput"; //añado el error + return -1; + } + + $now=new DateTimeImmutable( + 'now', + new DateTimeZone('Europe/Madrid'), + ); + + $invoice->fetch_thirdparty(); + $thirdparty = $invoice->thirdparty; + $valid_id = $thirdparty->id_prof_check(1, $thirdparty); + + //las facturas simplificadas no tienen tercero y por tanto tienen que evitar esta validación + if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { + dol_syslog('Skip invoice verifactu record registration due to thirdparty without a vaid idprof1'); + $invoice->error[]="NotNIFThirdparty"; + return -1; + } + + $invoice->fetch_lines(); + if (!count($invoice->lines)) { + dol_syslog('Skip invoice verifactu record registration to an invoice without lines'); + $invoice->error[]="NotLinesFacure"; + return -1; + } + + $invoiceref = dol_sanitizeFileName($invoice->ref); + $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; + //he añadido la fecha para que no se sobreescriban los XML + //de esta forma se tiene un historial de todas los XML enviados + if ($action === 'BILL_VALIDATE') { + $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + } elseif ($action === 'verifactuResend') { + $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + } else { + $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + } + + if (!file_exists($dir)) { + if (dol_mkdir($dir) < 0) { + dol_syslog('Unable to create verifactu files directory ' . $dir, LOG_ERR); + $invoice->error[]="NotCreateDirectoryVerifactu"; + return -1; + } + } + + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($db); + } + + $hookmanager->initHooks(array('autoverifactu')); + + $parameters = array( + 'file' => $file, + 'invoice' => $invoice, + 'action' => $action, + ); + + $reshook = $hookmanager->executeHooks( + 'beforeAutoverifactuRecord', + $parameters, + $invoice, + ); + + if ($reshook < 0) { + dol_syslog('Skip verfiactu record registry for invoice #' . $invoice->id); + return $reshook; + } elseif ($reshook) { + dol_syslog( + 'Verfiactu record registry interception on "beforeAutoverifactuRecord" for invoice #' + . $invoice->id + ); + + return $reshook; + } + + try { + $record = autoverifactuSendInvoice($invoice, $action, $xml); + + + // Skip document generation if send does not succeed. + if (!$record) { + return 0; + } + + $result = file_put_contents($file, $xml); + $result = $result && file_put_contents($hidden, $xml); + + if (!$result) { + throw new Exception('Unable to store XML invoice record', 500); + } else { + // Store invoice verifactu extrafields after record registration + $invoice->array_options['options_verifactu_hash'] = $record->hash; + $invoice->array_options['options_verifactu_tms'] = $record->hashedAt->getTimestamp(); + + if ($error = $record->error ?? null) { + $invoice->array_options['options_verifactu_error'] = $error->message; + $invoice->array_options['options_verifactu_error_code'] = $error->code; + } + + + $result = $invoice->insertExtraFields(); + + if ($result <= 0) { + throw new Exception('Unable to update invoice extra fields', 500); + } + + $parameters['record'] = $record; + $parameters['xml'] = $xml; + + $reshook = $hookmanager->executeHooks( + 'afterAutoverifactuRecord', + $parameters, + $invoice, + ); + } + } catch (Error | Exception $e) { + if (isset($xml) && $xml) { + file_put_contents($file, $xml); + } + + if (isset($record) && $record) { + autoverifactuSendInvoice($invoice, 'anulacion'); + } + + dol_syslog('Error on verifactu request ' . print_r($e, true), LOG_ERR); + return -1; + } + + return 1; } /** @@ -250,194 +245,189 @@ function autoverifactuRegisterInvoice($invoice, $action) */ function autoverifactuSendInvoice($invoice, $action, &$xml = '') { - global $user; - - if (!autoverifactuSystemCheck()) { - dol_syslog('Veri*Factu bridge does not pass system checks'); - return; - } - - $enabled = getDolGlobalString('AUTOVERIFACTU_ENABLED') === '1'; - - if (!$enabled) { - dol_syslog('Veri*Factu bridge is not enabled'); - return; - } - - $recordType = ($action === 'BILL_VALIDATE' || $action === 'verifactuResend') ? 'alta' : 'anulacion'; - - - if ($recordType === 'alta' && autoverifactuIsInvoiceRecorded($invoice)) { - dol_syslog( - 'Skip verifactu invoice registration because invoice #' - . $invoice->id . - 'is already registered', - ); - $invoice->error[]="alradyRegisterInvoice";//añado los errores - return -1 ; - } - - - $record = autoverifactuInvoiceToRecord($invoice, $recordType); - - - if (!$record) { - throw new Exception('Inconsistent invoice data'); - } - - global $hookmanager; - $parameters = array('record' => &$record, 'invoice' => $invoice, 'action' => $action); - $reshook = $hookmanager->executeHooks( - 'autoverifactuRecord', - $parameters, - $record, - ); - - if ($reshook < 0) { - dol_syslog('Skip verifactu record registry for invoice #' . $invoice->id); - return $reshook; - } elseif ($reshook) { - dol_syslog( - 'Verifactu record registry interception on "autoverifactuRecord" for invoice #' - . $invoice->id, - ); - - return $reshook; - } - - global $mysoc; - - $issuer = array( - 'name' => $mysoc->nom, - 'idprof1' => $mysoc->idprof1, - ); - //no exisiste la funcion autoverifactuValidateIssuer - /*$issuerIsValid = autoverifactuValidateIssuer($issuer); - - if (!$issuerIsValid) { - throw new Exception('Inconsistent issuer data'); - }*/ - - $envelope = $xml = autoverifactuSoapEnvelope( - $record, - $issuer - ); - $res; - - try { - $res = autoverifactuSoapRequest($envelope); - } catch (\Throwable $th) { - if($th->getCode()===503){ - //en caso de un error interno y que la factura sea alta meto en la lista a enviar - if($recordType==="alta"){ - $invoice->array_options['options_verifactu_status'] = '3'; - $invoice->insertExtraFields(); - dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); - return $record; - throw new Exception($th->getMessage(), 503); - }else{ - throw new Exception($th->getMessage(), 400); - } - }else{ - throw new Exception($th->getMessage(), 400); - } - - } - - - $status = $res->getElementsByTagName('EstadoRegistro')[0]; -/* echo "
"; - echo "
"; - echo "---------------NODE-----------------"; - echo "
"; - var_dump($status->nodeValue); - echo "
"; - echo "---------------NODE-----------------"; - echo "
"; - echo "
"; */ - if ($status->nodeValue === 'Incorrecto') { - - - dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); - dol_syslog($envelope, LOG_DEBUG); - if($operationTypeNode->nodeValue === "Anulacion"){ - //error de anulacion - $invoice->array_options['options_verifactu_status'] = '7'; - }else{ - //error de alta - - if(in_array($invoice->array_options['options_verifactu_status'], array('0','2'),true)){ - //No esta regsitrado(Pendiente de envio o rechazado) - $invoice->array_options['options_verifactu_status'] = '2'; - }else{ - //esta regsitrado (Registrado correctamente pero con errores o Registrado correctamente pero con errores múltiples veces) - $invoice->array_options['options_verifactu_status'] = '5'; - } - - } - $invoice->ref=$record->invoiceId->invoiceNumber; - - $errCode = $res->getElementsByTagName('CodigoErrorRegistro')[0] ?? null; - $errMessage = $res->getElementsByTagName('DescripcionErrorRegistro')[0] ?? null; - if (!$errMessage || !$errCode) { - dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); - dol_syslog($envelope, LOG_DEBUG); - throw new Exception($res->saveXML(), 500); - } - $record->error = new stdClass(); - $record->error->code = $errCode->nodeValue; - $record->error->message = $errMessage->nodeValue; - $result = $invoice->update($user); - $invoice->insertExtraFields(); - if ($result <= 0) { - throw new Exception($invoice->error, 1); - } - //throw new Exception($res->saveXML(), 400); - - } elseif ($status->nodeValue === 'AceptadoConErrores') { - $errCode = $res->getElementsByTagName('CodigoErrorRegistro')[0] ?? null; - $errMessage = $res->getElementsByTagName('DescripcionErrorRegistro')[0] ?? null; - if (!$errMessage || !$errCode) { - dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); - dol_syslog($envelope, LOG_DEBUG); - throw new Exception($res->saveXML(), 500); - } - - $record->error = new stdClass(); - $record->error->code = $errCode->nodeValue; - $record->error->message = $errMessage->nodeValue; - //actualizo el estado a Enviada y correcta con errores - $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; - if($operationTypeNode->nodeValue === "Anulacion"){ - //error de anulacion cuando esta la factura registrada - $invoice->array_options['options_verifactu_status'] = '7'; - }else{ - // - if( in_array($invoice->array_options['options_verifactu_status'], array('4','5'),true)){ - //hay errores en facturas de corrección - $invoice->array_options['options_verifactu_status'] = '5'; - }else{ - //no hay errores en facturas de correción - $invoice->array_options['options_verifactu_status'] = '4'; - } - } - - - $invoice->insertExtraFields(); - }else{ - //actualizo el estado a Enviada y correcta - $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; - //actualizo el estado segun sea anulacion o alta - $operationTypeNode->nodeValue === "Anulacion"? $invoice->array_options['options_verifactu_status'] = '6' : $invoice->array_options['options_verifactu_status'] = '1'; - $invoice->array_options['options_verifactu_error'] = ''; - $invoice->array_options['options_verifactu_error_code'] = ''; - - $invoice->insertExtraFields(); - } - - - - return $record; + global $user; + + if (!autoverifactuSystemCheck()) { + dol_syslog('Veri*Factu bridge does not pass system checks'); + return; + } + + $enabled = getDolGlobalString('AUTOVERIFACTU_ENABLED') === '1'; + + if (!$enabled) { + dol_syslog('Veri*Factu bridge is not enabled'); + return; + } + + $recordType = ($action === 'BILL_VALIDATE' || $action === 'verifactuResend') ? 'alta' : 'anulacion'; + + + if ($recordType === 'alta' && autoverifactuIsInvoiceRecorded($invoice)) { + dol_syslog( + 'Skip verifactu invoice registration because invoice #' + . $invoice->id . + 'is already registered', + ); + $invoice->error[]="alradyRegisterInvoice";//añado los errores + return -1 ; + } + + + $record = autoverifactuInvoiceToRecord($invoice, $recordType); + + + if (!$record) { + throw new Exception('Inconsistent invoice data'); + } + + global $hookmanager; + $parameters = array('record' => &$record, 'invoice' => $invoice, 'action' => $action); + $reshook = $hookmanager->executeHooks( + 'autoverifactuRecord', + $parameters, + $record, + ); + + if ($reshook < 0) { + dol_syslog('Skip verifactu record registry for invoice #' . $invoice->id); + return $reshook; + } elseif ($reshook) { + dol_syslog( + 'Verifactu record registry interception on "autoverifactuRecord" for invoice #' + . $invoice->id, + ); + + return $reshook; + } + + global $mysoc; + + $issuer = array( + 'name' => $mysoc->nom, + 'idprof1' => $mysoc->idprof1, + ); + //no exisiste la funcion autoverifactuValidateIssuer + /*$issuerIsValid = autoverifactuValidateIssuer($issuer); + + if (!$issuerIsValid) { + throw new Exception('Inconsistent issuer data'); + }*/ + + $envelope = $xml = autoverifactuSoapEnvelope( + $record, + $issuer + ); + $res; + + try { + $res = autoverifactuSoapRequest($envelope); + } catch (\Throwable $th) { + if ($th->getCode()===503) { + //en caso de un error interno y que la factura sea alta meto en la lista a enviar + if ($recordType==="alta") { + $invoice->array_options['options_verifactu_status'] = '3'; + $invoice->insertExtraFields(); + dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); + return $record; + throw new Exception($th->getMessage(), 503); + } else { + throw new Exception($th->getMessage(), 400); + } + } else { + throw new Exception($th->getMessage(), 400); + } + } + + + $status = $res->getElementsByTagName('EstadoRegistro')[0]; + /* echo "
"; + echo "
"; + echo "---------------NODE-----------------"; + echo "
"; + var_dump($status->nodeValue); + echo "
"; + echo "---------------NODE-----------------"; + echo "
"; + echo "
"; */ + if ($status->nodeValue === 'Incorrecto') { + dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); + dol_syslog($envelope, LOG_DEBUG); + if ($operationTypeNode->nodeValue === "Anulacion") { + //error de anulacion + $invoice->array_options['options_verifactu_status'] = '7'; + } else { + //error de alta + + if (in_array($invoice->array_options['options_verifactu_status'], array('0','2'), true)) { + //No esta regsitrado(Pendiente de envio o rechazado) + $invoice->array_options['options_verifactu_status'] = '2'; + } else { + //esta regsitrado (Registrado correctamente pero con errores o Registrado correctamente pero con errores múltiples veces) + $invoice->array_options['options_verifactu_status'] = '5'; + } + } + $invoice->ref=$record->invoiceId->invoiceNumber; + + $errCode = $res->getElementsByTagName('CodigoErrorRegistro')[0] ?? null; + $errMessage = $res->getElementsByTagName('DescripcionErrorRegistro')[0] ?? null; + if (!$errMessage || !$errCode) { + dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); + dol_syslog($envelope, LOG_DEBUG); + throw new Exception($res->saveXML(), 500); + } + $record->error = new stdClass(); + $record->error->code = $errCode->nodeValue; + $record->error->message = $errMessage->nodeValue; + $result = $invoice->update($user); + $invoice->insertExtraFields(); + if ($result <= 0) { + throw new Exception($invoice->error, 1); + } + //throw new Exception($res->saveXML(), 400); + } elseif ($status->nodeValue === 'AceptadoConErrores') { + $errCode = $res->getElementsByTagName('CodigoErrorRegistro')[0] ?? null; + $errMessage = $res->getElementsByTagName('DescripcionErrorRegistro')[0] ?? null; + if (!$errMessage || !$errCode) { + dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); + dol_syslog($envelope, LOG_DEBUG); + throw new Exception($res->saveXML(), 500); + } + + $record->error = new stdClass(); + $record->error->code = $errCode->nodeValue; + $record->error->message = $errMessage->nodeValue; + //actualizo el estado a Enviada y correcta con errores + $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; + if ($operationTypeNode->nodeValue === "Anulacion") { + //error de anulacion cuando esta la factura registrada + $invoice->array_options['options_verifactu_status'] = '7'; + } else { + // + if ( in_array($invoice->array_options['options_verifactu_status'], array('4','5'), true)) { + //hay errores en facturas de corrección + $invoice->array_options['options_verifactu_status'] = '5'; + } else { + //no hay errores en facturas de correción + $invoice->array_options['options_verifactu_status'] = '4'; + } + } + + + $invoice->insertExtraFields(); + } else { + //actualizo el estado a Enviada y correcta + $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; + //actualizo el estado segun sea anulacion o alta + $operationTypeNode->nodeValue === "Anulacion"? $invoice->array_options['options_verifactu_status'] = '6' : $invoice->array_options['options_verifactu_status'] = '1'; + $invoice->array_options['options_verifactu_error'] = ''; + $invoice->array_options['options_verifactu_error_code'] = ''; + + $invoice->insertExtraFields(); + } + + + + return $record; } /** @@ -452,81 +442,81 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') */ function autoverifactuSoapRequest($body, $ttl = 3) { - - global $db; - $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); - $base_url = $testMode ? VERIFACTU_TEST_BASE_URL : VERIFACTU_BASE_URL; - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $base_url . '/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP'); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); - curl_setopt($ch, CURLOPT_FAILONERROR, 1); - curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12'); - $certPath = DOL_DATA_ROOT . '/' . getDolGlobalString('AUTOVERIFACTU_CERT'); - curl_setopt($ch, CURLOPT_SSLCERT, $certPath); - $certPass = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); - curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $certPass); - curl_setopt( - $ch, - CURLOPT_HTTPHEADER, - array( - 'Content-Type: text/xml', - 'User-Agent: Mozilla/5.0 (compatible; Módulo Auto-Veri*Factu de Dolibarr/0.0.1', - ), - ); - //var_dump(htmlentities($body)); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - $res = curl_exec($ch); - dol_syslog('# RESPUESTA ALTA REGISTRO', LOG_DEBUG); - dol_syslog($res, LOG_DEBUG); - // echo "
"; echo "
"; echo "
"; echo "
"; - if ($res === false) { - $error = curl_error($ch); - $code = curl_errno($ch); - curl_close($ch); - throw new Exception('cURL error:' . $error, $code); - } - curl_close($ch); - // var_dump(htmlentities($res)); - $doc = new DOMDocument(); - $doc->loadXML($res . "\n"); - $faults = $doc->getElementsByTagName('Fault'); - //obtengo de la respuesta el tiempo de espara hasta la proxima registro - $shippingWaitingTimeNodes=$doc->getElementsByTagName('TiempoEsperaEnvio'); - if ($shippingWaitingTimeNodes->length > 0) { - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); - $shippingWaitingTime = (int) $shippingWaitingTimeNodes->item(0)->nodeValue; - $newShipment= $now->modify("+" . $shippingWaitingTime . " seconds"); - $newValueTimestamp=$newShipment->getTimestamp(); - //guardo la fecha en la que puedo realizar el proximo envio - $result = dolibarr_set_const($db, 'VERIFACTU_NEXT_DELIVERY_ALLOWED', $newValueTimestamp, 'chaine', 0, '', 0); - if($result<=0){ - dol_syslog('# VERIFACTU SAVE DOLIBARR CONST VERIFACTU_NEXT_DELIVERY_ALLOWED', LOG_DEBUG); - } - } - if ($faults->count() > 0) { - $fault = $faults[0]; - $code = $fault->getElementsByTagName('faultcode')[0]; - if (in_array($code->nodeValue, array('env:Server', 'sopaenv:Server'), true)) { - if ($ttl) { - // Retry on soapenv:Server errors with a limit of 3 attempts. - return autoverifactuSoapRequest($body, $ttl - 1); - } else { - // Exit if max retries is reached. - dol_syslog('# VERIFACTU API SERVICE UNAVAILABLE', LOG_DEBUG); - dol_syslog($res, LOG_DEBUG); - throw new Exception($res, 503); - } - } - dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); - dol_syslog($body, LOG_DEBUG); - throw new Exception($res, 400); - } - return $doc; + + global $db; + $testMode = (bool) getDolGlobalString('AUTOVERIFACTU_TEST_MODE'); + $base_url = $testMode ? VERIFACTU_TEST_BASE_URL : VERIFACTU_BASE_URL; + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $base_url . '/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + curl_setopt($ch, CURLOPT_FAILONERROR, 1); + curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12'); + $certPath = DOL_DATA_ROOT . '/' . getDolGlobalString('AUTOVERIFACTU_CERT'); + curl_setopt($ch, CURLOPT_SSLCERT, $certPath); + $certPass = getDolGlobalString('AUTOVERIFACTU_PASSWORD'); + curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $certPass); + curl_setopt( + $ch, + CURLOPT_HTTPHEADER, + array( + 'Content-Type: text/xml', + 'User-Agent: Mozilla/5.0 (compatible; Módulo Auto-Veri*Factu de Dolibarr/0.0.1', + ), + ); + //var_dump(htmlentities($body)); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + $res = curl_exec($ch); + dol_syslog('# RESPUESTA ALTA REGISTRO', LOG_DEBUG); + dol_syslog($res, LOG_DEBUG); + // echo "
"; echo "
"; echo "
"; echo "
"; + if ($res === false) { + $error = curl_error($ch); + $code = curl_errno($ch); + curl_close($ch); + throw new Exception('cURL error:' . $error, $code); + } + curl_close($ch); + // var_dump(htmlentities($res)); + $doc = new DOMDocument(); + $doc->loadXML($res . "\n"); + $faults = $doc->getElementsByTagName('Fault'); + //obtengo de la respuesta el tiempo de espara hasta la proxima registro + $shippingWaitingTimeNodes=$doc->getElementsByTagName('TiempoEsperaEnvio'); + if ($shippingWaitingTimeNodes->length > 0) { + $now=new DateTimeImmutable( + 'now', + new DateTimeZone('Europe/Madrid'), + ); + $shippingWaitingTime = (int) $shippingWaitingTimeNodes->item(0)->nodeValue; + $newShipment= $now->modify("+" . $shippingWaitingTime . " seconds"); + $newValueTimestamp=$newShipment->getTimestamp(); + //guardo la fecha en la que puedo realizar el proximo envio + $result = dolibarr_set_const($db, 'VERIFACTU_NEXT_DELIVERY_ALLOWED', $newValueTimestamp, 'chaine', 0, '', 0); + if ($result<=0) { + dol_syslog('# VERIFACTU SAVE DOLIBARR CONST VERIFACTU_NEXT_DELIVERY_ALLOWED', LOG_DEBUG); + } + } + if ($faults->count() > 0) { + $fault = $faults[0]; + $code = $fault->getElementsByTagName('faultcode')[0]; + if (in_array($code->nodeValue, array('env:Server', 'sopaenv:Server'), true)) { + if ($ttl) { + // Retry on soapenv:Server errors with a limit of 3 attempts. + return autoverifactuSoapRequest($body, $ttl - 1); + } else { + // Exit if max retries is reached. + dol_syslog('# VERIFACTU API SERVICE UNAVAILABLE', LOG_DEBUG); + dol_syslog($res, LOG_DEBUG); + throw new Exception($res, 503); + } + } + dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); + dol_syslog($body, LOG_DEBUG); + throw new Exception($res, 400); + } + return $doc; } /** @@ -540,42 +530,42 @@ function autoverifactuSoapRequest($body, $ttl = 3) */ function autoverifactuSoapEnvelope($record, $issuer, $representative = null) { - $xml = new DOMDocument(); - $envelope = $xml->createElement('soapenv:Envelope'); - $envelope->setAttribute('xmlns:soapenv', AUTOVERIFACTU_SOAPENV_NS); - $envelope->setAttribute('xmlns:sum', AUTOVERIFACTU_SUM_NS); - $envelope->setAttribute('xmlns:sum1', AUTOVERIFACTU_SUM1_NS); - $envelope->setAttribute('xmlns:xd', AUTOVERIFACTU_XD_NS); - $headerEl = $xml->createElement('soapenv:Header'); - $envelope->appendChild($headerEl); - $body = $xml->createElement('soapenv:Body'); - $envelope->appendChild($body); - $root = $xml->createElement('sum:RegFactuSistemaFacturacion'); - $body->appendChild($root); - $regHeaderEl = $xml->createElement('sum:Cabecera'); - $root->appendChild($regHeaderEl); - $issuerEl = $xml->createElement('sum1:ObligadoEmision'); - $regHeaderEl->appendChild($issuerEl); - $issuerNameEl = $xml->createElement('sum1:NombreRazon', htmlspecialchars($issuer['name'])); - $issuerEl->appendChild($issuerNameEl); - $issuerNifEl = $xml->createElement('sum1:NIF', htmlspecialchars($issuer['idprof1'])); - $issuerEl->appendChild($issuerNifEl); - if ($representative) { - $representativeEl = $xml->createElement('sum1:Representante'); - $regHeaderEl->appendChild($representativeEl); - - $reprNameEl = $xml->createElement('sum1:NombreRazon', htmlspecialchars($representative['name'])); - $representativeEl->appendChild($reprNameEl); - - $reprNifEl = $xml->createElement('sum1:NIF', htmlspecialchars($representative['idprof1'])); - $representativeEl->appendChild($reprNifEl); - } - - $recordEl = autoverifactuRecordToXML($record, $xml); - $root->appendChild($recordEl); - - $xml->appendChild($envelope); - return $xml->saveXML($envelope); + $xml = new DOMDocument(); + $envelope = $xml->createElement('soapenv:Envelope'); + $envelope->setAttribute('xmlns:soapenv', AUTOVERIFACTU_SOAPENV_NS); + $envelope->setAttribute('xmlns:sum', AUTOVERIFACTU_SUM_NS); + $envelope->setAttribute('xmlns:sum1', AUTOVERIFACTU_SUM1_NS); + $envelope->setAttribute('xmlns:xd', AUTOVERIFACTU_XD_NS); + $headerEl = $xml->createElement('soapenv:Header'); + $envelope->appendChild($headerEl); + $body = $xml->createElement('soapenv:Body'); + $envelope->appendChild($body); + $root = $xml->createElement('sum:RegFactuSistemaFacturacion'); + $body->appendChild($root); + $regHeaderEl = $xml->createElement('sum:Cabecera'); + $root->appendChild($regHeaderEl); + $issuerEl = $xml->createElement('sum1:ObligadoEmision'); + $regHeaderEl->appendChild($issuerEl); + $issuerNameEl = $xml->createElement('sum1:NombreRazon', htmlspecialchars($issuer['name'])); + $issuerEl->appendChild($issuerNameEl); + $issuerNifEl = $xml->createElement('sum1:NIF', htmlspecialchars($issuer['idprof1'])); + $issuerEl->appendChild($issuerNifEl); + if ($representative) { + $representativeEl = $xml->createElement('sum1:Representante'); + $regHeaderEl->appendChild($representativeEl); + + $reprNameEl = $xml->createElement('sum1:NombreRazon', htmlspecialchars($representative['name'])); + $representativeEl->appendChild($reprNameEl); + + $reprNifEl = $xml->createElement('sum1:NIF', htmlspecialchars($representative['idprof1'])); + $representativeEl->appendChild($reprNifEl); + } + + $recordEl = autoverifactuRecordToXML($record, $xml); + $root->appendChild($recordEl); + + $xml->appendChild($envelope); + return $xml->saveXML($envelope); } /** @@ -588,295 +578,283 @@ function autoverifactuSoapEnvelope($record, $issuer, $representative = null) */ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') { - - global $mysoc; - - $now = dol_now(); - $invoiceRef = trim($invoice->status > 0 ? $invoice->ref : $invoice->newref); - - $invoice->fetch_optionals(); - $invoice->fetch_thirdparty(); - $thirdparty = $invoice->thirdparty; - //ejecuto la funcion que añadira los diferentes textos - //legales que deben de ir en el pdf de la factura - autoverifactuSetLegalText($invoice); - - switch ($invoice->type) { - case Facture::TYPE_STANDARD: - case Facture::TYPE_DEPOSIT: - if (autoverifactuIsPosInvoice($invoice)) { - // Factura simplificada y facturas sin identificación del destinatario (Art. 6.1.D del R.D. 1619/2012). - $invoiceType = 'F2'; - } else { - // Factura (Art. 6, 7.2 y 7.3 del R.D. 1619/2012). - $invoiceType = 'F1'; - } - - // Factura emitida en sustitución de facturas simplificadas facturadas y declaradas. - // $invoiceType = 'F3'; - break; - case Facture::TYPE_REPLACEMENT: - case Facture::TYPE_CREDIT_NOTE: - if (autoverifactuIsPosInvoice($invoice)) { - // Factura rectificativa simplificada - $invoiceType = 'R5'; - } else { - - // Factura rectificativa corriente. - if(!isset($invoice->array_options['options_verifactu_rectification_type'])){ - throw new Exception("Error not value options_verifactu_rectification_type", 1); - } - $invoiceType = $invoice->array_options['options_verifactu_rectification_type'] ; - } - - break; - default: - $invoiceType = 'F1'; - } - - - $record = new stdClass(); - $record->type = $recordType; - $record->statusVerifactu=$invoice->array_options['options_verifactu_status']; - if (!empty($invoice->array_options['options_verifactu_date_operation'])) { - $record->dateOperation = new DateTimeImmutable( - date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_date_operation']), - new DateTimeZone('Europe/Madrid'), - ); - } else { - $record->dateOperation = null; - } - - $record->issuerName = htmlspecialchars(trim($mysoc->nom)); - $record->invoiceType = $invoiceType; - $record->description = 'Factura ' . htmlspecialchars($invoiceRef); - $record->invoiceId = new stdClass(); - $record->invoiceId->issuerId = trim($mysoc->idprof1); - $record->invoiceId->invoiceNumber = htmlspecialchars($invoiceRef); - $record->invoiceId->issueDate = new DateTimeImmutable( - date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_tms'] ?: $now), - new DateTimeZone('Europe/Madrid'), - ); - - // calculo el total y obtengo el total calculado para su posterior validación - $record->factureTotalAmount = number_format( - $invoice->total_ht + $invoice->total_tva + $invoice->total_localtax1 , - 2, - '.', - '' - ); - - $record->factureTotalTaxAmount=number_format($invoice->total_tva + $invoice->total_localtax1,2,'.',''); - - - $record->factureTtc = number_format($invoice->total_ttc - $invoice->total_localtax2, 2, '.', ''); - - $record->recipients = array(); - - // If is not simplified, add third party data to the record - if (!in_array($record->invoiceType, array('F2', 'R5'), true)) { - $recipient = new stdClass(); - - if ($thirdparty->country_code && $thirdparty->country_code !== 'ES') { - $recipient->name = htmlspecialchars(trim($thirdparty->nom)); - $recipient->country = $thirdparty->country_code; - if ($thirdparty->tva_intra) { - //NIF-IVA - $recipient->type = '02'; - $recipient->value = trim($thirdparty->tva_intra); - - }else{ - //en caso de ser de no ser de españa y que no nos den el NIF intra - //nos tienen que indicar que tipo de identificación es - if( - !in_array($thirdparty->array_options['options_verifactu_identification_thirdparty'],array('03','04','05','06','07') ) - ){ - //no existe tipo de identificacion - $invoice->errors[]='NotTypeIdentificationThirdparty'; - return 0; - } - if($thirdparty->array_options['options_verifactu_identification_thirdparty']=='03'){ - //Pasaporte (Passport) - $recipient->type = '03'; - $recipient->value = trim($thirdparty->idprof1); - }elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='04') { - //DOCUMENTO OFICIAL DE IDENTIFICACIÓN EXPEDIDO POR EL PAÍS (Document issued by the country) - $recipient->type = '04'; - $recipient->value = trim($thirdparty->idprof1); - }else if($thirdparty->array_options['options_verifactu_identification_thirdparty']=='05'){ - //CERTIFICADO DE RESIDENCIA (Residence Certificate) - $recipient->type = '05'; - $recipient->value = trim($thirdparty->idprof1); - }else if($thirdparty->array_options['options_verifactu_identification_thirdparty']=='06'){ - //OTRO DOCUMENTO PROBATORIO (Other supporting document) - $recipient->type = '06'; - $recipient->value = trim($thirdparty->idprof1); - }else if($thirdparty->array_options['options_verifactu_identification_thirdparty']=='07'){ - //No censado (Unregistered) - $recipient->type = '07'; - // $recipient->value = trim($thirdparty->idprof1); - } - } - - } else { - $recipient->name = htmlspecialchars(trim($thirdparty->nom)); - $recipient->nif = trim($thirdparty->idprof1); - - } - $record->recipients[0] = $recipient; - - } - - if ( - in_array( - $record->invoiceType, - array('R1', 'R2', 'R3', 'R4', 'R5'), - true - ) - ) { - - if( $invoice->type === (string)Facture::TYPE_REPLACEMENT) { - // Fix by substitution - $record->correctiveType = 'S'; - } else { - // Fix by differences - $record->correctiveType = 'I'; - } - - } else { - $record->correctiveType = null; - } - - $record->correctedInvoices = array(); - $record->correctedBaseAmount = null; - $record->correctedTaxAmount = null; - - // If is corrective, then add correctiveInvoices data to the record. - if ($record->correctiveType !== null) { - $sourceInvoice = autoverifactuGetSourceInvoice($invoice); - - if (!$sourceInvoice) { - - dol_syslog('Can not find the source invoice of the corrective invoice #' . $invoice->id, LOG_ERR); - $invoice->error[]="NotFoundSourceInvoiceCorrective"; - return -1; - } else { - $sourceInvoice->fetch_thirdparty(); - } - - $sourceId = new stdClass(); - $sourceId->issuerId = trim($mysoc->idprof1); - $sourceId->invoiceNumber = trim($sourceInvoice->ref); - $sourceId->issueDate = new DateTimeImmutable( - date('Y-m-d H:i:s', $sourceInvoice->array_options['options_verifactu_tms']), - new DateTimeZone('Europe/Madrid'), - ); - - $record->correctedInvoices[0] = $sourceId; - - if ($record->correctiveType === 'S') { - $record->correctedBaseAmount = number_format($sourceInvoice->total_ht, 2, '.', ''); - $record->correctedTaxAmount = number_format($sourceInvoice->total_tva, 2, '.', ''); - } else { - $record->correctedBaseAmount = null; - $record->correctedTaxAmount = null; - } - } - - $record->replacedInvoices = array(); - - $record->breakdown = autoverifactuLinesToBreakdown($invoice); - - - - $tax_total = 0; - $base_total = 0; - foreach ($record->breakdown as $line) { - - $equivalenceSurcharge=0; - if(isset($line->equivalenceSurcharge)){ - $equivalenceSurcharge= $line->equivalenceSurcharge->total; - } - - - $tax_total += (float) $line->taxAmount + (float)$equivalenceSurcharge; - $base_total += (float) $line->baseAmount; - - } - - $record->totalTaxAmount = number_format($tax_total, 2, '.', ''); - $record->totalAmount = number_format( - $base_total + $tax_total, - 2, - '.', - '', - ); - - - - $previous = autoverifactuGetPreviousValidInvoice($invoice, $now); - - if ($previous) { - $record->previousInvoiceId = new stdClass(); - $record->previousInvoiceId->issuerId = trim($mysoc->idprof1); - $record->previousInvoiceId->invoiceNumber = $invoiceRef; - $record->previousInvoiceId->issueDate = new DateTimeImmutable( - date('Y-m-d H:i:s', $previous->array_options['options_verifactu_tms']), - new DateTimeZone('Europe/Madrid'), - ); - - $previous->fetch_optionals(); - $record->previousHash = substr($previous->array_options['options_verifactu_hash'], 0, 64); - } else { - $record->previousInvoiceId = null; - $record->previousHash = null; - } - - $record->system = autoverifactuGetRecordComputerSystem(); - - /* - ! Cuando obentenos el registro horario guardado , y genereamos una factura de - ! anulacion o corregimos algun error despues del margen que nos dan (240 seg) - ! nos indica un error de tiempo. de la otra forma no nos indica ese error. (Inicado la hora de envio) - $record->hashedAt = new DateTimeImmutable( - date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_tms'] ?: $now), - new DateTimeZone('Europe/Madrid'), - );*/ - - $record->hashedAt = new DateTimeImmutable( - date('Y-m-d H:i:s', $now), - new DateTimeZone('Europe/Madrid'), - ); - $record->hash = autoverifactuCalculateRecordHash($record); - - global $hookmanager; - if (!is_object($hookmanager)) { - include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; - $hookmanager = new HookManager($db); - } - - $parameters = array( - 'record' => $record, - 'invoice' => $invoice, - ); - - $reshook = $hookmanager->executeHooks( - 'autoverifactuRecord', - $parameters, - $invoice, - ); - - if (!empty($reshook)) { - return $reshook; - } - - - - if (autoverifactuValidateRecord($record, $invoice->errors)) { - - return $record; - } - + + global $mysoc; + + $now = dol_now(); + $invoiceRef = trim($invoice->status > 0 ? $invoice->ref : $invoice->newref); + + $invoice->fetch_optionals(); + $invoice->fetch_thirdparty(); + $thirdparty = $invoice->thirdparty; + //ejecuto la funcion que añadira los diferentes textos + //legales que deben de ir en el pdf de la factura + autoverifactuSetLegalText($invoice); + + switch ($invoice->type) { + case Facture::TYPE_STANDARD: + case Facture::TYPE_DEPOSIT: + if (autoverifactuIsPosInvoice($invoice)) { + // Factura simplificada y facturas sin identificación del destinatario (Art. 6.1.D del R.D. 1619/2012). + $invoiceType = 'F2'; + } else { + // Factura (Art. 6, 7.2 y 7.3 del R.D. 1619/2012). + $invoiceType = 'F1'; + } + + // Factura emitida en sustitución de facturas simplificadas facturadas y declaradas. + // $invoiceType = 'F3'; + break; + case Facture::TYPE_REPLACEMENT: + case Facture::TYPE_CREDIT_NOTE: + if (autoverifactuIsPosInvoice($invoice)) { + // Factura rectificativa simplificada + $invoiceType = 'R5'; + } else { + // Factura rectificativa corriente. + if (!isset($invoice->array_options['options_verifactu_rectification_type'])) { + throw new Exception("Error not value options_verifactu_rectification_type", 1); + } + $invoiceType = $invoice->array_options['options_verifactu_rectification_type'] ; + } + + break; + default: + $invoiceType = 'F1'; + } + + + $record = new stdClass(); + $record->type = $recordType; + $record->statusVerifactu=$invoice->array_options['options_verifactu_status']; + if (!empty($invoice->array_options['options_verifactu_date_operation'])) { + $record->dateOperation = new DateTimeImmutable( + date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_date_operation']), + new DateTimeZone('Europe/Madrid'), + ); + } else { + $record->dateOperation = null; + } + + $record->issuerName = htmlspecialchars(trim($mysoc->nom)); + $record->invoiceType = $invoiceType; + $record->description = 'Factura ' . htmlspecialchars($invoiceRef); + $record->invoiceId = new stdClass(); + $record->invoiceId->issuerId = trim($mysoc->idprof1); + $record->invoiceId->invoiceNumber = htmlspecialchars($invoiceRef); + $record->invoiceId->issueDate = new DateTimeImmutable( + date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_tms'] ?: $now), + new DateTimeZone('Europe/Madrid'), + ); + + // calculo el total y obtengo el total calculado para su posterior validación + $record->factureTotalAmount = number_format( + $invoice->total_ht + $invoice->total_tva + $invoice->total_localtax1, + 2, + '.', + '' + ); + + $record->factureTotalTaxAmount=number_format($invoice->total_tva + $invoice->total_localtax1, 2, '.', ''); + + + $record->factureTtc = number_format($invoice->total_ttc - $invoice->total_localtax2, 2, '.', ''); + + $record->recipients = array(); + + // If is not simplified, add third party data to the record + if (!in_array($record->invoiceType, array('F2', 'R5'), true)) { + $recipient = new stdClass(); + + if ($thirdparty->country_code && $thirdparty->country_code !== 'ES') { + $recipient->name = htmlspecialchars(trim($thirdparty->nom)); + $recipient->country = $thirdparty->country_code; + if ($thirdparty->tva_intra) { + //NIF-IVA + $recipient->type = '02'; + $recipient->value = trim($thirdparty->tva_intra); + } else { + //en caso de ser de no ser de españa y que no nos den el NIF intra + //nos tienen que indicar que tipo de identificación es + if ( + !in_array($thirdparty->array_options['options_verifactu_identification_thirdparty'], array('03','04','05','06','07')) + ) { + //no existe tipo de identificacion + $invoice->errors[]='NotTypeIdentificationThirdparty'; + return 0; + } + if ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='03') { + //Pasaporte (Passport) + $recipient->type = '03'; + $recipient->value = trim($thirdparty->idprof1); + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='04') { + //DOCUMENTO OFICIAL DE IDENTIFICACIÓN EXPEDIDO POR EL PAÍS (Document issued by the country) + $recipient->type = '04'; + $recipient->value = trim($thirdparty->idprof1); + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='05') { + //CERTIFICADO DE RESIDENCIA (Residence Certificate) + $recipient->type = '05'; + $recipient->value = trim($thirdparty->idprof1); + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='06') { + //OTRO DOCUMENTO PROBATORIO (Other supporting document) + $recipient->type = '06'; + $recipient->value = trim($thirdparty->idprof1); + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='07') { + //No censado (Unregistered) + $recipient->type = '07'; + // $recipient->value = trim($thirdparty->idprof1); + } + } + } else { + $recipient->name = htmlspecialchars(trim($thirdparty->nom)); + $recipient->nif = trim($thirdparty->idprof1); + } + $record->recipients[0] = $recipient; + } + + if ( + in_array( + $record->invoiceType, + array('R1', 'R2', 'R3', 'R4', 'R5'), + true + ) + ) { + if ( $invoice->type === (string) Facture::TYPE_REPLACEMENT) { + // Fix by substitution + $record->correctiveType = 'S'; + } else { + // Fix by differences + $record->correctiveType = 'I'; + } + } else { + $record->correctiveType = null; + } + + $record->correctedInvoices = array(); + $record->correctedBaseAmount = null; + $record->correctedTaxAmount = null; + + // If is corrective, then add correctiveInvoices data to the record. + if ($record->correctiveType !== null) { + $sourceInvoice = autoverifactuGetSourceInvoice($invoice); + + if (!$sourceInvoice) { + dol_syslog('Can not find the source invoice of the corrective invoice #' . $invoice->id, LOG_ERR); + $invoice->error[]="NotFoundSourceInvoiceCorrective"; + return -1; + } else { + $sourceInvoice->fetch_thirdparty(); + } + + $sourceId = new stdClass(); + $sourceId->issuerId = trim($mysoc->idprof1); + $sourceId->invoiceNumber = trim($sourceInvoice->ref); + $sourceId->issueDate = new DateTimeImmutable( + date('Y-m-d H:i:s', $sourceInvoice->array_options['options_verifactu_tms']), + new DateTimeZone('Europe/Madrid'), + ); + + $record->correctedInvoices[0] = $sourceId; + + if ($record->correctiveType === 'S') { + $record->correctedBaseAmount = number_format($sourceInvoice->total_ht, 2, '.', ''); + $record->correctedTaxAmount = number_format($sourceInvoice->total_tva, 2, '.', ''); + } else { + $record->correctedBaseAmount = null; + $record->correctedTaxAmount = null; + } + } + + $record->replacedInvoices = array(); + + $record->breakdown = autoverifactuLinesToBreakdown($invoice); + + + + $tax_total = 0; + $base_total = 0; + foreach ($record->breakdown as $line) { + $equivalenceSurcharge=0; + if (isset($line->equivalenceSurcharge)) { + $equivalenceSurcharge= $line->equivalenceSurcharge->total; + } + + + $tax_total += (float) $line->taxAmount + (float) $equivalenceSurcharge; + $base_total += (float) $line->baseAmount; + } + + $record->totalTaxAmount = number_format($tax_total, 2, '.', ''); + $record->totalAmount = number_format( + $base_total + $tax_total, + 2, + '.', + '', + ); + + + + $previous = autoverifactuGetPreviousValidInvoice($invoice, $now); + + if ($previous) { + $record->previousInvoiceId = new stdClass(); + $record->previousInvoiceId->issuerId = trim($mysoc->idprof1); + $record->previousInvoiceId->invoiceNumber = $invoiceRef; + $record->previousInvoiceId->issueDate = new DateTimeImmutable( + date('Y-m-d H:i:s', $previous->array_options['options_verifactu_tms']), + new DateTimeZone('Europe/Madrid'), + ); + + $previous->fetch_optionals(); + $record->previousHash = substr($previous->array_options['options_verifactu_hash'], 0, 64); + } else { + $record->previousInvoiceId = null; + $record->previousHash = null; + } + + $record->system = autoverifactuGetRecordComputerSystem(); + + /* + ! Cuando obentenos el registro horario guardado , y genereamos una factura de + ! anulacion o corregimos algun error despues del margen que nos dan (240 seg) + ! nos indica un error de tiempo. de la otra forma no nos indica ese error. (Inicado la hora de envio) + $record->hashedAt = new DateTimeImmutable( + date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_tms'] ?: $now), + new DateTimeZone('Europe/Madrid'), + );*/ + + $record->hashedAt = new DateTimeImmutable( + date('Y-m-d H:i:s', $now), + new DateTimeZone('Europe/Madrid'), + ); + $record->hash = autoverifactuCalculateRecordHash($record); + + global $hookmanager; + if (!is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($db); + } + + $parameters = array( + 'record' => $record, + 'invoice' => $invoice, + ); + + $reshook = $hookmanager->executeHooks( + 'autoverifactuRecord', + $parameters, + $invoice, + ); + + if (!empty($reshook)) { + return $reshook; + } + + + + if (autoverifactuValidateRecord($record, $invoice->errors)) { + return $record; + } } @@ -893,232 +871,231 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') */ function autoverifactuRecordToXML($record, $xml = null) { - - $xml = $xml ?: new DOMDocument(); - - $recordElementName = $record->type === 'alta' - ? 'RegistroAlta' - : 'RegistroAnulacion'; - - $root = $xml->createElement('sum:RegistroFactura'); - - $recordEl = $xml->createElement('sum1:' . $recordElementName); - $root->appendChild($recordEl); - - $recordEl->appendChild($xml->createElement('sum1:IDVersion', '1.0')); - - if ($record->type === 'alta') { - $invoiceId = $xml->createElement('sum1:IDFactura'); - $recordEl->appendChild($invoiceId); - - $invoiceId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($record->invoiceId->issuerId))); - $invoiceId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($record->invoiceId->invoiceNumber))); - $invoiceId->appendChild($xml->createElement( - 'sum1:FechaExpedicionFactura', - $record->invoiceId->issueDate->format('d-m-Y') - )); - - $recordEl->appendChild($xml->createElement('sum1:NombreRazonEmisor', htmlspecialchars($record->issuerName))); - - - //etiquetas para subsanacion de errores - if(in_array( $record->statusVerifactu,array("2","4","5"),true)){ - $valueSubsanacion="S"; - $valueRechazoPrevio="X"; - - if($record->statusVerifactu==="4"){ - $valueRechazoPrevio="N"; - } - if($record->statusVerifactu==="5"){ - $valueRechazoPrevio="S"; - } - $recordEl->appendChild($xml->createElement('sum1:Subsanacion', $valueSubsanacion)); - $recordEl->appendChild($xml->createElement('sum1:RechazoPrevio', $valueRechazoPrevio)); - - } - - - $recordEl->appendChild($xml->createElement('sum1:TipoFactura', $record->invoiceType)); - - if ($record->dateOperation !== null) { - $recordEl->appendChild($xml->createElement('sum1:FechaOperacion', $record->dateOperation->format('d-m-Y'))); - } - - if ($record->correctiveType !== null) { - $recordEl->appendChild($xml->createElement('sum1:TipoRectificativa', $record->correctiveType)); - } - - if (count($record->correctedInvoices)) { - $correctedInvoices = $xml->createElement('sum1:FacturasRectificadas'); - $recordEl->appendChild($correctedInvoices); - - foreach ($record->correctedInvoices as $correctedInvoice) { - $fixId = $xml->createElement('sum1:IDFacturaRectificada'); - $correctedInvoices->appendChild($fixId); - - $fixId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($correctedInvoice->issuerId))); - $fixId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($correctedInvoice->invoiceNumber))); - $fixId->appendChild($xml->createElement( - 'sum1:FechaExpedicionFactura', - $correctedInvoice->issueDate->format('d-m-Y') - )); - } - } - - if (count($record->replacedInvoices)) { - $replacedInvoices = $xml->createElement('sum1:FacturasSustituidas'); - $recordEl->appendChild($replacedInvoices); - - foreach ($record->replacedInvoices as $replacedInvoice) { - $replId = $xml->createElement('sum1:IDFacturaSustituida'); - $replacedInvoices->appendChild($replId); - - $replId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($replacedInvoice->issuerId))); - $replId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($replacedInvoice->invoiceNumber))); - $replId->appendChild($xml->createElement( - 'sum1:FechaExpedicionFactura', - $replacedInvoice->issueDate->format('d-m-Y') - )); - } - } - - if ($record->correctedBaseAmount !== null && $record->correctedTaxAmount !== null) { - $importEl = $xml->createElement('sum1:ImporteRectificacion'); - $recordEl->appendChild($importEl); - - $recordEl->appendChild($xml->createElement('sum1:BaseRectificada', $record->correctedBaseAmount)); - $recordEl->appendChild($xml->createElement('sum1:CuotaRectificada', $record->correctedTaxAmount)); - } - - $recordEl->appendChild($xml->createElement('sum1:DescripcionOperacion', htmlspecialchars($record->description))); - - if (count($record->recipients)) { - $recipients = $xml->createElement('sum1:Destinatarios'); - $recordEl->appendChild($recipients); - - foreach ($record->recipients as $recipient) { - $recipientEl = $xml->createElement('sum1:IDDestinatario'); - $recipients->appendChild($recipientEl); - - $recipientEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($recipient->name))); - - if (isset($recipient->country, $recipient->type)) { - $foreignId = $xml->createElement('sum1:IDOtro'); - $recipientEl->appendChild($foreignId); - - $foreignId->appendChild($xml->createElement('sum1:CodigoPais', $recipient->country)); - $foreignId->appendChild($xml->createElement('sum1:IDType', $recipient->type)); - $foreignId->appendChild($xml->createElement('sum1:ID', htmlspecialchars($recipient->value))); - } else { - $recipientEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($recipient->nif))); - } - } - } - - $breakdown = $xml->createElement('sum1:Desglose'); - $recordEl->appendChild($breakdown); - foreach ($record->breakdown as $details) { - $dEl = $xml->createElement('sum1:DetalleDesglose'); - $breakdown->appendChild($dEl); - - $dEl->appendChild($xml->createElement('sum1:Impuesto', $details->taxType)); - if($details->taxType !== '05'){ - $dEl->appendChild($xml->createElement('sum1:ClaveRegimen', $details->regimeType)); - } - - - if ($details->exemptionCode) { - $dEl->appendChild($xml->createElement('sum1:OperacionExenta', $details->exemptionCode)); - } else { - // Se indicará la calificación de la operación en caso de no existir código de exención. - $dEl->appendChild($xml->createElement('sum1:CalificacionOperacion', $details->operationType)); - } - - - if (!($details->exemptionCode)) { - $dEl->appendChild($xml->createElement('sum1:TipoImpositivo', $details->taxRate)); - } - + + $xml = $xml ?: new DOMDocument(); + + $recordElementName = $record->type === 'alta' + ? 'RegistroAlta' + : 'RegistroAnulacion'; + + $root = $xml->createElement('sum:RegistroFactura'); + + $recordEl = $xml->createElement('sum1:' . $recordElementName); + $root->appendChild($recordEl); + + $recordEl->appendChild($xml->createElement('sum1:IDVersion', '1.0')); + + if ($record->type === 'alta') { + $invoiceId = $xml->createElement('sum1:IDFactura'); + $recordEl->appendChild($invoiceId); + + $invoiceId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($record->invoiceId->issuerId))); + $invoiceId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($record->invoiceId->invoiceNumber))); + $invoiceId->appendChild($xml->createElement( + 'sum1:FechaExpedicionFactura', + $record->invoiceId->issueDate->format('d-m-Y') + )); + + $recordEl->appendChild($xml->createElement('sum1:NombreRazonEmisor', htmlspecialchars($record->issuerName))); + + + //etiquetas para subsanacion de errores + if (in_array($record->statusVerifactu, array("2","4","5"), true)) { + $valueSubsanacion="S"; + $valueRechazoPrevio="X"; + + if ($record->statusVerifactu==="4") { + $valueRechazoPrevio="N"; + } + if ($record->statusVerifactu==="5") { + $valueRechazoPrevio="S"; + } + $recordEl->appendChild($xml->createElement('sum1:Subsanacion', $valueSubsanacion)); + $recordEl->appendChild($xml->createElement('sum1:RechazoPrevio', $valueRechazoPrevio)); + } + + + $recordEl->appendChild($xml->createElement('sum1:TipoFactura', $record->invoiceType)); + + if ($record->dateOperation !== null) { + $recordEl->appendChild($xml->createElement('sum1:FechaOperacion', $record->dateOperation->format('d-m-Y'))); + } + + if ($record->correctiveType !== null) { + $recordEl->appendChild($xml->createElement('sum1:TipoRectificativa', $record->correctiveType)); + } + + if (count($record->correctedInvoices)) { + $correctedInvoices = $xml->createElement('sum1:FacturasRectificadas'); + $recordEl->appendChild($correctedInvoices); + + foreach ($record->correctedInvoices as $correctedInvoice) { + $fixId = $xml->createElement('sum1:IDFacturaRectificada'); + $correctedInvoices->appendChild($fixId); + + $fixId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($correctedInvoice->issuerId))); + $fixId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($correctedInvoice->invoiceNumber))); + $fixId->appendChild($xml->createElement( + 'sum1:FechaExpedicionFactura', + $correctedInvoice->issueDate->format('d-m-Y') + )); + } + } + + if (count($record->replacedInvoices)) { + $replacedInvoices = $xml->createElement('sum1:FacturasSustituidas'); + $recordEl->appendChild($replacedInvoices); + + foreach ($record->replacedInvoices as $replacedInvoice) { + $replId = $xml->createElement('sum1:IDFacturaSustituida'); + $replacedInvoices->appendChild($replId); + + $replId->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($replacedInvoice->issuerId))); + $replId->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($replacedInvoice->invoiceNumber))); + $replId->appendChild($xml->createElement( + 'sum1:FechaExpedicionFactura', + $replacedInvoice->issueDate->format('d-m-Y') + )); + } + } + + if ($record->correctedBaseAmount !== null && $record->correctedTaxAmount !== null) { + $importEl = $xml->createElement('sum1:ImporteRectificacion'); + $recordEl->appendChild($importEl); + + $recordEl->appendChild($xml->createElement('sum1:BaseRectificada', $record->correctedBaseAmount)); + $recordEl->appendChild($xml->createElement('sum1:CuotaRectificada', $record->correctedTaxAmount)); + } + + $recordEl->appendChild($xml->createElement('sum1:DescripcionOperacion', htmlspecialchars($record->description))); + + if (count($record->recipients)) { + $recipients = $xml->createElement('sum1:Destinatarios'); + $recordEl->appendChild($recipients); + + foreach ($record->recipients as $recipient) { + $recipientEl = $xml->createElement('sum1:IDDestinatario'); + $recipients->appendChild($recipientEl); + + $recipientEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($recipient->name))); + + if (isset($recipient->country, $recipient->type)) { + $foreignId = $xml->createElement('sum1:IDOtro'); + $recipientEl->appendChild($foreignId); + + $foreignId->appendChild($xml->createElement('sum1:CodigoPais', $recipient->country)); + $foreignId->appendChild($xml->createElement('sum1:IDType', $recipient->type)); + $foreignId->appendChild($xml->createElement('sum1:ID', htmlspecialchars($recipient->value))); + } else { + $recipientEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($recipient->nif))); + } + } + } + + $breakdown = $xml->createElement('sum1:Desglose'); + $recordEl->appendChild($breakdown); + foreach ($record->breakdown as $details) { + $dEl = $xml->createElement('sum1:DetalleDesglose'); + $breakdown->appendChild($dEl); + + $dEl->appendChild($xml->createElement('sum1:Impuesto', $details->taxType)); + if ($details->taxType !== '05') { + $dEl->appendChild($xml->createElement('sum1:ClaveRegimen', $details->regimeType)); + } + + + if ($details->exemptionCode) { + $dEl->appendChild($xml->createElement('sum1:OperacionExenta', $details->exemptionCode)); + } else { + // Se indicará la calificación de la operación en caso de no existir código de exención. + $dEl->appendChild($xml->createElement('sum1:CalificacionOperacion', $details->operationType)); + } + + + if (!($details->exemptionCode)) { + $dEl->appendChild($xml->createElement('sum1:TipoImpositivo', $details->taxRate)); + } + $dEl->appendChild($xml->createElement('sum1:BaseImponibleOimporteNoSujeto', $details->baseAmount)); - - if (!($details->exemptionCode)) { - $dEl->appendChild($xml->createElement('sum1:CuotaRepercutida', $details->taxAmount)); - } - - // Se indicará el recargo de equivalencia y el tipo en caso de existir - if (!$details->exemptionCode && $details->operationType === 'S1' && isset($details->equivalenceSurcharge)) { - $dEl->appendChild($xml->createElement( - 'sum1:TipoRecargoEquivalencia', - $details->equivalenceSurcharge->type, - )); - $dEl->appendChild($xml->createElement( - 'sum1:CuotaRecargoEquivalencia', - $details->equivalenceSurcharge->total, - )); - } - } - - $recordEl->appendChild($xml->createElement('sum1:CuotaTotal', $record->totalTaxAmount)); - $recordEl->appendChild($xml->createElement('sum1:ImporteTotal', $record->totalAmount)); - } elseif ($record->type === 'anulacion') { - //anulacion - $invoiceId = $xml->createElement('sum1:IDFactura'); - $recordEl->appendChild($invoiceId); - $invoiceId->appendChild($xml->createElement('sum1:IDEmisorFacturaAnulada', htmlspecialchars($record->invoiceId->issuerId))); - $invoiceId->appendChild($xml->createElement('sum1:NumSerieFacturaAnulada', htmlspecialchars($record->invoiceId->invoiceNumber))); - $invoiceId->appendChild($xml->createElement('sum1:FechaExpedicionFacturaAnulada', $record->invoiceId->issueDate->format('d-m-Y'))); - } else { - throw new Exception('Invalid record type: ' . $record->type); - } - - $chainEl = $xml->createElement('sum1:Encadenamiento'); - $recordEl->appendChild($chainEl); - - if ($record->previousInvoiceId === null) { - $chainEl->appendChild($xml->createElement('sum1:PrimerRegistro', 'S')); - } else { - $prevEl = $xml->createElement('sum1:RegistroAnterior'); - $chainEl->appendChild($prevEl); - - $prevEl->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($record->previousInvoiceId->issuerId))); - $prevEl->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($record->previousInvoiceId->invoiceNumber))); - $prevEl->appendChild($xml->createElement( - 'sum1:FechaExpedicionFactura', - $record->previousInvoiceId->issueDate->format('d-m-Y') - )); - $prevEl->appendChild($xml->createElement('sum1:Huella', $record->previousHash)); - } - - $systemEl = $xml->createElement('sum1:SistemaInformatico'); - $recordEl->appendChild($systemEl); - - $systemEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($record->system->vendorName))); - $systemEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($record->system->vendorNif))); - $systemEl->appendChild($xml->createElement('sum1:NombreSistemaInformatico', htmlspecialchars($record->system->name))); - $systemEl->appendChild($xml->createElement('sum1:IdSistemaInformatico', htmlspecialchars($record->system->id))); - $systemEl->appendChild($xml->createElement('sum1:Version', htmlspecialchars($record->system->version))); - $systemEl->appendChild($xml->createElement('sum1:NumeroInstalacion', htmlspecialchars($record->system->installationNumber))); - $systemEl->appendChild($xml->createElement( - 'sum1:TipoUsoPosibleSoloVerifactu', - $record->system->onlySupportsVerifactu ? 'S' : 'N' - )); - $systemEl->appendChild($xml->createElement( - 'sum1:TipoUsoPosibleMultiOT', - $record->system->supportsMultipleTaxpayers ? 'S' : 'N' - )); - $systemEl->appendChild($xml->createElement( - 'sum1:IndicadorMultiplesOT', - $record->system->hasMultipleTaxpayers ? 'S' : 'N' - )); - - $recordEl->appendChild($xml->createElement( - 'sum1:FechaHoraHusoGenRegistro', - $record->hashedAt->format('c'), - )); - $recordEl->appendChild($xml->createElement('sum1:TipoHuella', '01')); // SHA-256 - $recordEl->appendChild($xml->createElement('sum1:Huella', $record->hash)); - - return $root; + + if (!($details->exemptionCode)) { + $dEl->appendChild($xml->createElement('sum1:CuotaRepercutida', $details->taxAmount)); + } + + // Se indicará el recargo de equivalencia y el tipo en caso de existir + if (!$details->exemptionCode && $details->operationType === 'S1' && isset($details->equivalenceSurcharge)) { + $dEl->appendChild($xml->createElement( + 'sum1:TipoRecargoEquivalencia', + $details->equivalenceSurcharge->type, + )); + $dEl->appendChild($xml->createElement( + 'sum1:CuotaRecargoEquivalencia', + $details->equivalenceSurcharge->total, + )); + } + } + + $recordEl->appendChild($xml->createElement('sum1:CuotaTotal', $record->totalTaxAmount)); + $recordEl->appendChild($xml->createElement('sum1:ImporteTotal', $record->totalAmount)); + } elseif ($record->type === 'anulacion') { + //anulacion + $invoiceId = $xml->createElement('sum1:IDFactura'); + $recordEl->appendChild($invoiceId); + $invoiceId->appendChild($xml->createElement('sum1:IDEmisorFacturaAnulada', htmlspecialchars($record->invoiceId->issuerId))); + $invoiceId->appendChild($xml->createElement('sum1:NumSerieFacturaAnulada', htmlspecialchars($record->invoiceId->invoiceNumber))); + $invoiceId->appendChild($xml->createElement('sum1:FechaExpedicionFacturaAnulada', $record->invoiceId->issueDate->format('d-m-Y'))); + } else { + throw new Exception('Invalid record type: ' . $record->type); + } + + $chainEl = $xml->createElement('sum1:Encadenamiento'); + $recordEl->appendChild($chainEl); + + if ($record->previousInvoiceId === null) { + $chainEl->appendChild($xml->createElement('sum1:PrimerRegistro', 'S')); + } else { + $prevEl = $xml->createElement('sum1:RegistroAnterior'); + $chainEl->appendChild($prevEl); + + $prevEl->appendChild($xml->createElement('sum1:IDEmisorFactura', htmlspecialchars($record->previousInvoiceId->issuerId))); + $prevEl->appendChild($xml->createElement('sum1:NumSerieFactura', htmlspecialchars($record->previousInvoiceId->invoiceNumber))); + $prevEl->appendChild($xml->createElement( + 'sum1:FechaExpedicionFactura', + $record->previousInvoiceId->issueDate->format('d-m-Y') + )); + $prevEl->appendChild($xml->createElement('sum1:Huella', $record->previousHash)); + } + + $systemEl = $xml->createElement('sum1:SistemaInformatico'); + $recordEl->appendChild($systemEl); + + $systemEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($record->system->vendorName))); + $systemEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($record->system->vendorNif))); + $systemEl->appendChild($xml->createElement('sum1:NombreSistemaInformatico', htmlspecialchars($record->system->name))); + $systemEl->appendChild($xml->createElement('sum1:IdSistemaInformatico', htmlspecialchars($record->system->id))); + $systemEl->appendChild($xml->createElement('sum1:Version', htmlspecialchars($record->system->version))); + $systemEl->appendChild($xml->createElement('sum1:NumeroInstalacion', htmlspecialchars($record->system->installationNumber))); + $systemEl->appendChild($xml->createElement( + 'sum1:TipoUsoPosibleSoloVerifactu', + $record->system->onlySupportsVerifactu ? 'S' : 'N' + )); + $systemEl->appendChild($xml->createElement( + 'sum1:TipoUsoPosibleMultiOT', + $record->system->supportsMultipleTaxpayers ? 'S' : 'N' + )); + $systemEl->appendChild($xml->createElement( + 'sum1:IndicadorMultiplesOT', + $record->system->hasMultipleTaxpayers ? 'S' : 'N' + )); + + $recordEl->appendChild($xml->createElement( + 'sum1:FechaHoraHusoGenRegistro', + $record->hashedAt->format('c'), + )); + $recordEl->appendChild($xml->createElement('sum1:TipoHuella', '01')); // SHA-256 + $recordEl->appendChild($xml->createElement('sum1:Huella', $record->hash)); + + return $root; } /** @@ -1132,145 +1109,145 @@ function autoverifactuRecordToXML($record, $xml = null) OLD FUNCTION function autoverifactuLinesToBreakdown($invoice) { - $breakdown = array(); + $breakdown = array(); + + $defaultRegime = getDolGlobalString('AUTOVERIFACTU_DEFAULT_REGIME') ?: '01'; + - $defaultRegime = getDolGlobalString('AUTOVERIFACTU_DEFAULT_REGIME') ?: '01'; - + foreach ($invoice->lines as $line) { - foreach ($invoice->lines as $line) { - - $details = new stdClass(); - $details->taxType = getDolGlobalString('AUTOVERIFACTU_TAX') ?: '01'; + $details = new stdClass(); + $details->taxType = getDolGlobalString('AUTOVERIFACTU_TAX') ?: '01'; // variable incorrecta options_verifactu_regim_type=> options_verifactu_regime_type - $details->regimeType = $line->array_options['options_verifactu_regime_type'] ?: $defaultRegime; - $details->operationType = $line->array_options['options_verifactu_operation_type'] ?: 'S1'; - $details->excemptionCode = $line->array_options['options_verifactu_tax_excemption'] ?: null; - $details->taxRate = number_format((float) $line->tva_tx, 2, '.', ''); - $details->baseAmount = number_format((float) $line->total_ht, 2, '.', ''); - $details->taxAmount = number_format((float) $line->total_tva, 2, '.', ''); - - if (!$details->exemptionCode && $details->operationType === 'S1' && $details->regimeType === '18') { - $details->equivalenceSurcharge = new stdClass(); - $details->equivalenceSurcharge->type = number_format((float) $line->localtax1_tx, 2, '.', '') ; - $details->equivalenceSurcharge->total = number_format((float) $line->total_localtax1, 2, '.', ''); - } - //falta añadir al array - $breakdown[] = $details; - } - - - return $breakdown; + $details->regimeType = $line->array_options['options_verifactu_regime_type'] ?: $defaultRegime; + $details->operationType = $line->array_options['options_verifactu_operation_type'] ?: 'S1'; + $details->excemptionCode = $line->array_options['options_verifactu_tax_excemption'] ?: null; + $details->taxRate = number_format((float) $line->tva_tx, 2, '.', ''); + $details->baseAmount = number_format((float) $line->total_ht, 2, '.', ''); + $details->taxAmount = number_format((float) $line->total_tva, 2, '.', ''); + + if (!$details->exemptionCode && $details->operationType === 'S1' && $details->regimeType === '18') { + $details->equivalenceSurcharge = new stdClass(); + $details->equivalenceSurcharge->type = number_format((float) $line->localtax1_tx, 2, '.', '') ; + $details->equivalenceSurcharge->total = number_format((float) $line->total_localtax1, 2, '.', ''); + } + //falta añadir al array + $breakdown[] = $details; + } + + + return $breakdown; } */ function autoverifactuLinesToBreakdown($invoice) { - - $grouped = array(); - $defaultRegime = getDolGlobalString('AUTOVERIFACTU_DEFAULT_REGIME') ?: '01'; - /* echo "
";
-    var_dump($invoice->lines);
-    echo "
"; - echo "
"; - echo "
"; - echo "
";*/ - foreach ($invoice->lines as $line) { - //echo getDolGlobalString('AUTOVERIFACTU_TAX') ."|".$line->array_options['options_verifactu_regime_type']."|". $line->array_options['options_verifactu_operation_type']."|".$line->array_options['options_verifactu_tax_excemption']."|".$line->tva_tx."|".$line->localtax1_tx ; - $taxType = $line->array_options['options_Verifactu_Tax'] ?: '01'; - $regimeType = $line->array_options['options_verifactu_regime_type'] ?: $defaultRegime; - $operationType = $line->array_options['options_verifactu_operation_type'] ?: 'S1'; - $exemptionCode = $line->array_options['options_verifactu_tax_excemption'] ?: null; - $taxRate = number_format((float) $line->tva_tx, 2, '.', ''); - $baseAmount = (float) $line->total_ht; - $taxAmount = (float) $line->total_tva; - /* echo "-----------------------------------"; - echo "
"; - var_dump($line->localtax1_tx); - echo "
"; - var_dump( !NumberIsZero($line->localtax1_tx)); - echo "
"; - echo "-----------------------------------";*/ - $equivalenceSurchargeType = !NumberIsZero($line->localtax1_tx) && $line->product_type==="0" ? number_format((float) $line->localtax1_tx, 2, '.', '') : null; - $equivalenceSurchargeTotal = $line->total_localtax1 ? (float) $line->total_localtax1 : 0.0; - /*echo "
"; - echo "******************"; - echo "
"; - echo $equivalenceSurchargeType; - echo "
"; - echo "******************";*/ - //genero in key determinado - //para cada uno de los - //diferentes tipos impositivos - $key = implode('|', array( - $taxType, - $regimeType, - $operationType, - $exemptionCode ?: '', - $taxRate, - $equivalenceSurchargeType ?: null - )); - /* echo "
"; - echo $key; - echo "
"; - echo $line->id; - echo "
"; - echo var_dump(isset($grouped[$key])); - echo "
";*/ - - - //si no existe creo lo añado - if (!isset($grouped[$key])) { - $grouped[$key] = array( - 'taxType' => $taxType, - 'regimeType' => $regimeType, - 'operationType' => $operationType, - 'exemptionCode' => $exemptionCode, - 'taxRate' => $taxRate, - 'baseAmount' => 0.0, - 'taxAmount' => 0.0, - 'equivalenceSurchargeType' => $equivalenceSurchargeType, - 'equivalenceSurchargeTotal' => 0.0 - ); - } - //sumo los tipos - $grouped[$key]['baseAmount'] += $baseAmount; - $grouped[$key]['taxAmount'] += $taxAmount; - $grouped[$key]['equivalenceSurchargeTotal'] += $equivalenceSurchargeTotal; - /*echo "
";
-        var_dump($grouped);
-        echo "
";*/ - } - //creo la clase y las guardo en el arrray - $breakdown = array(); - if(count($grouped)>12){ - $invoice->error[]="maximumNumberOfTaxRates"; - return -1; - } - foreach ($grouped as $group) { - $details = new stdClass(); - $details->taxType = $group['taxType']; - $details->regimeType = $group['regimeType']; - $details->operationType = $group['operationType']; - $details->exemptionCode = $group['exemptionCode']; - $details->excemptionCode = $group['exemptionCode']; - $details->taxRate = $group['taxRate']; - $details->baseAmount = number_format($group['baseAmount'], 2, '.', ''); - $details->taxAmount = number_format($group['taxAmount'], 2, '.', ''); - - if ($group['equivalenceSurchargeType'] ) { - /*echo $group['equivalenceSurchargeType']; - echo "
"; - echo $group['equivalenceSurchargeTotal'];*/ - $details->equivalenceSurcharge = new stdClass(); - $details->equivalenceSurcharge->type = $group['equivalenceSurchargeType']; - $details->equivalenceSurcharge->total = number_format($group['equivalenceSurchargeTotal'], 2, '.', ''); - } - $breakdown[] = $details; - } - //var_dump($breakdown); - return $breakdown; + + $grouped = array(); + $defaultRegime = getDolGlobalString('AUTOVERIFACTU_DEFAULT_REGIME') ?: '01'; + /* echo "
";
+	var_dump($invoice->lines);
+	echo "
"; + echo "
"; + echo "
"; + echo "
";*/ + foreach ($invoice->lines as $line) { + //echo getDolGlobalString('AUTOVERIFACTU_TAX') ."|".$line->array_options['options_verifactu_regime_type']."|". $line->array_options['options_verifactu_operation_type']."|".$line->array_options['options_verifactu_tax_excemption']."|".$line->tva_tx."|".$line->localtax1_tx ; + $taxType = $line->array_options['options_Verifactu_Tax'] ?: '01'; + $regimeType = $line->array_options['options_verifactu_regime_type'] ?: $defaultRegime; + $operationType = $line->array_options['options_verifactu_operation_type'] ?: 'S1'; + $exemptionCode = $line->array_options['options_verifactu_tax_excemption'] ?: null; + $taxRate = number_format((float) $line->tva_tx, 2, '.', ''); + $baseAmount = (float) $line->total_ht; + $taxAmount = (float) $line->total_tva; + /* echo "-----------------------------------"; + echo "
"; + var_dump($line->localtax1_tx); + echo "
"; + var_dump( !NumberIsZero($line->localtax1_tx)); + echo "
"; + echo "-----------------------------------";*/ + $equivalenceSurchargeType = !NumberIsZero($line->localtax1_tx) && $line->product_type==="0" ? number_format((float) $line->localtax1_tx, 2, '.', '') : null; + $equivalenceSurchargeTotal = $line->total_localtax1 ? (float) $line->total_localtax1 : 0.0; + /*echo "
"; + echo "******************"; + echo "
"; + echo $equivalenceSurchargeType; + echo "
"; + echo "******************";*/ + //genero in key determinado + //para cada uno de los + //diferentes tipos impositivos + $key = implode('|', array( + $taxType, + $regimeType, + $operationType, + $exemptionCode ?: '', + $taxRate, + $equivalenceSurchargeType ?: null + )); + /* echo "
"; + echo $key; + echo "
"; + echo $line->id; + echo "
"; + echo var_dump(isset($grouped[$key])); + echo "
";*/ + + + //si no existe creo lo añado + if (!isset($grouped[$key])) { + $grouped[$key] = array( + 'taxType' => $taxType, + 'regimeType' => $regimeType, + 'operationType' => $operationType, + 'exemptionCode' => $exemptionCode, + 'taxRate' => $taxRate, + 'baseAmount' => 0.0, + 'taxAmount' => 0.0, + 'equivalenceSurchargeType' => $equivalenceSurchargeType, + 'equivalenceSurchargeTotal' => 0.0 + ); + } + //sumo los tipos + $grouped[$key]['baseAmount'] += $baseAmount; + $grouped[$key]['taxAmount'] += $taxAmount; + $grouped[$key]['equivalenceSurchargeTotal'] += $equivalenceSurchargeTotal; + /*echo "
";
+		var_dump($grouped);
+		echo "
";*/ + } + //creo la clase y las guardo en el arrray + $breakdown = array(); + if (count($grouped)>12) { + $invoice->error[]="maximumNumberOfTaxRates"; + return -1; + } + foreach ($grouped as $group) { + $details = new stdClass(); + $details->taxType = $group['taxType']; + $details->regimeType = $group['regimeType']; + $details->operationType = $group['operationType']; + $details->exemptionCode = $group['exemptionCode']; + $details->excemptionCode = $group['exemptionCode']; + $details->taxRate = $group['taxRate']; + $details->baseAmount = number_format($group['baseAmount'], 2, '.', ''); + $details->taxAmount = number_format($group['taxAmount'], 2, '.', ''); + + if ($group['equivalenceSurchargeType'] ) { + /*echo $group['equivalenceSurchargeType']; + echo "
"; + echo $group['equivalenceSurchargeTotal'];*/ + $details->equivalenceSurcharge = new stdClass(); + $details->equivalenceSurcharge->type = $group['equivalenceSurchargeType']; + $details->equivalenceSurcharge->total = number_format($group['equivalenceSurchargeTotal'], 2, '.', ''); + } + $breakdown[] = $details; + } + //var_dump($breakdown); + return $breakdown; } - + /** * Return the invoice record computer system data. It uses $mysoc global variable to fill @@ -1280,22 +1257,22 @@ function autoverifactuLinesToBreakdown($invoice) */ function autoverifactuGetRecordComputerSystem() { - if (!autoverifactuSystemCheck()) { - return; - } - global $mysoc; - $system = new stdClass(); - $system->vendorName = trim($mysoc->nom); - $system->vendorNif = trim($mysoc->idprof1); - $system->name = 'Auto-Veri*Factu Dolibarr'; - $system->id = 'AV'; - $system->version = '1.0.0'; - $system->installationNumber = '001'; - $system->onlySupportsVerifactu = true; - // TODO: Handle muti company - $system->supportsMultipleTaxpayers = false; - $system->hasMultipleTaxpayers = false; - return $system; + if (!autoverifactuSystemCheck()) { + return; + } + global $mysoc; + $system = new stdClass(); + $system->vendorName = trim($mysoc->nom); + $system->vendorNif = trim($mysoc->idprof1); + $system->name = 'Auto-Veri*Factu Dolibarr'; + $system->id = 'AV'; + $system->version = '1.0.0'; + $system->installationNumber = '001'; + $system->onlySupportsVerifactu = true; + // TODO: Handle muti company + $system->supportsMultipleTaxpayers = false; + $system->hasMultipleTaxpayers = false; + return $system; } /** @@ -1306,28 +1283,28 @@ function autoverifactuGetRecordComputerSystem() * @return string Record sha256 hash. */ function autoverifactuCalculateRecordHash($record) -{ - if ($record->type == 'alta') { - echo "

"; - $payload = 'IDEmisorFactura=' . $record->invoiceId->issuerId; - $payload .= '&NumSerieFactura=' . $record->invoiceId->invoiceNumber; - $payload .= '&FechaExpedicionFactura=' . $record->invoiceId->issueDate->format('d-m-Y'); - $payload .= '&TipoFactura=' . $record->invoiceType; - $payload .= '&CuotaTotal=' . $record->totalTaxAmount; - $payload .= '&ImporteTotal=' . $record->totalAmount; - $payload .= '&Huella=' . ($record->previousHash ?? ''); - $payload .= '&FechaHoraHusoGenRegistro=' . $record->hashedAt->format('c'); - } elseif ($record->type === 'anulacion') { - // Otherwise, it's a validated invoice in process to be canceled. - $payload = 'IDEmisorFacturaAnulada=' . $record->invoiceId->issuerId; - $payload .= '&NumSerieFacturaAnulada=' . $record->invoiceId->invoiceNumber; - $payload .= '&FechaExpedicionFacturaAnulada=' . $record->invoiceId->issueDate->format('d-m-Y'); - $payload .= '&Huella=' . ($record->previousHash ?? ''); - $payload .= '&FechaHoraHusoGenRegistro=' . $record->hashedAt->format('c'); - } else { - $payload = ''; - } - return strtoupper(hash('sha256', $payload)); +{ + if ($record->type == 'alta') { + echo "

"; + $payload = 'IDEmisorFactura=' . $record->invoiceId->issuerId; + $payload .= '&NumSerieFactura=' . $record->invoiceId->invoiceNumber; + $payload .= '&FechaExpedicionFactura=' . $record->invoiceId->issueDate->format('d-m-Y'); + $payload .= '&TipoFactura=' . $record->invoiceType; + $payload .= '&CuotaTotal=' . $record->totalTaxAmount; + $payload .= '&ImporteTotal=' . $record->totalAmount; + $payload .= '&Huella=' . ($record->previousHash ?? ''); + $payload .= '&FechaHoraHusoGenRegistro=' . $record->hashedAt->format('c'); + } elseif ($record->type === 'anulacion') { + // Otherwise, it's a validated invoice in process to be canceled. + $payload = 'IDEmisorFacturaAnulada=' . $record->invoiceId->issuerId; + $payload .= '&NumSerieFacturaAnulada=' . $record->invoiceId->invoiceNumber; + $payload .= '&FechaExpedicionFacturaAnulada=' . $record->invoiceId->issueDate->format('d-m-Y'); + $payload .= '&Huella=' . ($record->previousHash ?? ''); + $payload .= '&FechaHoraHusoGenRegistro=' . $record->hashedAt->format('c'); + } else { + $payload = ''; + } + return strtoupper(hash('sha256', $payload)); } /** @@ -1342,142 +1319,140 @@ function autoverifactuCalculateRecordHash($record) */ function autoverifactuRegisterInvoiceList($invoices) { - global $db, $conf, $hookmanager, $user; - if (empty($invoices) || !is_array($invoices)) { - return 0; - } - if (empty($conf->facture->multidir_output[$conf->entity])) { - dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); - return -1; - } - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); - $recordsLote = array(); - $facturasValidasLote = array(); - //recorro las facturas - foreach ($invoices as $invoice) { - if ($invoice->type > Facture::TYPE_DEPOSIT) continue; - $invoice->fetch_thirdparty(); - $thirdparty = $invoice->thirdparty; - $valid_id = $thirdparty->id_prof_check(1, $thirdparty); - if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { - dol_syslog('Skip invoice #' . $invoice->id . ' due to thirdparty without valid idprof1'); - continue; - } - if (!count($invoice->lines)) { - dol_syslog('Skip invoice #' . $invoice->id . ' due to no lines'); - continue; - } - $recordType ='alta'; - $record = autoverifactuInvoiceToRecord($invoice, $recordType); - if ($record) { - $recordsLote[] = $record; - $facturasValidasLote[] = $invoice; // Guardamos la correspondencia - } - } - if (empty($recordsLote)) { - return 0; - } - - global $mysoc; - $issuer = array( - 'name' => $mysoc->nom, - 'idprof1' => $mysoc->idprof1, - ); - - try { - //genero el xml para envios masivos - $envelope = autoverifactuSoapEnvelopeMass($recordsLote, $issuer); - - - $resDOM = autoverifactuSoapRequest($envelope); - - $exitos = 0; - $registroFacturaNodes = $resDOM->getElementsByTagName('RespuestaLinea'); - - //analizamos uno a uno las repuetas para cada factura - foreach ($facturasValidasLote as $index => $invoice) { - $nodoRespuesta = $registroFacturaNodes->item($index); - $status = $nodoRespuesta ? $nodoRespuesta->getElementsByTagName('EstadoRegistro')[0]->nodeValue : 'Incorrecto'; - $invoiceref = dol_sanitizeFileName($invoice->ref); - $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; - if (!file_exists($dir)) dol_mkdir($dir); - - if ($status === 'Correcto' || $status === 'AceptadoConErrores') { - // Guardar localmente el XML individual o masivo por cumplimiento normativo de almacenamiento - if ($action === 'BILL_VALIDATE') { - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - } else if($action === 'verifactuResend'){ - $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - }else { - $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - } - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'xml' ; - $result = file_put_contents($file, $envelope); - $result = $result && file_put_contents($hidden, $envelope); - if($result){ - throw new Exception('Unable to store XML invoice record', 500); - } - // Actualizar huellas y estados de éxito (1 = Correcto, 4 = Aceptado con Errores) - $invoice->array_options['options_verifactu_hash'] = $recordsLote[$index]->hash; - $invoice->array_options['options_verifactu_tms'] = $recordsLote[$index]->hashedAt->getTimestamp(); - - if ($status === 'AceptadoConErrores') { - $errMessage = $nodoRespuesta->getElementsByTagName('DescripcionErrorRegistro')[0]->nodeValue; - $invoice->array_options['options_verifactu_error'] = $errMessage; - $errCode = $nodoRespuesta->getElementsByTagName('CodigoErrorRegistro')[0]->nodeValue; - $invoice->array_options['options_verifactu_error_code'] = $errCode; - - if( in_array($invoice->array_options['options_verifactu_status'], array('4','5'), true) ){ - //en caso de existir subsanaciones o estar registrada originalmente - $invoice->array_options['options_verifactu_status'] = '5'; - }else{ - //en caso de no estar registrada originalmente - $invoice->array_options['options_verifactu_status'] = '4'; - } - - } else { - //correcto - $invoice->array_options['options_verifactu_error'] = ''; - $invoice->array_options['options_verifactu_error_code'] = ''; - $invoice->array_options['options_verifactu_status'] = '1'; - } - $invoice->insertExtraFields(); - $exitos++; - }else{ - // Estado 'Incorrecto' (La factura individual ha sido rechazada estructuralmente) - $errMessage = $nodoRespuesta ? $nodoRespuesta->getElementsByTagName('DescripcionErrorRegistro')[0]->nodeValue : 'Error estructural en lote'; - $errCode = $nodoRespuesta->getElementsByTagName('CodigoErrorRegistro')[0]->nodeValue; - if(in_array($invoice->array_options['options_verifactu_status'], array('0','2'),true)){ - //No esta regsitrado(Pendiente de envio o rechazado) - $invoice->array_options['options_verifactu_status'] = '2'; // 2 = Rechazado - }else{ - //esta regsitrado (Registrado correctamente pero con errores o Registrado correctamente pero con errores múltiples veces) - $invoice->array_options['options_verifactu_status'] = '5'; - } - $invoice->array_options['options_verifactu_error'] = $errMessage; - $invoice->array_options['options_verifactu_error_code'] = $errCode; - $invoice->insertExtraFields(); - dol_syslog('Factura #' . $invoice->id . ' rechazada por AEAT: ' . $errMessage, LOG_ERR); - $invoice->ref=$record->invoiceId->invoiceNumber; - $result = $invoice->update($user); - if ($result <= 0) { - throw new Exception($invoice->error, 1); - } - } - } - - return $exitos == count($facturasValidasLote); - }catch (Exception $e) { - dol_syslog('Critical error in Veri*Factu mass mailing:' . $e->getMessage(), LOG_ERR); - return -1; - } - + global $db, $conf, $hookmanager, $user; + if (empty($invoices) || !is_array($invoices)) { + return 0; + } + if (empty($conf->facture->multidir_output[$conf->entity])) { + dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); + return -1; + } + $now=new DateTimeImmutable( + 'now', + new DateTimeZone('Europe/Madrid'), + ); + $recordsLote = array(); + $facturasValidasLote = array(); + //recorro las facturas + foreach ($invoices as $invoice) { + if ($invoice->type > Facture::TYPE_DEPOSIT) continue; + $invoice->fetch_thirdparty(); + $thirdparty = $invoice->thirdparty; + $valid_id = $thirdparty->id_prof_check(1, $thirdparty); + if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { + dol_syslog('Skip invoice #' . $invoice->id . ' due to thirdparty without valid idprof1'); + continue; + } + if (!count($invoice->lines)) { + dol_syslog('Skip invoice #' . $invoice->id . ' due to no lines'); + continue; + } + $recordType ='alta'; + $record = autoverifactuInvoiceToRecord($invoice, $recordType); + if ($record) { + $recordsLote[] = $record; + $facturasValidasLote[] = $invoice; // Guardamos la correspondencia + } + } + if (empty($recordsLote)) { + return 0; + } + + global $mysoc; + $issuer = array( + 'name' => $mysoc->nom, + 'idprof1' => $mysoc->idprof1, + ); + + try { + //genero el xml para envios masivos + $envelope = autoverifactuSoapEnvelopeMass($recordsLote, $issuer); + + + $resDOM = autoverifactuSoapRequest($envelope); + + $exitos = 0; + $registroFacturaNodes = $resDOM->getElementsByTagName('RespuestaLinea'); + + //analizamos uno a uno las repuetas para cada factura + foreach ($facturasValidasLote as $index => $invoice) { + $nodoRespuesta = $registroFacturaNodes->item($index); + $status = $nodoRespuesta ? $nodoRespuesta->getElementsByTagName('EstadoRegistro')[0]->nodeValue : 'Incorrecto'; + $invoiceref = dol_sanitizeFileName($invoice->ref); + $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; + if (!file_exists($dir)) dol_mkdir($dir); + + if ($status === 'Correcto' || $status === 'AceptadoConErrores') { + // Guardar localmente el XML individual o masivo por cumplimiento normativo de almacenamiento + if ($action === 'BILL_VALIDATE') { + $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + } elseif ($action === 'verifactuResend') { + $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + } else { + $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + } + $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'xml' ; + $result = file_put_contents($file, $envelope); + $result = $result && file_put_contents($hidden, $envelope); + if ($result) { + throw new Exception('Unable to store XML invoice record', 500); + } + // Actualizar huellas y estados de éxito (1 = Correcto, 4 = Aceptado con Errores) + $invoice->array_options['options_verifactu_hash'] = $recordsLote[$index]->hash; + $invoice->array_options['options_verifactu_tms'] = $recordsLote[$index]->hashedAt->getTimestamp(); + + if ($status === 'AceptadoConErrores') { + $errMessage = $nodoRespuesta->getElementsByTagName('DescripcionErrorRegistro')[0]->nodeValue; + $invoice->array_options['options_verifactu_error'] = $errMessage; + $errCode = $nodoRespuesta->getElementsByTagName('CodigoErrorRegistro')[0]->nodeValue; + $invoice->array_options['options_verifactu_error_code'] = $errCode; + + if ( in_array($invoice->array_options['options_verifactu_status'], array('4','5'), true) ) { + //en caso de existir subsanaciones o estar registrada originalmente + $invoice->array_options['options_verifactu_status'] = '5'; + } else { + //en caso de no estar registrada originalmente + $invoice->array_options['options_verifactu_status'] = '4'; + } + } else { + //correcto + $invoice->array_options['options_verifactu_error'] = ''; + $invoice->array_options['options_verifactu_error_code'] = ''; + $invoice->array_options['options_verifactu_status'] = '1'; + } + $invoice->insertExtraFields(); + $exitos++; + } else { + // Estado 'Incorrecto' (La factura individual ha sido rechazada estructuralmente) + $errMessage = $nodoRespuesta ? $nodoRespuesta->getElementsByTagName('DescripcionErrorRegistro')[0]->nodeValue : 'Error estructural en lote'; + $errCode = $nodoRespuesta->getElementsByTagName('CodigoErrorRegistro')[0]->nodeValue; + if (in_array($invoice->array_options['options_verifactu_status'], array('0','2'), true)) { + //No esta regsitrado(Pendiente de envio o rechazado) + $invoice->array_options['options_verifactu_status'] = '2'; // 2 = Rechazado + } else { + //esta regsitrado (Registrado correctamente pero con errores o Registrado correctamente pero con errores múltiples veces) + $invoice->array_options['options_verifactu_status'] = '5'; + } + $invoice->array_options['options_verifactu_error'] = $errMessage; + $invoice->array_options['options_verifactu_error_code'] = $errCode; + $invoice->insertExtraFields(); + dol_syslog('Factura #' . $invoice->id . ' rechazada por AEAT: ' . $errMessage, LOG_ERR); + $invoice->ref=$record->invoiceId->invoiceNumber; + $result = $invoice->update($user); + if ($result <= 0) { + throw new Exception($invoice->error, 1); + } + } + } + + return $exitos == count($facturasValidasLote); + } catch (Exception $e) { + dol_syslog('Critical error in Veri*Factu mass mailing:' . $e->getMessage(), LOG_ERR); + return -1; + } } /** @@ -1491,43 +1466,43 @@ function autoverifactuRegisterInvoiceList($invoices) */ function autoverifactuSoapEnvelopeMass($records, $issuer, $representative = null) { - - $xml = new DOMDocument('1.0', 'UTF-8'); - $envelope = $xml->createElement('soapenv:Envelope'); - $envelope->setAttribute('xmlns:soapenv', AUTOVERIFACTU_SOAPENV_NS); - $envelope->setAttribute('xmlns:sum', AUTOVERIFACTU_SUM_NS); - $envelope->setAttribute('xmlns:sum1', AUTOVERIFACTU_SUM1_NS); - $envelope->setAttribute('xmlns:xd', AUTOVERIFACTU_XD_NS); + $xml = new DOMDocument('1.0', 'UTF-8'); + + $envelope = $xml->createElement('soapenv:Envelope'); + $envelope->setAttribute('xmlns:soapenv', AUTOVERIFACTU_SOAPENV_NS); + $envelope->setAttribute('xmlns:sum', AUTOVERIFACTU_SUM_NS); + $envelope->setAttribute('xmlns:sum1', AUTOVERIFACTU_SUM1_NS); + $envelope->setAttribute('xmlns:xd', AUTOVERIFACTU_XD_NS); - $headerEl = $xml->createElement('soapenv:Header'); - $envelope->appendChild($headerEl); + $headerEl = $xml->createElement('soapenv:Header'); + $envelope->appendChild($headerEl); - $body = $xml->createElement('soapenv:Body'); - $envelope->appendChild($body); + $body = $xml->createElement('soapenv:Body'); + $envelope->appendChild($body); - // Contenedor principal ÚNICO para todo el lote - $root = $xml->createElement('sum:RegFactuSistemaFacturacion'); - $body->appendChild($root); + // Contenedor principal ÚNICO para todo el lote + $root = $xml->createElement('sum:RegFactuSistemaFacturacion'); + $body->appendChild($root); - // Cabecera ÚNICA del emisor - $regHeaderEl = $xml->createElement('sum:Cabecera'); - $root->appendChild($regHeaderEl); + // Cabecera ÚNICA del emisor + $regHeaderEl = $xml->createElement('sum:Cabecera'); + $root->appendChild($regHeaderEl); - $issuerEl = $xml->createElement('sum1:ObligadoEmision'); - $regHeaderEl->appendChild($issuerEl); + $issuerEl = $xml->createElement('sum1:ObligadoEmision'); + $regHeaderEl->appendChild($issuerEl); - $issuerEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($issuer['name']))); - $issuerEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($issuer['idprof1']))); + $issuerEl->appendChild($xml->createElement('sum1:NombreRazon', htmlspecialchars($issuer['name']))); + $issuerEl->appendChild($xml->createElement('sum1:NIF', htmlspecialchars($issuer['idprof1']))); - - foreach ($records as $record) { - $recordEl = autoverifactuRecordToXML($record, $xml); - $root->appendChild($recordEl); - } - $xml->appendChild($envelope); - return $xml->saveXML($envelope); + foreach ($records as $record) { + $recordEl = autoverifactuRecordToXML($record, $xml); + $root->appendChild($recordEl); + } + + $xml->appendChild($envelope); + return $xml->saveXML($envelope); } /* @@ -1535,154 +1510,155 @@ function autoverifactuSoapEnvelopeMass($records, $issuer, $representative = null true si es cero o vacio false si tiene un valor != 0 */ -function NumberIsZero($valor) { - if(!isset($valor)){ - return true; - } - - // Comprobamos si el texto es un 0 con o sin decimales - if (preg_match('/^0(\.0+)?$/', $valor)) { - - // Verificamos si realmente contiene un punto antes de hacer el explode - if (strpos($valor, '.') !== false) { - $cantidadDecimales = strlen(explode('.', $valor)[1]); - } else { - $cantidadDecimales = 0; // Si no hay punto, tiene 0 decimales - } - - return true; - } - - return false; +function NumberIsZero($valor) +{ + if (!isset($valor)) { + return true; + } + + // Comprobamos si el texto es un 0 con o sin decimales + if (preg_match('/^0(\.0+)?$/', $valor)) { + // Verificamos si realmente contiene un punto antes de hacer el explode + if (strpos($valor, '.') !== false) { + $cantidadDecimales = strlen(explode('.', $valor)[1]); + } else { + $cantidadDecimales = 0; // Si no hay punto, tiene 0 decimales + } + + return true; + } + + return false; } /* * añade los textos legales al pdf dependiendo de las caractericticas de la factura */ -function autoverifactuSetLegalText($invoice){ - - if(!isset($invoice->array_options["options_verifactu_pdfLegalText"])){ - $invoice->array_options["options_verifactu_pdfLegalText"] = []; - }else if(strlen($invoice->array_options["options_verifactu_pdfLegalText"])>0){ - $invoice->array_options["options_verifactu_pdfLegalText"] = explode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); - } - - - - //IRPF - if(!NumberIsZero($invoice->total_localtax2)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextIRPF"; - } - - $SujetoPasivo = true; - if(in_array("VerifactuLegalTextSujetoPasivo",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $SujetoPasivo = false; - } - $criterioCaja = true; - if(in_array("VerifactuLegalTextCriterioCaja",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $criterioCaja = false; - } - $excemptionIVA = []; - if(in_array("VerifactuLegalTextTaxExcemptionE1",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E1'; - } - if(in_array("VerifactuLegalTextTaxExcemptionE2",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E2'; - } - if(in_array("VerifactuLegalTextTaxExcemptionE3",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E3'; - } - if(in_array("VerifactuLegalTextTaxExcemptionE4",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E4'; - } - if(in_array("VerifactuLegalTextTaxExcemptionE5",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E5'; - } - if(in_array("VerifactuLegalTextTaxExcemptionE6",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $excemptionIVA[]='E6'; - } - - $rebu=true; - if(in_array("VerifactuLegalTextREBU",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $rebu = false; - } - $agenciaViajes=true; - if(in_array("VerifactuLegalTextAgenciaViajes",$invoice->array_options['options_verifactu_pdfLegalText'])){ - $agenciaViajes = false; - } - - foreach ($invoice->lines as $line) { - //exceciones IVA - if($line->array_options['options_verifactu_tax_excemption'] ){ - switch ($line->array_options['options_verifactu_tax_excemption']) { - case 'E1': - if(!in_array('E1', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE1"; - $excemptionIVA[]='E1'; - } - - break; - case 'E2': - if(!in_array('E2', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE2"; - $excemptionIVA[]='E2'; - } - break; - case 'E3': - if(!in_array('E3', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE3"; - $excemptionIVA[]='E3'; - } - break; - case 'E4': - if(!in_array('E4', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE4"; - $excemptionIVA[]='E4'; - } - break; - case 'E5': - if(!in_array('E5', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE5"; - $excemptionIVA[]='E5'; - } - - break; - case 'E6': - if(!in_array('E6', $excemptionIVA)){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE6"; - $excemptionIVA[]='E6'; - } - break; - default: - throw new Exception("Error options_verifactu_error not valid value", 1); - break; - } - } - - //Inversión del Sujeto Pasivo - if($line->array_options['options_verifactu_operation_type']==='S2' && $SujetoPasivo){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextSujetoPasivo"; - $SujetoPasivo=false; - } - //regimen de criterio de caja - if($line->array_options['options_verifactu_regime_type']==="07" && $criterioCaja){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextCriterioCaja"; - $criterioCaja=false; - } - - if($line->array_options['options_verifactu_regime_type']==="03" && $rebu){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextREBU"; - $rebu=false; - } - if($line->array_options['options_verifactu_regime_type']==="09" && $agenciaViajes){ - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextAgenciaViajes"; - $agenciaViajes=false; - } - } - $invoice->array_options["options_verifactu_pdfLegalText"]=implode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); - - $result = $invoice->insertExtraFields(); - if ($result < 0) { - throw new Exception("Error save options_verifactu_pdfLegalText ", 1); - } -} \ No newline at end of file +function autoverifactuSetLegalText($invoice) +{ + + if (!isset($invoice->array_options["options_verifactu_pdfLegalText"])) { + $invoice->array_options["options_verifactu_pdfLegalText"] = []; + } elseif (strlen($invoice->array_options["options_verifactu_pdfLegalText"])>0) { + $invoice->array_options["options_verifactu_pdfLegalText"] = explode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); + } + + + + //IRPF + if (!NumberIsZero($invoice->total_localtax2)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextIRPF"; + } + + $SujetoPasivo = true; + if (in_array("VerifactuLegalTextSujetoPasivo", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $SujetoPasivo = false; + } + $criterioCaja = true; + if (in_array("VerifactuLegalTextCriterioCaja", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $criterioCaja = false; + } + $excemptionIVA = []; + if (in_array("VerifactuLegalTextTaxExcemptionE1", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E1'; + } + if (in_array("VerifactuLegalTextTaxExcemptionE2", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E2'; + } + if (in_array("VerifactuLegalTextTaxExcemptionE3", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E3'; + } + if (in_array("VerifactuLegalTextTaxExcemptionE4", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E4'; + } + if (in_array("VerifactuLegalTextTaxExcemptionE5", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E5'; + } + if (in_array("VerifactuLegalTextTaxExcemptionE6", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[]='E6'; + } + + $rebu=true; + if (in_array("VerifactuLegalTextREBU", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $rebu = false; + } + $agenciaViajes=true; + if (in_array("VerifactuLegalTextAgenciaViajes", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $agenciaViajes = false; + } + + foreach ($invoice->lines as $line) { + //exceciones IVA + if ($line->array_options['options_verifactu_tax_excemption'] ) { + switch ($line->array_options['options_verifactu_tax_excemption']) { + case 'E1': + if (!in_array('E1', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE1"; + $excemptionIVA[]='E1'; + } + + break; + case 'E2': + if (!in_array('E2', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE2"; + $excemptionIVA[]='E2'; + } + break; + case 'E3': + if (!in_array('E3', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE3"; + $excemptionIVA[]='E3'; + } + break; + case 'E4': + if (!in_array('E4', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE4"; + $excemptionIVA[]='E4'; + } + break; + case 'E5': + if (!in_array('E5', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE5"; + $excemptionIVA[]='E5'; + } + + break; + case 'E6': + if (!in_array('E6', $excemptionIVA)) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE6"; + $excemptionIVA[]='E6'; + } + break; + default: + throw new Exception("Error options_verifactu_error not valid value", 1); + break; + } + } + + //Inversión del Sujeto Pasivo + if ($line->array_options['options_verifactu_operation_type']==='S2' && $SujetoPasivo) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextSujetoPasivo"; + $SujetoPasivo=false; + } + //regimen de criterio de caja + if ($line->array_options['options_verifactu_regime_type']==="07" && $criterioCaja) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextCriterioCaja"; + $criterioCaja=false; + } + + if ($line->array_options['options_verifactu_regime_type']==="03" && $rebu) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextREBU"; + $rebu=false; + } + if ($line->array_options['options_verifactu_regime_type']==="09" && $agenciaViajes) { + $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextAgenciaViajes"; + $agenciaViajes=false; + } + } + $invoice->array_options["options_verifactu_pdfLegalText"]=implode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); + + $result = $invoice->insertExtraFields(); + if ($result < 0) { + throw new Exception("Error save options_verifactu_pdfLegalText ", 1); + } +} From 5f7949b81be3c7e3bf3b755e13218c91cca6ec52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 15:57:07 +0200 Subject: [PATCH 3/6] feat: apply custom formating cs rules --- admin/about.php | 2 +- admin/autodeclaration.php | 2 +- admin/setup.php | 10 +- class/actions_autoverifactu.class.php | 92 ++-- class/verifactuqueue.class.php | 6 +- .../facture/doc/pdf_Autoverifactu.modules.php | 424 +++++++++--------- core/modules/modAutoverifactu.class.php | 8 +- ...actu_AutoverifactuFreezeInvoices.class.php | 18 +- css/selector_status.css.php | 22 +- dev/tools/phpcs/dolibarr-ruleset.xml | 3 + lib/validation.lib.php | 109 ++--- lib/verifactu.lib.php | 344 +++++++------- 12 files changed, 517 insertions(+), 523 deletions(-) diff --git a/admin/about.php b/admin/about.php index be51f6e..0fad12e 100755 --- a/admin/about.php +++ b/admin/about.php @@ -58,7 +58,7 @@ llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-autoverifactu page-admin_about'); // Subheader -$linkback = ''.$langs->trans("BackToModuleList").''; +$linkback = '' . $langs->trans('BackToModuleList') . ''; echo load_fiche_titre($langs->trans($title), $linkback, 'title_setup'); diff --git a/admin/autodeclaration.php b/admin/autodeclaration.php index 18bc535..24f36f5 100644 --- a/admin/autodeclaration.php +++ b/admin/autodeclaration.php @@ -83,7 +83,7 @@ llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-autoverifactu page-admin_autodeclaration'); // Subheader -$linkback = ''.$langs->trans('BackToModuleList').''; +$linkback = '' . $langs->trans('BackToModuleList') . ''; echo load_fiche_titre($langs->trans($title), $linkback, 'title_setup'); diff --git a/admin/setup.php b/admin/setup.php index 8c43df4..daa1b51 100755 --- a/admin/setup.php +++ b/admin/setup.php @@ -47,7 +47,9 @@ $langs->loadLangs(array('admin', 'autoverifactu@autoverifactu')); // Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context -/** @var HookManager $hookmanager */ +/** + * @var HookManager $hookmanager +*/ $hookmanager->initHooks(array('autoverifactusetup', 'globalsetup')); // Parameters @@ -275,7 +277,7 @@ class="valignmiddle inline-block linkobject hideobject" llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-autoverifactu page-admin'); // Subheader -$linkback = '' . img_picto($langs->trans('BackToModuleList'), 'back', 'class="pictofixedwidth"').''.$langs->trans('BackToModuleList').''; +$linkback = '' . img_picto($langs->trans('BackToModuleList'), 'back', 'class="pictofixedwidth"') . '' . $langs->trans('BackToModuleList') . ''; echo load_fiche_titre($langs->trans($title), $linkback, 'title_setup'); @@ -300,11 +302,11 @@ class="valignmiddle inline-block linkobject hideobject" } if (empty($setupnotempty)) { - echo '
'.$langs->trans('NothingToSetup'); + echo '
' . $langs->trans('NothingToSetup'); } $formfile->form_attach_new_file( - $_SERVER["PHP_SELF"] . '?action=upload', + $_SERVER['PHP_SELF'] . '?action=upload', $langs->trans('UploadCertificate'), 0, 0, diff --git a/class/actions_autoverifactu.class.php b/class/actions_autoverifactu.class.php index 3a744f8..077bc94 100644 --- a/class/actions_autoverifactu.class.php +++ b/class/actions_autoverifactu.class.php @@ -71,7 +71,7 @@ class ActionsAutoverifactu extends CommonHookActions /** * Constructor * - * @param DoliDB $db Database handler. + * @param DoliDB $db Database handler. */ public function __construct($db) { @@ -81,12 +81,12 @@ public function __construct($db) /** * Overload the doActions function : replacing the parent's function with the one below * - * @param array $parameters Hook metadata (context, etc...) - * @param CommonObject $object The object to process (an invoice if you are - * in invoice module, a propale in propale's module, etc...) - * @param ?string $action Current action (if set). Generally create or edit or null + * @param array $parameters Hook metadata (context, etc...) + * @param CommonObject $object The object to process (an invoice if you are + * in invoice module, a propale in propale's module, etc...) + * @param ?string $action Current action (if set). Generally create or edit or null * - * @return int Return integer < 0 on error, 0 on success, 1 to replace + * @return int Return integer < 0 on error, 0 on success, 1 to replace * standard code */ public function doActions($parameters, &$object, &$action) @@ -95,9 +95,9 @@ public function doActions($parameters, &$object, &$action) global $langs, $mysoc, $dolibarr_main_url_root; - if ($parameters['currentcontext'] ==='invoicelist') { + if ($parameters['currentcontext'] === 'invoicelist') { //añade estilo a los estados de verifactu. - echo ''; + echo ''; } if ($parameters['currentcontext'] === 'invoicecard') { @@ -158,15 +158,15 @@ public function doActions($parameters, &$object, &$action) } break; case 'edit_extras': - $attribute=GETPOST("attribute", "alpha"); + $attribute = GETPOST('attribute', 'alpha'); //evito que se editen estos campos if ( - $attribute==="verifactu_status" || - $attribute==="verifactu_hash" || - $attribute === "verifactu_error" || - $attribute === "verifactu_error_code" || - $attribute ==="verifactu_pdfLegalText" || - $attribute==="VerifactuTimeStamp" + $attribute === 'verifactu_status' || + $attribute === 'verifactu_hash' || + $attribute === 'verifactu_error' || + $attribute === 'verifactu_error_code' || + $attribute === 'verifactu_pdfLegalText' || + $attribute === 'VerifactuTimeStamp' ) { $this->errors[] = $langs->trans('NotEdit'); $action = ''; @@ -174,25 +174,25 @@ public function doActions($parameters, &$object, &$action) break; case 'add': if (in_array($object->type, array(Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE), true)) { - $rectificationType=GETPOST("options_verifactu_rectification_type", "alpha"); + $rectificationType = GETPOST('options_verifactu_rectification_type', 'alpha'); if (empty($rectificationType)) { $this->errors[] = $langs->trans('RectificationTypeRequired'); - header('Location: '.$_SERVER['PHP_SELF'].'?action=create'); + header('Location: ' . $_SERVER['PHP_SELF'] . '?action=create'); } } break; case 'verifactuResend': //esta accion se da cuando una factura ha tenido un error y se quiere reenviar unavez subsanado el error - $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); //compruebo que el a pasado el tiempo de espera par la proxima peticion de la api - if ($now->getTimestamp()getTimestamp() < getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0')) { //en caso de que no se pueda enviar lo indico $langs->load('autoverifactu@autoverifactu'); - $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED') - $now->getTimestamp()); return 0; - } elseif (in_array($object->array_options['options_verifactu_status'], array("2","4","5"), true)) { + } elseif (in_array($object->array_options['options_verifactu_status'], array('2','4','5'), true)) { //en caso de poder enviarla lo envio $result = autoverifactuRegisterInvoice($object, $action); if ($result <= 0) { @@ -229,11 +229,11 @@ public function doActions($parameters, &$object, &$action) /** * Execute action before PDF (document) creation * - * @param array $parameters Array of parameters. - * @param CommonObject $object Object output on PDF. - * @param string $action 'add', 'update', 'view'. + * @param array $parameters Array of parameters. + * @param CommonObject $object Object output on PDF. + * @param string $action 'add', 'update', 'view'. * - * @return int Return integer <0 if KO, + * @return int Return integer <0 if KO, * =0 if OK but we want to process standard actions too, * >0 if OK and we want to replace standard actions. */ @@ -269,11 +269,11 @@ public function beforePDFCreation($parameters, &$object, &$action) * Execute action after PDF (document) header creation. Writes the QR code before the * invoice body is opened. * - * @param array $parameters Array of parameters. - * @param PDFCT &$pdfhandler Object output on PDF. - * @param string $action 'add', 'update', 'view'. + * @param array $parameters Array of parameters. + * @param PDFCT &$pdfhandler Object output on PDF. + * @param string $action 'add', 'update', 'view'. * - * @return int Return always 0. + * @return int Return always 0. * Overwrites the hookmanager results array */ public function printUnderHeaderPDFline($parameters, &$pdfhandler) @@ -286,7 +286,7 @@ public function printUnderHeaderPDFline($parameters, &$pdfhandler) && $object->status > Facture::STATUS_DRAFT && $object->type <= Facture::TYPE_DEPOSIT && autoverifactuEnabled() - && $modelpdf !== "Autoverifactu" //en caso de que no tenga la plantilla autoverifactu que ya incluye el QR + && $modelpdf !== 'Autoverifactu' //en caso de que no tenga la plantilla autoverifactu que ya incluye el QR ) { $pdf = &$parameters['pdf']; @@ -304,14 +304,14 @@ public function printUnderHeaderPDFline($parameters, &$pdfhandler) //A este respecto, se deben mantener como mínimo 2 milímetros de espacio vacío (en blanco) alrededor de los cuatro lados del código «QR», recomendándose que sean 6 milímetros. //La presentación del código «QR» incluirá también un texto que siempre deberá ir precediéndolo: «QR tributario:», y que se situará encima del propio código «QR» // (preferiblemente centrado con respecto a este), de manera que sirva para identificarlo y distinguirlo de otros posibles códigos «QR» que pudiera contener la factura para otros cometidos. - $pdf->setTopMargin($pdfhandler->tab_top -5); + $pdf->setTopMargin($pdfhandler->tab_top - 5); $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); $pdf->write2DBarcode( $base_url . $endpoint . '?' . $query, 'QRCODE,M', $pdfhandler->marge_gauche, - $pdfhandler->tab_top-1, + $pdfhandler->tab_top - 1, 32, 32, array( @@ -337,9 +337,9 @@ public function printUnderHeaderPDFline($parameters, &$pdfhandler) * Execute action on card page buttons render. If it is a facture page, * it adds a "verifactu" button to the row. * - * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of the page. - * @param string $action Global action. + * @param array $parameters Array of parameters. + * @param CommonObect &$object Instance of the owner object of the page. + * @param string $action Global action. * * @return null Empty response. The button * html is echoed to the output @@ -397,7 +397,7 @@ public function addMoreActionsButtons($parameters, &$object, $action) && $object->status > Facture::STATUS_DRAFT && $object->type <= Facture::TYPE_DEPOSIT && autoverifactuEnabled() - && in_array($object->array_options['options_verifactu_status'], array("2","4","5"), true) + && in_array($object->array_options['options_verifactu_status'], array('2','4','5'), true) ) { echo dolGetButtonAction( $langs->trans('VerifactuResend'), @@ -421,10 +421,10 @@ public function addMoreActionsButtons($parameters, &$object, $action) * then check userRights for each button based on the button action and * the state of the invoice. * - * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of - * the page. - * @param string $action Global action. + * @param array $parameters Array of parameters. + * @param CommonObect &$object Instance of the owner object of + * the page. + * @param string $action Global action. * * @return int<0,1> 1 if button has been overwrited, * 0 otherwise. @@ -523,25 +523,25 @@ public function formObjectOptions($parameters, $object, $action) return; } - if ($parameters['currentcontext'] === 'invoicecard' && $action==="fixErrors" && $object->id>0) { + if ($parameters['currentcontext'] === 'invoicecard' && $action === 'fixErrors' && $object->id > 0) { //accion de mostrar los erroes y una explicacion require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php'; $langs->load('autoverifactu@autoverifactu'); $form = new Form($db); $formquestion; - if ($object->array_options['options_verifactu_error_code'] === "2001" ) { + if ($object->array_options['options_verifactu_error_code'] === '2001' ) { //El NIF del bloque Destinatarios no está identificado en el censo de la AEAT. - $message = $langs->trans("Errorcode2001", $object->thirdparty->idprof1); + $message = $langs->trans('Errorcode2001', $object->thirdparty->idprof1); $parametros = $_GET; $parametros['id'] = $object->id; - $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $url = $_SERVER['PHP_SELF'] . '?id=' . $object->id; $this->formAlert($message, $url); } else { //los demas errores en teoria no deberian producirse porque la aplicación //daria error y no enviaria la petición - $message= $langs->trans("ErrorCodeErrorAplication"); - $url= $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $message = $langs->trans('ErrorCodeErrorAplication'); + $url = $_SERVER['PHP_SELF'] . '?id=' . $object->id; $this->formAlert($message, $url); } return 0; diff --git a/class/verifactuqueue.class.php b/class/verifactuqueue.class.php index 9aa32d7..2bd3da0 100644 --- a/class/verifactuqueue.class.php +++ b/class/verifactuqueue.class.php @@ -19,15 +19,15 @@ public function processMassiveQueue() { global $conf, $langs; $langs->load('autoverifactu@autoverifactu'); - $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); - if ($now->getTimestamp()getTimestamp() < getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0')) { //sigue en espera return 0; } else { //se puede enviar include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; //obtengo las facturas en cola max 30. - $sql = "SELECT fk_object FROM " . MAIN_DB_PREFIX . "facture_extrafields WHERE verifactu_status ='3' LIMIT 30"; + $sql = 'SELECT fk_object FROM ' . MAIN_DB_PREFIX . "facture_extrafields WHERE verifactu_status ='3' LIMIT 30"; $resql = $this->db->query($sql); if ($resql && $this->db->num_rows($resql) > 0) { //en caso de existir facturas en cola genero un array con las facturas diff --git a/core/modules/facture/doc/pdf_Autoverifactu.modules.php b/core/modules/facture/doc/pdf_Autoverifactu.modules.php index 7a6fc40..11dfc6a 100644 --- a/core/modules/facture/doc/pdf_Autoverifactu.modules.php +++ b/core/modules/facture/doc/pdf_Autoverifactu.modules.php @@ -34,13 +34,13 @@ * \brief File of class to generate customers invoices from Verifactu model */ -require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; -require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/modules/facture/modules_facture.php'; +require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php'; -require_once dirname(__DIR__, 4). '/lib/validation.lib.php'; +require_once dirname(__DIR__, 4) . '/lib/validation.lib.php'; require_once dirname(__DIR__, 4) . '/lib/autoverifactu.lib.php'; @@ -102,6 +102,7 @@ class pdf_Autoverifactu extends ModelePDFFactures /** * Dolibarr version of the loaded document + * * @var string */ public $version = 'dolibarr'; @@ -125,20 +126,20 @@ class pdf_Autoverifactu extends ModelePDFFactures /** * Constructor * - * @param DoliDB $db Database handler + * @param DoliDB $db Database handler */ public function __construct($db) { global $conf, $langs, $mysoc; // Translations - $langs->loadLangs(array("main", "bills")); + $langs->loadLangs(array('main', 'bills')); $this->db = $db; - $this->name = "Autoverifactu"; - $this->description = "Factura PDF plantilla Autoverifactu. Una plantilla compatible con el QR de Verifactu"; + $this->name = 'Autoverifactu'; + $this->description = 'Factura PDF plantilla Autoverifactu. Una plantilla compatible con el QR de Verifactu'; $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template // Dimension page @@ -215,20 +216,20 @@ public function __construct($db) /** * Function to build pdf onto disk * - * @param Facture $object Object to generate - * @param Translate $outputlangs Lang output object - * @param string $srctemplatepath Full path of source filename for generator using a template file - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref - * @return int 1=OK, 0=KO + * @param Facture $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO */ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) { // phpcs:enable global $user, $langs, $conf, $mysoc, $hookmanager, $nblines; - dol_syslog("write_file outputlangs->defaultlang=".(is_object($outputlangs) ? $outputlangs->defaultlang : 'null')); + dol_syslog('write_file outputlangs->defaultlang=' . (is_object($outputlangs) ? $outputlangs->defaultlang : 'null')); if (!is_object($outputlangs)) { $outputlangs = $langs; @@ -239,7 +240,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede } // Load translation files required by the page - $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); + $outputlangs->loadLangs(array('main', 'bills', 'products', 'dict', 'companies')); // Show Draft Watermark @@ -252,7 +253,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) { $outputlangsbis = new Translate('', $conf); $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')); - $outputlangsbis->loadLangs(array("main", "bills", "products", "dict", "companies")); + $outputlangsbis->loadLangs(array('main', 'bills', 'products', 'dict', 'companies')); } $nblines = count($object->lines); @@ -268,14 +269,14 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $objphoto = new Product($this->db); $objphoto->fetch($object->lines[$i]->fk_product); - $pdir = get_exdir($object->lines[$i]->fk_product, 2, 0, 0, $objphoto, 'product').$object->lines[$i]->fk_product."/photos/"; - $dir = $conf->product->dir_output.'/'.$pdir; + $pdir = get_exdir($object->lines[$i]->fk_product, 2, 0, 0, $objphoto, 'product') . $object->lines[$i]->fk_product . '/photos/'; + $dir = $conf->product->dir_output . '/' . $pdir; $realpath = ''; foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) { $filename = $obj['photo']; //if ($obj['photo_vignette']) $filename='thumbs/'.$obj['photo_vignette']; - $realpath = $dir.$filename; + $realpath = $dir . $filename; break; } @@ -291,22 +292,22 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede if ($conf->facture->dir_output) { $object->fetch_thirdparty(); - $deja_regle = $object->getSommePaiement((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); - $amount_credit_notes_included = $object->getSumCreditNotesUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); - $amount_deposits_included = $object->getSumDepositsUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); + $deja_regle = $object->getSommePaiement((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? 1 : 0); + $amount_credit_notes_included = $object->getSumCreditNotesUsed((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? 1 : 0); + $amount_deposits_included = $object->getSumDepositsUsed((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? 1 : 0); // Definition of $dir and $file if ($object->specimen) { $dir = empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity]; - $file = $dir."/SPECIMEN.pdf"; + $file = $dir . '/SPECIMEN.pdf'; } else { $objectref = dol_sanitizeFileName($object->ref); - $dir = (empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity])."/".$objectref; - $file = $dir."/".$objectref.".pdf"; + $dir = (empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity]) . '/' . $objectref; + $file = $dir . '/' . $objectref . '.pdf'; } if (!file_exists($dir)) { if (dol_mkdir($dir) < 0) { - $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + $this->error = $langs->transnoentities('ErrorCanNotCreateDir', $dir); return 0; } } @@ -314,7 +315,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede if (file_exists($dir)) { // Add pdfgeneration hook if (!is_object($hookmanager)) { - include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; $hookmanager = new HookManager($this->db); } $hookmanager->initHooks(array('pdfgeneration')); @@ -362,7 +363,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede if (!empty($conf->mycompany->multidir_output[$object->entity])) { $logodir = $conf->mycompany->multidir_output[$object->entity]; } - $pagecount = $pdf->setSourceFile($logodir.'/' . getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')); + $pagecount = $pdf->setSourceFile($logodir . '/' . getDolGlobalString('MAIN_ADD_PDF_BACKGROUND')); $tplidx = $pdf->importPage(1); } @@ -371,10 +372,10 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $pdf->SetDrawColor(128, 128, 128); $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); - $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle")); - $pdf->SetCreator("Dolibarr ".DOL_VERSION); - $pdf->SetAuthor($mysoc->name.($user->id > 0 ? ' - '.$outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : '')); - $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + $pdf->SetSubject($outputlangs->transnoentities('PdfInvoiceTitle')); + $pdf->SetCreator('Dolibarr ' . DOL_VERSION); + $pdf->SetAuthor($mysoc->name . ($user->id > 0 ? ' - ' . $outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : '')); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref) . ' ' . $outputlangs->transnoentities('PdfInvoiceTitle') . ' ' . $outputlangs->convToOutputCharset($object->thirdparty->name)); if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) { $pdf->SetCompression(false); } @@ -511,7 +512,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt('FACTURE_RIB_NUMBER')) { $pdf->SetXY($this->marge_gauche + 30, $pdf->GetY() - 15); $pdf->SetFont('', '', $default_font_size - 4); - $pdf->MultiCell(40, 3, $langs->transnoentitiesnoconv("INVOICE_ADD_EPC_QR_CODEPay"), 0, 'L', 0); + $pdf->MultiCell(40, 3, $langs->transnoentitiesnoconv('INVOICE_ADD_EPC_QR_CODEPay'), 0, 'L', 0); } } @@ -573,16 +574,16 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede //verifactu_pdfLegalText - if (isset($object->array_options["options_verifactu_pdfLegalText"])) { - $langs->load("autoverifactu@autoverifactu"); - $LegalText="Texto Legal "; - $LegalText .= '
'.$object->array_options["options_verifactu_pdfLegalTextUser"] ; - $LegalTextArray = explode(',', $object->array_options["options_verifactu_pdfLegalText"]); + if (isset($object->array_options['options_verifactu_pdfLegalText'])) { + $langs->load('autoverifactu@autoverifactu'); + $LegalText = 'Texto Legal '; + $LegalText .= '
' . $object->array_options['options_verifactu_pdfLegalTextUser'] ; + $LegalTextArray = explode(',', $object->array_options['options_verifactu_pdfLegalText']); foreach ($LegalTextArray as $value) { - $LegalText .= '
'.$langs->trans($value); + $LegalText .= '
' . $langs->trans($value); } - $LegalText .= "

"; + $LegalText .= '

'; $notetoshow = dol_concatdesc($notetoshow, $LegalText, false, true); } // Extrafields in noteº @@ -774,13 +775,13 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede // Collection of totals by value of VAT in $this->tva["taux"]=total_tva $prev_progress = $object->lines[$i]->get_prev_progress($object->id); if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) { // Compute progress from previous situation - if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) { + if (isModEnabled('multicurrency') && $object->multicurrency_tx != 1) { $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; } else { $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; } } else { - if (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) { + if (isModEnabled('multicurrency') && $object->multicurrency_tx != 1) { $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva; } else { $tvaligne = $sign * $object->lines[$i]->total_tva; @@ -841,10 +842,10 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede } $this->tva[$vatrate] += $tvaligne; // ->tva is abandoned, we use now ->tva_array that is more complete $vatcode = $object->lines[$i]->vat_src_code; - if (empty($this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'])) { - $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] = 0; + if (empty($this->tva_array[$vatrate . ($vatcode ? ' (' . $vatcode . ')' : '')]['amount'])) { + $this->tva_array[$vatrate . ($vatcode ? ' (' . $vatcode . ')' : '')]['amount'] = 0; } - $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate.($vatcode ? ' ('.$vatcode.')' : '')]['amount'] + $tvaligne); + $this->tva_array[$vatrate . ($vatcode ? ' (' . $vatcode . ')' : '')] = array('vatrate' => $vatrate, 'vatcode' => $vatcode, 'amount' => $this->tva_array[$vatrate . ($vatcode ? ' (' . $vatcode . ')' : '')]['amount'] + $tvaligne); if ($posYAfterImage > $posYAfterDescription) { $nexY = $posYAfterImage; @@ -909,7 +910,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; } - dol_syslog("bottomlasttab=".$bottomlasttab." this->page_hauteur=".$this->page_hauteur." heightforinfotot=".$heightforinfotot." heightforfreetext=".$heightforfreetext." heightforfooter=".$heightforfooter); + dol_syslog('bottomlasttab=' . $bottomlasttab . ' this->page_hauteur=' . $this->page_hauteur . ' heightforinfotot=' . $heightforinfotot . ' heightforfreetext=' . $heightforfreetext . ' heightforfooter=' . $heightforfooter); // Display info area $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs, $outputlangsbis); @@ -955,11 +956,11 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede return 1; // No error } else { - $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + $this->error = $langs->transnoentities('ErrorCanNotCreateDir', $dir); return 0; } } else { - $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); + $this->error = $langs->transnoentities('ErrorConstantNotDefined', 'FAC_OUTPUTDIR'); return 0; } } @@ -1005,11 +1006,11 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei // Loop on each discount available (deposits and credit notes and excess of payment included) - $sql = "SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva, re.amount_ttc, re.multicurrency_amount_ttc,"; - $sql .= " re.description, re.fk_facture_source,"; - $sql .= " f.type, f.datef"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f"; - $sql .= " WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ".((int) $object->id); + $sql = 'SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva, re.amount_ttc, re.multicurrency_amount_ttc,'; + $sql .= ' re.description, re.fk_facture_source,'; + $sql .= ' f.type, f.datef'; + $sql .= ' FROM ' . MAIN_DB_PREFIX . 'societe_remise_except as re, ' . MAIN_DB_PREFIX . 'facture as f'; + $sql .= ' WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ' . ((int) $object->id); $resql = $this->db->query($sql); if ($resql) { $num = $this->db->num_rows($resql); @@ -1035,13 +1036,13 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei $obj = $this->db->fetch_object($resql); if ($obj->type == 2) { - $text = $outputlangs->transnoentities("CreditNote"); + $text = $outputlangs->transnoentities('CreditNote'); } elseif ($obj->type == 3) { - $text = $outputlangs->transnoentities("Deposit"); + $text = $outputlangs->transnoentities('Deposit'); } elseif ($obj->type == 0) { - $text = $outputlangs->transnoentities("ExcessReceived"); + $text = $outputlangs->transnoentities('ExcessReceived'); } else { - $text = $outputlangs->transnoentities("UnknownType"); + $text = $outputlangs->transnoentities('UnknownType'); } $invoice->fetch($obj->fk_facture_source); @@ -1049,7 +1050,7 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei $pdf->SetXY($tab3_posx, $tab3_top + $y); $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($obj->datef), 'day', false, $outputlangs, true), 0, 'L', 0); $pdf->SetXY($tab3_posx + 21, $tab3_top + $y); - $pdf->MultiCell(20, 3, price((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0); + $pdf->MultiCell(20, 3, price((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0); $pdf->SetXY($tab3_posx + 40, $tab3_top + $y); $pdf->MultiCell(20, 3, $text, 0, 'L', 0); $pdf->SetXY($tab3_posx + 58, $tab3_top + $y); @@ -1066,13 +1067,13 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei // Loop on each payment // TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql - $sql = "SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,"; - $sql .= " cp.code"; - $sql .= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id"; - $sql .= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ".((int) $object->id); + $sql = 'SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,'; + $sql .= ' cp.code'; + $sql .= ' FROM ' . MAIN_DB_PREFIX . 'paiement_facture as pf, ' . MAIN_DB_PREFIX . 'paiement as p'; + $sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as cp ON p.fk_paiement = cp.id'; + $sql .= ' WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ' . ((int) $object->id); //$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1"; - $sql .= " ORDER BY p.datep"; + $sql .= ' ORDER BY p.datep'; $resql = $this->db->query($sql); if ($resql) { @@ -1101,9 +1102,9 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei $pdf->SetXY($tab3_posx, $tab3_top + $y); $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date), 'day', false, $outputlangs, true), 0, 'L', 0); $pdf->SetXY($tab3_posx + 21, $tab3_top + $y); - $pdf->MultiCell(20, 3, price($sign * ((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0); + $pdf->MultiCell(20, 3, price($sign * ((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0); $pdf->SetXY($tab3_posx + 40, $tab3_top + $y); - $oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort".$row->code); + $oper = $outputlangs->transnoentitiesnoconv('PaymentTypeShort' . $row->code); $pdf->MultiCell(20, 3, $oper, 0, 'L', 0); $maxY = max($pdf->GetY() - $tab3_top - 3, $maxY); @@ -1127,22 +1128,22 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei /** * Function _tableau_versements_header * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object invoice - * @param Translate $outputlangs Object langs for output - * @param int $default_font_size Font size - * @param int $tab3_posx pos x - * @param int $tab3_top pos y - * @param int $tab3_width width - * @param int $tab3_height height + * @param TCPDF $pdf Object PDF + * @param Facture $object Object invoice + * @param Translate $outputlangs Object langs for output + * @param int $default_font_size Font size + * @param int $tab3_posx pos x + * @param int $tab3_top pos y + * @param int $tab3_width width + * @param int $tab3_height height * @return void */ protected function _tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height) { // phpcs:enable - $title = $outputlangs->transnoentities("PaymentsAlreadyDone"); + $title = $outputlangs->transnoentities('PaymentsAlreadyDone'); if ($object->type == 2) { - $title = $outputlangs->transnoentities("PaymentsBackAlreadyDone"); + $title = $outputlangs->transnoentities('PaymentsBackAlreadyDone'); } $pdf->SetFont('', '', $default_font_size - 3); @@ -1153,13 +1154,13 @@ protected function _tableau_versements_header($pdf, $object, $outputlangs, $defa $pdf->SetFont('', '', $default_font_size - 4); $pdf->SetXY($tab3_posx, $tab3_top); - $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities('Payment'), 0, 'L', 0); $pdf->SetXY($tab3_posx + 21, $tab3_top); - $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities('Amount'), 0, 'L', 0); $pdf->SetXY($tab3_posx + 40, $tab3_top); - $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities('Type'), 0, 'L', 0); $pdf->SetXY($tab3_posx + 58, $tab3_top); - $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities('Num'), 0, 'L', 0); $pdf->line($tab3_posx, $tab3_top - 1 + $tab3_height, $tab3_posx + $tab3_width, $tab3_top - 1 + $tab3_height); } @@ -1169,12 +1170,12 @@ protected function _tableau_versements_header($pdf, $object, $outputlangs, $defa /** * Show miscellaneous information (payment mode, payment term, ...) * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object to show - * @param int $posy Y - * @param Translate $outputlangs Langs object - * @param Translate $outputlangsbis Object lang for output bis - * @return int Pos y + * @param TCPDF $pdf Object PDF + * @param Facture $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @param Translate $outputlangsbis Object lang for output bis + * @return int Pos y */ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis) { @@ -1190,9 +1191,9 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan $pdf->SetFont('', 'B', $default_font_size - 2); $pdf->SetXY($this->marge_gauche, $posy); if ($mysoc->forme_juridique_code == 92) { - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoiceAsso"), 0, 'L', 0); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('VATIsNotUsedForInvoiceAsso'), 0, 'L', 0); } else { - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('VATIsNotUsedForInvoice'), 0, 'L', 0); } $posy = $pdf->GetY() + 4; @@ -1208,12 +1209,12 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement)) { $pdf->SetFont('', 'B', $default_font_size - 2); $pdf->SetXY($this->marge_gauche, $posy); - $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $titre = $outputlangs->transnoentities('PaymentConditions') . ':'; $pdf->MultiCell(43, 4, $titre, 0, 'L'); $pdf->SetFont('', '', $default_font_size - 2); $pdf->SetXY($posxval, $posy); - $lib_condition_paiement = ($outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) != 'PaymentCondition'.$object->cond_reglement_code) ? $outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code) : $outputlangs->convToOutputCharset($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement_label); + $lib_condition_paiement = ($outputlangs->transnoentities('PaymentCondition' . $object->cond_reglement_code) != 'PaymentCondition' . $object->cond_reglement_code) ? $outputlangs->transnoentities('PaymentCondition' . $object->cond_reglement_code) : $outputlangs->convToOutputCharset($object->cond_reglement_doc ? $object->cond_reglement_doc : $object->cond_reglement_label); $lib_condition_paiement = str_replace('\n', "\n", $lib_condition_paiement); $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, 'L'); @@ -1224,12 +1225,12 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan if (getDolGlobalInt('INVOICE_CATEGORY_OF_OPERATION') == 2 && $this->categoryOfOperation >= 0) { $pdf->SetFont('', 'B', $default_font_size - 2); $pdf->SetXY($this->marge_gauche, $posy); - $categoryOfOperationTitle = $outputlangs->transnoentities("MentionCategoryOfOperations").' : '; + $categoryOfOperationTitle = $outputlangs->transnoentities('MentionCategoryOfOperations') . ' : '; $pdf->MultiCell($posxval - $this->marge_gauche, 4, $categoryOfOperationTitle, 0, 'L'); $pdf->SetFont('', '', $default_font_size - 2); $pdf->SetXY($posxval, $posy); - $categoryOfOperationLabel = $outputlangs->transnoentities("MentionCategoryOfOperations" . $this->categoryOfOperation); + $categoryOfOperationLabel = $outputlangs->transnoentities('MentionCategoryOfOperations' . $this->categoryOfOperation); $pdf->MultiCell($posxend - $posxval, 4, $categoryOfOperationLabel, 0, 'L'); $posy = $pdf->GetY() + 3; // for 2 lines @@ -1240,16 +1241,16 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan if (empty($object->mode_reglement_code) && !getDolGlobalInt('FACTURE_CHQ_NUMBER') && !getDolGlobalInt('FACTURE_RIB_NUMBER')) { - $this->error = $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"); + $this->error = $outputlangs->transnoentities('ErrorNoPaiementModeConfigured'); } elseif (($object->mode_reglement_code == 'CHQ' && !getDolGlobalInt('FACTURE_CHQ_NUMBER') && empty($object->fk_account) && empty($object->fk_bank)) || ($object->mode_reglement_code == 'VIR' && !getDolGlobalInt('FACTURE_RIB_NUMBER') && empty($object->fk_account) && empty($object->fk_bank))) { // Avoid having any valid PDF with setup that is not complete - $outputlangs->load("errors"); + $outputlangs->load('errors'); $pdf->SetXY($this->marge_gauche, $posy); $pdf->SetTextColor(200, 0, 0); $pdf->SetFont('', 'B', $default_font_size - 2); - $this->error = $outputlangs->transnoentities("ErrorPaymentModeDefinedToWithoutSetup", $object->mode_reglement_code); + $this->error = $outputlangs->transnoentities('ErrorPaymentModeDefinedToWithoutSetup', $object->mode_reglement_code); $pdf->MultiCell(80, 3, $this->error, 0, 'L', 0); $pdf->SetTextColor(0, 0, 0); @@ -1262,20 +1263,20 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan && $object->mode_reglement_code != 'VIR') { $pdf->SetFont('', 'B', $default_font_size - 2); $pdf->SetXY($this->marge_gauche, $posy); - $titre = $outputlangs->transnoentities("PaymentMode").':'; + $titre = $outputlangs->transnoentities('PaymentMode') . ':'; $pdf->MultiCell(80, 5, $titre, 0, 'L'); $pdf->SetFont('', '', $default_font_size - 2); $pdf->SetXY($posxval, $posy); - $lib_mode_reg = $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) != 'PaymentType'.$object->mode_reglement_code ? $outputlangs->transnoentities("PaymentType".$object->mode_reglement_code) : $outputlangs->convToOutputCharset($object->mode_reglement); + $lib_mode_reg = $outputlangs->transnoentities('PaymentType' . $object->mode_reglement_code) != 'PaymentType' . $object->mode_reglement_code ? $outputlangs->transnoentities('PaymentType' . $object->mode_reglement_code) : $outputlangs->convToOutputCharset($object->mode_reglement); //#21654: add account number used for the debit - if ($object->mode_reglement_code == "PRE") { - require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php'; + if ($object->mode_reglement_code == 'PRE') { + require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php'; $bac = new CompanyBankAccount($this->db); // @phan-suppress-next-line PhanPluginSuspiciousParamPosition $bac->fetch(0, '', $object->thirdparty->id); - $iban = $bac->iban.(($bac->iban && $bac->bic) ? ' / ' : '').$bac->bic; - $lib_mode_reg .= ' '.$outputlangs->trans("PaymentTypePREdetails", dol_trunc($iban, 6, 'right', 'UTF-8', 1)); + $iban = $bac->iban . (($bac->iban && $bac->bic) ? ' / ' : '') . $bac->bic; + $lib_mode_reg .= ' ' . $outputlangs->trans('PaymentTypePREdetails', dol_trunc($iban, 6, 'right', 'UTF-8', 1)); } $pdf->MultiCell(80, 5, $lib_mode_reg, 0, 'L'); @@ -1288,7 +1289,7 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan if ($this->emetteur->country_code == 'FR') { if (getDolGlobalInt('TAX_MODE') == 1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); + $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities('MentionVATDebitOptionIsOn'), 0, 1); $posy = $pdf->GetY() + 1; } @@ -1300,19 +1301,19 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan if (getDolGlobalString('PDF_SHOW_LINK_TO_ONLINE_PAYMENT')) { // Show online payment link // The list can be complete by the hook 'doValidatePayment' executed inside getValidOnlinePaymentMethods() - include_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; + include_once DOL_DOCUMENT_ROOT . '/core/lib/payments.lib.php'; $validpaymentmethod = getValidOnlinePaymentMethods(''); $useonlinepayment = count($validpaymentmethod); } if ($object->statut != Facture::STATUS_DRAFT && $useonlinepayment) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/payments.lib.php'; global $langs; $langs->loadLangs(array('payment', 'paybox', 'stripe')); $servicename = $langs->transnoentities('Online'); $paiement_url = getOnlinePaymentUrl('', 'invoice', $object->ref, '', '', ''); - $linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' '.$outputlangs->transnoentities("ClickHere").''; + $linktopay = $langs->trans('ToOfferALinkForOnlinePayment', $servicename) . ' ' . $outputlangs->transnoentities('ClickHere') . ''; $pdf->SetXY($this->marge_gauche, $posy); $pdf->writeHTMLCell(80, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); @@ -1412,7 +1413,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && $outputlangs->defaultlang != getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) { $outputlangsbis = new Translate('', $conf); $outputlangsbis->setDefaultLang(getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')); - $outputlangsbis->loadLangs(array("main", "dict", "companies", "bills", "products", "propal")); + $outputlangsbis->loadLangs(array('main', 'dict', 'companies', 'bills', 'products', 'propal')); $default_font_size--; } @@ -1435,16 +1436,16 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs // Total HT $pdf->SetFillColor(255, 255, 255); $pdf->SetXY($col1x, $tab2_top); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') ? "TotalHT" : "Total").(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transnoentities(!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') ? "TotalHT" : "Total") : ''), 0, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') ? 'TotalHT' : 'Total') . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transnoentities(!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT') ? 'TotalHT' : 'Total') : ''), 0, 'L', 1); - $total_ht = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht); + $total_ht = ((isModEnabled('multicurrency') && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht); $pdf->SetXY($col2x, $tab2_top); $pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, $outputlangs), 0, 'R', 1); // Show VAT by rates and total $pdf->SetFillColor(248, 248, 248); - $total_ttc = (isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; + $total_ttc = (isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; $this->atleastoneratenotnull = 0; if (!getDolGlobalString('MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT')) { @@ -1468,21 +1469,21 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $tvacompl = ''; if (preg_match('/\*/', (string) $tvakey)) { $tvakey = str_replace('*', '', (string) $tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + $tvacompl = ' (' . $outputlangs->transnoentities('NonPercuRecuperable') . ')'; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT1", $mysoc->country_code) : ''); + $totalvat = $outputlangs->transcountrynoentities('TotalLT1', $mysoc->country_code) . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transcountrynoentities('TotalLT1', $mysoc->country_code) : ''); $totalvat .= ' '; if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; + $totalvat .= vatrate(abs($tvakey), 1) . $tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); - $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); + $total_localtax = ((isModEnabled('multicurrency') && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1); @@ -1506,20 +1507,20 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $tvacompl = ''; if (preg_match('/\*/', (string) $tvakey)) { $tvakey = str_replace('*', '', (string) $tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + $tvacompl = ' (' . $outputlangs->transnoentities('NonPercuRecuperable') . ')'; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalLT2", $mysoc->country_code) : ''); + $totalvat = $outputlangs->transcountrynoentities('TotalLT2', $mysoc->country_code) . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transcountrynoentities('TotalLT2', $mysoc->country_code) : ''); $totalvat .= ' '; if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; + $totalvat .= vatrate(abs($tvakey), 1) . $tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); - $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); + $total_localtax = ((isModEnabled('multicurrency') && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1); @@ -1538,18 +1539,18 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $tvacompl = ''; if (preg_match('/\*/', $tvakey)) { $tvakey = str_replace('*', '', $tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + $tvacompl = ' (' . $outputlangs->transnoentities('NonPercuRecuperable') . ')'; } - $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : ''); + $totalvat = $outputlangs->transcountrynoentities('TotalVAT', $mysoc->country_code) . (is_object($outputlangsbis) ? ' / ' . $outputlangsbis->transcountrynoentities('TotalVAT', $mysoc->country_code) : ''); $totalvat .= ' '; if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') { - $totalvat .= vatrate($tvaval['vatrate'], 1).$tvacompl; + $totalvat .= vatrate($tvaval['vatrate'], 1) . $tvacompl; } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') { - $totalvat .= $tvaval['vatcode'].$tvacompl; + $totalvat .= $tvaval['vatcode'] . $tvacompl; } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate($tvaval['vatrate'], 1).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl; + $totalvat .= vatrate($tvaval['vatrate'], 1) . ($tvaval['vatcode'] ? ' (' . $tvaval['vatcode'] . ')' : '') . $tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); @@ -1574,19 +1575,19 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $tvacompl = ''; if (preg_match('/\*/', (string) $tvakey)) { $tvakey = str_replace('*', '', (string) $tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + $tvacompl = ' (' . $outputlangs->transnoentities('NonPercuRecuperable') . ')'; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT1", $mysoc->country_code).' '; + $totalvat = $outputlangs->transcountrynoentities('TotalLT1', $mysoc->country_code) . ' '; if (getDolGlobalString('PDF_LOCALTAX1_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; + $totalvat .= vatrate(abs($tvakey), 1) . $tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); - $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); + $total_localtax = ((isModEnabled('multicurrency') && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1); @@ -1609,19 +1610,19 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $tvacompl = ''; if (preg_match('/\*/', (string) $tvakey)) { $tvakey = str_replace('*', '', (string) $tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + $tvacompl = ' (' . $outputlangs->transnoentities('NonPercuRecuperable') . ')'; } - $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' '; + $totalvat = $outputlangs->transcountrynoentities('TotalLT2', $mysoc->country_code) . ' '; if (getDolGlobalString('PDF_LOCALTAX2_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate(abs($tvakey), 1).$tvacompl; + $totalvat .= vatrate(abs($tvakey), 1) . $tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); - $total_localtax = ((isModEnabled("multicurrency") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); + $total_localtax = ((isModEnabled('multicurrency') && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, 'MT') : $tvaval); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, 'R', 1); @@ -1632,7 +1633,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs if (price2num($object->revenuestamp, 'MT') != 0) { $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RevenueStamp"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('RevenueStamp'), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, 'R', 1); @@ -1643,7 +1644,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); $pdf->SetTextColor(0, 0, 60); $pdf->SetFillColor(224, 224, 224); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('TotalTTC'), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, 'R', 1); @@ -1659,7 +1660,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs // Billed - retained warranty $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("ToPayOn", dol_print_date($object->date_lim_reglement, 'day')), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('ToPayOn', dol_print_date($object->date_lim_reglement, 'day')), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($billedWithRetainedWarranty), $useborder, 'R', 1); @@ -1668,8 +1669,8 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $retainedWarrantyToPayOn = $outputlangs->transnoentities("RetainedWarranty").' ('.$object->retained_warranty.'%)'; - $retainedWarrantyToPayOn .= !empty($object->retained_warranty_date_limit) ? ' '.$outputlangs->transnoentities("toPayOn", dol_print_date($object->retained_warranty_date_limit, 'day')) : ''; + $retainedWarrantyToPayOn = $outputlangs->transnoentities('RetainedWarranty') . ' (' . $object->retained_warranty . '%)'; + $retainedWarrantyToPayOn .= !empty($object->retained_warranty_date_limit) ? ' ' . $outputlangs->transnoentities('toPayOn', dol_print_date($object->retained_warranty_date_limit, 'day')) : ''; $pdf->MultiCell($col2x - $col1x, $tab2_hl, $retainedWarrantyToPayOn, $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); @@ -1679,8 +1680,8 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs } $pdf->SetTextColor(0, 0, 0); - $creditnoteamount = $object->getSumCreditNotesUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); // Warning, this also include excess received - $depositsamount = $object->getSumDepositsUsed((isModEnabled("multicurrency") && $object->multicurrency_tx != 1) ? 1 : 0); + $creditnoteamount = $object->getSumCreditNotesUsed((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? 1 : 0); // Warning, this also include excess received + $depositsamount = $object->getSumDepositsUsed((isModEnabled('multicurrency') && $object->multicurrency_tx != 1) ? 1 : 0); //print "x".$creditnoteamount."-".$depositsamount;exit; $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT'); if (!empty($object->paye)) { @@ -1691,13 +1692,13 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs // Already paid + Deposits $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("Paid"), 0, 'L', 0); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('Paid'), 0, 'L', 0); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, 'R', 0); // Credit note if ($creditnoteamount) { - $labeltouse = ($outputlangs->transnoentities("CreditNotesOrExcessReceived") != "CreditNotesOrExcessReceived") ? $outputlangs->transnoentities("CreditNotesOrExcessReceived") : $outputlangs->transnoentities("CreditNotes"); + $labeltouse = ($outputlangs->transnoentities('CreditNotesOrExcessReceived') != 'CreditNotesOrExcessReceived') ? $outputlangs->transnoentities('CreditNotesOrExcessReceived') : $outputlangs->transnoentities('CreditNotes'); $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($col2x - $col1x, $tab2_hl, $labeltouse, 0, 'L', 0); @@ -1711,7 +1712,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $pdf->SetFillColor(255, 255, 255); $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('EscompteOfferedShort'), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, 'R', 1); @@ -1722,7 +1723,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $pdf->SetTextColor(0, 0, 60); $pdf->SetFillColor(224, 224, 224); $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities('RemainderToPay'), $useborder, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); @@ -1732,7 +1733,7 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs $index++; - if (getDolGlobalString("BILL_TEXT_TOTAL_FOOTER")) { + if (getDolGlobalString('BILL_TEXT_TOTAL_FOOTER')) { $index++; $index++; $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); @@ -1746,15 +1747,15 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs /** * Show table for lines * - * @param TCPDF $pdf Object PDF - * @param float|int $tab_top Top position of table - * @param float|int $tab_height Height of table (rectangle) - * @param int $nexY Y (not used) - * @param Translate $outputlangs Langs object - * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title - * @param int $hidebottom Hide bottom bar of array - * @param string $currency Currency code - * @return void + * @param TCPDF $pdf Object PDF + * @param float|int $tab_top Top position of table + * @param float|int $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @return void */ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '') { @@ -1776,12 +1777,12 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ if (empty($hidetop)) { // Show category of operations if (getDolGlobalInt('INVOICE_CATEGORY_OF_OPERATION') == 1 && $this->categoryOfOperation >= 0) { - $categoryOfOperations = $outputlangs->transnoentities("MentionCategoryOfOperations") . ' : ' . $outputlangs->transnoentities("MentionCategoryOfOperations" . $this->categoryOfOperation); + $categoryOfOperations = $outputlangs->transnoentities('MentionCategoryOfOperations') . ' : ' . $outputlangs->transnoentities('MentionCategoryOfOperations' . $this->categoryOfOperation); $pdf->SetXY($this->marge_gauche, $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($categoryOfOperations)) + 4, 2, $categoryOfOperations); } - $titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency)); + $titre = $outputlangs->transnoentities('AmountInCurrency', $outputlangs->transnoentitiesnoconv('Currency' . $currency)); $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4); $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); @@ -1801,7 +1802,7 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ $pdf->line($this->marge_gauche, $tab_top + 5, $this->page_largeur - $this->marge_droite, $tab_top + 5); // line takes a position y in 2nd parameter and 4th parameter $pdf->SetXY($this->posxdesc - 1, $tab_top + 1); - $pdf->MultiCell(108, 2, $outputlangs->transnoentities("Designation"), '', 'L'); + $pdf->MultiCell(108, 2, $outputlangs->transnoentities('Designation'), '', 'L'); } if (getDolGlobalString('MAIN_GENERATE_INVOICES_WITH_PICTURE')) { @@ -1816,27 +1817,27 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxtva - 3, $tab_top + 1); - $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities("VAT"), '', 'C'); + $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities('VAT'), '', 'C'); } } $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxup - 1, $tab_top + 1); - $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities("PriceUHT"), '', 'C'); + $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities('PriceUHT'), '', 'C'); } $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxqty - 1, $tab_top + 1); - $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities("Qty"), '', 'C'); + $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities('Qty'), '', 'C'); } if (getDolGlobalInt('PRODUCT_USE_UNITS')) { $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxunit - 1, $tab_top + 1); - $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("Unit"), '', 'C'); + $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities('Unit'), '', 'C'); } } @@ -1844,7 +1845,7 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1); - $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C'); + $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 1, 2, $outputlangs->transnoentities('ReductionShort'), '', 'C'); } } @@ -1852,14 +1853,14 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ $pdf->line($this->posxprogress - 1, $tab_top, $this->posxprogress - 1, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->posxprogress, $tab_top + 1); - $pdf->MultiCell($this->postotalht - $this->posxprogress, 2, $outputlangs->transnoentities("ProgressShort"), '', 'C'); + $pdf->MultiCell($this->postotalht - $this->posxprogress, 2, $outputlangs->transnoentities('ProgressShort'), '', 'C'); } } $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height); if (empty($hidetop)) { $pdf->SetXY($this->postotalht - 1, $tab_top + 1); - $pdf->MultiCell(30, 2, $outputlangs->transnoentities("TotalHTShort"), '', 'C'); + $pdf->MultiCell(30, 2, $outputlangs->transnoentities('TotalHTShort'), '', 'C'); } } @@ -1880,12 +1881,12 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output global $conf, $langs; $ltrdirection = 'L'; - if ($outputlangs->trans("DIRECTION") == 'rtl') { + if ($outputlangs->trans('DIRECTION') == 'rtl') { $ltrdirection = 'R'; } // Load traductions files required by page - $outputlangs->loadLangs(array("main", "bills", "propal", "companies")); + $outputlangs->loadLangs(array('main', 'bills', 'propal', 'companies')); $default_font_size = pdf_getPDFFontSize($outputlangs); @@ -1944,7 +1945,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $qr_x = ($this->page_largeur - $qr_width) / 2; $qr_y = 8; - $pdf->SetXY($qr_x+1, 3); + $pdf->SetXY($qr_x + 1, 3); $pdf->SetFont('', '', $default_font_size); $pdf->MultiCell(30, 10, 'QR tributario:', 0, 'C', 0, 1); @@ -1967,7 +1968,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output 25, ); - $pdf->SetXY($qr_x+1, $qr_y + $qr_width); + $pdf->SetXY($qr_x + 1, $qr_y + $qr_width); $pdf->MultiCell(30, 10, 'VERI*FACTU', 0, 'C', 0, 1); } @@ -1989,17 +1990,17 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $logodir = $conf->mycompany->multidir_output[$object->entity]; } if (!getDolGlobalInt('MAIN_PDF_USE_LARGE_LOGO')) { - $logo = $logodir.'/logos/thumbs/'.$this->emetteur->logo_small; + $logo = $logodir . '/logos/thumbs/' . $this->emetteur->logo_small; } else { - $logo = $logodir.'/logos/'.$this->emetteur->logo; + $logo = $logodir . '/logos/' . $this->emetteur->logo; } if (is_readable($logo)) { $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) } else { $pdf->SetTextColor(200, 0, 0); $pdf->SetFont('', 'B', $default_font_size - 2); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound", $logo), 0, 'L'); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('ErrorLogoFileNotFound', $logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('ErrorGoToGlobalSetup'), 0, 'L'); } } else { $text = $this->emetteur->name; @@ -2010,22 +2011,22 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $pdf->SetFont('', 'B', $default_font_size + 3); $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $title = $outputlangs->transnoentities("PdfInvoiceTitle"); + $title = $outputlangs->transnoentities('PdfInvoiceTitle'); if ($object->type == 1) { - $title = $outputlangs->transnoentities("InvoiceReplacement"); + $title = $outputlangs->transnoentities('InvoiceReplacement'); } if ($object->type == 2) { - $title = $outputlangs->transnoentities("InvoiceAvoir"); + $title = $outputlangs->transnoentities('InvoiceAvoir'); } if ($object->type == 3) { - $title = $outputlangs->transnoentities("InvoiceDeposit"); + $title = $outputlangs->transnoentities('InvoiceDeposit'); } if ($object->type == 4) { - $title = $outputlangs->transnoentities("InvoiceProForma"); + $title = $outputlangs->transnoentities('InvoiceProForma'); } if ($this->situationinvoice) { - $langs->loadLangs(array("other")); - $title = $outputlangs->transnoentities("PDFInvoiceSituation") . " " . $outputlangs->transnoentities("NumberingShort") . $object->situation_counter . " -"; + $langs->loadLangs(array('other')); + $title = $outputlangs->transnoentities('PDFInvoiceSituation') . ' ' . $outputlangs->transnoentities('NumberingShort') . $object->situation_counter . ' -'; } @@ -2033,17 +2034,17 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $title .= ' - '; if ($object->type == 0) { if ($this->situationinvoice) { - $title .= $outputlangsbis->transnoentities("PDFInvoiceSituation"); + $title .= $outputlangsbis->transnoentities('PDFInvoiceSituation'); } - $title .= $outputlangsbis->transnoentities("PdfInvoiceTitle"); + $title .= $outputlangsbis->transnoentities('PdfInvoiceTitle'); } elseif ($object->type == 1) { - $title .= $outputlangsbis->transnoentities("InvoiceReplacement"); + $title .= $outputlangsbis->transnoentities('InvoiceReplacement'); } elseif ($object->type == 2) { - $title .= $outputlangsbis->transnoentities("InvoiceAvoir"); + $title .= $outputlangsbis->transnoentities('InvoiceAvoir'); } elseif ($object->type == 3) { - $title .= $outputlangsbis->transnoentities("InvoiceDeposit"); + $title .= $outputlangsbis->transnoentities('InvoiceDeposit'); } elseif ($object->type == 4) { - $title .= $outputlangsbis->transnoentities("InvoiceProForma"); + $title .= $outputlangsbis->transnoentities('InvoiceProForma'); } } @@ -2055,10 +2056,10 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output - $title .= ' '.$outputlangs->convToOutputCharset($object->ref); + $title .= ' ' . $outputlangs->convToOutputCharset($object->ref); if ($object->statut == $object::STATUS_DRAFT) { $pdf->SetTextColor(128, 0, 0); - $title .= ' - '.$outputlangs->transnoentities("NotValidated"); + $title .= ' - ' . $outputlangs->transnoentities('NotValidated'); } $pdf->MultiCell($w, 3, $title, '', 'R'); @@ -2083,7 +2084,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : ".$outputlangs->convToOutputCharset($object->ref_customer), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('RefCustomer') . ' : ' . $outputlangs->convToOutputCharset($object->ref_customer), '', 'R'); } if (getDolGlobalString('PDF_SHOW_PROJECT_TITLE')) { @@ -2092,18 +2093,18 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("Project")." : ".(empty($object->project->title) ? '' : $object->project->title), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('Project') . ' : ' . (empty($object->project->title) ? '' : $object->project->title), '', 'R'); } } if (getDolGlobalString('PDF_SHOW_PROJECT')) { $object->fetch_projet(); if (!empty($object->project->ref)) { - $outputlangs->load("projects"); + $outputlangs->load('projects'); $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefProject")." : ".(empty($object->project->ref) ? '' : $object->project->ref), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('RefProject') . ' : ' . (empty($object->project->ref) ? '' : $object->project->ref), '', 'R'); } } @@ -2115,7 +2116,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementByInvoice").' : '.$outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('ReplacementByInvoice') . ' : ' . $outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R'); } if ($object->type == 1) { $objectreplaced = new Facture($this->db); @@ -2124,7 +2125,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('ReplacementInvoice') . ' : ' . $outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); } if ($object->type == 2 && !empty($object->fk_facture_source)) { $objectreplaced = new Facture($this->db); @@ -2133,41 +2134,41 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CorrectionInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('CorrectionInvoice') . ' : ' . $outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); } $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $title = $outputlangs->transnoentities("DateInvoice"); + $title = $outputlangs->transnoentities('DateInvoice'); if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) { - $title .= ' - '.$outputlangsbis->transnoentities("DateInvoice"); + $title .= ' - ' . $outputlangsbis->transnoentities('DateInvoice'); } - $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date, "day", false, $outputlangs, true), '', 'R'); + $pdf->MultiCell($w, 3, $title . ' : ' . dol_print_date($object->date, 'day', false, $outputlangs, true), '', 'R'); if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) { $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("DatePointOfTax")." : ".dol_print_date($object->date_pointoftax, "day", false, $outputlangs), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('DatePointOfTax') . ' : ' . dol_print_date($object->date_pointoftax, 'day', false, $outputlangs), '', 'R'); } if ($object->type != 2) { $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $title = $outputlangs->transnoentities("DateDue"); + $title = $outputlangs->transnoentities('DateDue'); if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE') && is_object($outputlangsbis)) { - $title .= ' - '.$outputlangsbis->transnoentities("DateDue"); + $title .= ' - ' . $outputlangsbis->transnoentities('DateDue'); } - $pdf->MultiCell($w, 3, $title." : ".dol_print_date($object->date_lim_reglement, "day", false, $outputlangs, true), '', 'R'); + $pdf->MultiCell($w, 3, $title . ' : ' . dol_print_date($object->date_lim_reglement, 'day', false, $outputlangs, true), '', 'R'); } if (!getDolGlobalString('MAIN_PDF_HIDE_CUSTOMER_CODE') && $object->thirdparty->code_client) { $posy += 3; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : ".$outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('CustomerCode') . ' : ' . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); } // Get contact @@ -2179,7 +2180,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $posy += 4; $pdf->SetXY($posx, $posy); $pdf->SetTextColor(0, 0, 60); - $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities('SalesRepresentative') . ' : ' . $usertmp->getFullName($langs), '', 'R'); } } @@ -2200,8 +2201,8 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $arrayidcontact = $object->getIdContact('internal', 'BILLING'); if (count($arrayidcontact) > 0) { $object->fetch_user($arrayidcontact[0]); - $labelbeforecontactname = ($outputlangs->transnoentities("FromContactName") != 'FromContactName' ? $outputlangs->transnoentities("FromContactName") : $outputlangs->transnoentities("Name")); - $carac_emetteur .= ($carac_emetteur ? "\n" : '').$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs)); + $labelbeforecontactname = ($outputlangs->transnoentities('FromContactName') != 'FromContactName' ? $outputlangs->transnoentities('FromContactName') : $outputlangs->transnoentities('Name')); + $carac_emetteur .= ($carac_emetteur ? "\n" : '') . $labelbeforecontactname . ' ' . $outputlangs->convToOutputCharset($object->user->getFullName($outputlangs)); $carac_emetteur .= "\n"; } @@ -2224,10 +2225,10 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $pdf->SetTextColor(0, 0, 0); $pdf->SetFont('', '', $default_font_size - 2); $pdf->SetXY($posx, $posy - 5); - $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillFrom"), 0, $ltrdirection); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities('BillFrom'), 0, $ltrdirection); $pdf->SetXY($posx, $posy); $pdf->SetFillColor(230, 230, 230); - $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1); + $pdf->MultiCell($widthrecbox, $hautcadre, '', 0, 'R', 1); $pdf->SetTextColor(0, 0, 60); } @@ -2282,7 +2283,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output $pdf->SetTextColor(0, 0, 0); $pdf->SetFont('', '', $default_font_size - 2); $pdf->SetXY($posx + 2, $posy - 5); - $pdf->MultiCell($widthrecbox - 2, 5, $outputlangs->transnoentities("BillTo"), 0, $ltrdirection); + $pdf->MultiCell($widthrecbox - 2, 5, $outputlangs->transnoentities('BillTo'), 0, $ltrdirection); $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); } @@ -2350,6 +2351,7 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** * Show footer of page. Need this->emetteur object + * * @param TCPDF $pdf PDF * @param Facture $object Object to show * @param Translate $outputlangs Object lang for output @@ -2363,10 +2365,10 @@ protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0, $h $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0); - $text="En cumplimiento de la normativa de Protección de Datos le informamos que el RESPONSABLE del tratamiento de los mismos es OYR SOLUTIONS S.L. + $text = 'En cumplimiento de la normativa de Protección de Datos le informamos que el RESPONSABLE del tratamiento de los mismos es OYR SOLUTIONS S.L. gestionados con la FINALIDAD de expedir un presupuesto o la correspondiente factura por la compra de un presto o la prestación de alguno de nuestros servicios. La LEGITIMACIÓN se basa en la existencia de una relación comercial de compra de productos o contractual para la prestación de un servicio. Serán DESTINATARIOS de sus datos aquellas organizaciones o entidades directamente relacionadas con el Responsable, así como las Administraciones Públicas con competencia en la materia. El plazo de CONSERVACIÓN de sus datos será hasta el fin de la prestación del servicio, y una vez finalizado, hasta que se solicite su supresión por parte del interesado. Entre sus DERECHOS se encuentra el de acceder, rectificar y suprimir, así como el de oposición, limitación y portabilidad. -Si tiene alguna pregunta relacionada con el cumplimiento del RGPD o la protección de datos, póngase en contacto con nuestro Responsable de Protección de Datos en el correo security@oyr.es"; +Si tiene alguna pregunta relacionada con el cumplimiento del RGPD o la protección de datos, póngase en contacto con nuestro Responsable de Protección de Datos en el correo security@oyr.es'; return pdf_pagefoot($pdf, $outputlangs, 'INVOICE_FREE_TEXT', $this->emetteur, $heightforqrinvoice + $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext, $this->page_largeur, $this->watermark); } diff --git a/core/modules/modAutoverifactu.class.php b/core/modules/modAutoverifactu.class.php index 7f593c8..df5732f 100644 --- a/core/modules/modAutoverifactu.class.php +++ b/core/modules/modAutoverifactu.class.php @@ -255,15 +255,15 @@ public function __construct($db) * 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'). + * @param string $options Options when enabling module ('', 'noboxes'). * - * @return int<-1,1> 1 if OK, <=0 if KO. + * @return int<-1,1> 1 if OK, <=0 if KO. */ public function init($options = '') { global $db, $langs; // , $conf; $langs->loadLangs(array('autoverifactu@autoverifactu')); - $now=new DateTimeImmutable( + $now = new DateTimeImmutable( 'now', new DateTimeZone('Europe/Madrid'), ); @@ -662,7 +662,7 @@ public function init($options = '') * Remove from database constants, boxes and permissions from Dolibarr database. * Data directories are not deleted * - * @param string $options Options when enabling module ('', 'noboxes') + * @param string $options Options when enabling module ('', 'noboxes') * * @return int<-1,1> 1 if OK, <=0 if KO */ diff --git a/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php b/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php index fc93e73..0c3ffa4 100644 --- a/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php +++ b/core/triggers/interface_10_modAutoverifactu_AutoverifactuFreezeInvoices.class.php @@ -211,12 +211,12 @@ public function runTrigger($action, $object, $user, $langs, $conf) return 0; } //creación de facturas de anulacion - $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); //Verifactu obliga a enviar peticiones a la api con unos tiempos de espera determinados enviados en la última respuesta //en caso de que el tiempo del proximo envio no haya pasado - if ($now->getTimestamp()array_options['options_verifactu_status'], array("7"), true)) { - $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + if ($now->getTimestamp() < getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0')) { + if (in_array($object->array_options['options_verifactu_status'], array('7'), true)) { + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED') - $now->getTimestamp()); return -1; } } else { @@ -240,20 +240,20 @@ public function runTrigger($action, $object, $user, $langs, $conf) //verificamos que el tiempo de espera a pasado // y si no lo incluimos en la lista de pendientes de envio - $now=new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); - if ($now->getTimestamp()array_options['options_verifactu_status'], array("2","4","5"), true)) { + if ($now->getTimestamp() < getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0')) { + if (in_array($object->array_options['options_verifactu_status'], array('2','4','5'), true)) { //en caso de eser facturas con errores, //no las enviamos a la lista de espera ya que no sabemos si han sido arregladas o no - $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED')-$now->getTimestamp()); + $this->errors[] = $langs->trans('notToDoList', getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED') - $now->getTimestamp()); return -1; } /*Para incluir la facturas anuladas en las acciones lista temporal habria que modificar la funcion autoverifactuRegisterInvoiceList y obtener de alguna forma la un identificador del tipo de factura de alta o anulacion */ $object->array_options['options_verifactu_status'] = '3'; $object->insertExtraFields(); - dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); + dol_syslog('VERI*FACTU: FACTURE ID ' . $object->id . ' TEMPORARILY QUEUED.', LOG_DEBUG); return 1; } else { //en caso de que el tiempo de espera haya pasado enviamos la factura diff --git a/css/selector_status.css.php b/css/selector_status.css.php index 94ec817..1180f5a 100644 --- a/css/selector_status.css.php +++ b/css/selector_status.css.php @@ -24,17 +24,17 @@ } $res = 0; -if (!$res && file_exists("../../../main.inc.php")) { - $res = @include "../../../main.inc.php"; +if (!$res && file_exists('../../../main.inc.php')) { + $res = @include '../../../main.inc.php'; } -if (!$res && file_exists("../../../../main.inc.php")) { - $res = @include "../../../../main.inc.php"; +if (!$res && file_exists('../../../../main.inc.php')) { + $res = @include '../../../../main.inc.php'; } if (!$res) { - die("Error: No se pudo encontrar el archivo main.inc.php de Dolibarr."); + die('Error: No se pudo encontrar el archivo main.inc.php de Dolibarr.'); } -$langs->load("autoverifactu@autoverifactu"); +$langs->load('autoverifactu@autoverifactu'); ?> @@ -56,31 +56,31 @@ /* --- VARIACIONES DE COLOR SEGÚN EL ESTADO DE VERI*FACTU --- */ /* Pendiente de envío */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect0"), ENT_QUOTES, 'UTF-8');?>"] { +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv('verifactuStatusSelect0'), ENT_QUOTES, 'UTF-8');?>"] { background-color: #2b82a4 !important; border-color: #1f617a !important; color: #ffffff !important; } /* Registrado Correctamente */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect1"), ENT_QUOTES, 'UTF-8');?>"] { +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv('verifactuStatusSelect1'), ENT_QUOTES, 'UTF-8');?>"] { background-color: #28a745 !important; border-color: #1e7e34 !important; color: #ffffff !important; } /* Rechazado */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect2"), ENT_QUOTES, 'UTF-8');?>"] { +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv('verifactuStatusSelect2'), ENT_QUOTES, 'UTF-8');?>"] { background-color: #dc3545 !important; border-color: #bd2130 !important; color: #ffffff !important; } /* En cola (Espera Temporal) */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect3"), ENT_QUOTES, 'UTF-8');?>"] { +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv('verifactuStatusSelect3'), ENT_QUOTES, 'UTF-8');?>"] { background-color: #ffc107 !important; border-color: #d39e00 !important; color: #212529 !important; } /* Registrado Correctamente pero con Errores */ -td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv("verifactuStatusSelect4"), ENT_QUOTES, 'UTF-8');?>"] { +td[data-key="facture.verifactu_status"][title="transnoentitiesnoconv('verifactuStatusSelect4'), ENT_QUOTES, 'UTF-8');?>"] { background-color: #fd7e14 !important; /* Naranja corporativo de advertencia */ border-color: #cf6206 !important; diff --git a/dev/tools/phpcs/dolibarr-ruleset.xml b/dev/tools/phpcs/dolibarr-ruleset.xml index c94cc66..829de78 100644 --- a/dev/tools/phpcs/dolibarr-ruleset.xml +++ b/dev/tools/phpcs/dolibarr-ruleset.xml @@ -30,6 +30,7 @@ --> + @@ -80,6 +81,7 @@ 4 + diff --git a/lib/validation.lib.php b/lib/validation.lib.php index e52e7af..ffa546d 100644 --- a/lib/validation.lib.php +++ b/lib/validation.lib.php @@ -37,9 +37,9 @@ /** * Compare the invoice record hash with the hash of the record from the immutable log. * - * @param Facture $invoice Target invoice. + * @param Facture $invoice Target invoice. * - * @retur int <0 if KO, 0 id not found, >0 on OK. + * @return int <0 if KO, 0 id not found, >0 on OK. */ function autoverifactuIntegrityCheck($invoice) { @@ -175,7 +175,7 @@ function autoverifactuInvoiceImmutableXMLPath($invoice, $type = 'alta') { global $conf; //genero el archivo xml con fecha para que no se sobrescriban y tener un historial - $now=new DateTimeImmutable( + $now = new DateTimeImmutable( 'now', new DateTimeZone('Europe/Madrid'), ); @@ -183,8 +183,8 @@ function autoverifactuInvoiceImmutableXMLPath($invoice, $type = 'alta') $invoiceref = dol_sanitizeFileName($invoice->ref); $dir = $conf->facture->multidir_output[$invoice->entity ?? $conf->entity] . '/' . $invoiceref; - $file = $dir . '/' . $invoiceref . '-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-' . $type .'-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-' . $type . '-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-' . $type . '-' . $now->format('Y-m-d_H-i-s') . '.xml'; return array($file, $hidden); } @@ -225,7 +225,7 @@ function autoverifactuGetPreviousValidInvoice($invoice, $tms = null) /** * Gets the source invoice from the fk_facture_source value. * - * @param Facture Invoice object. + * @param Facture $invoice Invoice object. * * @return Facture|null */ @@ -250,8 +250,8 @@ function autoverifactuGetSourceInvoice($invoice) /** * Recreate the original Veri*Factu invoice record from a blockedlog entry. * - * @param BlockedLog $blocedlog BlockedLog instance with the immutable data of the invoice validation. - * @param string $recorddType Record type. Can be 'alta' or 'anulacion'. + * @param BlockedLog $blockedlog BlockedLog instance with the immutable data of the invoice validation. + * @param string $recordType Record type. Can be 'alta' or 'anulacion'. * * @return stdClass Recreated invoice record. */ @@ -277,13 +277,13 @@ function autoverifactuRecordFromLog($blockedlog, $recordType = 'alta') $line = new FactureLigne($db); $line->localtax2_tx = $linedata->localtax2_tx; - $line->localtax1_tx =$linedata->localtax1_tx; + $line->localtax1_tx = $linedata->localtax1_tx; $line->tva_tx = $linedata->tva_tx; $line->total_localtax1 = $linedata->total_localtax1; $line->total_localtax2 = $linedata->total_localtax2; $line->total_ht = $linedata->total_ht; $line->total_tva = $linedata->total_tva; - $line->product_type=$linedata->product_type; + $line->product_type = $linedata->product_type; $lines[] = $line; } $blocked->lines = $lines; @@ -369,7 +369,7 @@ function autoverifactuEnabled() * Performs record data validation. * * @param stdClass $record Target record. - * @param array $error error array + * @param array $error error array * @return int 0 if validatio fail, 1 if succeed */ function autoverifactuValidateRecord($record, &$error) @@ -381,7 +381,7 @@ function autoverifactuValidateRecord($record, &$error) } if (!isset($record->breakdown, $record->totalTaxAmount, $record->totalAmount)) { - $error[]='NotValueNull'; //añado error + $error[] = 'NotValueNull'; //añado error return 0; } @@ -390,58 +390,58 @@ function autoverifactuValidateRecord($record, &$error) && count($record->recipients) ) { // If is simplified, it should not have recipients. - $error[]='NotValidateTypeF2F5NotRecipients';//añado error + $error[] = 'NotValidateTypeF2F5NotRecipients';//añado error return 0; } $isCorrective = preg_match('/R[0-5]/', $record->invoiceType); if ($isCorrective && !$record->correctiveType) { - $error[]='InvoceMustBeCorrectiveType';//añado error + $error[] = 'InvoceMustBeCorrectiveType';//añado error return 0; } elseif (!$isCorrective && $record->correctiveType) { - $error[]='InvoceNotMustBeCorrectiveType';//añado error + $error[] = 'InvoceNotMustBeCorrectiveType';//añado error return 0; } elseif (!$isCorrective && count($record->correctedInvoices)) { - $error[]='InvoceNotMustBeCorrectiveType';//añado error + $error[] = 'InvoceNotMustBeCorrectiveType';//añado error return 0; } if ($record->correctiveType === 'S') { // If its corrective by diferrence it should have base and tax amounts. if (!$record->correctedBaseAmount || !$record->correctedTaxAmount) { - $error[]='CorrectiveTypeDiferrenceShouldHaveBaseTaxAmounts';//añado error + $error[] = 'CorrectiveTypeDiferrenceShouldHaveBaseTaxAmounts';//añado error return 0; } } else { // If is corrective by substitution, it shouldn't. if ($record->correctedBaseAmount || $record->correctedTaxAmount) { - $error[]='CorrectiveTypeSubtitutionNotShouldHaveBaseTaxAmounts';//añado error + $error[] = 'CorrectiveTypeSubtitutionNotShouldHaveBaseTaxAmounts';//añado error return 0; } } if ($record->invoiceType === 'F3' && count($record->replacedInvoices)) { - $error[]='NotValidateTypeF3RemplaceInvoice';//añado error + $error[] = 'NotValidateTypeF3RemplaceInvoice';//añado error return 0; } elseif ($record->invoiceType !== 'F3' && count($record->replacedInvoices)) { - $error[]='NotValidateTypeNotF3RemplaceInvoice';//añado error + $error[] = 'NotValidateTypeNotF3RemplaceInvoice';//añado error return 0; } $expectedTax = 0; $expectedBase = 0; foreach ($record->breakdown as $details) { if (!isset($details->taxAmount, $details->baseAmount, $details->taxRate)) { - $error[]='NotValueNull';//añado error + $error[] = 'NotValueNull';//añado error return 0; } $validTaxAmount = false; - $validTaxAmountEquivalenceSurcharge=false; + $validTaxAmountEquivalenceSurcharge = false; $expectedLineTax = (float) $details->baseAmount * $details->taxRate / 100; if ( isset($details->equivalenceSurcharge)) { - if ($record->regimeType !=='18') { - $error[]="NotValidRegimeTypeEquivalenceSurcharge";//añado error + if ($record->regimeType !== '18') { + $error[] = 'NotValidRegimeTypeEquivalenceSurcharge';//añado error } - $expectedLineEquivalenceSurcharge= $details->baseAmount * $details->equivalenceSurcharge->type / 100; + $expectedLineEquivalenceSurcharge = $details->baseAmount * $details->equivalenceSurcharge->type / 100; for ($t = -0.02; $t <= 0.02; $t += 0.01) { $taxAmount = number_format($expectedLineEquivalenceSurcharge + $t, 2, '.', ''); /*var_dump($taxAmount); @@ -456,7 +456,7 @@ function autoverifactuValidateRecord($record, &$error) } } if (!$validTaxAmountEquivalenceSurcharge) { - $error[]="NotValidTaxAmountEquivalenceSurcharge";//añado error + $error[] = 'NotValidTaxAmountEquivalenceSurcharge';//añado error return 0; } $expectedTax += $details->equivalenceSurcharge->total; @@ -469,7 +469,7 @@ function autoverifactuValidateRecord($record, &$error) } } if (!$validTaxAmount) { - $error[]="NotValidTaxAmount";//añado error + $error[] = 'NotValidTaxAmount';//añado error return 0; } $expectedTax += $details->taxAmount; @@ -487,7 +487,7 @@ function autoverifactuValidateRecord($record, &$error) } } if ((int) $isTotalValid) { - $error[]='NotValueTotal';//añado error + $error[] = 'NotValueTotal';//añado error } return (int) $isTotalValid; } @@ -504,7 +504,7 @@ function autoverifactuIsInvoiceRecorded($invoice) $invoice->fetch_optionals(); // return !!($invoice->array_options['options_verifactu_hash'] ?? false); //ya pueden tener hash y tener que renviarlas en el caso de contener errores - return (!empty($invoice->array_options['options_verifactu_hash']) && !in_array($invoice->array_options['options_verifactu_status'], array("2","4","5"), true)); + return (!empty($invoice->array_options['options_verifactu_hash']) && !in_array($invoice->array_options['options_verifactu_status'], array('2','4','5'), true)); } /** @@ -536,74 +536,74 @@ function autoverifactuIsPosInvoice($invoice) /** * Performs validation checks to the record values. * - * @param stdClass $record Invoice record object. - * @param array $error array de errores + * @param stdClass $record Invoice record object. + * @param array $error array de errores * @return bool */ function autoverifactuValidateRecordValues($record, &$error) { if (!autoverifactuValidateRecordType($record->type)) { - $error[] = "NotRecordType";//añado error + $error[] = 'NotRecordType';//añado error return false; } if (!autoverifactuValidateInvoiceType($record->invoiceType)) { - $error[] = "NotRecordInvoiceType";//añado error + $error[] = 'NotRecordInvoiceType';//añado error return false; } if (!autoverifactuValidateDate($record->dateOperation, false)) { - $error[] = "NotRecordDateOperation";//añado error + $error[] = 'NotRecordDateOperation';//añado error return false; } if (!autoverifactuValidateAlphaNumber($record->description, 500)) { - $error[] = "NotValidRecordDescription";//añado error + $error[] = 'NotValidRecordDescription';//añado error return false; } if (!autoverifactuValidateAlphaNumber($record->invoiceId->invoiceNumber, 60)) { - $error[] = "NotValidRecordInvoice";//añado error + $error[] = 'NotValidRecordInvoice';//añado error return false; } if (!autoverifactuValidateNumber($record->factureTotalAmount, 12, 2)) { - $error[] = "NotValidRecordFactureTTC";//añado error + $error[] = 'NotValidRecordFactureTTC';//añado error return false; } if (!autoverifactuValidateNumber($record->factureTtc, 12, 2)) { - $error[] = "NotValidRecordTTC";//añado error + $error[] = 'NotValidRecordTTC';//añado error return false; } if ($record->factureTotalAmount !== $record->factureTtc) { - $error[] = "NotEqualRecordTTCAndRecordFactureTTC";//añado error + $error[] = 'NotEqualRecordTTCAndRecordFactureTTC';//añado error return false; } if (!autoverifactuValidateCorrectiveType($record->correctiveType, false)) { - $error[] = "NotValidRecordcorrectiveType";//añado error + $error[] = 'NotValidRecordcorrectiveType';//añado error return false; } if (!autoverifactuValidateNumber($record->correctedBaseAmount, 12, 2, false)) { - $error[] = "NotValidCorrectedBaseAmount";//añado error + $error[] = 'NotValidCorrectedBaseAmount';//añado error return false; } if (!autoverifactuValidateNumber($record->correctedTaxAmount, 12, 2, false)) { - $error[] = "NotValidCorrectedTaxAmount";//añado error + $error[] = 'NotValidCorrectedTaxAmount';//añado error return false; } if (!autoverifactuValidateNumber($record->totalTaxAmount, 12, 2)) { - $error[] = "NotValidRecordTotalTaxAmount";//añado error + $error[] = 'NotValidRecordTotalTaxAmount';//añado error return false; } if (!autoverifactuValidateNumber($record->totalAmount, 12, 2)) { - $error[] = "NotValidRecordTotalAmount";//añado error + $error[] = 'NotValidRecordTotalAmount';//añado error return false; } @@ -613,27 +613,27 @@ function autoverifactuValidateRecordValues($record, &$error) foreach ($record->breakdown as $breakdownDetails) { if (!autoverifactuValidateTaxType($breakdownDetails->taxType)) { - $error[]="NotValidateTaxType";//añado error + $error[] = 'NotValidateTaxType';//añado error return false; } if (!autoverifactuValidateRegimeType($breakdownDetails->regimeType)) { - $error[]="NotValidateRegimeType";//añado error + $error[] = 'NotValidateRegimeType';//añado error return false; } if (!autoverifactuValidateOperationType($breakdownDetails->operationType)) { - $error[]="NotValidateOperationType";//añado error + $error[] = 'NotValidateOperationType';//añado error return false; } if ( ! autoverifactuValidateNumber($breakdownDetails->taxRate, 4, 2)) { - $error[]="NotValidateTaxRate";//añado error + $error[] = 'NotValidateTaxRate';//añado error return false; } if ( !autoverifactuValidateNumber($breakdownDetails->baseAmount, 12, 2)) { - $error[]="NotValidateBaseAmount";//añado error + $error[] = 'NotValidateBaseAmount';//añado error return false; } if (!autoverifactuValidateExcemptionCode($breakdownDetails->excemptionCode, false)) { - $error[]="NotValidateExcemptionCode";//añado error + $error[] = 'NotValidateExcemptionCode';//añado error return false; } } @@ -850,10 +850,11 @@ function autoverifactuValidateExcemptionCode($value, $required = true) /** * Valida que las taxas y el total de la fectura y calculado sean los mismos. - * @param stdClass $record Invoice record object. * - * @return bool + * @param stdClass $record Invoice record object. + * @param string[] $error Array passed as reference carring validation errors. * + * @return bool */ function autoverifactuValidateTotalAndTotalTax($record, &$error) { @@ -869,7 +870,7 @@ function autoverifactuValidateTotalAndTotalTax($record, &$error) } } if (!$isTotalValid) { - $error[] ="NotValidCalculatedTotal";//añado error + $error[] = 'NotValidCalculatedTotal';//añado error return false; } $isTotalTaxAmountValid = false; @@ -881,7 +882,7 @@ function autoverifactuValidateTotalAndTotalTax($record, &$error) } } if (!$isTotalTaxAmountValid) { - $error[] ="NotValidCalculatedRate";//añado error + $error[] = 'NotValidCalculatedRate';//añado error return false; } return true; diff --git a/lib/verifactu.lib.php b/lib/verifactu.lib.php index 43f920b..9781c7f 100644 --- a/lib/verifactu.lib.php +++ b/lib/verifactu.lib.php @@ -50,9 +50,9 @@ /** * Verifactu invoice record registration. * - * @param Facture $invoice Target invoice. Invoice should not be validated, or - * action should be BILL_CANCEL. - * @param string $action Current action. + * @param Facture $invoice Target invoice. Invoice should not be validated, or + * action should be BILL_CANCEL. + * @param string $action Current action. * * @return int Return <0 if KO, 0 if skipped, >0 if OK. */ @@ -95,11 +95,11 @@ function autoverifactuRegisterInvoice($invoice, $action) ; if (empty($conf->facture->multidir_output[$conf->entity])) { dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); - $invoice->error[]="NotExistInvoiceOutput"; //añado el error + $invoice->error[] = 'NotExistInvoiceOutput'; //añado el error return -1; } - $now=new DateTimeImmutable( + $now = new DateTimeImmutable( 'now', new DateTimeZone('Europe/Madrid'), ); @@ -111,14 +111,14 @@ function autoverifactuRegisterInvoice($invoice, $action) //las facturas simplificadas no tienen tercero y por tanto tienen que evitar esta validación if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { dol_syslog('Skip invoice verifactu record registration due to thirdparty without a vaid idprof1'); - $invoice->error[]="NotNIFThirdparty"; + $invoice->error[] = 'NotNIFThirdparty'; return -1; } $invoice->fetch_lines(); if (!count($invoice->lines)) { dol_syslog('Skip invoice verifactu record registration to an invoice without lines'); - $invoice->error[]="NotLinesFacure"; + $invoice->error[] = 'NotLinesFacure'; return -1; } @@ -127,20 +127,20 @@ function autoverifactuRegisterInvoice($invoice, $action) //he añadido la fecha para que no se sobreescriban los XML //de esta forma se tiene un historial de todas los XML enviados if ($action === 'BILL_VALIDATE') { - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-alta-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-alta-' . $now->format('Y-m-d_H-i-s') . '.xml'; } elseif ($action === 'verifactuResend') { - $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-subsanacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-subsanacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; } else { - $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-anulacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-anulacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; } if (!file_exists($dir)) { if (dol_mkdir($dir) < 0) { dol_syslog('Unable to create verifactu files directory ' . $dir, LOG_ERR); - $invoice->error[]="NotCreateDirectoryVerifactu"; + $invoice->error[] = 'NotCreateDirectoryVerifactu'; return -1; } } @@ -235,9 +235,9 @@ function autoverifactuRegisterInvoice($invoice, $action) /** * Send an invoice as a record to the Veri*Factu SOAP endpoints. * - * @param Facture $invoice Target invoice. Invoice should not be published before - * @param string $action Triggered action. Can be BILL_VALIDATE or BILL_CANCEL. - * @param string &$xml Response body as an XML string. + * @param Facture $invoice Target invoice. Invoice should not be published before + * @param string $action Triggered action. Can be BILL_VALIDATE or BILL_CANCEL. + * @param string $xml Response body as an XML string. * * @return stdClass|null Registered record, null if skipped. * @@ -268,7 +268,7 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') . $invoice->id . 'is already registered', ); - $invoice->error[]="alradyRegisterInvoice";//añado los errores + $invoice->error[] = 'alradyRegisterInvoice';//añado los errores return -1 ; } @@ -322,12 +322,12 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') try { $res = autoverifactuSoapRequest($envelope); } catch (\Throwable $th) { - if ($th->getCode()===503) { + if ($th->getCode() === 503) { //en caso de un error interno y que la factura sea alta meto en la lista a enviar - if ($recordType==="alta") { + if ($recordType === 'alta') { $invoice->array_options['options_verifactu_status'] = '3'; $invoice->insertExtraFields(); - dol_syslog("VERI*FACTU: FACTURE ID ".$object->id." TEMPORARILY QUEUED.", LOG_DEBUG); + dol_syslog('VERI*FACTU: FACTURE ID ' . $object->id . ' TEMPORARILY QUEUED.', LOG_DEBUG); return $record; throw new Exception($th->getMessage(), 503); } else { @@ -352,7 +352,7 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') if ($status->nodeValue === 'Incorrecto') { dol_syslog('# REJECTED SOAP ENVELOPE', LOG_DEBUG); dol_syslog($envelope, LOG_DEBUG); - if ($operationTypeNode->nodeValue === "Anulacion") { + if ($operationTypeNode->nodeValue === 'Anulacion') { //error de anulacion $invoice->array_options['options_verifactu_status'] = '7'; } else { @@ -366,7 +366,7 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') $invoice->array_options['options_verifactu_status'] = '5'; } } - $invoice->ref=$record->invoiceId->invoiceNumber; + $invoice->ref = $record->invoiceId->invoiceNumber; $errCode = $res->getElementsByTagName('CodigoErrorRegistro')[0] ?? null; $errMessage = $res->getElementsByTagName('DescripcionErrorRegistro')[0] ?? null; @@ -398,7 +398,7 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') $record->error->message = $errMessage->nodeValue; //actualizo el estado a Enviada y correcta con errores $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; - if ($operationTypeNode->nodeValue === "Anulacion") { + if ($operationTypeNode->nodeValue === 'Anulacion') { //error de anulacion cuando esta la factura registrada $invoice->array_options['options_verifactu_status'] = '7'; } else { @@ -418,7 +418,7 @@ function autoverifactuSendInvoice($invoice, $action, &$xml = '') //actualizo el estado a Enviada y correcta $operationTypeNode = $res->getElementsByTagName('TipoOperacion')[0]; //actualizo el estado segun sea anulacion o alta - $operationTypeNode->nodeValue === "Anulacion"? $invoice->array_options['options_verifactu_status'] = '6' : $invoice->array_options['options_verifactu_status'] = '1'; + $operationTypeNode->nodeValue === 'Anulacion' ? $invoice->array_options['options_verifactu_status'] = '6' : $invoice->array_options['options_verifactu_status'] = '1'; $invoice->array_options['options_verifactu_error'] = ''; $invoice->array_options['options_verifactu_error_code'] = ''; @@ -483,18 +483,18 @@ function autoverifactuSoapRequest($body, $ttl = 3) $doc->loadXML($res . "\n"); $faults = $doc->getElementsByTagName('Fault'); //obtengo de la respuesta el tiempo de espara hasta la proxima registro - $shippingWaitingTimeNodes=$doc->getElementsByTagName('TiempoEsperaEnvio'); + $shippingWaitingTimeNodes = $doc->getElementsByTagName('TiempoEsperaEnvio'); if ($shippingWaitingTimeNodes->length > 0) { - $now=new DateTimeImmutable( + $now = new DateTimeImmutable( 'now', new DateTimeZone('Europe/Madrid'), ); $shippingWaitingTime = (int) $shippingWaitingTimeNodes->item(0)->nodeValue; - $newShipment= $now->modify("+" . $shippingWaitingTime . " seconds"); - $newValueTimestamp=$newShipment->getTimestamp(); + $newShipment = $now->modify('+' . $shippingWaitingTime . ' seconds'); + $newValueTimestamp = $newShipment->getTimestamp(); //guardo la fecha en la que puedo realizar el proximo envio $result = dolibarr_set_const($db, 'VERIFACTU_NEXT_DELIVERY_ALLOWED', $newValueTimestamp, 'chaine', 0, '', 0); - if ($result<=0) { + if ($result <= 0) { dol_syslog('# VERIFACTU SAVE DOLIBARR CONST VERIFACTU_NEXT_DELIVERY_ALLOWED', LOG_DEBUG); } } @@ -571,10 +571,10 @@ function autoverifactuSoapEnvelope($record, $issuer, $representative = null) /** * Return the invoice as a Veri*Factu record object. * -* @param Facture$invoice Target invoice. -* @param streing Record type. Can be 'alta' or 'anulacion'. +* @param Facture $invoice Target invoice. +* @param string $recordType Record type. Can be 'alta' or 'anulacion'. * -* @return stdClass|null Record representation. +* @return stdClass|null Record representation. */ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') { @@ -613,7 +613,7 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') } else { // Factura rectificativa corriente. if (!isset($invoice->array_options['options_verifactu_rectification_type'])) { - throw new Exception("Error not value options_verifactu_rectification_type", 1); + throw new Exception('Error not value options_verifactu_rectification_type', 1); } $invoiceType = $invoice->array_options['options_verifactu_rectification_type'] ; } @@ -626,7 +626,7 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') $record = new stdClass(); $record->type = $recordType; - $record->statusVerifactu=$invoice->array_options['options_verifactu_status']; + $record->statusVerifactu = $invoice->array_options['options_verifactu_status']; if (!empty($invoice->array_options['options_verifactu_date_operation'])) { $record->dateOperation = new DateTimeImmutable( date('Y-m-d H:i:s', $invoice->array_options['options_verifactu_date_operation']), @@ -655,7 +655,7 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') '' ); - $record->factureTotalTaxAmount=number_format($invoice->total_tva + $invoice->total_localtax1, 2, '.', ''); + $record->factureTotalTaxAmount = number_format($invoice->total_tva + $invoice->total_localtax1, 2, '.', ''); $record->factureTtc = number_format($invoice->total_ttc - $invoice->total_localtax2, 2, '.', ''); @@ -680,26 +680,26 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') !in_array($thirdparty->array_options['options_verifactu_identification_thirdparty'], array('03','04','05','06','07')) ) { //no existe tipo de identificacion - $invoice->errors[]='NotTypeIdentificationThirdparty'; + $invoice->errors[] = 'NotTypeIdentificationThirdparty'; return 0; } - if ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='03') { + if ($thirdparty->array_options['options_verifactu_identification_thirdparty'] == '03') { //Pasaporte (Passport) $recipient->type = '03'; $recipient->value = trim($thirdparty->idprof1); - } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='04') { + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty'] == '04') { //DOCUMENTO OFICIAL DE IDENTIFICACIÓN EXPEDIDO POR EL PAÍS (Document issued by the country) $recipient->type = '04'; $recipient->value = trim($thirdparty->idprof1); - } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='05') { + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty'] == '05') { //CERTIFICADO DE RESIDENCIA (Residence Certificate) $recipient->type = '05'; $recipient->value = trim($thirdparty->idprof1); - } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='06') { + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty'] == '06') { //OTRO DOCUMENTO PROBATORIO (Other supporting document) $recipient->type = '06'; $recipient->value = trim($thirdparty->idprof1); - } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty']=='07') { + } elseif ($thirdparty->array_options['options_verifactu_identification_thirdparty'] == '07') { //No censado (Unregistered) $recipient->type = '07'; // $recipient->value = trim($thirdparty->idprof1); @@ -740,7 +740,7 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') if (!$sourceInvoice) { dol_syslog('Can not find the source invoice of the corrective invoice #' . $invoice->id, LOG_ERR); - $invoice->error[]="NotFoundSourceInvoiceCorrective"; + $invoice->error[] = 'NotFoundSourceInvoiceCorrective'; return -1; } else { $sourceInvoice->fetch_thirdparty(); @@ -774,9 +774,9 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') $tax_total = 0; $base_total = 0; foreach ($record->breakdown as $line) { - $equivalenceSurcharge=0; + $equivalenceSurcharge = 0; if (isset($line->equivalenceSurcharge)) { - $equivalenceSurcharge= $line->equivalenceSurcharge->total; + $equivalenceSurcharge = $line->equivalenceSurcharge->total; } @@ -861,9 +861,9 @@ function autoverifactuInvoiceToRecord($invoice, $recordType = 'alta') /** * Serializes a record as a valid Vri*Factu XML record. * - * @param stdClass $record Invoice Veri*Factu record object. - * @param DOMDocument|null $xml Inherited document. If null, node will be created - * on a new DOMDocument instance. + * @param stdClass $record Invoice Veri*Factu record object. + * @param DOMDocument|null $xml Inherited document. If null, node will be created + * on a new DOMDocument instance. * * @return DOMElement XML record representation. * @@ -900,15 +900,15 @@ function autoverifactuRecordToXML($record, $xml = null) //etiquetas para subsanacion de errores - if (in_array($record->statusVerifactu, array("2","4","5"), true)) { - $valueSubsanacion="S"; - $valueRechazoPrevio="X"; + if (in_array($record->statusVerifactu, array('2','4','5'), true)) { + $valueSubsanacion = 'S'; + $valueRechazoPrevio = 'X'; - if ($record->statusVerifactu==="4") { - $valueRechazoPrevio="N"; + if ($record->statusVerifactu === '4') { + $valueRechazoPrevio = 'N'; } - if ($record->statusVerifactu==="5") { - $valueRechazoPrevio="S"; + if ($record->statusVerifactu === '5') { + $valueRechazoPrevio = 'S'; } $recordEl->appendChild($xml->createElement('sum1:Subsanacion', $valueSubsanacion)); $recordEl->appendChild($xml->createElement('sum1:RechazoPrevio', $valueRechazoPrevio)); @@ -1101,45 +1101,10 @@ function autoverifactuRecordToXML($record, $xml = null) /** * Get an invoice and returns its lines as a breakdown details array. * -* @param Facture $invoice Target invoice. +* @param Facture $invoice Target invoice. * * @return stdClass[] */ -/* -OLD FUNCTION -function autoverifactuLinesToBreakdown($invoice) -{ - $breakdown = array(); - - $defaultRegime = getDolGlobalString('AUTOVERIFACTU_DEFAULT_REGIME') ?: '01'; - - - foreach ($invoice->lines as $line) { - - - $details = new stdClass(); - $details->taxType = getDolGlobalString('AUTOVERIFACTU_TAX') ?: '01'; - // variable incorrecta options_verifactu_regim_type=> options_verifactu_regime_type - $details->regimeType = $line->array_options['options_verifactu_regime_type'] ?: $defaultRegime; - $details->operationType = $line->array_options['options_verifactu_operation_type'] ?: 'S1'; - $details->excemptionCode = $line->array_options['options_verifactu_tax_excemption'] ?: null; - $details->taxRate = number_format((float) $line->tva_tx, 2, '.', ''); - $details->baseAmount = number_format((float) $line->total_ht, 2, '.', ''); - $details->taxAmount = number_format((float) $line->total_tva, 2, '.', ''); - - if (!$details->exemptionCode && $details->operationType === 'S1' && $details->regimeType === '18') { - $details->equivalenceSurcharge = new stdClass(); - $details->equivalenceSurcharge->type = number_format((float) $line->localtax1_tx, 2, '.', '') ; - $details->equivalenceSurcharge->total = number_format((float) $line->total_localtax1, 2, '.', ''); - } - //falta añadir al array - $breakdown[] = $details; - } - - - return $breakdown; -} */ - function autoverifactuLinesToBreakdown($invoice) { @@ -1167,7 +1132,7 @@ function autoverifactuLinesToBreakdown($invoice) var_dump( !NumberIsZero($line->localtax1_tx)); echo "
"; echo "-----------------------------------";*/ - $equivalenceSurchargeType = !NumberIsZero($line->localtax1_tx) && $line->product_type==="0" ? number_format((float) $line->localtax1_tx, 2, '.', '') : null; + $equivalenceSurchargeType = !NumberIsZero($line->localtax1_tx) && $line->product_type === '0' ? number_format((float) $line->localtax1_tx, 2, '.', '') : null; $equivalenceSurchargeTotal = $line->total_localtax1 ? (float) $line->total_localtax1 : 0.0; /*echo "
"; echo "******************"; @@ -1219,8 +1184,8 @@ function autoverifactuLinesToBreakdown($invoice) } //creo la clase y las guardo en el arrray $breakdown = array(); - if (count($grouped)>12) { - $invoice->error[]="maximumNumberOfTaxRates"; + if (count($grouped) > 12) { + $invoice->error[] = 'maximumNumberOfTaxRates'; return -1; } foreach ($grouped as $group) { @@ -1278,14 +1243,14 @@ function autoverifactuGetRecordComputerSystem() /** * Calculate the record hash. * -* @param stdClass $record Invoice record object. +* @param stdClass $record Invoice record object. * * @return string Record sha256 hash. */ function autoverifactuCalculateRecordHash($record) { if ($record->type == 'alta') { - echo "

"; + echo '

'; $payload = 'IDEmisorFactura=' . $record->invoiceId->issuerId; $payload .= '&NumSerieFactura=' . $record->invoiceId->invoiceNumber; $payload .= '&FechaExpedicionFactura=' . $record->invoiceId->issueDate->format('d-m-Y'); @@ -1310,55 +1275,63 @@ function autoverifactuCalculateRecordHash($record) /** * Verifactu invoice record registration. (Crontab) * - * @param Facture $invoices Array object invoices. + * @param Facture[] $invoices Array object invoices. * - * @return int Return <0 if KO, 0 if skipped, >0 if OK. -*/ -/* - + * @return int Return <0 if KO, 0 if skipped, >0 if OK. */ function autoverifactuRegisterInvoiceList($invoices) { - global $db, $conf, $hookmanager, $user; + global $conf, $user; + if (empty($invoices) || !is_array($invoices)) { return 0; } + if (empty($conf->facture->multidir_output[$conf->entity])) { dol_syslog('Constant $conf->facture->multidir_output not defined', LOG_ERR); return -1; } - $now=new DateTimeImmutable( - 'now', - new DateTimeZone('Europe/Madrid'), - ); + + $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + $recordsLote = array(); $facturasValidasLote = array(); + //recorro las facturas foreach ($invoices as $invoice) { - if ($invoice->type > Facture::TYPE_DEPOSIT) continue; + if ($invoice->type > Facture::TYPE_DEPOSIT) { + continue; + } + $invoice->fetch_thirdparty(); $thirdparty = $invoice->thirdparty; $valid_id = $thirdparty->id_prof_check(1, $thirdparty); + if (!autoverifactuIsPosInvoice($invoice) && $valid_id <= 0 && !$thirdparty->tva_intra) { dol_syslog('Skip invoice #' . $invoice->id . ' due to thirdparty without valid idprof1'); continue; } + if (!count($invoice->lines)) { dol_syslog('Skip invoice #' . $invoice->id . ' due to no lines'); continue; } - $recordType ='alta'; + + $recordType = 'alta'; $record = autoverifactuInvoiceToRecord($invoice, $recordType); + if ($record) { $recordsLote[] = $record; $facturasValidasLote[] = $invoice; // Guardamos la correspondencia } } + if (empty($recordsLote)) { return 0; } global $mysoc; + $issuer = array( 'name' => $mysoc->nom, 'idprof1' => $mysoc->idprof1, @@ -1385,16 +1358,17 @@ function autoverifactuRegisterInvoiceList($invoices) if ($status === 'Correcto' || $status === 'AceptadoConErrores') { // Guardar localmente el XML individual o masivo por cumplimiento normativo de almacenamiento if ($action === 'BILL_VALIDATE') { - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-alta-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-alta-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-alta-' . $now->format('Y-m-d_H-i-s') . '.xml'; } elseif ($action === 'verifactuResend') { - $file = $dir . '/' . $invoiceref . '-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-subsanacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-subsanacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-subsanacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; } else { - $file = $dir . '/' . $invoiceref . '-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; - $hidden = $dir . '/.verifactu-anulacion-'.$now->format('Y-m-d_H-i-s').'.xml'; + $file = $dir . '/' . $invoiceref . '-anulacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; + $hidden = $dir . '/.verifactu-anulacion-' . $now->format('Y-m-d_H-i-s') . '.xml'; } - $file = $dir . '/' . $invoiceref . '-alta-'.$now->format('Y-m-d_H-i-s').'xml' ; + + $file = $dir . '/' . $invoiceref . '-alta-' . $now->format('Y-m-d_H-i-s') . 'xml' ; $result = file_put_contents($file, $envelope); $result = $result && file_put_contents($hidden, $envelope); if ($result) { @@ -1440,7 +1414,7 @@ function autoverifactuRegisterInvoiceList($invoices) $invoice->array_options['options_verifactu_error_code'] = $errCode; $invoice->insertExtraFields(); dol_syslog('Factura #' . $invoice->id . ' rechazada por AEAT: ' . $errMessage, LOG_ERR); - $invoice->ref=$record->invoiceId->invoiceNumber; + $invoice->ref = $record->invoiceId->invoiceNumber; $result = $invoice->update($user); if ($result <= 0) { throw new Exception($invoice->error, 1); @@ -1450,19 +1424,19 @@ function autoverifactuRegisterInvoiceList($invoices) return $exitos == count($facturasValidasLote); } catch (Exception $e) { - dol_syslog('Critical error in Veri*Factu mass mailing:' . $e->getMessage(), LOG_ERR); - return -1; + dol_syslog('Critical error in Veri*Factu mass mailing:' . $e->getMessage(), LOG_ERR); + return -1; } } /** * Gets an verifactu list invoice record and returns it inside a SOAP envelope. * - * @param stdClass $record list invoice record. - * @param array $issuer Issuer data with name and id keys. - * @param array|null $representative Representative data with name and id keys. + * @param stdClass[] $records List invoice record. + * @param array $issuer Issuer data with name and id keys. + * @param array|null $representative Representative data with name and id keys. * - * @return string SOAP XML enveloped record. + * @return string SOAP XML enveloped record. */ function autoverifactuSoapEnvelopeMass($records, $issuer, $representative = null) { @@ -1531,59 +1505,70 @@ function NumberIsZero($valor) return false; } -/* -* añade los textos legales al pdf dependiendo de las caractericticas de la factura -*/ +/** + * Añade los textos legales al pdf dependiendo de las caractericticas de la factura. + * + * @param Facture $invoice Facture object. + * + * @return Facture + * + * @throws Exception + */ function autoverifactuSetLegalText($invoice) { - - if (!isset($invoice->array_options["options_verifactu_pdfLegalText"])) { - $invoice->array_options["options_verifactu_pdfLegalText"] = []; - } elseif (strlen($invoice->array_options["options_verifactu_pdfLegalText"])>0) { - $invoice->array_options["options_verifactu_pdfLegalText"] = explode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); + if (!isset($invoice->array_options['options_verifactu_pdfLegalText'])) { + $invoice->array_options['options_verifactu_pdfLegalText'] = []; + } elseif (strlen($invoice->array_options['options_verifactu_pdfLegalText']) > 0) { + $invoice->array_options['options_verifactu_pdfLegalText'] = explode(',', $invoice->array_options['options_verifactu_pdfLegalText']); } - - - //IRPF + /* IRPF */ if (!NumberIsZero($invoice->total_localtax2)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextIRPF"; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextIRPF'; } $SujetoPasivo = true; - if (in_array("VerifactuLegalTextSujetoPasivo", $invoice->array_options['options_verifactu_pdfLegalText'])) { + if (in_array('VerifactuLegalTextSujetoPasivo', $invoice->array_options['options_verifactu_pdfLegalText'])) { $SujetoPasivo = false; } + $criterioCaja = true; - if (in_array("VerifactuLegalTextCriterioCaja", $invoice->array_options['options_verifactu_pdfLegalText'])) { + if (in_array('VerifactuLegalTextCriterioCaja', $invoice->array_options['options_verifactu_pdfLegalText'])) { $criterioCaja = false; } + $excemptionIVA = []; - if (in_array("VerifactuLegalTextTaxExcemptionE1", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E1'; + if (in_array('VerifactuLegalTextTaxExcemptionE1', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E1'; } - if (in_array("VerifactuLegalTextTaxExcemptionE2", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E2'; + + if (in_array('VerifactuLegalTextTaxExcemptionE2', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E2'; } - if (in_array("VerifactuLegalTextTaxExcemptionE3", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E3'; + + if (in_array('VerifactuLegalTextTaxExcemptionE3', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E3'; } - if (in_array("VerifactuLegalTextTaxExcemptionE4", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E4'; + + if (in_array('VerifactuLegalTextTaxExcemptionE4', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E4'; } - if (in_array("VerifactuLegalTextTaxExcemptionE5", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E5'; + + if (in_array('VerifactuLegalTextTaxExcemptionE5', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E5'; } - if (in_array("VerifactuLegalTextTaxExcemptionE6", $invoice->array_options['options_verifactu_pdfLegalText'])) { - $excemptionIVA[]='E6'; + + if (in_array('VerifactuLegalTextTaxExcemptionE6', $invoice->array_options['options_verifactu_pdfLegalText'])) { + $excemptionIVA[] = 'E6'; } - $rebu=true; - if (in_array("VerifactuLegalTextREBU", $invoice->array_options['options_verifactu_pdfLegalText'])) { + $rebu = true; + if (in_array('VerifactuLegalTextREBU', $invoice->array_options['options_verifactu_pdfLegalText'])) { $rebu = false; } - $agenciaViajes=true; - if (in_array("VerifactuLegalTextAgenciaViajes", $invoice->array_options['options_verifactu_pdfLegalText'])) { + + $agenciaViajes = true; + if (in_array('VerifactuLegalTextAgenciaViajes', $invoice->array_options['options_verifactu_pdfLegalText'])) { $agenciaViajes = false; } @@ -1593,72 +1578,73 @@ function autoverifactuSetLegalText($invoice) switch ($line->array_options['options_verifactu_tax_excemption']) { case 'E1': if (!in_array('E1', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE1"; - $excemptionIVA[]='E1'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE1'; + $excemptionIVA[] = 'E1'; } break; case 'E2': if (!in_array('E2', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE2"; - $excemptionIVA[]='E2'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE2'; + $excemptionIVA[] = 'E2'; } break; case 'E3': if (!in_array('E3', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE3"; - $excemptionIVA[]='E3'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE3'; + $excemptionIVA[] = 'E3'; } break; case 'E4': if (!in_array('E4', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE4"; - $excemptionIVA[]='E4'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE4'; + $excemptionIVA[] = 'E4'; } break; case 'E5': if (!in_array('E5', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE5"; - $excemptionIVA[]='E5'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE5'; + $excemptionIVA[] = 'E5'; } break; case 'E6': if (!in_array('E6', $excemptionIVA)) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextTaxExcemptionE6"; - $excemptionIVA[]='E6'; + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextTaxExcemptionE6'; + $excemptionIVA[] = 'E6'; } break; default: - throw new Exception("Error options_verifactu_error not valid value", 1); + throw new Exception('Error options_verifactu_error not valid value', 1); break; } } //Inversión del Sujeto Pasivo - if ($line->array_options['options_verifactu_operation_type']==='S2' && $SujetoPasivo) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextSujetoPasivo"; - $SujetoPasivo=false; + if ($line->array_options['options_verifactu_operation_type'] === 'S2' && $SujetoPasivo) { + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextSujetoPasivo'; + $SujetoPasivo = false; } //regimen de criterio de caja - if ($line->array_options['options_verifactu_regime_type']==="07" && $criterioCaja) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextCriterioCaja"; - $criterioCaja=false; + if ($line->array_options['options_verifactu_regime_type'] === '07' && $criterioCaja) { + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextCriterioCaja'; + $criterioCaja = false; } - if ($line->array_options['options_verifactu_regime_type']==="03" && $rebu) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextREBU"; - $rebu=false; + if ($line->array_options['options_verifactu_regime_type'] === '03' && $rebu) { + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextREBU'; + $rebu = false; } - if ($line->array_options['options_verifactu_regime_type']==="09" && $agenciaViajes) { - $invoice->array_options["options_verifactu_pdfLegalText"][]="VerifactuLegalTextAgenciaViajes"; - $agenciaViajes=false; + if ($line->array_options['options_verifactu_regime_type'] === '09' && $agenciaViajes) { + $invoice->array_options['options_verifactu_pdfLegalText'][] = 'VerifactuLegalTextAgenciaViajes'; + $agenciaViajes = false; } } - $invoice->array_options["options_verifactu_pdfLegalText"]=implode(',', $invoice->array_options["options_verifactu_pdfLegalText"]); + + $invoice->array_options['options_verifactu_pdfLegalText'] = implode(',', $invoice->array_options['options_verifactu_pdfLegalText']); $result = $invoice->insertExtraFields(); if ($result < 0) { - throw new Exception("Error save options_verifactu_pdfLegalText ", 1); + throw new Exception('Error save options_verifactu_pdfLegalText ', 1); } } From a8380b7fee58663b7934e8489513d532ec92dc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 16:28:01 +0200 Subject: [PATCH 4/6] feat: unified phpcs config file --- .phpcs.xml.dist | 460 ++++++++++++++++++++++++++- dev/tools/phpcs/dolibarr-ruleset.dtd | 18 -- dev/tools/phpcs/dolibarr-ruleset.xml | 450 -------------------------- 3 files changed, 453 insertions(+), 475 deletions(-) delete mode 100644 dev/tools/phpcs/dolibarr-ruleset.dtd delete mode 100644 dev/tools/phpcs/dolibarr-ruleset.xml diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 2868170..cfe0b67 100755 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -1,10 +1,22 @@ - + + Autoverifactu coding standard. + + + + + + + ./admin ./ajax @@ -14,11 +26,445 @@ ./js ./lib - + + + /\.git/ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 4 + + + 4 + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 0 + + + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + 0 + + + + + 0 + + + + 0 + + + + + 0 + + + + + + + + + 0 + + + + + 0 + + + + + + + 0 + + + + + + + + + + 0 + + + + + 0 + + + + 0 + + + + + + + + 0 + + + 0 + + + + 0 + + + + + + + + 0 + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tools/phpcs/dolibarr-ruleset.dtd b/dev/tools/phpcs/dolibarr-ruleset.dtd deleted file mode 100644 index 24aa329..0000000 --- a/dev/tools/phpcs/dolibarr-ruleset.dtd +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/dev/tools/phpcs/dolibarr-ruleset.xml b/dev/tools/phpcs/dolibarr-ruleset.xml deleted file mode 100644 index 829de78..0000000 --- a/dev/tools/phpcs/dolibarr-ruleset.xml +++ /dev/null @@ -1,450 +0,0 @@ - - - - Dolibarr coding standard. - - - - - - /\.git/ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 4 - - - 4 - - - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - - - - - - - - - 0 - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - 0 - - - 0 - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - - 0 - - - - - 0 - - - - 0 - - - - - 0 - - - - - - - - - 0 - - - - - 0 - - - - - - - 0 - - - - - - - - - - 0 - - - - - 0 - - - - 0 - - - - - - - - 0 - - - 0 - - - - 0 - - - - - - - - 0 - - - - - - - - 0 - - - - - - - - - - - - - - - - - - - - - - - - From f819c6b14c81d2d31a3e75e052b9e171a0d10572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 17:47:33 +0200 Subject: [PATCH 5/6] feat: github workflows yaml files --- .github/workflows/release.yml | 6 +++++- .github/workflows/tests.yml | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd57a20..dd61e95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,9 +9,13 @@ permissions: contents: "write" jobs: + tests: + name: Release tests + uses: ./.github/workflows/tests.yml + release: name: Release pushed tag - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest env: TAG: ${{ github.ref_name }} steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..a705e18 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,28 @@ +name: Tests + +on: + pull_request: + branches: [main] + + workflow_call: + +jobs: + cs: + name: Coding Standards + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Cache composer dependencies + uses: actions/cache@v4 + with: + path: vendor + key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: Composer install + run: composer -q install + + - name: Check Coding Standards + run: vendor/bin/phpcs -q From 8d382683e317b497aaa9da4db1137de21b46c06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Garc=C3=ADa?= Date: Sun, 16 Aug 2026 17:56:24 +0200 Subject: [PATCH 6/6] feat: coding standards formatting and linting --- admin/setup.php | 15 +- ajax/dismiss_notice.php | 8 +- class/actions_autoverifactu.class.php | 111 +++++++----- class/verifactuqueue.class.php | 128 +++++++++---- .../facture/doc/pdf_Autoverifactu.modules.php | 170 +++++++++--------- lib/setup.lib.php | 2 + lib/validation.lib.php | 10 +- lib/verifactu.lib.php | 12 +- 8 files changed, 272 insertions(+), 184 deletions(-) diff --git a/admin/setup.php b/admin/setup.php index daa1b51..484cf1d 100755 --- a/admin/setup.php +++ b/admin/setup.php @@ -34,31 +34,30 @@ require_once dirname(__DIR__) . '/lib/validation.lib.php'; /** + * Global variables. + * * @var Conf $conf * @var DoliDB $db * @var HookManager $hookmanager * @var Translate $langs * @var User $user */ - global $db, $langs, $conf; -// Translations +/* Translations */ $langs->loadLangs(array('admin', 'autoverifactu@autoverifactu')); -// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context -/** - * @var HookManager $hookmanager -*/ +// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules +// contains an array of hook context. $hookmanager->initHooks(array('autoverifactusetup', 'globalsetup')); -// Parameters +/* Parameters */ $action = GETPOST('action', 'aZ09'); $error = 0; $setupnotempty = 0; -// Access control +/* Access control */ if (!$user->admin) { accessforbidden(); } diff --git a/ajax/dismiss_notice.php b/ajax/dismiss_notice.php index be7923c..0f51a16 100644 --- a/ajax/dismiss_notice.php +++ b/ajax/dismiss_notice.php @@ -49,13 +49,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php'; require_once dirname(__DIR__) . '/lib/autoverifactu.lib.php'; -/** - * @var Conf $conf - * @var DoliDB $db - * @var HookManager $hookmanager - * @var Translate $langs - * @var User $user - */ +global $db, $user; $tag = trim(GETPOST('tag', 'alpha') ?: ''); $entity = GETPOSTINT('entity') ?: 1; diff --git a/class/actions_autoverifactu.class.php b/class/actions_autoverifactu.class.php index 077bc94..7b01ced 100644 --- a/class/actions_autoverifactu.class.php +++ b/class/actions_autoverifactu.class.php @@ -37,41 +37,53 @@ class ActionsAutoverifactu extends CommonHookActions { /** - * @var DoliDB Database handler. + * Handles the dolibarr's database client singleton object. + * + * @var DoliDBMysqli */ public $db; /** - * @var string Error code (or message) + * Handles an error code (or message). + * + * @var string */ public $error = ''; /** - * @var string[] Errors. + * Handles an array of string error codes (or messages). + * + * @var string[] */ public $errors = array(); /** - * @var mixed[] Hook results. Propagated to $hookmanager->resArray for later reuse. + * Hook results. Propagated to $hookmanager->resArray for later reuse. + * + * @var mixed[] */ public $results = array(); /** - * @var ?string String displayed by executeHook() immediately after return. + * String displayed by executeHook() immediately after return. + * + * @var ?string */ public $resprints; /** - * @var int Priority of hook (50 is used if value is not defined). + * Priority of hook (50 is used if value is not defined). + * + * @var ?int */ public $priority; /** - * Constructor + * Class constructor. * - * @param DoliDB $db Database handler. + * @param DoliDBMysqli $db Database handler. */ public function __construct($db) { @@ -270,8 +282,7 @@ public function beforePDFCreation($parameters, &$object, &$action) * invoice body is opened. * * @param array $parameters Array of parameters. - * @param PDFCT &$pdfhandler Object output on PDF. - * @param string $action 'add', 'update', 'view'. + * @param PDFCT $pdfhandler Object output on PDF. * * @return int Return always 0. * Overwrites the hookmanager results array @@ -338,7 +349,7 @@ public function printUnderHeaderPDFline($parameters, &$pdfhandler) * it adds a "verifactu" button to the row. * * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of the page. + * @param CommonObect $object Instance of the owner object of the page. * @param string $action Global action. * * @return null Empty response. The button @@ -422,12 +433,12 @@ public function addMoreActionsButtons($parameters, &$object, $action) * the state of the invoice. * * @param array $parameters Array of parameters. - * @param CommonObect &$object Instance of the owner object of + * @param CommonObect $object Instance of the owner object of * the page. * @param string $action Global action. * - * @return int<0,1> 1 if button has been overwrited, - * 0 otherwise. + * @return int<0,1> 1 if button has been overwrited, + * 0 otherwise. */ public function dolGetButtonAction(&$parameters, $object, $action) { @@ -513,22 +524,26 @@ public function dolGetButtonAction(&$parameters, $object, $action) } } + /** + * Form object options. + * + * @param array $parameters Parameters + * @param CommonObject $object Object + * @param string $action Action + * + * @return int + */ public function formObjectOptions($parameters, $object, $action) { - - global $extrafields, $langs, $db ; - + global $extrafields, $langs; if ($parameters['currentcontext'] !== 'invoicecard' || $object->element !== 'facture') { return; } - if ($parameters['currentcontext'] === 'invoicecard' && $action === 'fixErrors' && $object->id > 0) { - //accion de mostrar los erroes y una explicacion - require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php'; + if ($action === 'fixErrors' && $object->id > 0) { + // Accion de mostrar los erroes y una explicacion $langs->load('autoverifactu@autoverifactu'); - $form = new Form($db); - $formquestion; if ($object->array_options['options_verifactu_error_code'] === '2001' ) { //El NIF del bloque Destinatarios no está identificado en el censo de la AEAT. @@ -544,6 +559,7 @@ public function formObjectOptions($parameters, $object, $action) $url = $_SERVER['PHP_SELF'] . '?id=' . $object->id; $this->formAlert($message, $url); } + return 0; } @@ -556,30 +572,38 @@ public function formObjectOptions($parameters, $object, $action) ), true ) && $object->id !== null // never hide the field for invoice creation forms - // && $action === 'edit_extras' ) { - //$extrafields->attributes['facture']['list']['verifactu_rectification_type'] = '0'; + $extrafields->attributes['facture']['list']['verifactu_rectification_type'] = '0'; + } else { + echo ''; } - //css para ocultar de los campos adjuntos el icono de editar - print ' - '; + + echo ' + '; } - //funcion que genera una ventana emergente con el mensaje parado por parametro con un btn de aceptar, - // que te lleva a la url pasada por parametro. + /** + * Funcion que genera una ventana emergente con el mensaje parado por parametro con un btn de aceptar, + * que te lleva a la url pasada por parametro. + * + * @param string $message Mensaje a mostrar en la ventana. + * @param string $url URL de destino del enlace de la notificación. + * + * @return null + */ private function formAlert($message, $url) { ?> @@ -597,7 +621,7 @@ private function formAlert($message, $url) modal: true, resizable: false, closeOnEscape: true, - width: 550, + width: 550, height: "auto", buttons: [ { @@ -605,7 +629,6 @@ private function formAlert($message, $url) class: "button", // Clase CSS nativa de los botones de Dolibarr click: function() { jQuery(this).dialog("close"); - window.location.href = ''; } } diff --git a/class/verifactuqueue.class.php b/class/verifactuqueue.class.php index 2bd3da0..85d4004 100644 --- a/class/verifactuqueue.class.php +++ b/class/verifactuqueue.class.php @@ -1,56 +1,118 @@ + * Copyright (C) 2024 Frédéric France + * Copyright (C) 2026 Yamil Esteban + * + * 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/custom/autoverifactu/class/verufactuqueue.class.php + * \inroup autoverifactu + * \brief Invoice record queue handler + */ require_once DOL_DOCUMENT_ROOT . '/custom/autoverifactu/lib/verifactu.lib.php'; +/** + * Class VerifactuQueue. + */ class VerifactuQueue { + /** + * Handles the dolibarr's database client singleton object. + * + * @var DoliDBMysqli + */ private $db; + /** + * Handles a list of queue processing errors. + * + * @var string[] + */ + public $errors = array(); + + /** + * Class constructor. Stores the $db reference as an internal attribute. + * + * @param DoliDBMysqli $db Database client instance. + */ public function __construct($db) { $this->db = $db; } - /* - Funcion para obtener las facturas con el estado en cola (3) cuando se pueda enviar - a la api una peticion porque el tiempo de espera ya a pasado. - */ + /** + * Checks if the last waiting time reported by the Veri*Factu API responses has been exceeded. + * + * @return bool + */ + private function isDeliveryAllowed() + { + $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); + return $now->getTimestamp() >= getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0'); + } + + /** + * Loads pending invoices and performs a batch submit of invoice records to the Verii*Factu SOAP API. + * + * @return int + */ public function processMassiveQueue() { global $conf, $langs; + $langs->load('autoverifactu@autoverifactu'); - $now = new DateTimeImmutable('now', new DateTimeZone('Europe/Madrid')); - if ($now->getTimestamp() < getDolGlobalString('VERIFACTU_NEXT_DELIVERY_ALLOWED', '0')) { - //sigue en espera - return 0; - } else { - //se puede enviar - include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; - //obtengo las facturas en cola max 30. - $sql = 'SELECT fk_object FROM ' . MAIN_DB_PREFIX . "facture_extrafields WHERE verifactu_status ='3' LIMIT 30"; - $resql = $this->db->query($sql); - if ($resql && $this->db->num_rows($resql) > 0) { - //en caso de existir facturas en cola genero un array con las facturas - $listInvoice = array(); - while ($obj = $this->db->fetch_object($resql)) { - $invoice = new Facture($this->db); - if ($invoice->fetch($obj->fk_object) > 0) { - $invoice->fetch_optionals(); - $listInvoice[] = $invoice; - } + + if (!$this->isDeliveryAllowed()) { + return -1; + } + + include_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; + + // Obtengo las facturas en cola max 30. + $sql = 'SELECT fk_object FROM ' . MAIN_DB_PREFIX . "facture_extrafields WHERE verifactu_status ='3' LIMIT 30"; + + $resql = $this->db->query($sql); + + if ($resql && $this->db->num_rows($resql) > 0) { + // En caso de existir facturas en cola genero un array con las facturas. + $invoices = array(); + while ($obj = $this->db->fetch_object($resql)) { + $invoice = new Facture($this->db); + + if ($invoice->fetch($obj->fk_object) > 0) { + $invoice->fetch_optionals(); + $invoices[] = $invoice; } - //genero el xml y las envio - $result = autoverifactuRegisterInvoiceList($listInvoice); - if ($result < 0) { - if (!empty($object->errors)) { - $this->errors = array_merge($this->errors, (array) $object->errors); - } else { - $this->errors[] = $langs->trans('RecordCreationFail'); - } + } + + // genero el xml y las envio + $result = autoverifactuRegisterInvoiceList($invoices); + + if ($result < 0) { + if (!empty($object->errors)) { + $this->errors = array_merge($this->errors, (array) $object->errors); + } else { + $this->errors[] = $langs->trans('RecordCreationFail'); } - return $result; } - return 0; + + return $result; } + + return 0; } } diff --git a/core/modules/facture/doc/pdf_Autoverifactu.modules.php b/core/modules/facture/doc/pdf_Autoverifactu.modules.php index 11dfc6a..8e2cde0 100644 --- a/core/modules/facture/doc/pdf_Autoverifactu.modules.php +++ b/core/modules/facture/doc/pdf_Autoverifactu.modules.php @@ -44,10 +44,7 @@ require_once dirname(__DIR__, 4) . '/lib/autoverifactu.lib.php'; -//!importante /* - - 7. Ubicación del QR en la factura El QR debe ubicarse al principio de la factura, preferentemente en: @@ -62,41 +59,45 @@ 30x30 mm como mínimo 40x40 mm como máximo Este rango asegura que el QR pueda ser escaneado correctamente por cualquier dispositivo. - - */ - - - - - +*/ /** - * Class to generate the customer invoice PDF with template Verifactu + * Class to generate the customer invoice PDF with template Verifactu */ class pdf_Autoverifactu extends ModelePDFFactures { /** - * @var DoliDB Database handler + * Database handler. + * + * @var DoliDB */ public $db; /** - * @var string model name + * Model name. + * + * @var string */ public $name; /** - * @var string model description (short text) + * Model description (short text) + * + * @var string */ public $description; /** - * @var int Save the name of generated file as the main doc when generating a doc with this template + * Save the name of generated file as the main doc when generating a doc with this template + * + * @var int */ public $update_main_doc_field; /** - * @var string document type + * Document type + * + * @var string */ public $type; @@ -108,35 +109,39 @@ class pdf_Autoverifactu extends ModelePDFFactures public $version = 'dolibarr'; /** - * @var bool Situation invoice type + * Situation invoice type + * + * @var bool */ public $situationinvoice; /** - * @var float X position for the situation progress column + * X position for the situation progress column + * + * @var float */ public $posxprogress; /** - * @var int Category of operation + * Category of operation + * + * @var int */ public $categoryOfOperation = -1; // unknown by default /** - * Constructor + * Constructor * - * @param DoliDB $db Database handler + * @param DoliDB $db Database handler. */ public function __construct($db) { - global $conf, $langs, $mysoc; + global $langs, $mysoc; // Translations $langs->loadLangs(array('main', 'bills')); - - $this->db = $db; $this->name = 'Autoverifactu'; $this->description = 'Factura PDF plantilla Autoverifactu. Una plantilla compatible con el QR de Verifactu'; @@ -216,12 +221,13 @@ public function __construct($db) /** * Function to build pdf onto disk * - * @param Facture $object Object to generate - * @param Translate $outputlangs Lang output object - * @param string $srctemplatepath Full path of source filename for generator using a template file - * @param int $hidedetails Do not show line details - * @param int $hidedesc Do not show desc - * @param int $hideref Do not show ref + * @param Facture $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * * @return int 1=OK, 0=KO */ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0) @@ -971,11 +977,12 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede /** * Show payments table * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object invoice - * @param int $posy Position y in PDF - * @param Translate $outputlangs Object langs for output - * @param int $heightforfooter Height for footer + * @param TCPDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @param int $heightforfooter Height for footer + * * @return int Return integer <0 if KO, >0 if OK */ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $heightforfooter = 0) @@ -1128,14 +1135,15 @@ protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $hei /** * Function _tableau_versements_header * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object invoice - * @param Translate $outputlangs Object langs for output - * @param int $default_font_size Font size - * @param int $tab3_posx pos x - * @param int $tab3_top pos y - * @param int $tab3_width width - * @param int $tab3_height height + * @param TCPDF $pdf Object PDF + * @param Facture $object Object invoice + * @param Translate $outputlangs Object langs for output + * @param int $default_font_size Font size + * @param int $tab3_posx pos x + * @param int $tab3_top pos y + * @param int $tab3_width width + * @param int $tab3_height height + * * @return void */ protected function _tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height) @@ -1170,11 +1178,12 @@ protected function _tableau_versements_header($pdf, $object, $outputlangs, $defa /** * Show miscellaneous information (payment mode, payment term, ...) * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object to show - * @param int $posy Y - * @param Translate $outputlangs Langs object - * @param Translate $outputlangsbis Object lang for output bis + * @param TCPDF $pdf Object PDF + * @param Facture $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @param Translate $outputlangsbis Object lang for output bis + * * @return int Pos y */ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis) @@ -1389,12 +1398,13 @@ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlan /** * Show total to pay * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object invoice - * @param int $deja_regle Amount already paid (in the currency of invoice) - * @param int $posy Position depart - * @param Translate $outputlangs Object langs - * @param Translate $outputlangsbis Object lang for output bis + * @param TCPDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Amount already paid (in the currency of invoice) + * @param int $posy Position depart + * @param Translate $outputlangs Object langs + * @param Translate $outputlangsbis Object lang for output bis + * * @return int Position pour suite */ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis) @@ -1747,14 +1757,15 @@ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs /** * Show table for lines * - * @param TCPDF $pdf Object PDF - * @param float|int $tab_top Top position of table - * @param float|int $tab_height Height of table (rectangle) - * @param int $nexY Y (not used) - * @param Translate $outputlangs Langs object - * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title - * @param int $hidebottom Hide bottom bar of array - * @param string $currency Currency code + * @param TCPDF $pdf Object PDF + * @param float|int $tab_top Top position of table + * @param float|int $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * * @return void */ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = '') @@ -1868,11 +1879,12 @@ protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $ /** * Show top header of page. * - * @param TCPDF $pdf Object PDF - * @param Facture $object Object to show - * @param int $showaddress 0=no, 1=yes - * @param Translate $outputlangs Object lang for output - * @param Translate $outputlangsbis Object lang for output bis + * @param TCPDF $pdf Object PDF + * @param Facture $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @param Translate $outputlangsbis Object lang for output bis + * * @return float|int Return topshift value */ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null) @@ -2048,14 +2060,6 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output } } - - - - - - - - $title .= ' ' . $outputlangs->convToOutputCharset($object->ref); if ($object->statut == $object::STATUS_DRAFT) { $pdf->SetTextColor(128, 0, 0); @@ -2350,21 +2354,21 @@ protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $output // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** - * Show footer of page. Need this->emetteur object + * Show footer of page. Need this->emetteur object * - * @param TCPDF $pdf PDF - * @param Facture $object Object to show - * @param Translate $outputlangs Object lang for output - * @param int $hidefreetext 1=Hide free text - * @param int $heightforqrinvoice Height for QR invoices - * @return int Return height of bottom margin including footer text + * @param TCPDF $pdf PDF + * @param Facture $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @param int $heightforqrinvoice Height for QR invoices + * + * @return int Return height of bottom margin including footer text */ protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0, $heightforqrinvoice = 0) { $showdetails = getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS', 0); - $text = 'En cumplimiento de la normativa de Protección de Datos le informamos que el RESPONSABLE del tratamiento de los mismos es OYR SOLUTIONS S.L. gestionados con la FINALIDAD de expedir un presupuesto o la correspondiente factura por la compra de un presto o la prestación de alguno de nuestros servicios. La LEGITIMACIÓN se basa en la existencia de una relación comercial de compra de productos o contractual para la prestación de un servicio. Serán DESTINATARIOS de sus datos aquellas organizaciones o entidades directamente relacionadas con el Responsable, así como las Administraciones Públicas con competencia en la materia. El plazo de CONSERVACIÓN de sus datos será hasta el fin de la prestación del servicio, y una vez finalizado, hasta que se solicite su supresión por parte del interesado. Entre sus DERECHOS se encuentra el de acceder, rectificar y suprimir, así como el de oposición, limitación y portabilidad. diff --git a/lib/setup.lib.php b/lib/setup.lib.php index 620ded7..a64d12d 100644 --- a/lib/setup.lib.php +++ b/lib/setup.lib.php @@ -44,6 +44,8 @@ function autoverifactuGetPost($field) /** * Handles POST requests to the module's setup page. + * + * @return null */ function autoverifactuSetupPost() { diff --git a/lib/validation.lib.php b/lib/validation.lib.php index ffa546d..a26f171 100644 --- a/lib/validation.lib.php +++ b/lib/validation.lib.php @@ -368,8 +368,9 @@ function autoverifactuEnabled() /** * Performs record data validation. * - * @param stdClass $record Target record. - * @param array $error error array + * @param stdClass $record Target record. + * @param array $error error array + * * @return int 0 if validatio fail, 1 if succeed */ function autoverifactuValidateRecord($record, &$error) @@ -536,8 +537,9 @@ function autoverifactuIsPosInvoice($invoice) /** * Performs validation checks to the record values. * - * @param stdClass $record Invoice record object. - * @param array $error array de errores + * @param stdClass $record Invoice record object. + * @param array $error array de errores + * * @return bool */ function autoverifactuValidateRecordValues($record, &$error) diff --git a/lib/verifactu.lib.php b/lib/verifactu.lib.php index 9781c7f..13ca6bb 100644 --- a/lib/verifactu.lib.php +++ b/lib/verifactu.lib.php @@ -1479,11 +1479,13 @@ function autoverifactuSoapEnvelopeMass($records, $issuer, $representative = null return $xml->saveXML($envelope); } -/* -Esta funcion nos indica si un valor es 0 o esta vacio -true si es cero o vacio -false si tiene un valor != 0 -*/ +/** + * Esta funcion nos indica si un valor es 0 o esta vacio true si es cero o vacio false si tiene un valor != 0 + * + * @param mixed $valor Valor a evaluar. + * + * @return bool + */ function NumberIsZero($valor) { if (!isset($valor)) {