diff --git a/htdocs/admin/fichinter.php b/htdocs/admin/fichinter.php index 4e4438263c3..cf637d37329 100644 --- a/htdocs/admin/fichinter.php +++ b/htdocs/admin/fichinter.php @@ -208,6 +208,32 @@ if ($action == 'updateMask') { $error++; } + if (!$error) { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } else { + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} elseif ($action == "set_FICHINTER_ALLOW_ONLINE_SIGN") { + $val = GETPOST('FICHINTER_ALLOW_ONLINE_SIGN', 'alpha'); + $res = dolibarr_set_const($db, "FICHINTER_ALLOW_ONLINE_SIGN", ($val == 'on' ? 1 : 0), 'bool', 0, '', $conf->entity); + + if (!($res > 0)) { + $error++; + } + + if (!$error) { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } else { + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} elseif ($action == "set_FICHINTER_ALLOW_EXTERNAL_DOWNLOAD") { + $val = GETPOST('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD', 'alpha'); + $res = dolibarr_set_const($db, "FICHINTER_ALLOW_EXTERNAL_DOWNLOAD", ($val == 'on' ? 1 : 0), 'bool', 0, '', $conf->entity); + + if (!($res > 0)) { + $error++; + } + if (!$error) { setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); } else { @@ -594,6 +620,39 @@ print ''; print ''; print ''; +// Allow online signing +print '
'; +print ''; +print ''; +print ''; +print ''; +print $langs->trans("AllowOnlineSign"); +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print '
'; +// Allow external download +print '
'; +print ''; +print ''; +print ''; +print ''; +print $langs->trans("AllowExternalDownload"); +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print '
'; + print ''; print ''; diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php index 7866b972db1..c71fed19f6d 100644 --- a/htdocs/core/ajax/onlineSign.php +++ b/htdocs/core/ajax/onlineSign.php @@ -314,6 +314,93 @@ if ($action == "importSignature") { // We should just create an image file with the signature. } } + } elseif ($mode == 'fichinter') { + require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + $object = new Fichinter($db); + $object->fetch(0, $ref); + + $upload_dir = !empty($conf->ficheinter->multidir_output[$object->entity])?$conf->ficheinter->multidir_output[$object->entity]:$conf->ficheinter->dir_output; + $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/'; + $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) { + // Defined modele of doc + $last_main_doc_file = $object->last_main_doc; + $directdownloadlink = $object->getLastMainDocLink('fichinter'); // 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 + $s = array(); // Array with size of each page. Exemple 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); + } catch (Exception $e) { + dol_syslog("Error when manipulating some PDF by onlineSign: ".$e->getMessage(), LOG_ERR); + $response = $e->getMessage(); + $error++; + } + } + + // 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 + $xforimgstart = 105; + $yforimgstart = (empty($s['h']) ? 250 : $s['h'] - 57); + $wforimg = $s['w']/1 - ($xforimgstart + 16); + $pdf->Image($upload_dir.$filename, $xforimgstart, $yforimgstart, $wforimg, round($wforimg / 4)); + //$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. + } + } } } else { $error++; diff --git a/htdocs/core/lib/signature.lib.php b/htdocs/core/lib/signature.lib.php index 070cbe0801f..9cc8f1f03a9 100644 --- a/htdocs/core/lib/signature.lib.php +++ b/htdocs/core/lib/signature.lib.php @@ -131,6 +131,21 @@ function getOnlineSignatureUrl($mode, $type, $ref = '', $localorexternal = 1) } else { $out .= '&securekey='.dol_hash($securekeyseed.$type.$ref.(!isModEnabled('multicompany') ? '' : $object->entity), '0'); } + } elseif ($type == 'fichinter') { + $securekeyseed = isset($conf->global->FICHINTER_ONLINE_SIGNATURE_SECURITY_TOKEN) ? $conf->global->FICHINTER_ONLINE_SIGNATURE_SECURITY_TOKEN : ''; + $out = $urltouse.'/public/onlinesign/newonlinesign.php?source=fichinter&ref='.($mode ? '' : ''); + if ($mode == 1) { + $out .= 'fichinter_ref'; + } + if ($mode == 0) { + $out .= urlencode($ref); + } + $out .= ($mode ? '' : ''); + if ($mode == 1) { + $out .= "hash('".$securekeyseed."' + '".$type."' + fichinter_ref)"; + } else { + $out .= '&securekey='.dol_hash($securekeyseed.$type.$ref.(!isModEnabled('multicompany') ? '' : $object->entity), '0'); + } } // For multicompany diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index d172a865811..a0d7cab9f51 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -1713,6 +1713,13 @@ if ($action == 'create') { $linktoelem = $form->showLinkToObjectBlock($object, null, array('fichinter')); $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem); + // Show online signature link + if ($object->statut != Fichinter::STATUS_DRAFT && $conf->global->FICHINTER_ALLOW_ONLINE_SIGN) { + print '
'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php'; + + print showOnlineSignatureUrl('fichinter', $object->ref).'
'; + } print '
'; diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index 7a5f3bc73ad..e36598d04bc 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -442,7 +442,7 @@ class Fichinter extends CommonObject $sql .= " f.datec, f.dateo, f.datee, f.datet, f.fk_user_author,"; $sql .= " f.date_valid as datev,"; $sql .= " f.tms as datem,"; - $sql .= " f.duree, f.fk_projet as fk_project, f.note_public, f.note_private, f.model_pdf, f.extraparams, fk_contrat, f.entity as entity"; + $sql .= " f.duree, f.fk_projet as fk_project, f.note_public, f.note_private, f.model_pdf, f.last_main_doc, f.extraparams, fk_contrat, f.entity as entity"; $sql .= " FROM ".MAIN_DB_PREFIX."fichinter as f"; if ($ref) { $sql .= " WHERE f.entity IN (".getEntity('intervention').")"; @@ -482,6 +482,8 @@ class Fichinter extends CommonObject $this->extraparams = (array) json_decode($obj->extraparams, true); + $this->last_main_doc = $obj->last_main_doc; + if ($this->statut == 0) { $this->brouillon = 1; } diff --git a/htdocs/langs/en_US/commercial.lang b/htdocs/langs/en_US/commercial.lang index 9978118f763..eba95a8aabb 100644 --- a/htdocs/langs/en_US/commercial.lang +++ b/htdocs/langs/en_US/commercial.lang @@ -76,10 +76,14 @@ NoLimit=No limit ToOfferALinkForOnlineSignature=Link for online signature WelcomeOnOnlineSignaturePageProposal=Welcome to the page to accept commercial proposals from %s WelcomeOnOnlineSignaturePageContract=Welcome to %s Contract PDF Signing Page +WelcomeOnOnlineSignaturePageFichinter=Welcome to %s Intervention PDF Signing Page ThisScreenAllowsYouToSignDocFromProposal=This screen allow you to accept and sign, or refuse, a quote/commercial proposal ThisScreenAllowsYouToSignDocFromContract=This screen allow you to sign contract on PDF format online. +ThisScreenAllowsYouToSignDocFromFichinter=This screen allow you to sign intervention on PDF format online. ThisIsInformationOnDocumentToSignProposal=This is information on document to accept or refuse ThisIsInformationOnDocumentToSignContract=This is information on contract to sign +ThisIsInformationOnDocumentToSignFichinter=This is information on intervention to sign SignatureProposalRef=Signature of quote/commercial proposal %s SignatureContractRef=Signature of contract %s +SignatureFichinterRef=Signature of intervention %s FeatureOnlineSignDisabled=Feature for online signing disabled or document generated before the feature was enabled diff --git a/htdocs/langs/en_US/interventions.lang b/htdocs/langs/en_US/interventions.lang index 767688a4ce8..7524439f3ec 100644 --- a/htdocs/langs/en_US/interventions.lang +++ b/htdocs/langs/en_US/interventions.lang @@ -69,3 +69,5 @@ GenerateInter=Generate intervention FichinterNoContractLinked=Intervention %s has been created without a linked contract. ErrorFicheinterCompanyDoesNotExist=Company does not exist. Intervention has not been created. NextDateToIntervention=Date for next intervention generation +AllowOnlineSign=Allow online signing +AllowExternalDownload=Allow external download \ No newline at end of file diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index d07d6d2efba..7e9afd4e27c 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -104,6 +104,7 @@ IdProduct=Product ID LineBuyPriceHT=Buy Price Amount net of tax for line SignPropal=Accept proposal SignContract=Sign contract +SignFichinter=Sign intervention RefusePropal=Refuse proposal Sign=Sign NoSign=Refuse @@ -111,5 +112,6 @@ PropalAlreadySigned=Proposal already accepted PropalAlreadyRefused=Proposal already refused PropalSigned=Proposal accepted ContractSigned=Contract signed +FichinterSigned=Intervention signed PropalRefused=Proposal refused ConfirmRefusePropal=Are you sure you want to refuse this commercial proposal? diff --git a/htdocs/langs/es_ES/commercial.lang b/htdocs/langs/es_ES/commercial.lang index 5fe49a5b4f4..8292b6391d6 100644 --- a/htdocs/langs/es_ES/commercial.lang +++ b/htdocs/langs/es_ES/commercial.lang @@ -68,13 +68,22 @@ ActionAC_OTH_AUTO=Eventos creados automáticamente ActionAC_MANUAL=Eventos creados manualmente ActionAC_AUTO=Eventos creados automáticamente ActionAC_OTH_AUTOShort=Auto +ActionAC_EVENTORGANIZATION=Eventos de organización Stats=Estadísticas de venta StatusProsp=Estado prospección DraftPropals=Presupuestos borrador NoLimit=Sin límite ToOfferALinkForOnlineSignature=Enlace para la firma en línea -WelcomeOnOnlineSignaturePage=Bienvenido a la página para aceptar presupuestos de %s -ThisScreenAllowsYouToSignDocFrom=Esta pantalla le permite aceptar y firmar, o rechazar, una presupuesto/propuesta comercial -ThisIsInformationOnDocumentToSign=Esta es la información del documento para aceptar o rechazar +WelcomeOnOnlineSignaturePageProposal=Bienvenido a la página para firmar presupuestos de %s +WelcomeOnOnlineSignaturePageContract=Bienvenido a la página para firmar contratos de %s +WelcomeOnOnlineSignaturePageFichinter=Bienvenido a la página para firmar intervenciones de %s +ThisScreenAllowsYouToSignDocFromProposal=Esta página permite aceptar y firmar o rechazar un presupuesto o propuesta comercial. +ThisScreenAllowsYouToSignDocFromContract=Esta página permite aceptar y firmar el contrato PDF online. +ThisScreenAllowsYouToSignDocFromFichinter=Esta página permite aceptar y firmar una intervención en formato PDF online. +ThisIsInformationOnDocumentToSignProposal=Esta es la información del presupuesto para aceptar o rechazar +ThisIsInformationOnDocumentToSignContract=Esta es la información del contrato a firmar +ThisIsInformationOnDocumentToSignFichinter=Esta es la información de la intervención a firmar SignatureProposalRef=Firma del presupuesto/propuesta comercial %s +SignatureContractRef=Firma del contrato %s +SignatureFichinterRef=Firma de la intervención %s FeatureOnlineSignDisabled=Característica para la firma en línea inhabilitada o documento generado antes de que se habilitara la característica diff --git a/htdocs/langs/es_ES/interventions.lang b/htdocs/langs/es_ES/interventions.lang index 83471928031..b335c533713 100644 --- a/htdocs/langs/es_ES/interventions.lang +++ b/htdocs/langs/es_ES/interventions.lang @@ -66,3 +66,8 @@ RepeatableIntervention=Plantilla de intervención ToCreateAPredefinedIntervention=Para crear una intervención predefinida o recurrente, cree una intervención común y conviértala en plantilla de intervención ConfirmReopenIntervention=¿Está seguro de querer volver a abrir la intervención %s ? GenerateInter=Generar intervención +FichinterNoContractLinked=La intervención %s se ha creado sin un contacto vinculado. +ErrorFicheinterCompanyDoesNotExist=La compañía no existe, la intervención no se ha creado. +NextDateToIntervention=Fecha para la próxima generación de intervención +AllowOnlineSign=Permitir firma online +AllowExternalDownload=Permitir descarga externa \ No newline at end of file diff --git a/htdocs/langs/es_ES/main.lang b/htdocs/langs/es_ES/main.lang index 2af1c00c5cf..00488783f8a 100644 --- a/htdocs/langs/es_ES/main.lang +++ b/htdocs/langs/es_ES/main.lang @@ -926,6 +926,7 @@ DirectDownloadInternalLink=Enlace de descarga privado PrivateDownloadLinkDesc=Debe iniciar sesión y necesita permisos para ver o descargar el archivo Download=Descargar DownloadDocument=Descargar el documento +DownloadSignedDocument=Descargar el documento firmado ActualizeCurrency=Actualizar el tipo de cambio Fiscalyear=Año fiscal ModuleBuilder=Módulo Builder diff --git a/htdocs/langs/es_ES/propal.lang b/htdocs/langs/es_ES/propal.lang index 2f31aab4e89..159daf31178 100644 --- a/htdocs/langs/es_ES/propal.lang +++ b/htdocs/langs/es_ES/propal.lang @@ -103,11 +103,15 @@ IdProposal=ID de Presupuesto IdProduct=ID del Producto LineBuyPriceHT=Precio de compra Importe neto de impuestos por línea SignPropal=Aceptar presupuesto +SignContract=Firmar contrato +SignFichinter=Firmar intervención RefusePropal=Rechazar presupuesto Sign=Firma NoSign=Establecer no firmado PropalAlreadySigned=Presupuesto ya aceptado PropalAlreadyRefused=Presupuesto ya rechazado PropalSigned=Presupuesto aceptado +ContractSigned=Contrato firmado +FichinterSigned=Intervención firmada PropalRefused=Presupuesto rechazado ConfirmRefusePropal=¿Está seguro de querer rechazar este presupuesto? diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php index 91c3ec2ce73..fa16492a169 100644 --- a/htdocs/public/onlinesign/newonlinesign.php +++ b/htdocs/public/onlinesign/newonlinesign.php @@ -130,6 +130,8 @@ if ($source == 'proposal') { $securekeyseed = getDolGlobalString('PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN'); } elseif ($source == 'contract') { $securekeyseed = getDolGlobalString('CONTRACT_ONLINE_SIGNATURE_SECURITY_TOKEN'); +} elseif ($source == 'fichinter') { + $securekeyseed = getDolGlobalString('FICHINTER_ONLINE_SIGNATURE_SECURITY_TOKEN'); } if (!dol_verifyHash($securekeyseed.$type.$ref.(isModEnabled('multicompany') ? $entity : ''), $SECUREKEY, '0')) { httponly_accessforbidden('Bad value for securitykey. Value provided '.dol_escape_htmltag($SECUREKEY).' does not match expected value for ref='.dol_escape_htmltag($ref), 403, 1); @@ -143,6 +145,10 @@ if ($source == 'proposal') { require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php'; $object = new Contrat($db); $result= $object->fetch(0, $ref); +} elseif ($source == 'fichinter') { + require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php'; + $object = new Fichinter($db); + $result= $object->fetch(0, $ref); } else { httponly_accessforbidden($langs->trans('ErrorBadParameters')." - Bad value for source", 400, 1); } @@ -289,6 +295,9 @@ if (empty($text)) { } elseif ($source == 'contract') { $text .= '
'.$langs->trans("WelcomeOnOnlineSignaturePageContract", $mysoc->name).''."\n"; $text .= ''.$langs->trans("ThisScreenAllowsYouToSignDocFromContract", $creditor).'

'."\n"; + } elseif ($source == 'fichinter') { + $text .= '
'.$langs->trans("WelcomeOnOnlineSignaturePageFichinter", $mysoc->name).''."\n"; + $text .= ''.$langs->trans("ThisScreenAllowsYouToSignDocFromFichinter", $creditor).'

'."\n"; } } print $text; @@ -300,6 +309,8 @@ if ($source == 'proposal') { print ''.$langs->trans("ThisIsInformationOnDocumentToSignProposal").' :'."\n"; } elseif ($source == 'contract') { print ''.$langs->trans("ThisIsInformationOnDocumentToSignContract").' :'."\n"; +} elseif ($source == 'fichinter') { + print ''.$langs->trans("ThisIsInformationOnDocumentToSignFichinter").' :'."\n"; } $found = false; $error = 0; @@ -430,6 +441,55 @@ if ($source == 'proposal') { } + print ''; + print ''; + print ''."\n"; +} elseif ($source == 'fichinter') { // Signature on fichinter + $found = true; + $langs->load("fichinter"); + + $result = $object->fetch_thirdparty($object->socid); + // Proposer + print ''.$langs->trans("Proposer"); + print ''; + print img_picto('', 'company', 'class="pictofixedwidth"'); + print ''.$creditor.''; + print ''; + print ''."\n"; + + // Target + print ''.$langs->trans("ThirdParty"); + print ''; + print img_picto('', 'company', 'class="pictofixedwidth"'); + print ''.$object->thirdparty->name.''; + print ''."\n"; + + // Object + $text = ''.$langs->trans("SignatureFichinterRef", $object->ref).''; + print ''.$langs->trans("Designation"); + print ''.$text; + + $last_main_doc_file = $object->last_main_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); + } + + $directdownloadlink = $object->getLastMainDocLink('fichinter'); + if ($directdownloadlink) { + print '
'; + print img_mime($object->last_main_doc, ''); + if ($message == "signed") { + print $langs->trans("DownloadSignedDocument").''; + } else { + print $langs->trans("DownloadDocument").''; + } + } + + print ''; print ''; print ''."\n"; @@ -542,6 +602,12 @@ if ($action == "dosign" && empty($cancel)) { } else { print ''; } + } elseif ($source == 'fichinter') { + if ($message == 'signed') { + print ''.$langs->trans("FichinterSigned").''; + } else { + print ''; + } } } print ''."\n";