diff --git a/.github/workflows/phan.yml b/.github/workflows/phan.yml index 8851694c4f3..4fdedc212ce 100644 --- a/.github/workflows/phan.yml +++ b/.github/workflows/phan.yml @@ -90,7 +90,7 @@ jobs: cs2pr --prepend-filename --prepend-source --notices-as-warnings _phan.xml - name: Provide phan log as artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 if: ${{ always() }} with: name: phan-srcrt diff --git a/dev/initdemo/mysqldump_dolibarr_24.0.0.sql b/dev/initdemo/mysqldump_dolibarr_24.0.0.sql index d060ffe5c65..51d09ade521 100644 --- a/dev/initdemo/mysqldump_dolibarr_24.0.0.sql +++ b/dev/initdemo/mysqldump_dolibarr_24.0.0.sql @@ -82148,133 +82148,6 @@ INSERT INTO `llx_usergroup_user` VALUES /*!40000 ALTER TABLE `llx_usergroup_user` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `llx_verifactudolibarr_add_tpls` --- - -DROP TABLE IF EXISTS `llx_verifactudolibarr_add_tpls`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `llx_verifactudolibarr_add_tpls` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `title` varchar(100) NOT NULL, - `template` varchar(100) NOT NULL, - `status` int(11) NOT NULL DEFAULT 0, - `hash_tmp` varchar(100) NOT NULL, - `tms` datetime NOT NULL, - `content_tmp` longtext NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `llx_verifactudolibarr_add_tpls` --- - -LOCK TABLES `llx_verifactudolibarr_add_tpls` WRITE; -/*!40000 ALTER TABLE `llx_verifactudolibarr_add_tpls` DISABLE KEYS */; -INSERT INTO `llx_verifactudolibarr_add_tpls` VALUES -(1,'Verifactu casa interior','crabe_verifactu_casa_int',1,'1a70a6e54dd7a88e4fa45932ca280b90f349c9b435ce01e53995c7111152ecb7','2025-12-12 11:18:43','\n * Copyright (C) 2005-2012 Regis Houssin \n * Copyright (C) 2008 Raphael Bertrand \n * Copyright (C) 2010-2014 Juanjo Menent \n * Copyright (C) 2012 Christophe Battarel \n * Copyright (C) 2012 Cédric Salvador \n * Copyright (C) 2012-2014 Raphaël Doursenaud \n * Copyright (C) 2015 Marcos García \n * Copyright (C) 2017-2018 Ferran Marcet \n * Copyright (C) 2018-2020 Frédéric France \n * Copyright (C) 2022 Anthony Berton \n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n * or see https://www.gnu.org/\n */\n\n/**\n * \\file htdocs/core/modules/facture/doc/pdf_crabe.modules.php\n * \\ingroup facture\n * \\brief File of class to generate customers invoices from crabe model\n */\n\nrequire_once DOL_DOCUMENT_ROOT.\'/core/modules/facture/modules_facture.php\';\nrequire_once DOL_DOCUMENT_ROOT.\'/product/class/product.class.php\';\nrequire_once DOL_DOCUMENT_ROOT.\'/core/lib/company.lib.php\';\nrequire_once DOL_DOCUMENT_ROOT.\'/core/lib/functions2.lib.php\';\nrequire_once DOL_DOCUMENT_ROOT.\'/core/lib/pdf.lib.php\';\n\n\n/**\n * Class to generate the customer invoice PDF with template Crabe\n */\nclass pdf_crabe_verifactu_casa_int extends ModelePDFFactures\n{\n /**\n * @var DoliDb Database handler\n */\n public $db;\n\n /**\n * @var string model name\n */\n public $name;\n\n /**\n * @var string model description (short text)\n */\n public $description;\n\n /**\n * @var int Save the name of generated file as the main doc when generating a doc with this template\n */\n public $update_main_doc_field;\n\n /**\n * @var string document type\n */\n public $type;\n\n /**\n * Dolibarr version of the loaded document\n * @var string\n */\n public $version = \'dolibarr\';\n\n /**\n * @var int page_largeur\n */\n public $page_largeur;\n\n /**\n * @var int page_hauteur\n */\n public $page_hauteur;\n\n /**\n * @var array format\n */\n public $format;\n\n /**\n * @var int marge_gauche\n */\n public $marge_gauche;\n\n /**\n * @var int marge_droite\n */\n public $marge_droite;\n\n /**\n * @var int marge_haute\n */\n public $marge_haute;\n\n /**\n * @var int marge_basse\n */\n public $marge_basse;\n\n /**\n * Issuer\n * @var Societe Object that emits\n */\n public $emetteur;\n\n /**\n * @var bool Situation invoice type\n */\n public $situationinvoice;\n\n /**\n * @var float X position for the situation progress column\n */\n public $posxprogress;\n\n /**\n * @var int Category of operation\n */\n public $categoryOfOperation = -1; // unknown by default\n\n\n /**\n * Constructor\n *\n * @param DoliDB $db Database handler\n */\n public function __construct($db)\n {\n global $conf, $langs, $mysoc;\n\n // Translations\n $langs->loadLangs(array(\"main\", \"bills\"));\n\n $this->db = $db;\n $this->name = \"Verifactu casa interior\";\n $this->name_verifactu = \"crabe_verifactu_casa_int\";\n $this->description = $langs->trans(\'PDFCrabeDescription\');\n $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template\n\n // Dimension page\n $this->type = \'pdf\';\n $formatarray = pdf_getFormat();\n $this->page_largeur = $formatarray[\'width\'];\n $this->page_hauteur = $formatarray[\'height\'];\n $this->format = array($this->page_largeur, $this->page_hauteur);\n $this->marge_gauche = getDolGlobalInt(\'MAIN_PDF_MARGIN_LEFT\', 10);\n $this->marge_droite = getDolGlobalInt(\'MAIN_PDF_MARGIN_RIGHT\', 10);\n $this->marge_haute = getDolGlobalInt(\'MAIN_PDF_MARGIN_TOP\', 10);\n $this->marge_basse = getDolGlobalInt(\'MAIN_PDF_MARGIN_BOTTOM\', 10);\n\n $this->option_logo = 1; // Display logo\n $this->option_tva = 1; // Manage the vat option FACTURE_TVAOPTION\n $this->option_modereg = 1; // Display payment mode\n $this->option_condreg = 1; // Display payment terms\n $this->option_multilang = 1; // Available in several languages\n $this->option_escompte = 1; // Displays if there has been a discount\n $this->option_credit_note = 1; // Support credit notes\n $this->option_freetext = 1; // Support add of a personalised text\n $this->option_draft_watermark = 1; // Support add of a watermark on drafts\n $this->watermark = \'\';\n\n // Get source company\n $this->emetteur = $mysoc;\n if (empty($this->emetteur->country_code)) {\n $this->emetteur->country_code = substr($langs->defaultlang, -2); // By default, if was not defined\n }\n\n // Define position of columns\n $this->posxdesc = $this->marge_gauche + 1;\n if (getDolGlobalInt(\'PRODUCT_USE_UNITS\')) {\n $this->posxtva = 101;\n $this->posxup = 118;\n $this->posxqty = 135;\n $this->posxunit = 151;\n } else {\n $this->posxtva = 106;\n $this->posxup = 122;\n $this->posxqty = 145;\n $this->posxunit = 162;\n }\n $this->posxprogress = 151; // Only displayed for situation invoices\n $this->posxdiscount = 162;\n $this->posxprogress = 174;\n $this->postotalht = 174;\n if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) || !empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {\n $this->posxtva = $this->posxup;\n }\n $this->posxpicture = $this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH) ? 20 : $conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images\n if ($this->page_largeur < 210) { // To work with US executive format\n $this->posxpicture -= 20;\n $this->posxtva -= 20;\n $this->posxup -= 20;\n $this->posxqty -= 20;\n $this->posxunit -= 20;\n $this->posxdiscount -= 20;\n $this->posxprogress -= 20;\n $this->postotalht -= 20;\n }\n\n $this->tva = array();\n $this->tva_array = array();\n $this->localtax1 = array();\n $this->localtax2 = array();\n $this->atleastoneratenotnull = 0;\n $this->atleastonediscount = 0;\n $this->situationinvoice = false;\n }\n\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps\n /**\n * Function to build pdf onto disk\n *\n * @param Facture $object Object to generate\n * @param Translate $outputlangs Lang output object\n * @param string $srctemplatepath Full path of source filename for generator using a template file\n * @param int $hidedetails Do not show line details\n * @param int $hidedesc Do not show desc\n * @param int $hideref Do not show ref\n * @return int 1=OK, 0=KO\n */\n public function write_file($object, $outputlangs, $srctemplatepath = \'\', $hidedetails = 0, $hidedesc = 0, $hideref = 0)\n {\n // phpcs:enable\n global $user, $langs, $conf, $mysoc, $hookmanager, $nblines;\n \n $hideref = 1; //Casa interior\n\n dol_syslog(\"write_file outputlangs->defaultlang=\".(is_object($outputlangs) ? $outputlangs->defaultlang : \'null\'));\n\n if (!is_object($outputlangs)) {\n $outputlangs = $langs;\n }\n // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO\n if (!empty($conf->global->MAIN_USE_FPDF)) {\n $outputlangs->charset_output = \'ISO-8859-1\';\n }\n\n // Load translation files required by the page\n $outputlangs->loadLangs(array(\"main\", \"bills\", \"products\", \"dict\", \"companies\"));\n\n // Show Draft Watermark\n if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK))) {\n $this->watermark = $conf->global->FACTURE_DRAFT_WATERMARK;\n }\n\n global $outputlangsbis;\n $outputlangsbis = null;\n if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {\n $outputlangsbis = new Translate(\'\', $conf);\n $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);\n $outputlangsbis->loadLangs(array(\"main\", \"bills\", \"products\", \"dict\", \"companies\"));\n }\n\n $nblines = count($object->lines);\n\n // Loop on each lines to detect if there is at least one image to show\n $realpatharray = array();\n if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE)) {\n for ($i = 0; $i < $nblines; $i++) {\n if (empty($object->lines[$i]->fk_product)) {\n continue;\n }\n\n $objphoto = new Product($this->db);\n $objphoto->fetch($object->lines[$i]->fk_product);\n\n $pdir = get_exdir($object->lines[$i]->fk_product, 2, 0, 0, $objphoto, \'product\').$object->lines[$i]->fk_product.\"/photos/\";\n $dir = $conf->product->dir_output.\'/\'.$pdir;\n\n $realpath = \'\';\n foreach ($objphoto->liste_photos($dir, 1) as $key => $obj) {\n $filename = $obj[\'photo\'];\n //if ($obj[\'photo_vignette\']) $filename=\'thumbs/\'.$obj[\'photo_vignette\'];\n $realpath = $dir.$filename;\n break;\n }\n\n if ($realpath) {\n $realpatharray[$i] = $realpath;\n }\n }\n }\n if (count($realpatharray) == 0) {\n $this->posxpicture = $this->posxtva;\n }\n\n if ($conf->facture->dir_output) {\n $object->fetch_thirdparty();\n\n $deja_regle = $object->getSommePaiement((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? 1 : 0);\n $amount_credit_notes_included = $object->getSumCreditNotesUsed((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? 1 : 0);\n $amount_deposits_included = $object->getSumDepositsUsed((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? 1 : 0);\n\n // Definition of $dir and $file\n if ($object->specimen) {\n $dir = empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity];\n $file = $dir.\"/SPECIMEN.pdf\";\n } else {\n $objectref = dol_sanitizeFileName($object->ref);\n $dir = (empty($conf->facture->multidir_output[$object->entity]) ? $conf->facture->dir_output : $conf->facture->multidir_output[$object->entity]).\"/\".$objectref;\n $file = $dir.\"/\".$objectref.\".pdf\";\n }\n if (!file_exists($dir)) {\n if (dol_mkdir($dir) < 0) {\n $this->error = $langs->transnoentities(\"ErrorCanNotCreateDir\", $dir);\n return 0;\n }\n }\n\n if (file_exists($dir)) {\n // Add pdfgeneration hook\n if (!is_object($hookmanager)) {\n include_once DOL_DOCUMENT_ROOT.\'/core/class/hookmanager.class.php\';\n $hookmanager = new HookManager($this->db);\n }\n $hookmanager->initHooks(array(\'pdfgeneration\'));\n $parameters = array(\'file\'=>$file, \'object\'=>$object, \'outputlangs\'=>$outputlangs);\n global $action;\n $reshook = $hookmanager->executeHooks(\'beforePDFCreation\', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks\n\n // Set nblines with the new facture lines content after hook\n $nblines = count($object->lines);\n $nbpayments = count($object->getListOfPayments());\n\n // Create pdf instance\n $pdf = pdf_getInstance($this->format);\n $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance\n $pdf->SetAutoPageBreak(1, 0);\n\n $heightforinfotot = 50 + (4 * $nbpayments); // Height reserved to output the info and total part and payment part\n if ($heightforinfotot > 220) {\n $heightforinfotot = 220;\n }\n $heightforfreetext = (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT) ? $conf->global->MAIN_PDF_FREETEXT_HEIGHT : 5); // Height reserved to output the free text on last page\n $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin)\n if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)) {\n $heightforfooter += 6;\n }\n\n $heightforqrinvoice_firstpage = 0;\n if (getDolGlobalString(\'INVOICE_ADD_SWISS_QR_CODE\') == \'bottom\') {\n $heightforqrinvoice_firstpage = $this->getHeightForQRInvoice(1, $object, $langs);\n if ($heightforqrinvoice_firstpage > 0) {\n // Shrink infotot to a base 30\n $heightforinfotot = 30 + (4 * $nbpayments); // Height reserved to output the info and total part and payment part\n }\n }\n\n if (class_exists(\'TCPDF\')) {\n $pdf->setPrintHeader(false);\n $pdf->setPrintFooter(false);\n }\n $pdf->SetFont(pdf_getPDFFont($outputlangs));\n\n // Set path to the background PDF File\n if (!empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) {\n $logodir = $conf->mycompany->dir_output;\n if (!empty($conf->mycompany->multidir_output[$object->entity])) {\n $logodir = $conf->mycompany->multidir_output[$object->entity];\n }\n $pagecount = $pdf->setSourceFile($logodir.\'/\'.$conf->global->MAIN_ADD_PDF_BACKGROUND);\n $tplidx = $pdf->importPage(1);\n }\n\n $pdf->Open();\n $pagenb = 0;\n $pdf->SetDrawColor(128, 128, 128);\n\n $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));\n $pdf->SetSubject($outputlangs->transnoentities(\"PdfInvoiceTitle\"));\n $pdf->SetCreator(\"Dolibarr \".DOL_VERSION);\n $pdf->SetAuthor($mysoc->name.($user->id > 0 ? \' - \'.$outputlangs->convToOutputCharset($user->getFullName($outputlangs)) : \'\'));\n $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref).\" \".$outputlangs->transnoentities(\"PdfInvoiceTitle\").\" \".$outputlangs->convToOutputCharset($object->thirdparty->name));\n if (getDolGlobalString(\'MAIN_DISABLE_PDF_COMPRESSION\')) {\n $pdf->SetCompression(false);\n }\n\n // Set certificate\n $cert = empty($user->conf->CERTIFICATE_CRT) ? \'\' : $user->conf->CERTIFICATE_CRT;\n $certprivate = empty($user->conf->CERTIFICATE_CRT_PRIVATE) ? \'\' : $user->conf->CERTIFICATE_CRT_PRIVATE;\n // If user has no certificate, we try to take the company one\n if (!$cert) {\n $cert = empty($conf->global->CERTIFICATE_CRT) ? \'\' : $conf->global->CERTIFICATE_CRT;\n }\n if (!$certprivate) {\n $certprivate = empty($conf->global->CERTIFICATE_CRT_PRIVATE) ? \'\' : $conf->global->CERTIFICATE_CRT_PRIVATE;\n }\n // If a certificate is found\n if ($cert) {\n $info = array(\n \'Name\' => $this->emetteur->name,\n \'Location\' => getCountry($this->emetteur->country_code, 0),\n \'Reason\' => \'INVOICE\',\n \'ContactInfo\' => $this->emetteur->email\n );\n $pdf->setSignature($cert, $certprivate, $this->emetteur->name, \'\', 2, $info);\n }\n\n $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right\n\n // Set $this->atleastonediscount if you have at least one discount\n // and determine category of operation\n $categoryOfOperation = 0;\n $nbProduct = 0;\n $nbService = 0;\n for ($i = 0; $i < $nblines; $i++) {\n if ($object->lines[$i]->remise_percent) {\n $this->atleastonediscount++;\n }\n\n // determine category of operation\n if ($categoryOfOperation < 2) {\n $lineProductType = $object->lines[$i]->product_type;\n if ($lineProductType == Product::TYPE_PRODUCT) {\n $nbProduct++;\n } elseif ($lineProductType == Product::TYPE_SERVICE) {\n $nbService++;\n }\n if ($nbProduct > 0 && $nbService > 0) {\n // mixed products and services\n $categoryOfOperation = 2;\n }\n }\n }\n // determine category of operation\n if ($categoryOfOperation <= 0) {\n // only services\n if ($nbProduct == 0 && $nbService > 0) {\n $categoryOfOperation = 1;\n }\n }\n $this->categoryOfOperation = $categoryOfOperation;\n if (empty($this->atleastonediscount)) { // retrieve space not used by discount\n $delta = ($this->posxprogress - $this->posxdiscount);\n $this->posxpicture += $delta;\n $this->posxtva += $delta;\n $this->posxup += $delta;\n $this->posxqty += $delta;\n $this->posxunit += $delta;\n $this->posxdiscount += $delta;\n // post of fields after are not modified, stay at same position\n }\n\n $progress_width = 0;\n // Situation invoice handling\n if ($object->situation_cycle_ref && empty($conf->global->MAIN_PDF_HIDE_SITUATION)) {\n $this->situationinvoice = true;\n $progress_width = 10;\n $this->posxpicture -= $progress_width;\n $this->posxtva -= $progress_width;\n $this->posxup -= $progress_width;\n $this->posxqty -= $progress_width;\n $this->posxunit -= $progress_width;\n $this->posxdiscount -= $progress_width;\n $this->posxprogress -= $progress_width;\n }\n\n // New page\n $pdf->AddPage();\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n $pagenb++;\n\n // Output header (logo, ref and address blocks). This is first call for first page.\n $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->MultiCell(0, 3, \'\'); // Set interline to 3\n $pdf->SetTextColor(0, 0, 0);\n\n // $pdf->GetY() here can\'t be used. It is bottom of the second addresse box but first one may be higher\n\n // $tab_top is y where we must continue content (90 = 42 + 48: 42 is height of logo and ref, 48 is address blocks)\n $tab_top = 90 + $top_shift; // top_shift is an addition for linked objects or addons (0 in most cases)\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n\n // You can add more thing under header here, if you increase $extra_under_address_shift too.\n $extra_under_address_shift = 0;\n $qrcodestring = \'\';\n if (!empty($conf->global->INVOICE_ADD_ZATCA_QR_CODE)) {\n $qrcodestring = $object->buildZATCAQRString();\n } elseif (getDolGlobalString(\'INVOICE_ADD_SWISS_QR_CODE\') == \'1\') {\n $qrcodestring = $object->buildSwitzerlandQRString();\n }\n\n if ($qrcodestring) {\n $qrcodecolor = array(\'25\', \'25\', \'25\');\n // set style for QR-code\n $styleQr = array(\n \'border\' => false,\n \'padding\' => 0,\n \'fgcolor\' => $qrcodecolor,\n \'bgcolor\' => false, //array(255,255,255)\n \'module_width\' => 1, // width of a single module in points\n \'module_height\' => 1 // height of a single module in points\n );\n $pdf->write2DBarcode($qrcodestring, \'QRCODE,M\', $this->marge_gauche, $tab_top - 5, 25, 25, $styleQr, \'N\');\n $extra_under_address_shift += 25;\n }\n\n // Call hook printUnderHeaderPDFline\n $parameters = array(\n \'object\' => $object,\n \'i\' => $i,\n \'pdf\' =>& $pdf,\n \'outputlangs\' => $outputlangs,\n \'hidedetails\' => $hidedetails\n );\n $reshook = $hookmanager->executeHooks(\'printUnderHeaderPDFline\', $parameters, $this); // Note that $object may have been modified by hook\n if (!empty($hookmanager->resArray[\'extra_under_address_shift\'])) {\n $extra_under_address_shift += $hookmanager->resArray[\'extra_under_header_shift\'];\n }\n\n $tab_top += $extra_under_address_shift;\n $tab_top_newpage += 0;\n\n // Incoterm\n $height_incoterms = 0;\n if (isModEnabled(\'incoterm\')) {\n $desc_incoterms = $object->getIncotermsForPDF();\n if ($desc_incoterms) {\n $tab_top -= 2;\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($desc_incoterms), 0, 1);\n $nexY = $pdf->GetY();\n $height_incoterms = $nexY - $tab_top;\n\n // Rect takes a length in 3rd parameter\n $pdf->SetDrawColor(192, 192, 192);\n $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_incoterms + 1);\n\n $tab_top = $nexY + 6;\n }\n }\n\n // Display notes\n $notetoshow = empty($object->note_public) ? \'\' : $object->note_public;\n if (!empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) {\n // Get first sale rep\n if (is_object($object->thirdparty)) {\n $salereparray = $object->thirdparty->getSalesRepresentatives($user);\n $salerepobj = new User($this->db);\n $salerepobj->fetch($salereparray[0][\'id\']);\n if (!empty($salerepobj->signature)) {\n $notetoshow = dol_concatdesc($notetoshow, $salerepobj->signature);\n }\n }\n }\n // Extrafields in note\n $extranote = $this->getExtrafieldsInHtml($object, $outputlangs);\n if (!empty($extranote)) {\n $notetoshow = dol_concatdesc($notetoshow, $extranote);\n }\n if ($notetoshow) {\n $tab_top -= 2;\n\n $substitutionarray = pdf_getSubstitutionArray($outputlangs, null, $object);\n complete_substitutions_array($substitutionarray, $outputlangs, $object);\n\n $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);\n $notetoshow = convertBackOfficeMediasLinksToPublicLinks($notetoshow);\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->writeHTMLCell(190, 3, $this->posxdesc - 1, $tab_top - 1, dol_htmlentitiesbr($notetoshow), 0, 1);\n $nexY = $pdf->GetY();\n $height_note = $nexY - $tab_top;\n\n // Rect takes a length in 3rd parameter\n $pdf->SetDrawColor(192, 192, 192);\n $pdf->Rect($this->marge_gauche, $tab_top - 1, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $height_note + 1);\n\n $tab_top = $nexY + 6;\n }\n\n $iniY = $tab_top + 7;\n $curY = $tab_top + 7;\n $nexY = $tab_top + 7;\n\n // Loop on each lines\n for ($i = 0; $i < $nblines; $i++) {\n $curY = $nexY;\n $pdf->SetFont(\'\', \'\', $default_font_size - 1); // Into loop to work with multipage\n $pdf->SetTextColor(0, 0, 0);\n\n // Define size of image if we need it\n $imglinesize = array();\n if (!empty($realpatharray[$i])) {\n $imglinesize = pdf_getSizeForImage($realpatharray[$i]);\n }\n\n $pdf->setTopMargin($tab_top_newpage);\n $page_bottom_margin = $heightforfooter + $heightforfreetext + $heightforinfotot + $this->getHeightForQRInvoice($pdf->getPage(), $object, $langs);\n $pdf->setPageOrientation(\'\', 1, $page_bottom_margin);\n $pageposbefore = $pdf->getPage();\n\n $showpricebeforepagebreak = 1;\n $posYAfterImage = 0;\n $posYAfterDescription = 0;\n\n // We start with Photo of product line\n if (isset($imglinesize[\'width\']) && isset($imglinesize[\'height\']) && ($curY + $imglinesize[\'height\']) > ($this->page_hauteur - $page_bottom_margin)) { // If photo too high, we moved completely on new page\n $pdf->AddPage(\'\', \'\', true);\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n $pdf->setPage($pageposbefore + 1);\n\n $curY = $tab_top_newpage;\n\n // Allows data in the first page if description is long enough to break in multiples pages\n if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {\n $showpricebeforepagebreak = 1;\n } else {\n $showpricebeforepagebreak = 0;\n }\n }\n\n if (isset($imglinesize[\'width\']) && isset($imglinesize[\'height\'])) {\n $curX = $this->posxpicture - 1;\n $pdf->Image($realpatharray[$i], $curX + (($this->posxtva - $this->posxpicture - $imglinesize[\'width\']) / 2), $curY, $imglinesize[\'width\'], $imglinesize[\'height\'], \'\', \'\', \'\', 2, 300); // Use 300 dpi\n // $pdf->Image does not increase value return by getY, so we save it manually\n $posYAfterImage = $curY + $imglinesize[\'height\'];\n }\n\n // Description of product line\n $curX = $this->posxdesc - 1;\n\n $pdf->startTransaction();\n $this->pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX - $progress_width, 3, $curX, $curY, $hideref, $hidedesc);\n $pageposafter = $pdf->getPage();\n if ($pageposafter > $pageposbefore) { // There is a pagebreak\n $pdf->rollbackTransaction(true);\n $pageposafter = $pageposbefore;\n //print $pageposafter.\'-\'.$pageposbefore;exit;\n $pdf->setPageOrientation(\'\', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it.\n $this->pdf_writelinedesc($pdf, $object, $i, $outputlangs, $this->posxpicture - $curX - $progress_width, 3, $curX, $curY, $hideref, $hidedesc);\n $pageposafter = $pdf->getPage();\n $posyafter = $pdf->GetY();\n //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;\n if ($posyafter > ($this->page_hauteur - $page_bottom_margin)) { // There is no space left for total+free text\n if ($i == ($nblines - 1)) { // No more lines, and no space left to show total, so we create a new page\n $pdf->AddPage(\'\', \'\', true);\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n $pdf->setPage($pageposafter + 1);\n }\n } else {\n // We found a page break\n\n // Allows data in the first page if description is long enough to break in multiples pages\n if (!empty($conf->global->MAIN_PDF_DATA_ON_FIRST_PAGE)) {\n $showpricebeforepagebreak = 1;\n } else {\n $showpricebeforepagebreak = 0;\n }\n }\n } else // No pagebreak\n {\n $pdf->commitTransaction();\n }\n $posYAfterDescription = $pdf->GetY();\n\n $nexY = $pdf->GetY();\n $pageposafter = $pdf->getPage();\n $pdf->setPage($pageposbefore);\n $pdf->setTopMargin($this->marge_haute);\n $pdf->setPageOrientation(\'\', 1, 0); // The only function to edit the bottom margin of current page to set it.\n\n // We suppose that a too long description or photo were moved completely on next page\n if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {\n $pdf->setPage($pageposafter);\n $curY = $tab_top_newpage;\n }\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 1); // We reposition the default font\n\n // VAT Rate\n if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {\n $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);\n $pdf->SetXY($this->posxtva - 5, $curY);\n $pdf->MultiCell($this->posxup - $this->posxtva + 4, 3, $vat_rate, 0, \'R\');\n }\n\n // Unit price before discount\n $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);\n $pdf->SetXY($this->posxup, $curY);\n $pdf->MultiCell($this->posxqty - $this->posxup - 0.8, 3, $up_excl_tax, 0, \'R\', 0);\n\n // Quantity\n $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);\n $pdf->SetXY($this->posxqty, $curY);\n $pdf->MultiCell($this->posxunit - $this->posxqty - 0.8, 4, $qty, 0, \'R\'); // Enough for 6 chars\n\n // Unit\n if (getDolGlobalInt(\'PRODUCT_USE_UNITS\')) {\n $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);\n $pdf->SetXY($this->posxunit, $curY);\n $pdf->MultiCell($this->posxdiscount - $this->posxunit - 0.8, 4, $unit, 0, \'L\');\n }\n\n // Discount on line\n if ($object->lines[$i]->remise_percent) {\n $pdf->SetXY($this->posxdiscount - 2, $curY);\n $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);\n $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 2, 3, $remise_percent, 0, \'R\');\n }\n\n // Situation progress\n if ($this->situationinvoice) {\n $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails);\n $pdf->SetXY($this->posxprogress, $curY);\n $pdf->MultiCell($this->postotalht - $this->posxprogress + 1, 3, $progress, 0, \'R\');\n }\n\n // Total HT line\n $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);\n $pdf->SetXY($this->postotalht, $curY);\n $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->postotalht, 3, $total_excl_tax, 0, \'R\', 0);\n\n\n $sign = 1;\n if (isset($object->type) && $object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {\n $sign = -1;\n }\n // Collection of totals by value of VAT in $this->tva[\"taux\"]=total_tva\n $prev_progress = $object->lines[$i]->get_prev_progress($object->id);\n if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) { // Compute progress from previous situation\n if (isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) {\n $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;\n } else {\n $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;\n }\n } else {\n if (isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) {\n $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva;\n } else {\n $tvaligne = $sign * $object->lines[$i]->total_tva;\n }\n }\n\n $localtax1ligne = $object->lines[$i]->total_localtax1;\n $localtax2ligne = $object->lines[$i]->total_localtax2;\n $localtax1_rate = $object->lines[$i]->localtax1_tx;\n $localtax2_rate = $object->lines[$i]->localtax2_tx;\n $localtax1_type = $object->lines[$i]->localtax1_type;\n $localtax2_type = $object->lines[$i]->localtax2_type;\n\n // TODO remise_percent is an obsolete field for object parent\n /*if ($object->remise_percent) {\n $tvaligne -= ($tvaligne * $object->remise_percent) / 100;\n }\n if ($object->remise_percent) {\n $localtax1ligne -= ($localtax1ligne * $object->remise_percent) / 100;\n }\n if ($object->remise_percent) {\n $localtax2ligne -= ($localtax2ligne * $object->remise_percent) / 100;\n }*/\n\n $vatrate = (string) $object->lines[$i]->tva_tx;\n\n // Retrieve type from database for backward compatibility with old records\n if ((!isset($localtax1_type) || $localtax1_type == \'\' || !isset($localtax2_type) || $localtax2_type == \'\') // if tax type not defined\n && (!empty($localtax1_rate) || !empty($localtax2_rate))) { // and there is local tax\n $localtaxtmp_array = getLocalTaxesFromRate($vatrate, 0, $object->thirdparty, $mysoc);\n $localtax1_type = isset($localtaxtmp_array[0]) ? $localtaxtmp_array[0] : \'\';\n $localtax2_type = isset($localtaxtmp_array[2]) ? $localtaxtmp_array[2] : \'\';\n }\n\n // retrieve global local tax\n if ($localtax1_type && $localtax1ligne != 0) {\n if (empty($this->localtax1[$localtax1_type][$localtax1_rate])) {\n $this->localtax1[$localtax1_type][$localtax1_rate] = $localtax1ligne;\n } else {\n $this->localtax1[$localtax1_type][$localtax1_rate] += $localtax1ligne;\n }\n }\n if ($localtax2_type && $localtax2ligne != 0) {\n if (empty($this->localtax2[$localtax2_type][$localtax2_rate])) {\n $this->localtax2[$localtax2_type][$localtax2_rate] = $localtax2ligne;\n } else {\n $this->localtax2[$localtax2_type][$localtax2_rate] += $localtax2ligne;\n }\n }\n\n if (($object->lines[$i]->info_bits & 0x01) == 0x01) {\n $vatrate .= \'*\';\n }\n\n // Fill $this->tva and $this->tva_array\n if (!isset($this->tva[$vatrate])) {\n $this->tva[$vatrate] = 0;\n }\n $this->tva[$vatrate] += $tvaligne; // ->tva is abandonned, we use now ->tva_array that is more complete\n $vatcode = $object->lines[$i]->vat_src_code;\n if (empty($this->tva_array[$vatrate.($vatcode ? \' (\'.$vatcode.\')\' : \'\')][\'amount\'])) {\n $this->tva_array[$vatrate.($vatcode ? \' (\'.$vatcode.\')\' : \'\')][\'amount\'] = 0;\n }\n $this->tva_array[$vatrate.($vatcode ? \' (\'.$vatcode.\')\' : \'\')] = array(\'vatrate\'=>$vatrate, \'vatcode\'=>$vatcode, \'amount\'=> $this->tva_array[$vatrate.($vatcode ? \' (\'.$vatcode.\')\' : \'\')][\'amount\'] + $tvaligne);\n\n if ($posYAfterImage > $posYAfterDescription) {\n $nexY = $posYAfterImage;\n }\n\n // Add line\n if (!empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblines - 1)) {\n $pdf->setPage($pageposafter);\n $pdf->SetLineStyle(array(\'dash\'=>\'1,1\', \'color\'=>array(80, 80, 80)));\n //$pdf->SetDrawColor(190,190,200);\n $pdf->line($this->marge_gauche, $nexY + 1, $this->page_largeur - $this->marge_droite, $nexY + 1);\n $pdf->SetLineStyle(array(\'dash\'=>0));\n }\n\n $nexY += 2; // Add space between lines\n\n // Detect if some page were added automatically and output _tableau for past pages\n while ($pagenb < $pageposafter) {\n $pdf->setPage($pagenb);\n if ($pagenb == 1) {\n $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforqrinvoice_firstpage, 0, $outputlangs, 0, 1, $object->multicurrency_code);\n } else {\n $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);\n }\n $this->_pagefoot($pdf, $object, $outputlangs, 1, $this->getHeightForQRInvoice($pagenb, $object, $langs));\n $pagenb++;\n $pdf->setPage($pagenb);\n $pdf->setPageOrientation(\'\', 1, 0); // The only function to edit the bottom margin of current page to set it.\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n }\n if (isset($object->lines[$i + 1]->pagebreak) && $object->lines[$i + 1]->pagebreak) {\n if ($pagenb == 1) {\n $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforqrinvoice_firstpage, 0, $outputlangs, 0, 1, $object->multicurrency_code);\n } else {\n $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);\n }\n $this->_pagefoot($pdf, $object, $outputlangs, 1, $this->getHeightForQRInvoice($pagenb, $object, $langs));\n // New page\n $pdf->AddPage();\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n $pagenb++;\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n }\n }\n\n // Show square\n if ($pagenb == 1) {\n $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter - $heightforqrinvoice_firstpage, 0, $outputlangs, 0, 0, $object->multicurrency_code);\n $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter - $heightforqrinvoice_firstpage + 1;\n } else {\n $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);\n $bottomlasttab = $this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;\n }\n dol_syslog(\"bottomlasttab=\".$bottomlasttab.\" this->page_hauteur=\".$this->page_hauteur.\" heightforinfotot=\".$heightforinfotot.\" heightforfreetext=\".$heightforfreetext.\" heightforfooter=\".$heightforfooter);\n\n // Display info area\n $posy = $this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs, $outputlangsbis);\n\n // Display total area\n $posy = $this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs, $outputlangsbis);\n\n // Display Payments area\n if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) {\n $posy = $this->_tableau_versements($pdf, $object, $posy, $outputlangs, $heightforfooter);\n }\n\n // Pagefoot\n $this->_pagefoot($pdf, $object, $outputlangs, 0, $this->getHeightForQRInvoice($pdf->getPage(), $object, $langs));\n if (method_exists($pdf, \'AliasNbPages\')) {\n $pdf->AliasNbPages();\n }\n\n if (getDolGlobalString(\'INVOICE_ADD_SWISS_QR_CODE\') == \'bottom\') {\n $result = $this->addBottomQRInvoice($pdf, $object, $outputlangs);\n if (!$result) {\n $pdf->Close();\n return 0;\n }\n }\n $pdf->Close();\n\n $pdf->Output($file, \'F\');\n\n // Add pdfgeneration hook\n $hookmanager->initHooks(array(\'pdfgeneration\'));\n $parameters = array(\'file\'=>$file, \'object\'=>$object, \'outputlangs\'=>$outputlangs);\n global $action;\n $reshook = $hookmanager->executeHooks(\'afterPDFCreation\', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks\n if ($reshook < 0) {\n $this->error = $hookmanager->error;\n $this->errors = $hookmanager->errors;\n }\n\n dolChmod($file);\n\n $this->result = array(\'fullpath\'=>$file);\n\n return 1; // No error\n } else {\n $this->error = $langs->transnoentities(\"ErrorCanNotCreateDir\", $dir);\n return 0;\n }\n } else {\n $this->error = $langs->transnoentities(\"ErrorConstantNotDefined\", \"FAC_OUTPUTDIR\");\n return 0;\n }\n }\n\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show payments table\n *\n * @param TCPDF $pdf Object PDF\n * @param Facture $object Object invoice\n * @param int $posy Position y in PDF\n * @param Translate $outputlangs Object langs for output\n * @param int $heightforfooter Height for footer\n * @return int <0 if KO, >0 if OK\n */\n protected function _tableau_versements(&$pdf, $object, $posy, $outputlangs, $heightforfooter = 0)\n {\n // phpcs:enable\n global $conf;\n\n $sign = 1;\n if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {\n $sign = -1;\n }\n\n $current_page = $pdf->getPage();\n $tab3_posx = 120;\n $tab3_top = $posy + 8;\n $tab3_width = 80;\n $tab3_height = 4;\n if ($this->page_largeur < 210) { // To work with US executive format\n $tab3_posx -= 15;\n }\n\n $default_font_size = pdf_getPDFFontSize($outputlangs);\n\n $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height);\n\n $y = 0;\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 4);\n\n\n // Loop on each discount available (deposits and credit notes and excess of payment included)\n $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,\";\n $sql .= \" re.description, re.fk_facture_source,\";\n $sql .= \" f.type, f.datef\";\n $sql .= \" FROM \".MAIN_DB_PREFIX.\"societe_remise_except as re, \".MAIN_DB_PREFIX.\"facture as f\";\n $sql .= \" WHERE re.fk_facture_source = f.rowid AND re.fk_facture = \".((int) $object->id);\n $resql = $this->db->query($sql);\n if ($resql) {\n $num = $this->db->num_rows($resql);\n $i = 0;\n $invoice = new Facture($this->db);\n while ($i < $num) {\n $y += 3;\n if ($tab3_top + $y >= ($this->page_hauteur - $heightforfooter)) {\n $y = 0;\n $current_page++;\n $pdf->AddPage(\'\', \'\', true);\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n $pdf->setPage($current_page);\n $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height);\n }\n\n $obj = $this->db->fetch_object($resql);\n\n if ($obj->type == 2) {\n $text = $outputlangs->transnoentities(\"CreditNote\");\n } elseif ($obj->type == 3) {\n $text = $outputlangs->transnoentities(\"Deposit\");\n } elseif ($obj->type == 0) {\n $text = $outputlangs->transnoentities(\"ExcessReceived\");\n } else {\n $text = $outputlangs->transnoentities(\"UnknownType\");\n }\n\n $invoice->fetch($obj->fk_facture_source);\n\n $pdf->SetXY($tab3_posx, $tab3_top + $y);\n $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($obj->datef), \'day\', false, $outputlangs, true), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 21, $tab3_top + $y);\n $pdf->MultiCell(20, 3, price((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 40, $tab3_top + $y);\n $pdf->MultiCell(20, 3, $text, 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 58, $tab3_top + $y);\n $pdf->MultiCell(20, 3, $invoice->ref, 0, \'L\', 0);\n\n $pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);\n\n $i++;\n }\n } else {\n $this->error = $this->db->lasterror();\n return -1;\n }\n\n // Loop on each payment\n // TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql\n $sql = \"SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,\";\n $sql .= \" cp.code\";\n $sql .= \" FROM \".MAIN_DB_PREFIX.\"paiement_facture as pf, \".MAIN_DB_PREFIX.\"paiement as p\";\n $sql .= \" LEFT JOIN \".MAIN_DB_PREFIX.\"c_paiement as cp ON p.fk_paiement = cp.id\";\n $sql .= \" WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = \".((int) $object->id);\n //$sql.= \" WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1\";\n $sql .= \" ORDER BY p.datep\";\n\n $resql = $this->db->query($sql);\n if ($resql) {\n $num = $this->db->num_rows($resql);\n $i = 0;\n while ($i < $num) {\n $y += 3;\n if ($tab3_top + $y >= ($this->page_hauteur - $heightforfooter)) {\n $y = 0;\n $current_page++;\n $pdf->AddPage(\'\', \'\', true);\n if (!empty($tplidx)) {\n $pdf->useTemplate($tplidx);\n }\n if (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\')) {\n $top_shift = $this->_pagehead($pdf, $object, 0, $outputlangs);\n $tab_top_newpage = (!getDolGlobalInt(\'MAIN_PDF_DONOTREPEAT_HEAD\') ? 42 + $top_shift : 10);\n }\n $pdf->setPage($current_page);\n $this->_tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top + $y - 3, $tab3_width, $tab3_height);\n }\n\n $row = $this->db->fetch_object($resql);\n\n $pdf->SetXY($tab3_posx, $tab3_top + $y);\n $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date), \'day\', false, $outputlangs, true), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 21, $tab3_top + $y);\n $pdf->MultiCell(20, 3, price($sign * ((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 40, $tab3_top + $y);\n $oper = $outputlangs->transnoentitiesnoconv(\"PaymentTypeShort\".$row->code);\n\n $pdf->MultiCell(20, 3, $oper, 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 58, $tab3_top + $y);\n $pdf->MultiCell(30, 3, $row->num, 0, \'L\', 0);\n\n $pdf->line($tab3_posx, $tab3_top + $y + 3, $tab3_posx + $tab3_width, $tab3_top + $y + 3);\n\n $i++;\n }\n\n return $tab3_top + $y + 3;\n } else {\n $this->error = $this->db->lasterror();\n return -1;\n }\n }\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Function _tableau_versements_header\n *\n * @param TCPDF $pdf Object PDF\n * @param Facture $object Object invoice\n * @param Translate $outputlangs Object langs for output\n * @param int $default_font_size Font size\n * @param int $tab3_posx pos x\n * @param int $tab3_top pos y\n * @param int $tab3_width width\n * @param int $tab3_height height\n * @return void\n */\n protected function _tableau_versements_header($pdf, $object, $outputlangs, $default_font_size, $tab3_posx, $tab3_top, $tab3_width, $tab3_height)\n {\n // phpcs:enable\n $title = $outputlangs->transnoentities(\"PaymentsAlreadyDone\");\n if ($object->type == 2) {\n $title = $outputlangs->transnoentities(\"PaymentsBackAlreadyDone\");\n }\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 3);\n $pdf->SetXY($tab3_posx, $tab3_top - 4);\n $pdf->MultiCell(60, 3, $title, 0, \'L\', 0);\n\n $pdf->line($tab3_posx, $tab3_top, $tab3_posx + $tab3_width, $tab3_top);\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 4);\n $pdf->SetXY($tab3_posx, $tab3_top);\n $pdf->MultiCell(20, 3, $outputlangs->transnoentities(\"Payment\"), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 21, $tab3_top);\n $pdf->MultiCell(20, 3, $outputlangs->transnoentities(\"Amount\"), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 40, $tab3_top);\n $pdf->MultiCell(20, 3, $outputlangs->transnoentities(\"Type\"), 0, \'L\', 0);\n $pdf->SetXY($tab3_posx + 58, $tab3_top);\n $pdf->MultiCell(20, 3, $outputlangs->transnoentities(\"Num\"), 0, \'L\', 0);\n\n $pdf->line($tab3_posx, $tab3_top - 1 + $tab3_height, $tab3_posx + $tab3_width, $tab3_top - 1 + $tab3_height);\n }\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show miscellaneous information (payment mode, payment term, ...)\n *\n * @param TCPDF $pdf Object PDF\n * @param Facture $object Object to show\n * @param int $posy Y\n * @param Translate $outputlangs Langs object\n * @param Translate $outputlangsbis Object lang for output bis\n * @return int Pos y\n */\n protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis)\n {\n // phpcs:enable\n global $conf, $mysoc;\n\n $default_font_size = pdf_getPDFFontSize($outputlangs);\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n\n // If France, show VAT mention if not applicable\n if ($this->emetteur->country_code == \'FR\' && empty($mysoc->tva_assuj)) {\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $pdf->SetXY($this->marge_gauche, $posy);\n if ($mysoc->forme_juridique_code == 92) {\n $pdf->MultiCell(100, 3, $outputlangs->transnoentities(\"VATIsNotUsedForInvoiceAsso\"), 0, \'L\', 0);\n } else {\n $pdf->MultiCell(100, 3, $outputlangs->transnoentities(\"VATIsNotUsedForInvoice\"), 0, \'L\', 0);\n }\n\n $posy = $pdf->GetY() + 4;\n }\n\n $posxval = 52;\n $posxend = 110; // End of x for text on left side\n if ($this->page_largeur < 210) { // To work with US executive format\n $posxend -= 10;\n }\n\n // Show payments conditions\n if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement)) {\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $pdf->SetXY($this->marge_gauche, $posy);\n $titre = $outputlangs->transnoentities(\"PaymentConditions\").\':\';\n $pdf->MultiCell(43, 4, $titre, 0, \'L\');\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->SetXY($posxval, $posy);\n $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);\n $lib_condition_paiement = str_replace(\'\\n\', \"\\n\", $lib_condition_paiement);\n $pdf->MultiCell(67, 4, $lib_condition_paiement, 0, \'L\');\n\n $posy = $pdf->GetY() + 3; // We need spaces for 2 lines payment conditions\n }\n\n // Show category of operations\n if (getDolGlobalInt(\'INVOICE_CATEGORY_OF_OPERATION\') == 2 && $this->categoryOfOperation >= 0) {\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $pdf->SetXY($this->marge_gauche, $posy);\n $categoryOfOperationTitle = $outputlangs->transnoentities(\"MentionCategoryOfOperations\").\' : \';\n $pdf->MultiCell($posxval - $this->marge_gauche, 4, $categoryOfOperationTitle, 0, \'L\');\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->SetXY($posxval, $posy);\n $categoryOfOperationLabel = $outputlangs->transnoentities(\"MentionCategoryOfOperations\" . $this->categoryOfOperation);\n $pdf->MultiCell($posxend - $posxval, 4, $categoryOfOperationLabel, 0, \'L\');\n\n $posy = $pdf->GetY() + 3; // for 2 lines\n }\n\n if ($object->type != 2) {\n // Check a payment mode is defined\n if (empty($object->mode_reglement_code)\n && !getDolGlobalInt(\'FACTURE_CHQ_NUMBER\')\n && !getDolGlobalInt(\'FACTURE_RIB_NUMBER\')) {\n $this->error = $outputlangs->transnoentities(\"ErrorNoPaiementModeConfigured\");\n } elseif (($object->mode_reglement_code == \'CHQ\' && !getDolGlobalInt(\'FACTURE_CHQ_NUMBER\') && empty($object->fk_account) && empty($object->fk_bank))\n || ($object->mode_reglement_code == \'VIR\' && !getDolGlobalInt(\'FACTURE_RIB_NUMBER\') && empty($object->fk_account) && empty($object->fk_bank))) {\n // Avoid having any valid PDF with setup that is not complete\n $outputlangs->load(\"errors\");\n\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->SetTextColor(200, 0, 0);\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $this->error = $outputlangs->transnoentities(\"ErrorPaymentModeDefinedToWithoutSetup\", $object->mode_reglement_code);\n $pdf->MultiCell(80, 3, $this->error, 0, \'L\', 0);\n $pdf->SetTextColor(0, 0, 0);\n\n $posy = $pdf->GetY() + 1;\n }\n\n // Show payment mode\n if (!empty($object->mode_reglement_code)\n && $object->mode_reglement_code != \'CHQ\'\n && $object->mode_reglement_code != \'VIR\') {\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $pdf->SetXY($this->marge_gauche, $posy);\n $titre = $outputlangs->transnoentities(\"PaymentMode\").\':\';\n $pdf->MultiCell(80, 5, $titre, 0, \'L\');\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->SetXY($posxval, $posy);\n $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);\n //#21654: add account number used for the debit\n if ($object->mode_reglement_code == \"PRE\") {\n require_once DOL_DOCUMENT_ROOT.\'/societe/class/companybankaccount.class.php\';\n $bac = new CompanyBankAccount($this->db);\n $bac->fetch(0, $object->thirdparty->id);\n $iban= $bac->iban.(($bac->iban && $bac->bic) ? \' / \' : \'\').$bac->bic;\n $lib_mode_reg .= \' \'.$outputlangs->trans(\"PaymentTypePREdetails\", dol_trunc($iban, 6, \'right\', \'UTF-8\', 1));\n }\n $pdf->MultiCell(80, 5, $lib_mode_reg, 0, \'L\');\n\n $posy = $pdf->GetY();\n }\n\n // Show if Option VAT debit option is on also if transmitter is french\n // Decret n°2099-1299 2022-10-07\n // French mention : \"Option pour le paiement de la taxe d\'après les débits\"\n if ($this->emetteur->country_code == \'FR\') {\n if (isset($conf->global->TAX_MODE) && $conf->global->TAX_MODE == 1) {\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->writeHTMLCell(80, 5, \'\', \'\', $outputlangs->transnoentities(\"MentionVATDebitOptionIsOn\"), 0, 1);\n\n $posy = $pdf->GetY() + 1;\n }\n }\n\n // Show online payment link\n if (empty($object->mode_reglement_code) || $object->mode_reglement_code == \'CB\' || $object->mode_reglement_code == \'VAD\') {\n $useonlinepayment = 0;\n if (!empty($conf->global->PDF_SHOW_LINK_TO_ONLINE_PAYMENT)) {\n if (isModEnabled(\'paypal\')) {\n $useonlinepayment++;\n }\n if (isModEnabled(\'stripe\')) {\n $useonlinepayment++;\n }\n if (isModEnabled(\'paybox\')) {\n $useonlinepayment++;\n }\n }\n\n if ($object->statut != Facture::STATUS_DRAFT && $useonlinepayment) {\n require_once DOL_DOCUMENT_ROOT.\'/core/lib/payments.lib.php\';\n global $langs;\n\n $langs->loadLangs(array(\'payment\', \'paybox\', \'stripe\'));\n $servicename = $langs->transnoentities(\'Online\');\n $paiement_url = getOnlinePaymentUrl(\'\', \'invoice\', $object->ref, \'\', \'\', \'\');\n $linktopay = $langs->trans(\"ToOfferALinkForOnlinePayment\", $servicename).\' \'.$outputlangs->transnoentities(\"ClickHere\").\'\';\n\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->writeHTMLCell(80, 5, \'\', \'\', dol_htmlentitiesbr($linktopay), 0, 1);\n\n $posy = $pdf->GetY() + 1;\n }\n }\n\n // Show payment mode CHQ\n if (empty($object->mode_reglement_code) || $object->mode_reglement_code == \'CHQ\') {\n // If payment mode unregulated or payment mode forced to CHQ\n if (getDolGlobalInt(\'FACTURE_CHQ_NUMBER\')) {\n $diffsizetitle = (empty($conf->global->PDF_DIFFSIZE_TITLE) ? 3 : $conf->global->PDF_DIFFSIZE_TITLE);\n\n if ($conf->global->FACTURE_CHQ_NUMBER > 0) {\n $account = new Account($this->db);\n $account->fetch(getDolGlobalInt(\'FACTURE_CHQ_NUMBER\'));\n\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->SetFont(\'\', \'B\', $default_font_size - $diffsizetitle);\n $pdf->MultiCell(100, 3, $outputlangs->transnoentities(\'PaymentByChequeOrderedTo\', $account->proprio), 0, \'L\', 0);\n $posy = $pdf->GetY() + 1;\n\n if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->SetFont(\'\', \'\', $default_font_size - $diffsizetitle);\n $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, \'L\', 0);\n $posy = $pdf->GetY() + 2;\n }\n }\n if ($conf->global->FACTURE_CHQ_NUMBER == -1) {\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->SetFont(\'\', \'B\', $default_font_size - $diffsizetitle);\n $pdf->MultiCell(100, 3, $outputlangs->transnoentities(\'PaymentByChequeOrderedTo\', $this->emetteur->name), 0, \'L\', 0);\n $posy = $pdf->GetY() + 1;\n\n if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) {\n $pdf->SetXY($this->marge_gauche, $posy);\n $pdf->SetFont(\'\', \'\', $default_font_size - $diffsizetitle);\n $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, \'L\', 0);\n $posy = $pdf->GetY() + 2;\n }\n }\n }\n }\n\n // If payment mode not forced or forced to VIR, show payment with BAN\n if (empty($object->mode_reglement_code) || $object->mode_reglement_code == \'VIR\') {\n if ($object->fk_account > 0 || $object->fk_bank > 0 || getDolGlobalInt(\'FACTURE_RIB_NUMBER\')) {\n $bankid = ($object->fk_account <= 0 ? $conf->global->FACTURE_RIB_NUMBER : $object->fk_account);\n if ($object->fk_bank > 0) {\n $bankid = $object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank\n }\n $account = new Account($this->db);\n $account->fetch($bankid);\n\n $curx = $this->marge_gauche;\n $cury = $posy;\n\n $posy = pdf_bank($pdf, $outputlangs, $curx, $cury, $account, 0, $default_font_size);\n\n $posy += 2;\n }\n }\n }\n\n return $posy;\n }\n\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show total to pay\n *\n * @param TCPDF $pdf Object PDF\n * @param Facture $object Object invoice\n * @param int $deja_regle Amount already paid (in the currency of invoice)\n * @param int $posy Position depart\n * @param Translate $outputlangs Objet langs\n * @param Translate $outputlangsbis Object lang for output bis\n * @return int Position pour suite\n */\n protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis)\n {\n // phpcs:enable\n global $conf, $mysoc, $hookmanager;\n\n $sign = 1;\n if ($object->type == 2 && !empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) {\n $sign = -1;\n }\n\n $default_font_size = pdf_getPDFFontSize($outputlangs);\n\n $outputlangsbis = null;\n if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && $outputlangs->defaultlang != $conf->global->PDF_USE_ALSO_LANGUAGE_CODE) {\n $outputlangsbis = new Translate(\'\', $conf);\n $outputlangsbis->setDefaultLang($conf->global->PDF_USE_ALSO_LANGUAGE_CODE);\n $outputlangsbis->loadLangs(array(\"main\", \"dict\", \"companies\", \"bills\", \"products\", \"propal\"));\n $default_font_size--;\n }\n\n $tab2_top = $posy;\n $tab2_hl = 4;\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n\n // Total table\n $col1x = 120;\n $col2x = 170;\n if ($this->page_largeur < 210) { // To work with US executive format\n $col1x -= 15;\n $col2x -= 10;\n }\n $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);\n\n $useborder = 0;\n $index = 0;\n\n // Total HT\n $pdf->SetFillColor(255, 255, 255);\n $pdf->SetXY($col1x, $tab2_top);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) ? \"TotalHT\" : \"Total\").(is_object($outputlangsbis) ? \' / \'.$outputlangsbis->transnoentities(empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) ? \"TotalHT\" : \"Total\") : \'\'), 0, \'L\', 1);\n\n $total_ht = ((isModEnabled(\"multicurrency\") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ht : $object->total_ht);\n $pdf->SetXY($col2x, $tab2_top);\n $pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (!empty($object->remise) ? $object->remise : 0)), 0, $outputlangs), 0, \'R\', 1);\n\n // Show VAT by rates and total\n $pdf->SetFillColor(248, 248, 248);\n\n $total_ttc = (isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;\n\n $this->atleastoneratenotnull = 0;\n if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {\n $tvaisnull = ((!empty($this->tva) && count($this->tva) == 1 && isset($this->tva[\'0.000\']) && is_float($this->tva[\'0.000\'])) ? true : false);\n if (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) {\n // Nothing to do\n } else {\n //Local tax 1 before VAT\n //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION==\'localtax1on\')\n //{\n foreach ($this->localtax1 as $localtax_type => $localtax_rate) {\n if (in_array((string) $localtax_type, array(\'1\', \'3\', \'5\'))) {\n continue;\n }\n\n foreach ($localtax_rate as $tvakey => $tvaval) {\n if ($tvakey != 0) { // On affiche pas taux 0\n //$this->atleastoneratenotnull++;\n\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $tvacompl = \'\';\n if (preg_match(\'/\\*/\', $tvakey)) {\n $tvakey = str_replace(\'*\', \'\', $tvakey);\n $tvacompl = \" (\".$outputlangs->transnoentities(\"NonPercuRecuperable\").\")\";\n }\n\n $totalvat = $outputlangs->transcountrynoentities(\"TotalLT1\", $mysoc->country_code).(is_object($outputlangsbis) ? \' / \'.$outputlangsbis->transcountrynoentities(\"TotalLT1\", $mysoc->country_code) : \'\');\n $totalvat .= \' \';\n $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, \'L\', 1);\n\n $total_localtax = ((isModEnabled(\"multicurrency\") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, \'MT\') : $tvaval);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, \'R\', 1);\n }\n }\n }\n //}\n //Local tax 2 before VAT\n //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION==\'localtax2on\')\n //{\n foreach ($this->localtax2 as $localtax_type => $localtax_rate) {\n if (in_array((string) $localtax_type, array(\'1\', \'3\', \'5\'))) {\n continue;\n }\n\n foreach ($localtax_rate as $tvakey => $tvaval) {\n if ($tvakey != 0) { // On affiche pas taux 0\n //$this->atleastoneratenotnull++;\n\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $tvacompl = \'\';\n if (preg_match(\'/\\*/\', $tvakey)) {\n $tvakey = str_replace(\'*\', \'\', $tvakey);\n $tvacompl = \" (\".$outputlangs->transnoentities(\"NonPercuRecuperable\").\")\";\n }\n $totalvat = $outputlangs->transcountrynoentities(\"TotalLT2\", $mysoc->country_code).(is_object($outputlangsbis) ? \' / \'.$outputlangsbis->transcountrynoentities(\"TotalLT2\", $mysoc->country_code) : \'\');\n $totalvat .= \' \';\n $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, \'L\', 1);\n\n $total_localtax = ((isModEnabled(\"multicurrency\") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, \'MT\') : $tvaval);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, \'R\', 1);\n }\n }\n }\n\n //}\n\n // VAT\n foreach ($this->tva_array as $tvakey => $tvaval) {\n if ($tvakey != 0) { // On affiche pas taux 0\n $this->atleastoneratenotnull++;\n\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $tvacompl = \'\';\n if (preg_match(\'/\\*/\', $tvakey)) {\n $tvakey = str_replace(\'*\', \'\', $tvakey);\n $tvacompl = \" (\".$outputlangs->transnoentities(\"NonPercuRecuperable\").\")\";\n }\n $totalvat = $outputlangs->transcountrynoentities(\"TotalVAT\", $mysoc->country_code).(is_object($outputlangsbis) ? \' / \'.$outputlangsbis->transcountrynoentities(\"TotalVAT\", $mysoc->country_code) : \'\');\n $totalvat .= \' \';\n if (getDolGlobalString(\'PDF_VAT_LABEL_IS_CODE_OR_RATE\') == \'rateonly\') {\n $totalvat .= vatrate($tvaval[\'vatrate\'], 1).$tvacompl;\n } elseif (getDolGlobalString(\'PDF_VAT_LABEL_IS_CODE_OR_RATE\') == \'codeonly\') {\n $totalvat .= $tvaval[\'vatcode\'].$tvacompl;\n } else {\n $totalvat .= vatrate($tvaval[\'vatrate\'], 1).($tvaval[\'vatcode\'] ? \' (\'.$tvaval[\'vatcode\'].\')\' : \'\').$tvacompl;\n }\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, \'L\', 1);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval[\'amount\'], \'MT\'), 0, $outputlangs), 0, \'R\', 1);\n }\n }\n\n //Local tax 1 after VAT\n //if (!empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION==\'localtax1on\')\n //{\n foreach ($this->localtax1 as $localtax_type => $localtax_rate) {\n if (in_array((string) $localtax_type, array(\'2\', \'4\', \'6\'))) {\n continue;\n }\n\n foreach ($localtax_rate as $tvakey => $tvaval) {\n if ($tvakey != 0) { // On affiche pas taux 0\n //$this->atleastoneratenotnull++;\n\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $tvacompl = \'\';\n if (preg_match(\'/\\*/\', $tvakey)) {\n $tvakey = str_replace(\'*\', \'\', $tvakey);\n $tvacompl = \" (\".$outputlangs->transnoentities(\"NonPercuRecuperable\").\")\";\n }\n $totalvat = $outputlangs->transcountrynoentities(\"TotalLT1\", $mysoc->country_code).\' \';\n $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;\n\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, \'L\', 1);\n\n $total_localtax = ((isModEnabled(\"multicurrency\") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, \'MT\') : $tvaval);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, \'R\', 1);\n }\n }\n }\n //}\n //Local tax 2 after VAT\n //if (!empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION==\'localtax2on\')\n //{\n foreach ($this->localtax2 as $localtax_type => $localtax_rate) {\n if (in_array((string) $localtax_type, array(\'2\', \'4\', \'6\'))) {\n continue;\n }\n\n foreach ($localtax_rate as $tvakey => $tvaval) {\n //$this->atleastoneratenotnull++;\n\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $tvacompl = \'\';\n if (preg_match(\'/\\*/\', $tvakey)) {\n $tvakey = str_replace(\'*\', \'\', $tvakey);\n $tvacompl = \" (\".$outputlangs->transnoentities(\"NonPercuRecuperable\").\")\";\n }\n $totalvat = $outputlangs->transcountrynoentities(\"TotalLT2\", $mysoc->country_code).\' \';\n\n $totalvat .= vatrate(abs($tvakey), 1).$tvacompl;\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, \'L\', 1);\n\n $total_localtax = ((isModEnabled(\"multicurrency\") && isset($object->multicurrency_tx) && $object->multicurrency_tx != 1) ? price2num($tvaval * $object->multicurrency_tx, \'MT\') : $tvaval);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($total_localtax, 0, $outputlangs), 0, \'R\', 1);\n }\n }\n //}\n\n // Revenue stamp\n if (price2num($object->revenuestamp) != 0) {\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"RevenueStamp\"), $useborder, \'L\', 1);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, \'R\', 1);\n }\n\n // Total TTC\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->SetFillColor(224, 224, 224);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"TotalTTC\"), $useborder, \'L\', 1);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, \'R\', 1);\n\n // Retained warranty\n if ($object->displayRetainedWarranty()) {\n $pdf->SetTextColor(40, 40, 40);\n $pdf->SetFillColor(255, 255, 255);\n\n $retainedWarranty = $object->getRetainedWarrantyAmount();\n $billedWithRetainedWarranty = $object->total_ttc - $retainedWarranty;\n\n // Billed - retained warranty\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"ToPayOn\", dol_print_date($object->date_lim_reglement, \'day\')), $useborder, \'L\', 1);\n\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($billedWithRetainedWarranty), $useborder, \'R\', 1);\n\n // retained warranty\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n\n $retainedWarrantyToPayOn = $outputlangs->transnoentities(\"RetainedWarranty\").\' (\'.$object->retained_warranty.\'%)\';\n $retainedWarrantyToPayOn .= !empty($object->retained_warranty_date_limit) ? \' \'.$outputlangs->transnoentities(\"toPayOn\", dol_print_date($object->retained_warranty_date_limit, \'day\')) : \'\';\n\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $retainedWarrantyToPayOn, $useborder, \'L\', 1);\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($retainedWarranty), $useborder, \'R\', 1);\n }\n }\n }\n\n $pdf->SetTextColor(0, 0, 0);\n $creditnoteamount = $object->getSumCreditNotesUsed((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? 1 : 0); // Warning, this also include excess received\n $depositsamount = $object->getSumDepositsUsed((isModEnabled(\"multicurrency\") && $object->multicurrency_tx != 1) ? 1 : 0);\n //print \"x\".$creditnoteamount.\"-\".$depositsamount;exit;\n $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, \'MT\');\n if (!empty($object->paye)) {\n $resteapayer = 0;\n }\n\n if (($deja_regle > 0 || $creditnoteamount > 0 || $depositsamount > 0) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) {\n // Already paid + Deposits\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"Paid\"), 0, \'L\', 0);\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, \'R\', 0);\n\n // Credit note\n if ($creditnoteamount) {\n $labeltouse = ($outputlangs->transnoentities(\"CreditNotesOrExcessReceived\") != \"CreditNotesOrExcessReceived\") ? $outputlangs->transnoentities(\"CreditNotesOrExcessReceived\") : $outputlangs->transnoentities(\"CreditNotes\");\n $index++;\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $labeltouse, 0, \'L\', 0);\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($creditnoteamount, 0, $outputlangs), 0, \'R\', 0);\n }\n\n // Escompte\n if ($object->close_code == Facture::CLOSECODE_DISCOUNTVAT) {\n $index++;\n $pdf->SetFillColor(255, 255, 255);\n\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"EscompteOfferedShort\"), $useborder, \'L\', 1);\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, \'R\', 1);\n\n $resteapayer = 0;\n }\n\n $index++;\n $pdf->SetTextColor(0, 0, 60);\n $pdf->SetFillColor(224, 224, 224);\n $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities(\"RemainderToPay\"), $useborder, \'L\', 1);\n $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);\n $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, \'R\', 1);\n\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->SetTextColor(0, 0, 0);\n }\n\n $index++;\n return ($tab2_top + ($tab2_hl * $index));\n }\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show table for lines\n *\n * @param TCPDF $pdf Object PDF\n * @param string $tab_top Top position of table\n * @param string $tab_height Height of table (rectangle)\n * @param int $nexY Y (not used)\n * @param Translate $outputlangs Langs object\n * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title\n * @param int $hidebottom Hide bottom bar of array\n * @param string $currency Currency code\n * @return void\n */\n protected function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop = 0, $hidebottom = 0, $currency = \'\')\n {\n global $conf;\n\n // Force to disable hidetop and hidebottom\n $hidebottom = 0;\n if ($hidetop) {\n $hidetop = -1;\n }\n\n $currency = !empty($currency) ? $currency : $conf->currency;\n $default_font_size = pdf_getPDFFontSize($outputlangs);\n\n // Amount in (at tab_top - 1)\n $pdf->SetTextColor(0, 0, 0);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n\n if (empty($hidetop)) {\n // Show category of operations\n if (getDolGlobalInt(\'INVOICE_CATEGORY_OF_OPERATION\') == 1 && $this->categoryOfOperation >= 0) {\n $categoryOfOperations = $outputlangs->transnoentities(\"MentionCategoryOfOperations\") . \' : \' . $outputlangs->transnoentities(\"MentionCategoryOfOperations\" . $this->categoryOfOperation);\n $pdf->SetXY($this->marge_gauche, $tab_top - 4);\n $pdf->MultiCell(($pdf->GetStringWidth($categoryOfOperations)) + 4, 2, $categoryOfOperations);\n }\n\n $titre = $outputlangs->transnoentities(\"AmountInCurrency\", $outputlangs->transnoentitiesnoconv(\"Currency\".$currency));\n $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top - 4);\n $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);\n\n //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR=\'230,230,230\';\n if (!empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) {\n $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_droite - $this->marge_gauche, 5, \'F\', null, explode(\',\', $conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));\n }\n }\n\n $pdf->SetDrawColor(128, 128, 128);\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n\n // Output Rect\n $this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur - $this->marge_gauche - $this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect takes a length in 3rd parameter and 4th parameter\n\n if (empty($hidetop)) {\n $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\n\n $pdf->SetXY($this->posxdesc - 1, $tab_top + 1);\n $pdf->MultiCell(108, 2, $outputlangs->transnoentities(\"Designation\"), \'\', \'L\');\n }\n\n if (!empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE)) {\n $pdf->line($this->posxpicture - 1, $tab_top, $this->posxpicture - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n //$pdf->SetXY($this->posxpicture-1, $tab_top+1);\n //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities(\"Photo\"),\'\',\'C\');\n }\n }\n\n if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) {\n $pdf->line($this->posxtva - 1, $tab_top, $this->posxtva - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxtva - 3, $tab_top + 1);\n $pdf->MultiCell($this->posxup - $this->posxtva + 3, 2, $outputlangs->transnoentities(\"VAT\"), \'\', \'C\');\n }\n }\n\n $pdf->line($this->posxup - 1, $tab_top, $this->posxup - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxup - 1, $tab_top + 1);\n $pdf->MultiCell($this->posxqty - $this->posxup - 1, 2, $outputlangs->transnoentities(\"PriceUHT\"), \'\', \'C\');\n }\n\n $pdf->line($this->posxqty - 1, $tab_top, $this->posxqty - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxqty - 1, $tab_top + 1);\n $pdf->MultiCell($this->posxunit - $this->posxqty - 1, 2, $outputlangs->transnoentities(\"Qty\"), \'\', \'C\');\n }\n\n if (getDolGlobalInt(\'PRODUCT_USE_UNITS\')) {\n $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxunit - 1, $tab_top + 1);\n $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities(\"Unit\"), \'\', \'C\');\n }\n }\n\n if ($this->atleastonediscount) {\n $pdf->line($this->posxdiscount - 1, $tab_top, $this->posxdiscount - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1);\n $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 1, 2, $outputlangs->transnoentities(\"ReductionShort\"), \'\', \'C\');\n }\n }\n\n if ($this->situationinvoice) {\n $pdf->line($this->posxprogress - 1, $tab_top, $this->posxprogress - 1, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->posxprogress, $tab_top + 1);\n $pdf->MultiCell($this->postotalht - $this->posxprogress, 2, $outputlangs->transnoentities(\"ProgressShort\"), \'\', \'C\');\n }\n }\n\n $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height);\n if (empty($hidetop)) {\n $pdf->SetXY($this->postotalht - 1, $tab_top + 1);\n $pdf->MultiCell(30, 2, $outputlangs->transnoentities(\"TotalHTShort\"), \'\', \'C\');\n }\n }\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show top header of page.\n *\n * @param TCPDF $pdf Object PDF\n * @param Facture $object Object to show\n * @param int $showaddress 0=no, 1=yes\n * @param Translate $outputlangs Object lang for output\n * @param Translate $outputlangsbis Object lang for output bis\n * @return int top shift of linked object lines\n */\n protected function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $outputlangsbis = null)\n {\n global $conf, $langs;\n\n $ltrdirection = \'L\';\n if ($outputlangs->trans(\"DIRECTION\") == \'rtl\') $ltrdirection = \'R\';\n\n // Load traductions files required by page\n $outputlangs->loadLangs(array(\"main\", \"bills\", \"propal\", \"companies\"));\n\n $default_font_size = pdf_getPDFFontSize($outputlangs);\n\n pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);\n\n $pdf->SetTextColor(0, 0, 60);\n $pdf->SetFont(\'\', \'B\', $default_font_size + 3);\n\n $w = 110;\n\n $posy = $this->marge_haute;\n $posx = $this->page_largeur - $this->marge_droite - $w;\n\n $pdf->SetXY($this->marge_gauche, $posy);\n\n // Logo\n if (!getDolGlobalInt(\'PDF_DISABLE_MYCOMPANY_LOGO\')) {\n if ($this->emetteur->logo) {\n $logodir = $conf->mycompany->dir_output;\n if (!empty($conf->mycompany->multidir_output[$object->entity])) {\n $logodir = $conf->mycompany->multidir_output[$object->entity];\n }\n if (!getDolGlobalInt(\'MAIN_PDF_USE_LARGE_LOGO\')) {\n $logo = $logodir.\'/logos/thumbs/\'.$this->emetteur->logo_small;\n } else {\n $logo = $logodir.\'/logos/\'.$this->emetteur->logo;\n }\n if (is_readable($logo)) {\n $height = pdf_getHeightForLogo($logo);\n $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto)\n } else {\n $pdf->SetTextColor(200, 0, 0);\n $pdf->SetFont(\'\', \'B\', $default_font_size - 2);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"ErrorLogoFileNotFound\", $logo), 0, \'L\');\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"ErrorGoToGlobalSetup\"), 0, \'L\');\n }\n } else {\n $text = $this->emetteur->name;\n $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, $ltrdirection);\n }\n }\n\n $pdf->SetFont(\'\', \'B\', $default_font_size + 3);\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $title = $outputlangs->transnoentities(\"PdfInvoiceTitle\");\n if ($object->type == 1) {\n $title = $outputlangs->transnoentities(\"InvoiceReplacement\");\n }\n if ($object->type == 2) {\n $title = $outputlangs->transnoentities(\"InvoiceAvoir\");\n }\n if ($object->type == 3) {\n $title = $outputlangs->transnoentities(\"InvoiceDeposit\");\n }\n if ($object->type == 4) {\n $title = $outputlangs->transnoentities(\"InvoiceProForma\");\n }\n if ($this->situationinvoice) {\n $langs->loadLangs(array(\"other\"));\n $title = $outputlangs->transnoentities(\"PDFInvoiceSituation\") . \" \" . $outputlangs->transnoentities(\"NumberingShort\") . $object->situation_counter . \" -\";\n }\n if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {\n $title .= \' - \';\n if ($object->type == 0) {\n if ($this->situationinvoice) {\n $title .= $outputlangsbis->transnoentities(\"PDFInvoiceSituation\");\n }\n $title .= $outputlangsbis->transnoentities(\"PdfInvoiceTitle\");\n } elseif ($object->type == 1) {\n $title .= $outputlangsbis->transnoentities(\"InvoiceReplacement\");\n } elseif ($object->type == 2) {\n $title .= $outputlangsbis->transnoentities(\"InvoiceAvoir\");\n } elseif ($object->type == 3) {\n $title .= $outputlangsbis->transnoentities(\"InvoiceDeposit\");\n } elseif ($object->type == 4) {\n $title .= $outputlangsbis->transnoentities(\"InvoiceProForma\");\n }\n }\n $title .= \' \'.$outputlangs->convToOutputCharset($object->ref);\n if ($object->statut == $object::STATUS_DRAFT) {\n $pdf->SetTextColor(128, 0, 0);\n $title .= \' - \'.$outputlangs->transnoentities(\"NotValidated\");\n }\n\n $pdf->MultiCell($w, 3, $title, \'\', \'R\');\n\n $pdf->SetFont(\'\', \'B\', $default_font_size);\n\n /*\n $posy += 5;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $textref = $outputlangs->transnoentities(\"Ref\").\" : \".$outputlangs->convToOutputCharset($object->ref);\n if ($object->statut == $object::STATUS_DRAFT) {\n $pdf->SetTextColor(128, 0, 0);\n $textref .= \' - \'.$outputlangs->transnoentities(\"NotValidated\");\n }\n $pdf->MultiCell($w, 4, $textref, \'\', \'R\');*/\n\n $posy += 3;\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n\n if ($object->ref_customer) {\n $posy += 4;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"RefCustomer\").\" : \".$outputlangs->convToOutputCharset($object->ref_customer), \'\', \'R\');\n }\n\n if (!empty($conf->global->PDF_SHOW_PROJECT_TITLE)) {\n $object->fetch_projet();\n if (!empty($object->project->ref)) {\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"Project\").\" : \".(empty($object->project->title) ? \'\' : $object->project->title), \'\', \'R\');\n }\n }\n\n if (!empty($conf->global->PDF_SHOW_PROJECT)) {\n $object->fetch_projet();\n if (!empty($object->project->ref)) {\n $outputlangs->load(\"projects\");\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"RefProject\").\" : \".(empty($object->project->ref) ? \'\' : $object->project->ref), \'\', \'R\');\n }\n }\n\n $objectidnext = $object->getIdReplacingInvoice(\'validated\');\n if ($object->type == 0 && $objectidnext) {\n $objectreplacing = new Facture($this->db);\n $objectreplacing->fetch($objectidnext);\n\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"ReplacementByInvoice\").\' : \'.$outputlangs->convToOutputCharset($objectreplacing->ref), \'\', \'R\');\n }\n if ($object->type == 1) {\n $objectreplaced = new Facture($this->db);\n $objectreplaced->fetch($object->fk_facture_source);\n\n $posy += 4;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"ReplacementInvoice\").\' : \'.$outputlangs->convToOutputCharset($objectreplaced->ref), \'\', \'R\');\n }\n if ($object->type == 2 && !empty($object->fk_facture_source)) {\n $objectreplaced = new Facture($this->db);\n $objectreplaced->fetch($object->fk_facture_source);\n\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"CorrectionInvoice\").\' : \'.$outputlangs->convToOutputCharset($objectreplaced->ref), \'\', \'R\');\n }\n\n $posy += 4;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $title = $outputlangs->transnoentities(\"DateInvoice\");\n if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {\n $title .= \' - \'.$outputlangsbis->transnoentities(\"DateInvoice\");\n }\n $pdf->MultiCell($w, 3, $title.\" : \".dol_print_date($object->date, \"day\", false, $outputlangs, true), \'\', \'R\');\n\n if (!empty($conf->global->INVOICE_POINTOFTAX_DATE)) {\n $posy += 4;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"DatePointOfTax\").\" : \".dol_print_date($object->date_pointoftax, \"day\", false, $outputlangs), \'\', \'R\');\n }\n\n if ($object->type != 2) {\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $title = $outputlangs->transnoentities(\"DateDue\");\n if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE) && is_object($outputlangsbis)) {\n $title .= \' - \'.$outputlangsbis->transnoentities(\"DateDue\");\n }\n $pdf->MultiCell($w, 3, $title.\" : \".dol_print_date($object->date_lim_reglement, \"day\", false, $outputlangs, true), \'\', \'R\');\n }\n\n if (empty($conf->global->MAIN_PDF_HIDE_CUSTOMER_CODE) && $object->thirdparty->code_client) {\n $posy += 3;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"CustomerCode\").\" : \".$outputlangs->transnoentities($object->thirdparty->code_client), \'\', \'R\');\n }\n\n // Get contact\n if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) {\n $arrayidcontact = $object->getIdContact(\'internal\', \'SALESREPFOLL\');\n if (count($arrayidcontact) > 0) {\n $usertmp = new User($this->db);\n $usertmp->fetch($arrayidcontact[0]);\n $posy += 4;\n $pdf->SetXY($posx, $posy);\n $pdf->SetTextColor(0, 0, 60);\n $pdf->MultiCell($w, 3, $outputlangs->transnoentities(\"SalesRepresentative\").\" : \".$usertmp->getFullName($langs), \'\', \'R\');\n }\n }\n\n $posy += 1;\n\n $top_shift = 0;\n // Show list of linked objects\n $current_y = $pdf->getY();\n $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, \'R\', $default_font_size);\n if ($current_y < $pdf->getY()) {\n $top_shift = $pdf->getY() - $current_y;\n }\n \n //=======QR verifactu========\n \n if ($object->array_options[\'options_verifactu_url\'] !=\"\") {\n \n $outputlangs->loadLangs(array(\"verifactudolibarr@verifactudolibarr\"));\n \n $url = $object->array_options[\'options_verifactu_url\'];\n \n $style = [\'border\'=>false, \'padding\'=>0, \'fgcolor\'=>[0,0,0], \'bgcolor\'=>false];\n // posicion: x=150mm, y=20mm, ancho/alto en mm\n \n $pdf->SetXY(100,11);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->MultiCell(25, \'\', $outputlangs->transnoentities(\'verifactu_qr_tributario\'), 0, \'L\', 0);\n \n \n $pdf->write2DBarcode($url, \'QRCODE,H\', 100, 17, 20, 20, $style, \'N\');\n \n $pdf->SetXY(74, 38);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->MultiCell(75, \'\', $outputlangs->transnoentities(\'verifactu_doc_verificable_tributario\'), 0, \'C\', 0);\n \n $top_shift+=8;\n }\n \n //=======QR verifactu========\n\n if ($showaddress) {\n // Sender properties\n $carac_emetteur = \'\';\n // Add internal contact of object if defined\n $arrayidcontact = $object->getIdContact(\'internal\', \'BILLING\');\n if (count($arrayidcontact) > 0) {\n $object->fetch_user($arrayidcontact[0]);\n $labelbeforecontactname = ($outputlangs->transnoentities(\"FromContactName\") != \'FromContactName\' ? $outputlangs->transnoentities(\"FromContactName\") : $outputlangs->transnoentities(\"Name\"));\n $carac_emetteur .= ($carac_emetteur ? \"\\n\" : \'\').$labelbeforecontactname.\" \".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs));\n $carac_emetteur .= \"\\n\";\n }\n\n $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, \'\', 0, \'source\', $object);\n\n // Show sender\n $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;\n $posy += $top_shift;\n $posx = $this->marge_gauche;\n if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {\n $posx = $this->page_largeur - $this->marge_droite - 80;\n }\n\n $hautcadre = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;\n $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;\n\n\n // Show sender frame\n if (empty($conf->global->MAIN_PDF_NO_SENDER_FRAME)) {\n $pdf->SetTextColor(0, 0, 0);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->SetXY($posx, $posy - 5);\n $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities(\"BillFrom\"), 0, $ltrdirection);\n $pdf->SetXY($posx, $posy);\n $pdf->SetFillColor(230, 230, 230);\n $pdf->MultiCell($widthrecbox, $hautcadre, \"\", 0, \'R\', 1);\n $pdf->SetTextColor(0, 0, 60);\n }\n\n // Show sender name\n if (empty($conf->global->MAIN_PDF_HIDE_SENDER_NAME)) {\n $pdf->SetXY($posx + 2, $posy + 3);\n $pdf->SetFont(\'\', \'B\', $default_font_size);\n $pdf->MultiCell($widthrecbox - 2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, $ltrdirection);\n $posy = $pdf->getY();\n }\n\n // Show sender information\n $pdf->SetXY($posx + 2, $posy);\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->MultiCell($widthrecbox - 2, 4, $carac_emetteur, 0, $ltrdirection);\n\n\n // If BILLING contact defined on invoice, we use it\n $usecontact = false;\n $arrayidcontact = $object->getIdContact(\'external\', \'BILLING\');\n if (count($arrayidcontact) > 0) {\n $usecontact = true;\n $result = $object->fetch_contact($arrayidcontact[0]);\n }\n\n // Recipient name\n if ($usecontact && ($object->contact->socid != $object->thirdparty->id && (!isset($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT) || !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)))) {\n $thirdparty = $object->contact;\n } else {\n $thirdparty = $object->thirdparty;\n }\n\n $carac_client_name = pdfBuildThirdpartyName($thirdparty, $outputlangs);\n\n $mode = \'target\';\n $carac_client = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, ($usecontact ? $object->contact : \'\'), $usecontact, $mode, $object);\n\n // Show recipient\n $widthrecbox = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;\n if ($this->page_largeur < 210) {\n $widthrecbox = 84; // To work with US executive format\n }\n $posy = !empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;\n $posy += $top_shift;\n $posx = $this->page_largeur - $this->marge_droite - $widthrecbox;\n if (!empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) {\n $posx = $this->marge_gauche;\n }\n\n // Show recipient frame\n if (empty($conf->global->MAIN_PDF_NO_RECIPENT_FRAME)) {\n $pdf->SetTextColor(0, 0, 0);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->SetXY($posx + 2, $posy - 5);\n $pdf->MultiCell($widthrecbox - 2, 5, $outputlangs->transnoentities(\"BillTo\"), 0, $ltrdirection);\n $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);\n }\n\n // Show recipient name\n $pdf->SetXY($posx + 2, $posy + 3);\n $pdf->SetFont(\'\', \'B\', $default_font_size);\n $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name, 0, $ltrdirection);\n\n $posy = $pdf->getY();\n\n // Show recipient information\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->SetXY($posx + 2, $posy);\n $pdf->MultiCell($widthrecbox - 2, 4, $carac_client, 0, $ltrdirection);\n\n // Show shipping address\n if (getDolGlobalInt(\'INVOICE_SHOW_SHIPPING_ADDRESS\')) {\n $idaddressshipping = $object->getIdContact(\'external\', \'SHIPPING\');\n\n if (!empty($idaddressshipping)) {\n $contactshipping = $object->fetch_Contact($idaddressshipping[0]);\n $companystatic = new Societe($this->db);\n $companystatic->fetch($object->contact->fk_soc);\n $carac_client_name_shipping=pdfBuildThirdpartyName($object->contact, $outputlangs);\n $carac_client_shipping = pdf_build_address($outputlangs, $this->emetteur, $companystatic, $object->contact, $usecontact, \'target\', $object);\n } else {\n $carac_client_name_shipping=pdfBuildThirdpartyName($object->thirdparty, $outputlangs);\n $carac_client_shipping=pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, \'\', 0, \'target\', $object);\n }\n if (!empty($carac_client_shipping)) {\n $posy += $hautcadre;\n\n // Show shipping frame\n $pdf->SetXY($posx + 2, $posy - 5);\n $pdf->SetFont(\'\', \'\', $default_font_size - 2);\n $pdf->MultiCell($widthrecbox, \'\', $outputlangs->transnoentities(\'ShippingTo\'), 0, \'L\', 0);\n $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);\n\n // Show shipping name\n $pdf->SetXY($posx + 2, $posy + 3);\n $pdf->SetFont(\'\', \'B\', $default_font_size);\n $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_name_shipping, \'\', \'L\');\n\n $posy = $pdf->getY();\n\n // Show shipping information\n $pdf->SetXY($posx+2, $posy);\n $pdf->SetFont(\'\', \'\', $default_font_size - 1);\n $pdf->MultiCell($widthrecbox - 2, 2, $carac_client_shipping, \'\', \'L\');\n $top_shift += $hautcadre;\n }\n }\n }\n\n $pdf->SetTextColor(0, 0, 0);\n return $top_shift;\n }\n\n // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore\n /**\n * Show footer of page. Need this->emetteur object\n *\n * @param TCPDF $pdf PDF\n * @param Facture $object Object to show\n * @param Translate $outputlangs Object lang for output\n * @param int $hidefreetext 1=Hide free text\n * @param int $heightforqrinvoice Height for QR invoices\n * @return int Return height of bottom margin including footer text\n */#VPDFC:1a70a6e54dd7a88e4fa45932ca280b90f349c9b435ce01e53995c7111152ecb7\n protected function _pagefoot(&$pdf, $object, $outputlangs, $hidefreetext = 0, $heightforqrinvoice = 0)\n {\n $showdetails = getDolGlobalInt(\'MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS\', 0);\n 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);\n }\n \n public function pdf_writelinedesc(&$pdf, $object, $i, $outputlangs, $w, $h, $posx, $posy, $hideref = 0, $hidedesc = 0, $issupplierline = 0)\n {\n global $db, $conf, $langs, $hookmanager;\n\n $reshook = 0;\n $result = \'\';\n //if (is_object($hookmanager) && ( (isset($object->lines[$i]->product_type) && $object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line) ) )\n if (is_object($hookmanager)) { // Old code is commented on preceding line. Reproduct this test in the pdf_xxx function if you don\'t want your hook to run\n $special_code = empty($object->lines[$i]->special_code) ? \'\' : $object->lines[$i]->special_code;\n if (!empty($object->lines[$i]->fk_parent_line) && $object->lines[$i]->fk_parent_line > 0) {\n $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line);\n }\n $parameters = array(\'pdf\'=>$pdf, \'i\'=>$i, \'outputlangs\'=>$outputlangs, \'w\'=>$w, \'h\'=>$h, \'posx\'=>$posx, \'posy\'=>$posy, \'hideref\'=>$hideref, \'hidedesc\'=>$hidedesc, \'issupplierline\'=>$issupplierline, \'special_code\'=>$special_code);\n $action = \'\';\n $reshook = $hookmanager->executeHooks(\'pdf_writelinedesc\', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks\n\n if (!empty($hookmanager->resPrint)) {\n $result .= $hookmanager->resPrint;\n }\n }\n if (empty($reshook)) {\n $labelproductservice = $this->pdf_getlinedesc($object, $i, $outputlangs, $hideref, $hidedesc, $issupplierline);\n\n //var_dump($labelproductservice);exit;\n\n // Fix bug of some HTML editors that replace links ]*src=\")([^\"]*)(&)([^\"]*\")/\', \'\\1\\2&\\4\', $labelproductservice, -1, $nbrep);\n\n //var_dump($labelproductservice);exit;\n\n // Description\n $pdf->writeHTMLCell($w, $h, $posx, $posy, $outputlangs->convToOutputCharset($labelproductservice), 0, 1, false, true, \'J\', true);\n $result .= $labelproductservice;\n }\n return $result;\n }\n \n function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $issupplierline = 0)\n {\n global $db, $conf, $langs;\n\n $idprod = (!empty($object->lines[$i]->fk_product) ? $object->lines[$i]->fk_product : false);\n $label = (!empty($object->lines[$i]->label) ? $object->lines[$i]->label : (!empty($object->lines[$i]->product_label) ? $object->lines[$i]->product_label : \'\'));\n $product_barcode = (!empty($object->lines[$i]->product_barcode) ? $object->lines[$i]->product_barcode : \"\");\n $desc = (!empty($object->lines[$i]->desc) ? $object->lines[$i]->desc : (!empty($object->lines[$i]->description) ? $object->lines[$i]->description : \'\'));\n $ref_supplier = (!empty($object->lines[$i]->ref_supplier) ? $object->lines[$i]->ref_supplier : (!empty($object->lines[$i]->ref_fourn) ? $object->lines[$i]->ref_fourn : \'\')); // TODO Not yet saved for supplier invoices, only supplier orders\n $note = (!empty($object->lines[$i]->note) ? $object->lines[$i]->note : \'\');\n $dbatch = (!empty($object->lines[$i]->detail_batch) ? $object->lines[$i]->detail_batch : false);\n\n $multilangsactive = getDolGlobalInt(\'MAIN_MULTILANGS\');\n\n if ($issupplierline) {\n include_once DOL_DOCUMENT_ROOT.\'/fourn/class/fournisseur.product.class.php\';\n $prodser = new ProductFournisseur($db);\n } else {\n include_once DOL_DOCUMENT_ROOT.\'/product/class/product.class.php\';\n $prodser = new Product($db);\n\n if (getDolGlobalString(\'PRODUIT_CUSTOMER_PRICES\') || getDolGlobalString(\'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES\')) {\n include_once DOL_DOCUMENT_ROOT . \'/product/class/productcustomerprice.class.php\';\n }\n }\n\n //id\n $idprod = (!empty($object->lines[$i]->fk_product) ? $object->lines[$i]->fk_product : false);\n if ($idprod) {\n $prodser->fetch($idprod);\n //load multilangs\n if ($multilangsactive) {\n $prodser->getMultiLangs();\n $object->lines[$i]->multilangs = $prodser->multilangs;\n }\n }\n //label\n if (!empty($object->lines[$i]->label)) {\n $label = \'\'.$object->lines[$i]->label.\'\';\n } else {\n if (!empty($object->lines[$i]->multilangs[$outputlangs->defaultlang][\'label\']) && $multilangsactive) {\n $label = \'\'.$object->lines[$i]->multilangs[$outputlangs->defaultlang][\'label\'].\'\';\n } else {\n if (!empty($object->lines[$i]->product_label)) {\n $label = \'\'.$object->lines[$i]->product_label.\'\';\n } else {\n $label = \'\';\n }\n }\n }\n //description\n if (!empty($object->lines[$i]->desc)) {\n $desc = $object->lines[$i]->desc;\n } else {\n if (!empty($object->lines[$i]->multilangs[$outputlangs->defaultlang][\'description\']) && $multilangsactive) {\n $desc = $object->lines[$i]->multilangs[$outputlangs->defaultlang][\'description\'];\n } else {\n if (!empty($object->lines[$i]->description)) {\n $desc = $object->lines[$i]->description;\n } else {\n $desc = \'\';\n }\n }\n }\n //ref supplier\n $ref_supplier = (!empty($object->lines[$i]->ref_supplier) ? $object->lines[$i]->ref_supplier : (!empty($object->lines[$i]->ref_fourn) ? $object->lines[$i]->ref_fourn : \'\')); // TODO Not yet saved for supplier invoices, only supplier orders\n //note\n $note = (!empty($object->lines[$i]->note) ? $object->lines[$i]->note : \'\');\n //dbatch\n $dbatch = (!empty($object->lines[$i]->detail_batch) ? $object->lines[$i]->detail_batch : false);\n\n if ($idprod) {\n // If a predefined product and multilang and on other lang, we renamed label with label translated\n if ($multilangsactive && ($outputlangs->defaultlang != $langs->defaultlang)) {\n $translatealsoifmodified = getDolGlobalString(\'MAIN_MULTILANG_TRANSLATE_EVEN_IF_MODIFIED\'); // By default if value was modified manually, we keep it (no translation because we don\'t have it)\n\n // TODO Instead of making a compare to see if param was modified, check that content contains reference translation. If yes, add the added part to the new translation\n // ($textwasnotmodified is replaced with $textwasmodifiedorcompleted and we add completion).\n\n // Set label\n // If we want another language, and if label is same than default language (we did not force it to a specific value), we can use translation.\n //var_dump($outputlangs->defaultlang.\' - \'.$langs->defaultlang.\' - \'.$label.\' - \'.$prodser->label);exit;\n $textwasnotmodified = ($label == $prodser->label);\n if (!empty($prodser->multilangs[$outputlangs->defaultlang][\"label\"]) && ($textwasnotmodified || $translatealsoifmodified)) {\n $label = $prodser->multilangs[$outputlangs->defaultlang][\"label\"];\n }\n\n // Set desc\n // Manage HTML entities description test because $prodser->description is store with htmlentities but $desc no\n $textwasnotmodified = false;\n if (!empty($desc) && dol_textishtml($desc) && !empty($prodser->description) && dol_textishtml($prodser->description)) {\n $textwasnotmodified = (strpos(dol_html_entity_decode($desc, ENT_QUOTES | ENT_HTML5), dol_html_entity_decode($prodser->description, ENT_QUOTES | ENT_HTML5)) !== false);\n } else {\n $textwasnotmodified = ($desc == $prodser->description);\n }\n if (!empty($prodser->multilangs[$outputlangs->defaultlang][\"description\"])) {\n if ($textwasnotmodified) {\n $desc = str_replace($prodser->description, $prodser->multilangs[$outputlangs->defaultlang][\"description\"], $desc);\n } elseif ($translatealsoifmodified) {\n $desc = $prodser->multilangs[$outputlangs->defaultlang][\"description\"];\n }\n }\n\n // Set note\n $textwasnotmodified = ($note == $prodser->note_public);\n if (!empty($prodser->multilangs[$outputlangs->defaultlang][\"other\"]) && ($textwasnotmodified || $translatealsoifmodified)) {\n $note = $prodser->multilangs[$outputlangs->defaultlang][\"other\"];\n }\n }\n } elseif (($object->element == \'facture\' || $object->element == \'facturefourn\') && preg_match(\'/^\\(DEPOSIT\\).+/\', $desc)) { // We must not replace \'(DEPOSIT)\' when it is alone, it will be translated and detailed later\n $desc = str_replace(\'(DEPOSIT)\', $outputlangs->trans(\'Deposit\'), $desc);\n }\n\n $libelleproduitservice = \'\'; // Default value\n if (!getDolGlobalString(\'PDF_HIDE_PRODUCT_LABEL_IN_SUPPLIER_LINES\')) {\n // Description short of product line\n $libelleproduitservice = $label;\n if (!empty($libelleproduitservice) && getDolGlobalString(\'PDF_BOLD_PRODUCT_LABEL\')) {\n // Adding may convert the original string into a HTML string. So we have to first\n // convert \\n into
we text is not already HTML.\n if (!dol_textishtml($libelleproduitservice)) {\n $libelleproduitservice = str_replace(\"\\n\", \'
\', $libelleproduitservice);\n }\n $libelleproduitservice = \'\'.$libelleproduitservice.\'\';\n }\n }\n\n\n // Add ref of subproducts\n if (getDolGlobalString(\'SHOW_SUBPRODUCT_REF_IN_PDF\')) {\n $prodser->get_sousproduits_arbo();\n if (!empty($prodser->sousprods) && is_array($prodser->sousprods) && count($prodser->sousprods)) {\n $outputlangs->load(\'mrp\');\n $tmparrayofsubproducts = reset($prodser->sousprods);\n\n $qtyText = null;\n if (isset($object->lines[$i]->qty) && !empty($object->lines[$i]->qty)) {\n $qtyText = $object->lines[$i]->qty;\n } elseif (isset($object->lines[$i]->qty_shipped) && !empty($object->lines[$i]->qty_shipped)) {\n $qtyText = $object->lines[$i]->qty;\n }\n\n if (getDolGlobalString(\'MAIN_GENERATE_DOCUMENTS_HIDE_REF\')) {\n foreach ($tmparrayofsubproducts as $subprodval) {\n $libelleproduitservice = dol_concatdesc(\n dol_concatdesc($libelleproduitservice, \" * \".$subprodval[3]),\n (!empty($qtyText) ?\n $outputlangs->trans(\'Qty\').\':\'.$qtyText.\' x \'.$outputlangs->trans(\'AssociatedProducts\').\':\'.$subprodval[1].\'= \'.$outputlangs->trans(\'QtyTot\').\':\'.$subprodval[1] * $qtyText :\n $outputlangs->trans(\'Qty\').\' \'.$outputlangs->trans(\'AssociatedProducts\').\':\'.$subprodval[1])\n );\n }\n } else {\n foreach ($tmparrayofsubproducts as $subprodval) {\n $libelleproduitservice = dol_concatdesc(\n dol_concatdesc($libelleproduitservice, \" * \".$subprodval[5].(($subprodval[5] && $subprodval[3]) ? \' - \' : \'\').$subprodval[3]),\n (!empty($qtyText) ?\n $outputlangs->trans(\'Qty\').\':\'.$qtyText.\' x \'.$outputlangs->trans(\'AssociatedProducts\').\':\'.$subprodval[1].\'= \'.$outputlangs->trans(\'QtyTot\').\':\'.$subprodval[1] * $qtyText :\n $outputlangs->trans(\'Qty\').\' \'.$outputlangs->trans(\'AssociatedProducts\').\':\'.$subprodval[1])\n );\n }\n }\n }\n }\n\n if (isModEnabled(\'barcode\') && getDolGlobalString(\'MAIN_GENERATE_DOCUMENTS_SHOW_PRODUCT_BARCODE\') && !empty($product_barcode)) {\n $libelleproduitservice = dol_concatdesc($libelleproduitservice, $outputlangs->trans(\"BarCode\").\" \".$product_barcode);\n }\n\n // Description long of product line\n if (!empty($desc) && ($desc != $label)) {\n if ($desc == \'(CREDIT_NOTE)\' && $object->lines[$i]->fk_remise_except) {\n $discount = new DiscountAbsolute($db);\n $discount->fetch($object->lines[$i]->fk_remise_except);\n $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;\n $libelleproduitservice = $outputlangs->transnoentitiesnoconv(\"DiscountFromCreditNote\", $sourceref);\n } elseif ($desc == \'(DEPOSIT)\' && $object->lines[$i]->fk_remise_except) {\n $discount = new DiscountAbsolute($db);\n $discount->fetch($object->lines[$i]->fk_remise_except);\n $sourceref = !empty($discount->discount_type) ? $discount->ref_invoice_supplier_source : $discount->ref_facture_source;\n $libelleproduitservice = $outputlangs->transnoentitiesnoconv(\"DiscountFromDeposit\", $sourceref);\n // Add date of deposit\n if (getDolGlobalString(\'INVOICE_ADD_DEPOSIT_DATE\')) {\n $libelleproduitservice .= \' (\'.dol_print_date($discount->datec, \'day\', \'\', $outputlangs).\')\';\n }\n } elseif ($desc == \'(EXCESS RECEIVED)\' && $object->lines[$i]->fk_remise_except) {\n $discount = new DiscountAbsolute($db);\n $discount->fetch($object->lines[$i]->fk_remise_except);\n $libelleproduitservice = $outputlangs->transnoentitiesnoconv(\"DiscountFromExcessReceived\", $discount->ref_facture_source);\n } elseif ($desc == \'(EXCESS PAID)\' && $object->lines[$i]->fk_remise_except) {\n $discount = new DiscountAbsolute($db);\n $discount->fetch($object->lines[$i]->fk_remise_except);\n $libelleproduitservice = $outputlangs->transnoentitiesnoconv(\"DiscountFromExcessPaid\", $discount->ref_invoice_supplier_source);\n } else {\n if ($idprod) {\n // Check if description must be output\n if (!empty($object->element)) {\n $tmpkey = \'MAIN_DOCUMENTS_HIDE_DESCRIPTION_FOR_\'.strtoupper($object->element);\n if (getDolGlobalString($tmpkey)) {\n $hidedesc = 1;\n }\n }\n if (empty($hidedesc)) {\n if (getDolGlobalString(\'MAIN_DOCUMENTS_DESCRIPTION_FIRST\')) {\n $libelleproduitservice = dol_concatdesc($desc, $libelleproduitservice);\n } else {\n if (getDolGlobalString(\'HIDE_LABEL_VARIANT_PDF\') && $prodser->isVariant()) {\n $libelleproduitservice = $desc;\n } else {\n $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);\n }\n }\n }\n } else {\n $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desc);\n }\n }\n }\n\n // We add ref of product (and supplier ref if defined)\n $prefix_prodserv = \"\";\n $ref_prodserv = \"\";\n if (getDolGlobalString(\'PRODUCT_ADD_TYPE_IN_DOCUMENTS\')) { // In standard mode, we do not show this\n if ($prodser->isService()) {\n $prefix_prodserv = $outputlangs->transnoentitiesnoconv(\"Service\").\" \";\n } else {\n $prefix_prodserv = $outputlangs->transnoentitiesnoconv(\"Product\").\" \";\n }\n }\n\n if (empty($hideref)) {\n if ($issupplierline) {\n if (!getDolGlobalString(\'PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES\')) { // Common case\n $ref_prodserv = $prodser->ref; // Show local ref\n if ($ref_supplier) {\n $ref_prodserv .= ($prodser->ref ? \' (\' : \'\').$outputlangs->transnoentitiesnoconv(\"SupplierRef\").\' \'.$ref_supplier.($prodser->ref ? \')\' : \'\');\n }\n } elseif (getDolGlobalInt(\'PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES\') == 1) {\n $ref_prodserv = $ref_supplier;\n } elseif (getDolGlobalInt(\'PDF_HIDE_PRODUCT_REF_IN_SUPPLIER_LINES\') == 2) {\n $ref_prodserv = $ref_supplier.\' (\'.$outputlangs->transnoentitiesnoconv(\"InternalRef\").\' \'.$prodser->ref.\')\';\n }\n } else {\n $ref_prodserv = $prodser->ref; // Show local ref only\n\n if (getDolGlobalString(\'PRODUIT_CUSTOMER_PRICES\') || getDolGlobalString(\'PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES\')) {\n $productCustomerPriceStatic = new ProductCustomerPrice($db);\n $filter = array(\'fk_product\' => (string) $idprod, \'fk_soc\' => (string) $object->socid);\n\n $nbCustomerPrices = $productCustomerPriceStatic->fetchAll(\'\', \'\', 1, 0, $filter);\n\n if ($nbCustomerPrices > 0) {\n $productCustomerPrice = null;\n if (count($productCustomerPriceStatic->lines) > 0) {\n $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours\n foreach ($productCustomerPriceStatic->lines as $k => $custprice_line) {\n if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {\n $productCustomerPrice = $custprice_line;\n break;\n }\n }\n }\n\n if (isset($productCustomerPrice) && !empty($productCustomerPrice->ref_customer)) {\n switch ($conf->global->PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE) {\n case 1:\n $ref_prodserv = $productCustomerPrice->ref_customer;\n break;\n\n case 2:\n $ref_prodserv = $productCustomerPrice->ref_customer . \' (\' . $outputlangs->transnoentitiesnoconv(\'InternalRef\') . \' \' . $ref_prodserv . \')\';\n break;\n\n default:\n $ref_prodserv = $ref_prodserv . \' (\' . $outputlangs->transnoentitiesnoconv(\'RefCustomer\') . \' \' . $productCustomerPrice->ref_customer . \')\';\n }\n }\n }\n }\n }\n\n if (!empty($libelleproduitservice) && !empty($ref_prodserv)) {\n $ref_prodserv .= \" - \";\n }\n }\n\n if (!empty($ref_prodserv) && getDolGlobalString(\'PDF_BOLD_PRODUCT_REF_AND_PERIOD\')) {\n if (!dol_textishtml($libelleproduitservice)) {\n $libelleproduitservice = str_replace(\"\\n\", \'
\', $libelleproduitservice);\n }\n $ref_prodserv = \'\'.$ref_prodserv.\'\';\n // $prefix_prodserv and $ref_prodser are not HTML var\n }\n $libelleproduitservice = $prefix_prodserv.$ref_prodserv.$libelleproduitservice;\n\n // Add an additional description for the category products\n if (getDolGlobalString(\'CATEGORY_ADD_DESC_INTO_DOC\') && $idprod && isModEnabled(\'category\')) {\n include_once DOL_DOCUMENT_ROOT.\'/categories/class/categorie.class.php\';\n $categstatic = new Categorie($db);\n // recovering the list of all the categories linked to product\n $tblcateg = $categstatic->containing($idprod, Categorie::TYPE_PRODUCT);\n foreach ($tblcateg as $cate) {\n // Adding the descriptions if they are filled\n $desccateg = $cate->description;\n if ($desccateg) {\n $libelleproduitservice = dol_concatdesc($libelleproduitservice, $desccateg);\n }\n }\n }\n\n if (!empty($object->lines[$i]->date_start) || !empty($object->lines[$i]->date_end)) {\n $format = \'day\';\n $period = \'\';\n // Show duration if exists\n if ($object->lines[$i]->date_start && $object->lines[$i]->date_end) {\n $period = \'(\'.$outputlangs->transnoentitiesnoconv(\'DateFromTo\', dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs), dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)).\')\';\n }\n if ($object->lines[$i]->date_start && !$object->lines[$i]->date_end) {\n $period = \'(\'.$outputlangs->transnoentitiesnoconv(\'DateFrom\', dol_print_date($object->lines[$i]->date_start, $format, false, $outputlangs)).\')\';\n }\n if (!$object->lines[$i]->date_start && $object->lines[$i]->date_end) {\n $period = \'(\'.$outputlangs->transnoentitiesnoconv(\'DateUntil\', dol_print_date($object->lines[$i]->date_end, $format, false, $outputlangs)).\')\';\n }\n //print \'>\'.$outputlangs->charset_output.\',\'.$period;\n if (getDolGlobalString(\'PDF_BOLD_PRODUCT_REF_AND_PERIOD\')) {\n if (!dol_textishtml($libelleproduitservice)) {\n $libelleproduitservice = str_replace(\"\\n\", \'
\', $libelleproduitservice);\n }\n $libelleproduitservice .= \'
\'.$period.\'\';\n } else {\n $libelleproduitservice = dol_concatdesc($libelleproduitservice, $period);\n }\n //print $libelleproduitservice;\n }\n\n // Show information for lot\n if (!empty($dbatch)) {\n // $object is a shipment.\n //var_dump($object->lines[$i]->details_entrepot); // array from llx_expeditiondet (we can have several lines for one fk_origin_line)\n //var_dump($object->lines[$i]->detail_batch); // array from llx_expeditiondet_batch (each line with a lot is linked to llx_expeditiondet)\n\n include_once DOL_DOCUMENT_ROOT.\'/product/stock/class/entrepot.class.php\';\n include_once DOL_DOCUMENT_ROOT.\'/product/class/productbatch.class.php\';\n $tmpwarehouse = new Entrepot($db);\n $tmpproductbatch = new Productbatch($db);\n\n $format = \'day\';\n foreach ($dbatch as $detail) {\n $dte = array();\n if ($detail->eatby) {\n $dte[] = $outputlangs->transnoentitiesnoconv(\'printEatby\', dol_print_date($detail->eatby, $format, false, $outputlangs));\n }\n if ($detail->sellby) {\n $dte[] = $outputlangs->transnoentitiesnoconv(\'printSellby\', dol_print_date($detail->sellby, $format, false, $outputlangs));\n }\n if ($detail->batch) {\n $dte[] = $outputlangs->transnoentitiesnoconv(\'printBatch\', $detail->batch);\n }\n if ($detail->qty) {\n $dte[] = $outputlangs->transnoentitiesnoconv(\'printQty\', (string) $detail->qty);\n }\n\n // Add also info of planned warehouse for lot\n if ($object->element == \'shipping\' && $detail->fk_origin_stock > 0 && getDolGlobalInt(\'PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT\')) {\n $resproductbatch = $tmpproductbatch->fetch($detail->fk_origin_stock);\n if ($resproductbatch > 0) {\n $reswarehouse = $tmpwarehouse->fetch($tmpproductbatch->warehouseid);\n if ($reswarehouse > 0) {\n $dte[] = $tmpwarehouse->ref;\n }\n }\n }\n\n $libelleproduitservice .= \"__N__ \".implode(\" - \", $dte);\n }\n } else {\n if (getDolGlobalInt(\'PRODUCTBATCH_SHOW_WAREHOUSE_ON_SHIPMENT\')) {\n // TODO Show warehouse for shipment line without batch\n }\n }\n\n // Now we convert \\n into br\n if (dol_textishtml($libelleproduitservice)) {\n $libelleproduitservice = preg_replace(\'/__N__/\', \'
\', $libelleproduitservice);\n } else {\n $libelleproduitservice = preg_replace(\'/__N__/\', \"\\n\", $libelleproduitservice);\n }\n $libelleproduitservice = dol_htmlentitiesbr($libelleproduitservice, 1);\n\n return $libelleproduitservice;\n }\n}\n'); -/*!40000 ALTER TABLE `llx_verifactudolibarr_add_tpls` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `llx_verifactudolibarr_facture_log` --- - -DROP TABLE IF EXISTS `llx_verifactudolibarr_facture_log`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `llx_verifactudolibarr_facture_log` ( - `rowid` int(10) unsigned NOT NULL AUTO_INCREMENT, - `facture` varchar(22) DEFAULT NULL, - `datec` datetime DEFAULT NULL, - `fk_user_author` varchar(22) DEFAULT NULL, - `processed` enum('SI','NO') DEFAULT 'NO', - `processed_date` datetime DEFAULT NULL, - `error_log` enum('SI','NO') DEFAULT NULL, - `send_data` longtext DEFAULT NULL, - `response_data` mediumtext DEFAULT NULL, - PRIMARY KEY (`rowid`) USING BTREE -) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='Almacena el log de envío a la integración'; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `llx_verifactudolibarr_facture_log` --- - -LOCK TABLES `llx_verifactudolibarr_facture_log` WRITE; -/*!40000 ALTER TABLE `llx_verifactudolibarr_facture_log` DISABLE KEYS */; -INSERT INTO `llx_verifactudolibarr_facture_log` VALUES -(1,'464','2025-11-11 13:18:13','','SI','2025-11-11 13:18:14','NO','\n44890487FMarta Molina PérezES2025-F0242025-11-11Documento verificable2025-11-11F1S19530.0010.00953.0001S14200.0010.00420.0001S1375.0010.0037.5001S1325.0010.0032.5001S1700.0010.0070.0001S11200.0010.00120.0001S1190.0010.0019.0001S1250.0010.0025.0001S1360.0010.0036.0001S11650.0010.00165.0001S1600.0010.0060.0001S1890.0010.0089.0001S1850.0010.0085.0001S1400.0010.0040.0001S1400.0010.0040.0001S1315.0010.0031.5001S14900.0010.00490.0001S15976.0010.00597.6001S11404.0010.00140.4001S12500.0010.00250.0001S1-27727.2710.00-2772.7301S1-9090.9110.00-909.0901S1-196.8210.00-19.68010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F024&fecha=11-11-2025&importe=0.00\",\"queueId\":1}}'), -(2,'465','2025-11-25 07:23:46','','SI','2025-11-25 07:23:47','NO','\n24390713HVictor Guillermo Cortes TronchES2025-F0252025-11-25Documento verificable2025-11-25F1S13550.0021.00745.5001S11125.0021.00236.2501S1700.0021.00147.0001S1850.0021.00178.5001S16900.0021.001449.0001S12660.0021.00558.6001S1560.0021.00117.6001S160.0021.0012.6001S13680.0021.00772.8001S13200.0021.00672.0001S15800.0021.001218.0001S11361.350.000.0001S1-3.4721.00-0.7301S1-5785.1221.00-1214.8801S1-16157.0321.00-3392.9801S1-7139.3821.00-1499.2601S1-1361.350.000.00010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F025&fecha=25-11-2025&importe=0.00\",\"queueId\":2}}'), -(3,'466','2025-11-26 12:19:21','','SI','2025-11-26 12:19:22','NO','\n48388162AIgnacio Navarrete DualdeES2025-F0262025-11-26Documento verificable2025-11-26F1S11710.0021.00359.1001S16000.0021.001260.0001S12370.0021.00497.7001S1660.0021.00138.6001S1660.0021.00138.6001S12085.0021.00437.8501S1799.2021.00167.8301S18228.2421.001727.9301S1750.0021.00157.5001S11265.0021.00265.6501S11420.0021.00298.2001S1667.0021.00140.0701S1120.0021.0025.2001S12300.0021.00483.0001S1650.0021.00136.5001S1295.0021.0061.9501S195.0021.0019.9501S11400.0021.00294.0001S1840.0021.00176.4001S145.0021.009.4501S1711.7221.00149.4601S1280.0021.0058.8001S1194.0021.0040.7401S1198.0021.0041.5801S176.0021.0015.9601S176.0021.0015.9601S1634.610.000.0001S1-535.3321.00-112.4201S1-634.610.000.0001S1-33359.8321.00-7005.56010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F026&fecha=26-11-2025&importe=0.00\",\"queueId\":3}}'), -(4,'469','2025-11-26 16:26:20','','SI','2025-11-26 16:26:22','NO','\n48388162AIgnacio Navarrete DualdeES2025-F0272025-11-26Documento verificable2025-11-26F1S1-1710.0021.00-359.1001S1-6000.0021.00-1260.0001S1-2370.0021.00-497.7001S1-660.0021.00-138.6001S1-660.0021.00-138.6001S1-2085.0021.00-437.8501S1-799.2021.00-167.8301S1-8228.2421.00-1727.9301S1-750.0021.00-157.5001S1-1265.0021.00-265.6501S1-1420.0021.00-298.2001S1-667.0021.00-140.0701S1-120.0021.00-25.2001S1-2300.0021.00-483.0001S1-650.0021.00-136.5001S1-295.0021.00-61.9501S1-95.0021.00-19.9501S1-1400.0021.00-294.0001S1-840.0021.00-176.4001S1-45.0021.00-9.4501S1-711.7221.00-149.4601S1-280.0021.00-58.8001S1-194.0021.00-40.7401S1-198.0021.00-41.5801S1-76.0021.00-15.9601S1-76.0021.00-15.9601S1-634.610.000.0001S1535.3321.00112.4201S1634.610.000.0001S133359.8321.007005.56010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F027&fecha=26-11-2025&importe=0.00\",\"queueId\":4}}'), -(5,'470','2025-11-26 16:28:57','','SI','2025-11-26 16:28:58','NO','\n24373623VJuana Mª Alegría LlovetES2025-F0282025-11-26Documento verificable2025-11-26F1S11710.0021.00359.1001S16000.0021.001260.0001S12370.0021.00497.7001S1660.0021.00138.6001S1660.0021.00138.6001S12085.0021.00437.8501S1799.2021.00167.8301S18228.2421.001727.9301S1750.0021.00157.5001S11265.0021.00265.6501S11420.0021.00298.2001S1667.0021.00140.0701S1120.0021.0025.2001S12300.0021.00483.0001S1650.0021.00136.5001S1295.0021.0061.9501S195.0021.0019.9501S11400.0021.00294.0001S1840.0021.00176.4001S145.0021.009.4501S1711.7221.00149.4601S1280.0021.0058.8001S1194.0021.0040.7401S1198.0021.0041.5801S176.0021.0015.9601S176.0021.0015.9601S1634.610.000.0001S1-535.3321.00-112.4201S1-634.610.000.0001S1-33359.8321.00-7005.56010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F028&fecha=26-11-2025&importe=0.00\",\"queueId\":5}}'), -(6,'472','2025-11-26 18:39:59','','SI','2025-11-26 18:40:00','NO','\n44896705SRosa García DosdáES2025-F0292025-11-26Documento verificable2025-11-26F1S18256.4021.001733.8401S1900.0021.00189.0001S11235.0021.00259.3501S1990.0021.00207.9001S1925.0021.00194.2501S1350.0021.0073.5001S1285.0021.0059.8501S1450.0021.0094.5001S1200.0021.0042.0001S1120.0021.0025.2001S12950.0021.00619.5001S11300.0021.00273.0001S1735.0021.00154.3501S1360.0021.0075.6001S1495.0021.00103.9501S1570.0021.00119.7001S11141.750.000.0001S1610.0021.00128.1001S11400.0021.00294.0001S13386.4021.00711.1401S1-15.1221.00-3.1801S1-9917.3621.00-2082.6401S1-15585.3321.00-3272.9101S1-1141.740.000.00010.000.00\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F029&fecha=26-11-2025&importe=0.00\",\"queueId\":6}}'), -(7,'473','2025-11-26 19:32:44','','SI','2025-11-26 19:32:46','NO','\n44896705SRosa García DosdáES2025-F0302025-11-26Documento verificable2025-11-26F1S114469.0010.001446.9001S13835.0010.00383.5001S14900.0010.00490.0001S11170.0010.00117.0001S15490.0010.00549.0001S11215.0010.00121.5001S11456.0010.00145.6001S1350.0010.0035.0001S159.5010.005.9501S11377.0010.00137.7001S1588.0010.0058.8001S1582.0010.0058.2001S1186.0010.0018.6001S1200.0010.0020.0001S11000.0010.00100.0001S1380.0010.0038.0001S1620.0010.0062.0001S12500.0010.00250.0001S11900.0010.00190.0001S1833.6010.0083.3601S1663.0010.0066.3001S1148.6010.0014.8601S1204.0010.0020.4001S1108.0010.0010.8001S1564.0010.0056.4001S1780.0010.0078.0001S1359.0010.0035.9001S16070.0010.00607.0001S1-147.4921.00-30.9801S12700.0010.00270.0001S1-9090.9110.00-909.0901S1-31818.1810.00-3181.820115000.001348.88\n','{\"success\":true,\"data\":{\"verifactuUrl\":\"https:\\/\\/prewww2.aeat.es\\/wlpl\\/TIKE-CONT\\/ValidarQR?nif=B40529687&numserie=2025-F030&fecha=26-11-2025&importe=15000.00\",\"queueId\":7}}'), -(8,'474','2025-12-23 09:14:59','','SI','2025-12-23 09:15:00','SI','\n24362205FAngel Brazales MarcoES2025-F0312025-12-23Documento verificable2025-12-23F1S1371.9021.0078.1001450.0078.10\n','null'), -(9,'474','2025-12-23 09:15:29','','SI','2025-12-23 09:15:29','SI','\n24362205FAngel Brazales MarcoES2025-F0312025-12-23Documento verificable2025-12-23F1S1371.9021.0078.1001450.0078.10\n','null'), -(10,'474','2025-12-23 09:15:53','','SI','2025-12-23 09:15:53','SI','\n24362205FAngel Brazales MarcoES2025-F0312025-12-23Documento verificable2025-12-23F1S1371.9021.0078.1001450.0078.10\n','null'), -(11,'474','2025-12-23 09:17:09','','SI','2025-12-23 09:17:09','SI','\n24362205FAngel Brazales MarcoES2025-F0312025-12-23Documento verificable2025-12-23F1S1371.9021.0078.1001450.0078.10\n','null'), -(12,'474','2025-12-23 09:19:52','','SI','2025-12-23 09:19:53','SI','\n24362205FAngel Brazales MarcoES2025-F0312025-12-23Documento verificable2025-12-23F1S1371.9021.0078.1001450.0078.10\n','null'), -(13,'475','2025-12-23 09:25:05','','SI','2025-12-23 09:25:06','SI','\n19984467CAdelina Boltá EscolanoES2025-F0312025-12-23Documento verificable2025-12-23F1S1578.5121.00121.4901700.00121.49\n','null'); -/*!40000 ALTER TABLE `llx_verifactudolibarr_facture_log` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `llx_verifactudolibarr_messages` --- - -DROP TABLE IF EXISTS `llx_verifactudolibarr_messages`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `llx_verifactudolibarr_messages` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `Message` text DEFAULT NULL, - `date` datetime DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `llx_verifactudolibarr_messages` --- - -LOCK TABLES `llx_verifactudolibarr_messages` WRITE; -/*!40000 ALTER TABLE `llx_verifactudolibarr_messages` DISABLE KEYS */; -/*!40000 ALTER TABLE `llx_verifactudolibarr_messages` ENABLE KEYS */; -UNLOCK TABLES; - --- --- Table structure for table `llx_verifactudolibarr_tax_type` --- - -DROP TABLE IF EXISTS `llx_verifactudolibarr_tax_type`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `llx_verifactudolibarr_tax_type` ( - `rowid` int(11) NOT NULL AUTO_INCREMENT, - `tva_id` int(11) NOT NULL, - `veri_type` varchar(11) NOT NULL, - PRIMARY KEY (`rowid`) -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `llx_verifactudolibarr_tax_type` --- - -LOCK TABLES `llx_verifactudolibarr_tax_type` WRITE; -/*!40000 ALTER TABLE `llx_verifactudolibarr_tax_type` DISABLE KEYS */; -INSERT INTO `llx_verifactudolibarr_tax_type` VALUES -(1,44,'01'), -(2,43,'01'), -(3,42,'01'), -(4,41,'01'); -/*!40000 ALTER TABLE `llx_verifactudolibarr_tax_type` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `llx_webhook_history` -- diff --git a/htdocs/accountancy/bookkeeping/export.php b/htdocs/accountancy/bookkeeping/export.php index cb04d31acbf..ba785b3bf5c 100644 --- a/htdocs/accountancy/bookkeeping/export.php +++ b/htdocs/accountancy/bookkeeping/export.php @@ -1,7 +1,7 @@ * Copyright (C) 2013-2016 Florian Henry - * Copyright (C) 2013-2025 Alexandre Spangaro + * Copyright (C) 2013-2026 Alexandre Spangaro * Copyright (C) 2022 Lionel Vessiller * Copyright (C) 2016-2017 Laurent Destailleur * Copyright (C) 2018-2025 Frédéric France @@ -869,7 +869,7 @@ if ($action == 'export_file') { ); } - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").'...', '', 'export_fileconfirm', $form_question, '', 1, 390, 700); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").'...', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 500, 700); } // Print form confirm diff --git a/htdocs/admin/tools/ui/class/documentation.class.php b/htdocs/admin/tools/ui/class/documentation.class.php index cc145d3c5db..aabc27c4724 100644 --- a/htdocs/admin/tools/ui/class/documentation.class.php +++ b/htdocs/admin/tools/ui/class/documentation.class.php @@ -31,21 +31,21 @@ class Documentation /** * Views * - * @var array + * @var array|array */ public $view = array(); /** * Menu - Set in setMenu in order to use dol_buildpath and called in constructor * - * @var array + * @var array, submenu?: array}> */ public $menu = array(); /** * Summary - Set in setSummary and called in constructor * - * @var array + * @var array */ public $summary = array(); @@ -159,7 +159,7 @@ class Documentation ), 'Inputs' => array( 'url' => dol_buildpath($this->baseUrl.'/components/inputs.php', 1), - 'icon' => 'fas fa-comments', + 'icon' => 'far fa-edit', 'submenu' => array(), 'summary' => array( 'DocBasicUsage' => '#setinputssection-basicusage', @@ -167,6 +167,12 @@ class Documentation 'DocHelperFunctionsGetSearchFilterToolInput' => '#setinputssection-getSearchFilterToolInput', ) ), + 'ExperimentalUxInputAjaxFeedback' => array( + 'url' => dol_buildpath($this->baseUrl.'/content/input-feedback.php', 1), + 'icon' => 'far fa-share-square', + 'submenu' => array(), + 'summary' => array(), + ), ), ); @@ -247,12 +253,6 @@ class Documentation 'ExperimentalUxContributionTitle' => '#experimental-ux-contribution', ), ), - 'ExperimentalUxInputAjaxFeedback' => array( - 'url' => dol_buildpath($this->baseUrl.'/experimental/experiments/input-feedback/index.php', 1), - 'icon' => 'fas fa-flask', - 'submenu' => array(), - 'summary' => array(), - ), 'UxDolibarrContext' => array( 'url' => dol_buildpath($this->baseUrl.'/experimental/experiments/dolibarr-context/index.php', 1), 'icon' => 'fas fa-flask', @@ -369,7 +369,7 @@ class Documentation /** * Recursive function to set Menu * - * @param array $menu $this->menu or submenus + * @param array, submenu?: array}> $menu Menu entry or submenu * @param int $level level of menu * @return void */ @@ -446,9 +446,9 @@ class Documentation foreach ($this->view as $view) { $i++; if ($i == 1) { - $menu_entry = $this->menu[$view]; + $menu_entry = $this->menu[$view] ?? []; } else { - $menu_entry = $menu_entry['submenu'][$view]; + $menu_entry = $menu_entry['submenu'][$view] ?? []; } } } @@ -464,7 +464,7 @@ class Documentation /** * Recursive function for Automatic Summary * - * @param array $menu $this->menu or submenus + * @param array{summary?: array, submenu?: array} $menu $this->menu or submenus * @param int $level level of menu * @param int $showsubmenu Show Sub menus: 0 = No, 1 = Yes * @param int $showsubmenu_summary Show summary of sub menus: 0 = No, 1 = Yes @@ -518,7 +518,7 @@ class Documentation /** * Output a View Code area * - * @param array $lines Lines of code to show + * @param array $lines Lines of code to show * @param string $option Source code language ('html', 'php' etc) * @return void */ diff --git a/htdocs/admin/tools/ui/experimental/experiments/input-feedback/index.php b/htdocs/admin/tools/ui/content/input-feedback.php similarity index 91% rename from htdocs/admin/tools/ui/experimental/experiments/input-feedback/index.php rename to htdocs/admin/tools/ui/content/input-feedback.php index 9da34fba339..0706b1a1531 100644 --- a/htdocs/admin/tools/ui/experimental/experiments/input-feedback/index.php +++ b/htdocs/admin/tools/ui/content/input-feedback.php @@ -18,7 +18,7 @@ */ // Load Dolibarr environment -require '../../../../../../main.inc.php'; +require '../../../../main.inc.php'; /** * @var DoliDB $db @@ -50,7 +50,7 @@ $js = [ '/includes/ace/src/ext-language_tools.js', ]; $css = [ - $experimentAssetsPath . 'feddback-01.css' + ]; // Output html head + body - Param is Title @@ -73,11 +73,10 @@ $documentation->showSidebar(); ?> showSummary(); ?>
-

Input Feedback (Experimental)

+

Input Feedback

- This experimental feature provides visual feedback on input fields based on their processing state. - Currently, it is only available in this documentation and may be integrated into the develop branch of Dolibarr in the future. + This feature provides visual feedback on input fields based on their processing state.

How It Works

@@ -153,7 +152,7 @@ document.getElementById(\'btn-process-fail\').addEventListener(\'click\', functi });', '', ); - echo $documentation->showCode($lines, 'html'); ?> + $documentation->showCode($lines); ?>
diff --git a/htdocs/blockedlog/admin/blockedlog_archives.php b/htdocs/blockedlog/admin/blockedlog_archives.php index c6d711a04c1..700adef9973 100644 --- a/htdocs/blockedlog/admin/blockedlog_archives.php +++ b/htdocs/blockedlog/admin/blockedlog_archives.php @@ -376,6 +376,7 @@ if ($action == 'export' && $user->hasRight('blockedlog', 'read')) { // read is $concatenateddata = $block_static->buildKeyForSignature(); // Version line archive VE1=sha256 + $signatureexport = ''; if ($formatexport == 'VE1') { // Note: The signature on export line is not used. It has been replaced with a global signature on all file. $signatureexport = dol_hash($previoushashexport.$concatenateddata, 'sha256'); @@ -777,6 +778,7 @@ if ($action == 'check' || $action == 'checkconfirmed') { $reg = array(); $period = ''; + $regnumber = ''; $formatexport = ''; if (preg_match('/\speriod=([^\s]+)/', $line, $reg)) { $period = $reg[1]; // Get period on first line @@ -884,24 +886,24 @@ if ($action == 'check' || $action == 'checkconfirmed') { $lineanalyzed = 1; $linetech = $line[0]; - $block_static->id = $line[1]; - $block_static->date_creation = $line[2]; - $block_static->action = $lineactioncode = $line[3]; - $block_static->module_source = $line[4]; + $block_static->id = (int) $line[1]; + $block_static->date_creation = (string) $line[2]; + $block_static->action = $lineactioncode = (string) $line[3]; + $block_static->module_source = (string) $line[4]; $block_static->amounts_taxexcl = $lineamountht = $line[5]; $block_static->amounts = $lineamountttc = $line[6]; - $block_static->ref_object = $lineref = $line[7]; - $block_static->date_object = $line[8]; - $block_static->user_fullname = $line[9]; - $block_static->linktoref = $line[10]; - $block_static->linktype = $line[11]; - $block_static->object_data = json_decode($line[12]); - $block_static->object_version = $line[13]; - $block_static->object_format = $line[14]; - $block_static->signature = $line[15]; + $block_static->ref_object = $lineref = (string) $line[7]; + $block_static->date_object = (string) $line[8]; + $block_static->user_fullname = (string) $line[9]; + $block_static->linktoref = (string) $line[10]; + $block_static->linktype = (string) $line[11]; + $block_static->object_data = json_decode((string) $line[12]); + $block_static->object_version = (string) $line[13]; + $block_static->object_format = (string) $line[14]; + $block_static->signature = (string) $line[15]; // Status from file: 'Valid' or 'KO' - $statusline = $line[16]; + $statusline = (string) $line[16]; // Status revalidated from calculation using the HMAC secret key (possible only when we are on the same instance than // the one hosting the initial database of the archive) diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index 3a6b76e40c5..9984056beae 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -1161,7 +1161,7 @@ class BlockedLog { $aaa = null; try { - $aaa = (object) jsonOrUnserialize($data); + $aaa = (object) jsonOrUnserialize($data, false); } catch (Exception $e) { // print $e->getErrs); } diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 369b7c53d58..cd653ce48de 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -1708,7 +1708,6 @@ class Invoices extends DolibarrApi $totalpaid = $this->invoice->getSommePaiement(); $totalcreditnotes = $this->invoice->getSumCreditNotesUsed(); $totaldeposits = $this->invoice->getSumDepositsUsed(); - $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT'); $this->db->begin(); @@ -1717,13 +1716,13 @@ class Invoices extends DolibarrApi // Clean parameters amount if payment is for a credit note if ($this->invoice->type == Facture::TYPE_CREDIT_NOTE) { - $resteapayer = price2num($resteapayer, 'MT'); + $resteapayer = price2num($this->invoice->total_ttc + $totalpaid - $totalcreditnotes - $totaldeposits, 'MT'); $amounts[$id] = (float) price2num(-1 * abs((float) $resteapayer), 'MT'); // Multicurrency $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT'); $multicurrency_amounts[$id] = (float) price2num(-1 * (float) $newvalue, 'MT'); } else { - $resteapayer = price2num($resteapayer, 'MT'); + $resteapayer = price2num($this->invoice->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits, 'MT'); $amounts[$id] = (float) $resteapayer; // Multicurrency $newvalue = price2num($this->invoice->multicurrency_total_ttc, 'MT'); diff --git a/htdocs/compta/resultat/index.php b/htdocs/compta/resultat/index.php index 717e18ac061..9c43f104b4f 100644 --- a/htdocs/compta/resultat/index.php +++ b/htdocs/compta/resultat/index.php @@ -54,7 +54,7 @@ $date_endyear = GETPOSTINT('date_endyear'); $nbofyear = 4; -// Change this to test different cases of setup +// Change this to test different cases of setup. //$conf->global->SOCIETE_FISCAL_MONTH_START = 7; diff --git a/htdocs/contact/agenda.php b/htdocs/contact/agenda.php index edcc64b8f94..35e64572768 100644 --- a/htdocs/contact/agenda.php +++ b/htdocs/contact/agenda.php @@ -324,7 +324,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); diff --git a/htdocs/contrat/agenda.php b/htdocs/contrat/agenda.php index b0a7fa92d62..438b11096dc 100644 --- a/htdocs/contrat/agenda.php +++ b/htdocs/contrat/agenda.php @@ -307,7 +307,7 @@ if ($object->id > 0) { $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index ea233483aae..f50011bee9e 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4943,6 +4943,8 @@ abstract class CommonObject $this->context = array_merge($this->context, array('newstatus' => $status)); if ($trigkey && $trigkey != 'none') { + $this->oldcopy = dol_clone($this); + // Call trigger $result = $this->call_trigger($trigkey, $user); if ($result < 0) { diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index 2d17e02ec1c..c1e28930a37 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -1335,8 +1335,8 @@ class DolGraph if ($this->type[$firstlot] == 'piesemicircle') { - $this->stringtoshow .= 'circumference: Math.PI,' . "\n"; - $this->stringtoshow .= 'rotation: -Math.PI,' . "\n"; + $this->stringtoshow .= 'circumference: 180,' . "\n"; + $this->stringtoshow .= 'rotation: -90,' . "\n"; } $this->stringtoshow .= 'elements: { arc: {' . "\n"; // Color of each arc diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 4cfaf896aef..a988c197ce0 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -15,7 +15,7 @@ * Copyright (C) 2012-2016 Marcos García * Copyright (C) 2012 Cedric Salvador * Copyright (C) 2012-2015 Raphaël Doursenaud - * Copyright (C) 2014-2023 Alexandre Spangaro + * Copyright (C) 2014-2026 Alexandre Spangaro * Copyright (C) 2018-2022 Ferran Marcet * Copyright (C) 2018-2026 Frédéric France * Copyright (C) 2018 Nicolas ZABOURI @@ -7387,7 +7387,7 @@ class Form if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) { $langs->load("errors"); $new_country_code = $reg[1]; - $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid'); + $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid'); $this->error .= '
'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : '')); } $this->error .= ''; diff --git a/htdocs/core/class/html.formcontract.class.php b/htdocs/core/class/html.formcontract.class.php index 11eca55e4b6..2eb6591b79b 100644 --- a/htdocs/core/class/html.formcontract.class.php +++ b/htdocs/core/class/html.formcontract.class.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2012-2026 Charlene BENKE * Copyright (C) 2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -77,9 +77,10 @@ class FormContract $ret = ''; // Search all contacts - $sql = "SELECT c.rowid, c.ref, c.fk_soc, c.statut,"; + $sql = "SELECT c.rowid, c.ref, c.fk_soc, c.statut, s.nom,"; $sql .= " c.ref_customer, c.ref_supplier"; $sql .= " FROM ".$this->db->prefix()."contrat as c"; + $sql .= " INNER JOIN".$this->db->prefix()."societe as s ON s.rowid = c.fk_soc"; $sql .= " WHERE c.entity = ".$conf->entity; //if ($contratListId) $sql.= " AND c.rowid IN (".$this->db->sanitize($contratListId).")"; if ($socid > 0) { @@ -115,6 +116,7 @@ class FormContract $labeltoshow = dol_trunc($obj->ref, 18); if ($showRef) { + $labeltoshow = $labeltoshow." - ".$obj->nom; if ($obj->ref_customer) { $labeltoshow = $labeltoshow." - ".$obj->ref_customer; } diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index bf21c1f6da3..bba94b3f1bb 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1937,11 +1937,12 @@ function dol_size($size, $type = '') * @param string $newstr String to replace bad chars with. * @param int $unaccent 1=Remove also accent (default), 0 do not remove them * @param int $includequotes 1=Include simple quotes (double is already included by default) + * @param int $allowdash 1=Allow dash char after a space and before a string, 0 do not allow * @return string String cleaned * * @see dol_string_nospecial(), dol_string_unaccent(), dol_sanitizePathName() */ -function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1, $includequotes = 0) +function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1, $includequotes = 0, $allowdash = 0) { $str = (string) $str; @@ -1955,9 +1956,13 @@ function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1, $includequotes } $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars); $tmp = preg_replace('/\-\-+/', '_', $tmp); - $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp); - $tmp = preg_replace('/\s+\-$/', '', $tmp); + if (empty($allowdash)) { + $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp); + $tmp = preg_replace('/\s+\-$/', '', $tmp); + } $tmp = str_replace('..', '', $tmp); + $tmp = str_replace('~', $newstr, $tmp); + $tmp = preg_replace('/\s{2,}/', ' ', $tmp); return $tmp; } @@ -1998,6 +2003,8 @@ function dol_sanitizePathName($str, $newstr = '_', $unaccent = 0, $allowdash = 0 } $tmp = str_replace('..', $newstr, $tmp); $tmp = str_replace('~', $newstr, $tmp); + $tmp = preg_replace('/\s{2,}/', ' ', $tmp); + return $tmp; } @@ -12798,7 +12805,7 @@ function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, // No need to make a return $head. Var is modified as a reference if (!empty($hookmanager)) { - $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule); + $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule, 'type' => $type); // @phan-suppress-next-line PhanTypeMismatchArgumentNullable $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object); if ($reshook > 0) { // Hook ask to replace completely the array @@ -15703,11 +15710,12 @@ function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $tex * Decode an encoded string. The string can be encoded in json format (recommended) or with serialize (avoid this) * * @param string $stringtodecode String to decode (json or serialize coded) + * @param boolean $assoc true=Return is converted into associative array * @return mixed The decoded object. */ -function jsonOrUnserialize($stringtodecode) +function jsonOrUnserialize($stringtodecode, $assoc = true) { - $result = json_decode($stringtodecode); + $result = json_decode($stringtodecode, $assoc); if ($result === null) { $result = unserialize($stringtodecode); // For backward compatibility. Is no more used in recent versions. } diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 0be4d164c0f..5c2b03dc3ee 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3214,13 +3214,7 @@ class CommandeFournisseur extends CommonOrder if ($qty < $this->line->packaging) { $qty = $this->line->packaging; } else { - // Ensure packaging is numeric, positive, and use fmod instead of %, to prevent error with decimal packaging values (resulting in division by zero) - if ( - !empty($this->line->packaging) - && is_numeric($this->line->packaging) - && (float) $this->line->packaging > 0 - && fmod((float) $qty, (float) $this->line->packaging) > 0 - ) { + if (!empty($this->line->packaging) && is_numeric($this->line->packaging) && (float) $this->line->packaging > 0 && (fmod((float) $qty, (float) $this->line->packaging) > 0)) { $coeff = intval($qty / $this->line->packaging) + 1; $qty = $this->line->packaging * $coeff; setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs'); diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index 33b999f1127..697fb9c7aa4 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -1598,6 +1598,11 @@ if (empty($reshook)) { dol_syslog("Try to find source object origin=".$object->origin_type." originid=".$object->origin_id." to add lines"); $result = $srcobject->fetch($object->origin_id); if ($result > 0) { + if (empty($object->delivery_date)) { + $tmpdate = $srcobject->delivery_date; + $object->setDeliveryDate($user, $tmpdate); + } + $object->set_id_projet($user, $srcobject->fk_project); $lines = $srcobject->lines; diff --git a/htdocs/install/mysql/data/llx_c_tva.sql b/htdocs/install/mysql/data/llx_c_tva.sql index 7f99eb8f9ed..5e3deaaacfb 100644 --- a/htdocs/install/mysql/data/llx_c_tva.sql +++ b/htdocs/install/mysql/data/llx_c_tva.sql @@ -207,7 +207,7 @@ insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (1 insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (140, '14','0','VAT rate - intermediary',1,__ENTITY__); insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (140, '8','0','VAT rate - reduced', 1,__ENTITY__); insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (140, '3','0','VAT rate - super-reduced', 1,__ENTITY__); -insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (140, '16','0','VAT rate - standard',1,__ENTITY__); +insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (140, '17','0','VAT rate - standard',1,__ENTITY__); -- MALI (id country=147) insert into llx_c_tva(fk_pays,taux,recuperableonly,note,active,entity) values (147, '0','0','VAT rate 0', 1,__ENTITY__); diff --git a/htdocs/langs/en_US/supplier_proposal.lang b/htdocs/langs/en_US/supplier_proposal.lang index c651d8b0c86..4867c0a5146 100644 --- a/htdocs/langs/en_US/supplier_proposal.lang +++ b/htdocs/langs/en_US/supplier_proposal.lang @@ -41,7 +41,7 @@ SendAskRef=Sending the price request %s SupplierProposalCard=Request card ConfirmDeleteAsk=Are you sure you want to delete this price request %s? ActionsOnSupplierProposal=Events on price request -DocModelAuroreDescription=A complete template for a vendor quotation request (old implementation of Sponge template) +DocModelAuroreDescription=A complete template for a vendor quotation request (old implementation of Zenith template) DocModelZenithDescription=A complete template for a vendor quotation request CommercialAsk=Price request DefaultModelSupplierProposalCreate=Default model creation diff --git a/htdocs/modulebuilder/template/myobject_agenda.php b/htdocs/modulebuilder/template/myobject_agenda.php index 712735c0328..b93a08f2ede 100644 --- a/htdocs/modulebuilder/template/myobject_agenda.php +++ b/htdocs/modulebuilder/template/myobject_agenda.php @@ -339,7 +339,7 @@ if ($object->id > 0) { $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); diff --git a/htdocs/product/agenda.php b/htdocs/product/agenda.php index 3bfeda941b0..9b534ad266f 100644 --- a/htdocs/product/agenda.php +++ b/htdocs/product/agenda.php @@ -251,7 +251,7 @@ if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); diff --git a/htdocs/projet/agenda.php b/htdocs/projet/agenda.php index 9456df8ff7b..2ccbd2320d3 100644 --- a/htdocs/projet/agenda.php +++ b/htdocs/projet/agenda.php @@ -245,7 +245,7 @@ if (!empty($object->id)) { $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); @@ -258,7 +258,7 @@ if (!empty($object->id)) { $param .= '&dateevent_endday='.GETPOSTINT('dateevent_endday'); } - + // Try to know count of actioncomm from cache require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php'; $cachekey = 'count_events_project_'.$object->id; $nbEvent = dol_getcache($cachekey); diff --git a/htdocs/societe/agenda.php b/htdocs/societe/agenda.php index 9dbcb742990..6af9aff6b68 100644 --- a/htdocs/societe/agenda.php +++ b/htdocs/societe/agenda.php @@ -241,7 +241,7 @@ if (isModEnabled('agenda') && ($user->hasRight('agenda', 'myactions', 'read') || $param .= '&search_complete='.urlencode($search_complete); } if ($search_filtert != '') { - $param .= '&search_filtert='.urlencode($search_filtert); + $param .= '&search_filtert='.urlencode((string) $search_filtert); } if ($search_dateevent_start != '') { $param .= '&dateevent_startyear='.GETPOSTINT('dateevent_startyear'); diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 9ce4ccb76c5..c1e62959e8a 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1135,8 +1135,9 @@ class Thirdparties extends DolibarrApi $sql = ''; if ($mode === 'customer') { $sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f"; - $sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id); + $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON f.rowid = re.fk_facture_source"; + $sql .= " WHERE re.fk_soc = ".((int) $id); if ($filter == "available") { $sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL"; } @@ -1145,7 +1146,8 @@ class Thirdparties extends DolibarrApi } } elseif ($mode === 'supplier') { $sql = "SELECT f.ref, f.type as factype, re.fk_invoice_supplier_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_invoice_supplier, re.fk_invoice_supplier_line"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture_fourn as f"; + $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture_fourn as f ON f.rowid = re.fk_invoice_supplier_source"; $sql .= " WHERE f.rowid = re.fk_invoice_supplier_source AND re.fk_soc = ".((int) $id); if ($filter == "available") { $sql .= " AND re.fk_invoice_supplier IS NULL AND re.fk_invoice_supplier_line IS NULL"; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index a043494c693..e9c4e0b1954 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -216,13 +216,13 @@ class Societe extends CommonObject 'idprof4' => array('type' => 'varchar(128)', 'label' => 'Idprof4', 'enabled' => 1, 'visible' => -1, 'position' => 205), 'idprof5' => array('type' => 'varchar(128)', 'label' => 'Idprof5', 'enabled' => 1, 'visible' => -1, 'position' => 206), 'idprof6' => array('type' => 'varchar(128)', 'label' => 'Idprof6', 'enabled' => 1, 'visible' => -1, 'position' => 207), - 'tva_intra' => array('type' => 'varchar(20)', 'label' => 'Tva intra', 'enabled' => 1, 'visible' => -1, 'position' => 210), + 'tva_intra' => array('type' => 'varchar(20)', 'label' => 'VATIntra', 'enabled' => 1, 'visible' => -1, 'position' => 210), 'capital' => array('type' => 'double(24,8)', 'label' => 'Capital', 'enabled' => 1, 'visible' => -1, 'position' => 215), 'fk_stcomm' => array('type' => 'integer', 'label' => 'CommercialStatus', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 220), 'note_public' => array('type' => 'html', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 225), 'note_private' => array('type' => 'html', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 230), - 'client' => array('type' => 'tinyint(4)', 'label' => 'Client', 'enabled' => 1, 'visible' => -1, 'position' => 240), - 'fournisseur' => array('type' => 'tinyint(4)', 'label' => 'Fournisseur', 'enabled' => 1, 'visible' => -1, 'position' => 245), + 'client' => array('type' => 'tinyint(4)', 'label' => 'Customer', 'enabled' => 1, 'visible' => -1, 'position' => 240), + 'fournisseur' => array('type' => 'tinyint(4)', 'label' => 'Supplier', 'enabled' => 1, 'visible' => -1, 'position' => 245), 'supplier_account' => array('type' => 'varchar(32)', 'label' => 'Supplier account', 'enabled' => 1, 'visible' => -1, 'position' => 250), 'fk_prospectlevel' => array('type' => 'varchar(12)', 'label' => 'ProspectLevel', 'enabled' => 1, 'visible' => -1, 'position' => 255), 'customer_bad' => array('type' => 'tinyint(4)', 'label' => 'Customer bad', 'enabled' => 1, 'visible' => -1, 'position' => 260), @@ -1141,11 +1141,11 @@ class Societe extends CommonObject } } - // Ajout du commercial affecte + // Addition of the assigned sales representative if ($this->commercial_id != '' && $this->commercial_id != -1) { $this->add_commercial($user, $this->commercial_id); } elseif (!$user->hasRight('societe', 'client', 'voir')) { - // si un commercial cree un client il lui est affecte automatiquement + // If a sales representative creates a customer, they are automatically assigned to them. $this->add_commercial($user, $user->id); } @@ -1506,9 +1506,9 @@ class Societe extends CommonObject $this->order_min_amount = price2num($this->order_min_amount); $this->supplier_order_min_amount = price2num($this->supplier_order_min_amount); - $this->tva_assuj = (is_numeric($this->tva_assuj)) ? (int) trim((string) $this->tva_assuj) : 0; - $this->tva_intra = dol_sanitizeFileName($this->tva_intra ?? '', ''); - $this->vat_reverse_charge = empty($this->vat_reverse_charge) ? 0 : 1; + $this->tva_assuj = (is_numeric($this->tva_assuj)) ? (int) trim((string) $this->tva_assuj) : 0; + $this->tva_intra = trim($this->tva_intra); + $this->vat_reverse_charge = empty($this->vat_reverse_charge) ? 0 : 1; if (empty($this->status)) { $this->status = 0; } @@ -1879,7 +1879,7 @@ class Societe extends CommonObject } } else { if ($this->db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { - // Doublon + // Duplicate $this->error = $langs->trans("ErrorDuplicateField"); $result = -1; } else { @@ -2179,7 +2179,7 @@ class Societe extends CommonObject $this->order_min_amount = $obj->order_min_amount; $this->supplier_order_min_amount = $obj->supplier_order_min_amount; - // multiprix + // multi price $this->price_level = $obj->price_level; // warehouse @@ -2567,7 +2567,7 @@ class Societe extends CommonObject if ($this->id) { $newclient = 1; if (($this->client == 2 || $this->client == 3) && !getDolGlobalInt('SOCIETE_DISABLE_PROSPECTSCUSTOMERS')) { - $newclient = 3; //If prospect, we keep prospect tag + $newclient = 3; // If prospected, we keep prospect tag } $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; $sql .= " SET client = ".((int) $newclient); @@ -3867,7 +3867,7 @@ class Societe extends CommonObject return 1; } if ($mod->code_modifiable) { - return 1; // A mettre en dernier + return 1; // To be put last } return 0; } else { @@ -3908,7 +3908,7 @@ class Societe extends CommonObject return 1; } if ($mod->code_modifiable) { - return 1; // A mettre en dernier + return 1; // To be put last } return 0; } else { @@ -4701,7 +4701,7 @@ class Societe extends CommonObject $this->db->begin(); - // Cree et positionne $this->id + // Creates and positions $this->id $result = $this->create($user); if ($result >= 0) { @@ -4738,7 +4738,7 @@ class Societe extends CommonObject return -1; } } else { - // $this->error deja positionne + // $this->error already positioned dol_syslog(get_class($this)."::create_from_member - 2 - ".$this->error." - ".implode(',', $this->errors), LOG_ERR); $this->db->rollback(); @@ -5440,7 +5440,7 @@ class Societe extends CommonObject $result = $companybankaccount->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); $this->last_main_doc = $companybankaccount->last_main_doc; } else { - // Positionne le modele sur le nom du modele a utiliser + // Set the model to the name of the model to be used if (!dol_strlen($modele)) { if (getDolGlobalString('COMPANY_ADDON_PDF')) { $modele = getDolGlobalString('COMPANY_ADDON_PDF'); diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 586db46dc84..802773f63d8 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -9463,6 +9463,7 @@ include dol_buildpath($path.'/theme/'.$theme.'/progress.inc.php', 0); include dol_buildpath($path.'/theme/'.$theme.'/timeline.inc.php', 0); include dol_buildpath($path.'/theme/'.$theme.'/search-input.inc.css', 0); include dol_buildpath($path.'/theme/'.$theme.'/tooltips.inc.css', 0); +include dol_buildpath($path.'/theme/'.$theme.'/input-feedback.css', 0); // Add custom CSS if defined diff --git a/htdocs/admin/tools/ui/experimental/experiments/input-feedback/assets/feddback-01.css b/htdocs/theme/eldy/input-feedback.css similarity index 100% rename from htdocs/admin/tools/ui/experimental/experiments/input-feedback/assets/feddback-01.css rename to htdocs/theme/eldy/input-feedback.css diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 3aa25c49b94..030bdd12828 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -9186,6 +9186,7 @@ include dol_buildpath($path.'/theme/'.$theme.'/progress.inc.php', 0); include dol_buildpath($path.'/theme/eldy/timeline.inc.php', 0); // actually md use same style as eldy theme include dol_buildpath($path.'/theme/'.$theme.'/search-input.inc.css', 0); // actually md use same style as eldy theme include dol_buildpath($path.'/theme/'.$theme.'/tooltips.inc.css', 0); +include dol_buildpath($path.'/theme/eldy/input-feedback.css', 0); // actually md use same style as eldy theme if (getDolGlobalString('THEME_CUSTOM_CSS')) { print getDolGlobalString('THEME_CUSTOM_CSS'); diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index d5ac4c886f8..75776878340 100644 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -634,7 +634,7 @@ if (empty($reshook)) { // Reopen ticket if ($object->fetch(GETPOSTINT('id'), GETPOST('track_id', 'alpha')) >= 0) { $new_status = GETPOSTINT('new_status'); - //$old_status = $object->status; + $res = $object->setStatut($new_status, null, '', $triggermodname); if ($res) { $url = 'card.php?track_id=' . $object->track_id; diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index 21a3cea83b9..8be726ba18d 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -1717,7 +1717,7 @@ class Ticket extends CommonObject $this->status = Ticket::STATUS_READ; $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; - $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'"; + $sql .= " SET fk_statut = ".((int) $this->status) .", date_read = '".$this->db->idate(dol_now())."'"; $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this)."::markAsRead"); @@ -1742,7 +1742,9 @@ class Ticket extends CommonObject $this->status = $this->oldcopy->status; $this->db->rollback(); + $this->error = implode(',', $this->errors); + dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR); return -1; } @@ -2009,8 +2011,11 @@ class Ticket extends CommonObject if ($this->status != Ticket::STATUS_CLOSED && $this->status != Ticket::STATUS_CANCELED) { // not closed $this->db->begin(); + $this->oldcopy = dol_clone($this); + $this->status = ($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED); + $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; - $sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'"; + $sql .= " SET fk_statut = ".((int) $this->status).", progress=100, date_close='".$this->db->idate(dol_now())."'"; $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this)."::close mode=".$mode); @@ -3068,8 +3073,10 @@ class Ticket extends CommonObject if ((getDolGlobalInt('TICKET_SET_STATUS_ON_ANSWER', -1) < 0 && ($object->status < self::STATUS_IN_PROGRESS && !$user->socid && !$private)) || ($object->status > self::STATUS_IN_PROGRESS && $public_area)) { + // Set status $object->setStatut($object::STATUS_IN_PROGRESS, null, '', 'TICKET_MODIFY'); } elseif (getDolGlobalInt('TICKET_SET_STATUS_ON_ANSWER', -1) >= 0 && empty($user->socid) && empty($private)) { + // Set status $object->setStatut(getDolGlobalInt('TICKET_SET_STATUS_ON_ANSWER'), null, '', 'TICKET_MODIFY'); } diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index 178b97b2417..1a39504ad93 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -298,7 +298,9 @@ if (empty($reshook)) { $result = $objecttmp->fetch($toselectid); if ($result > 0) { if ($objecttmp->status == Ticket::STATUS_CLOSED || $objecttmp->status == Ticket::STATUS_CANCELED) { + // Set status $result = $objecttmp->setStatut(Ticket::STATUS_ASSIGNED, null, '', 'TICKET_MODIFY'); + if ($result < 0) { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); $error++;