diff --git a/htdocs/admin/expedition.php b/htdocs/admin/expedition.php index 4f50ce75fe8..45ea1431143 100644 --- a/htdocs/admin/expedition.php +++ b/htdocs/admin/expedition.php @@ -480,6 +480,13 @@ print $form->textwithpicto($langs->trans("WatermarkOnDraftContractCards"), $html print ''; print "\n"; +// Allow OnLine Sign +print ''; +print ''.$langs->trans("AllowOnLineSign").''; +print ''; +print ajax_constantonoff('EXPEDITION_ALLOW_ONLINESIGN', array(), null, 0, 0, 0, 2, 0, 1); +print ''; + print ''; print $form->buttonsSaveCancel("Modify", ''); diff --git a/htdocs/core/actions_addupdatedelete.inc.php b/htdocs/core/actions_addupdatedelete.inc.php index fee69b1c9a0..11b838af679 100644 --- a/htdocs/core/actions_addupdatedelete.inc.php +++ b/htdocs/core/actions_addupdatedelete.inc.php @@ -102,6 +102,12 @@ if ($action == 'add' && !empty($permissiontoadd)) { $value = GETPOST($key, $tmparray[1]); } else { $value = GETPOST($key, 'nohtml'); + if (!empty($object->fields[$key]['arrayofkeyval']) && !empty($object->fields[$key]['multiinput'])) { + $tmparraymultiselect = GETPOST($key.'_multiselect', 'array'); + foreach ($tmparraymultiselect as $tmpvalue) { + $value .= (!empty($value) ? "," : "").$tmpvalue; + } + } } } elseif (preg_match('/^html/', $object->fields[$key]['type'])) { $tmparray = explode(':', $object->fields[$key]['type']); @@ -255,6 +261,12 @@ if ($action == 'update' && !empty($permissiontoadd)) { $value = GETPOST($key, $tmparray[1]); } else { $value = GETPOST($key, 'nohtml'); + if (!empty($object->fields[$key]['arrayofkeyval']) && !empty($object->fields[$key]['multiinput'])) { + $tmparraymultiselect = GETPOST($key.'_multiselect', 'array'); + foreach ($tmparraymultiselect as $keytmp => $tmpvalue) { + $value .= (!empty($value) ? "," : "").$tmpvalue; + } + } } } elseif (preg_match('/^html/', $object->fields[$key]['type'])) { $tmparray = explode(':', $object->fields[$key]['type']); diff --git a/htdocs/core/ajax/editinline.php b/htdocs/core/ajax/editinline.php new file mode 100644 index 00000000000..4d4fbe74e17 --- /dev/null +++ b/htdocs/core/ajax/editinline.php @@ -0,0 +1,110 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/ajax/editinline.php + * \brief Save edit inline changes + */ + + +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); // Disables token renewal +} +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +if (!defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} +if (!defined('NOREQUIRESOC')) { + define('NOREQUIRESOC', '1'); +} + +// Load Dolibarr environment +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php'; +require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/website2.lib.php'; + + +$action = GETPOST('action', 'alpha'); +$website_ref = GETPOST('website_ref'); +$page_id = GETPOST('page_id'); +$content = GETPOST('content', 'none'); +$element_id = GETPOST('element_id'); +$element_type = GETPOST('element_type'); + +$usercanmodify = $user->hasRight('website', 'write'); +if (!$usercanmodify) { + print "You don't have permission for this action."; + exit; +} + + +/* + * View + */ + +top_httphead(); + +if (!empty($action) && $action === 'updatedElementContent' && $usercanmodify && !empty($content) && !empty($element_id) && !empty($website_ref) && !empty($page_id)) { + // Page object + $objectpage = new WebsitePage($db); + $res = $objectpage->fetch($page_id); + if (!$res) { + print "Cannot find page with ID = " . $page_id . "."; + exit; + } + + // Website object + $objectwebsite = new Website($db); + $res = $objectwebsite->fetch($objectpage->fk_website); + if (!$res) { + print "Cannot find website with REF " . $objectpage->fk_website . "."; + exit; + } + + $db->begin(); + $error = 0; + + // Replace element content into database and tpl file + $objectpage->content = preg_replace('/<' . $element_type . '[^>]*id="' . $element_id . '"[^>]*>\K(.*?)(?=<\/' . $element_type . '>)/s', $content, $objectpage->content, 1); + $res = $objectpage->update($user); + if ($res) { + global $dolibarr_main_data_root; + $pathofwebsite = $dolibarr_main_data_root.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/'.$website_ref; + $filetpl = $pathofwebsite.'/page'.$objectpage->id.'.tpl.php'; + + $result = dolSavePageContent($filetpl, $objectwebsite, $objectpage, 1); + if (!$result) { + print "Failed to write file " . $filetpl . "."; + $error++; + } + } else { + print "Failed to save changes error " . $objectpage->error . "."; + $error++; + } + + if (!$error) { + $db->commit(); + print "Changes are saved for " . $element_type . " with id " . $element_id; + } else { + $db->rollback(); + } + + $db->close(); +} diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php index 48e140299e7..5abc559430f 100644 --- a/htdocs/core/ajax/onlineSign.php +++ b/htdocs/core/ajax/onlineSign.php @@ -678,6 +678,152 @@ if ($action == "importSignature") { $db->rollback(); } } + } elseif ($mode == 'expedition') { + require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php'; + + $object = new Expedition($db); + $object->fetch(0, $ref); + + $upload_dir = $conf->expedition->dir_output."/sending/"; + $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/'; + + $langs->loadLangs(array("main", "companies")); + + $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance + $default_font = pdf_getPDFFont($langs); // Must be + + $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S"); + $filename = "signatures/" . $date . "_signature.png"; + if (!is_dir($upload_dir . "signatures/")) { + if (!dol_mkdir($upload_dir . "signatures/")) { + $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/"; + $error++; + } + } + + if (!$error) { + $return = file_put_contents($upload_dir . $filename, $data); + if ($return == false) { + $error++; + $response = 'Error file_put_content: failed to create signature file.'; + } + } + + if (!$error) { + $last_main_doc_file = $object->last_main_doc; + // Defined modele of doc + if (empty($last_main_doc_file) || !dol_is_file(DOL_DATA_ROOT.'/'.$object->last_main_doc)) { + // It seems document has never been generated, or was generated and then deleted. + // So we try to regenerate it with its default template. + $defaulttemplate = ''; // We force the use an empty string instead of $object->model_pdf to be sure to use a "main" default template and not the last one used. + $object->generateDocument($defaulttemplate, $langs); + } + $last_main_doc_file = $object->last_main_doc; + $directdownloadlink = $object->getLastMainDocLink('expedition'); // url to download the $object->last_main_doc + if (preg_match('/\.pdf/i', $last_main_doc_file)) { + // TODO Use the $last_main_doc_file to defined the $newpdffilename and $sourcefile + $newpdffilename = $upload_dir . $ref . "_signed-" . $date . ".pdf"; + $sourcefile = $upload_dir . $ref . ".pdf"; + + + if (dol_is_file($sourcefile)) { + // We build the new PDF + $pdf = pdf_getInstance(); + if (class_exists('TCPDF')) { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($langs)); + + if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) { + $pdf->SetCompression(false); + } + + //$pdf->Open(); + $pagecount = $pdf->setSourceFile($sourcefile); // original PDF + + $param = array(); + $param['online_sign_name'] = $online_sign_name; + $param['pathtoimage'] = $upload_dir . $filename; + + $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297); + for ($i = 1; $i < ($pagecount + 1); $i++) { + try { + $tppl = $pdf->importPage($i); + $s = $pdf->getTemplatesize($tppl); + $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L'); + $pdf->useTemplate($tppl); + + if (getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) { + // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF + // TODO Get position of box from PDF template + + $param['xforimgstart'] = 111; + $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60); + $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16); + + dolPrintSignatureImage($pdf, $langs, $param); + } + } catch (Exception $e) { + dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR); + $response = $e->getMessage(); + $error++; + } + } + + if (!getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) { + // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF + // TODO Get position of box from PDF template + + $param['xforimgstart'] = 111; + $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60); + $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16); + + dolPrintSignatureImage($pdf, $langs, $param); + } + + //$pdf->Close(); + $pdf->Output($newpdffilename, "F"); + + // Index the new file and update the last_main_doc property of object. + $object->indexFile($newpdffilename, 1); + } + if (!$error) { + $response = "success"; + } + } elseif (preg_match('/\.odt/i', $last_main_doc_file)) { + // Adding signature on .ODT not yet supported + // TODO + } else { + // Document format not supported to insert online signature. + // We should just create an image file with the signature. + } + } + + if (!$error) { + $db->begin(); + + $sql = "UPDATE " . MAIN_DB_PREFIX . "expedition"; + $sql .= " SET signed_status = " . ((int) $object::STATUS_SIGNED) ; + $sql .= " WHERE rowid = " . ((int) $object->id); + + dol_syslog(__FILE__, LOG_DEBUG); + $resql = $db->query($sql); + if (!$resql) { + $error++; + } else { + $num = $db->affected_rows($resql); + } + + if (!$error) { + $db->commit(); + $response = "success"; + setEventMessages("ExpeditionSigned", null, 'warnings'); + } else { + $db->rollback(); + } + } } } else { $error++; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index b3235088bb7..450036f06a2 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7257,6 +7257,7 @@ abstract class CommonObject $validationClass = ' --success'; // the -- is use as class state in css : .--success can't be be defined alone it must be define with another class like .my-class.--success or input.--success } + $valuemultiselectinput = array(); $out = ''; $type = ''; $isDependList = 0; @@ -7303,7 +7304,19 @@ abstract class CommonObject // Special case that force options and type ($type can be integer, varchar, ...) if (!empty($this->fields[$key]['arrayofkeyval']) && is_array($this->fields[$key]['arrayofkeyval'])) { $param['options'] = $this->fields[$key]['arrayofkeyval']; - $type = (($this->fields[$key]['type'] == 'checkbox') ? $this->fields[$key]['type'] : 'select'); + // Special case that prevent to force $type to have multiple input + if (empty($this->fields[$key]['multiinput'])) { + $type = (($this->fields[$key]['type'] == 'checkbox') ? $this->fields[$key]['type'] : 'select'); + } else { + $valuearray = explode(",", $value); + foreach ($valuearray as $keytmp => $valuetmp) { + if (!empty($this->fields[$key]['arrayofkeyval'][$valuetmp])) { + $valuemultiselectinput[] = $valuetmp; + unset($valuearray[$keytmp]); + } + } + $value = implode(',', $valuearray); + } } $label = $this->fields[$key]['label']; @@ -7403,9 +7416,13 @@ abstract class CommonObject $out = ''; } elseif (preg_match('/^text/', (string) $type)) { if (!preg_match('/search_/', $keyprefix)) { // If keyprefix is search_ or search_options_, we must just use a simple text field + if (!empty($param['options'])) { + $out .= "
"; + $out .= $form->multiselectarray($keyprefix.$key.$keysuffix."_multiselect", $param['options'], (GETPOSTISSET($keyprefix.$key.$keysuffix."_multiselect") ? GETPOST($keyprefix.$key.$keysuffix."_multiselect") : $valuemultiselectinput), 0, 0, "flat maxwidthonphone".$morecss, 0, '90%', '', '', '', ((!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_EXTRAFIELDS_DISABLE_SELECT2')) ? 1 : -1)); + } require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; $doleditor = new DolEditor($keyprefix.$key.$keysuffix, $value, '', 200, 'dolibarr_notes', 'In', false, false, false, ROWS_5, '90%'); - $out = (string) $doleditor->Create(1, '', true, '', '', '', $morecss); + $out .= (string) $doleditor->Create(1, '', true, '', '', '', $morecss); } else { $out = ''; } @@ -7965,7 +7982,9 @@ abstract class CommonObject $type = 'varchar'; // convert varchar(xx) int varchar } if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { - $type = (($this->fields[$key]['type'] == 'checkbox') ? $this->fields[$key]['type'] : 'select'); + if (empty($this->fields[$key]['multiinput'])) { + $type = (($this->fields[$key]['type'] == 'checkbox') ? $this->fields[$key]['type'] : 'select'); + } } if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) { $type = 'link'; diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 05190edc8ae..c536efaabc8 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -890,7 +890,11 @@ class FormFile } else { $out .= ''; } - $out .= ' -