';
$MAXEVENT = 10;
$morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/contrat/agenda.php?id='.$object->id);
+
// List of actions on element
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
$formactions = new FormActions($db);
diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php
index f3b617a251a..2a8d1b815a7 100644
--- a/htdocs/contrat/class/contrat.class.php
+++ b/htdocs/contrat/class/contrat.class.php
@@ -663,7 +663,7 @@ class Contrat extends CommonObject
$sql .= " fk_user_author,";
$sql .= " fk_projet as fk_project,";
$sql .= " fk_commercial_signature, fk_commercial_suivi,";
- $sql .= " note_private, note_public, model_pdf, extraparams";
+ $sql .= " note_private, note_public, model_pdf, last_main_doc, extraparams";
$sql .= " FROM ".MAIN_DB_PREFIX."contrat";
if (!$id) {
$sql .= " WHERE entity IN (".getEntity('contract').")";
@@ -717,7 +717,7 @@ class Contrat extends CommonObject
$this->socid = $obj->fk_soc;
$this->fk_soc = $obj->fk_soc;
-
+ $this->last_main_doc = $obj->last_main_doc;
$this->extraparams = (array) json_decode($obj->extraparams, true);
$this->db->free($resql);
diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php
index 53eaf69aea1..9966b9c6093 100644
--- a/htdocs/core/ajax/onlineSign.php
+++ b/htdocs/core/ajax/onlineSign.php
@@ -224,6 +224,95 @@ if ($action == "importSignature") {
$response = "error sql";
}
}
+ } elseif ($mode == 'contract') {
+ require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
+ $object = new Contrat($db);
+ $object->fetch(0, $ref);
+
+ $upload_dir = !empty($conf->contrat->multidir_output[$object->entity])?$conf->contrat->multidir_output[$object->entity]:$conf->contrat->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('contrat'); // 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 = 5;
+ $yforimgstart = (empty($s['h']) ? 240 : $s['h'] - 65);
+ $wforimg = $s['w']/2 - $xforimgstart;
+
+ $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 d2f0c64f463..070cbe0801f 100644
--- a/htdocs/core/lib/signature.lib.php
+++ b/htdocs/core/lib/signature.lib.php
@@ -116,6 +116,21 @@ function getOnlineSignatureUrl($mode, $type, $ref = '', $localorexternal = 1)
$out .= '&hashp='.$hashp;
}
}*/
+ } elseif ($type == 'contract') {
+ $securekeyseed = isset($conf->global->CONTRACT_ONLINE_SIGNATURE_SECURITY_TOKEN) ? $conf->global->CONTRACT_ONLINE_SIGNATURE_SECURITY_TOKEN : '';
+ $out = $urltouse.'/public/onlinesign/newonlinesign.php?source=contract&ref='.($mode ? '' : '');
+ if ($mode == 1) {
+ $out .= 'contract_ref';
+ }
+ if ($mode == 0) {
+ $out .= urlencode($ref);
+ }
+ $out .= ($mode ? '' : '');
+ if ($mode == 1) {
+ $out .= "hash('".$securekeyseed."' + '".$type."' + contract_ref)";
+ } else {
+ $out .= '&securekey='.dol_hash($securekeyseed.$type.$ref.(!isModEnabled('multicompany') ? '' : $object->entity), '0');
+ }
}
// For multicompany
diff --git a/htdocs/langs/en_US/commercial.lang b/htdocs/langs/en_US/commercial.lang
index 21d282cd794..9978118f763 100644
--- a/htdocs/langs/en_US/commercial.lang
+++ b/htdocs/langs/en_US/commercial.lang
@@ -74,8 +74,12 @@ StatusProsp=Prospect status
DraftPropals=Draft commercial proposals
NoLimit=No limit
ToOfferALinkForOnlineSignature=Link for online signature
-WelcomeOnOnlineSignaturePage=Welcome to the page to accept commercial proposals from %s
-ThisScreenAllowsYouToSignDocFrom=This screen allow you to accept and sign, or refuse, a quote/commercial proposal
-ThisIsInformationOnDocumentToSign=This is information on document to accept or refuse
+WelcomeOnOnlineSignaturePageProposal=Welcome to the page to accept commercial proposals from %s
+WelcomeOnOnlineSignaturePageContract=Welcome to %s Contract 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.
+ThisIsInformationOnDocumentToSignProposal=This is information on document to accept or refuse
+ThisIsInformationOnDocumentToSignContract=This is information on contract to sign
SignatureProposalRef=Signature of quote/commercial proposal %s
+SignatureContractRef=Signature of contract %s
FeatureOnlineSignDisabled=Feature for online signing disabled or document generated before the feature was enabled
diff --git a/htdocs/langs/en_US/contracts.lang b/htdocs/langs/en_US/contracts.lang
index ab94a63bcc3..f0db53f3ddd 100644
--- a/htdocs/langs/en_US/contracts.lang
+++ b/htdocs/langs/en_US/contracts.lang
@@ -101,6 +101,8 @@ TypeContact_contrat_external_BILLING=Billing customer contact
TypeContact_contrat_external_CUSTOMER=Follow-up customer contact
TypeContact_contrat_external_SALESREPSIGN=Signing contract customer contact
HideClosedServiceByDefault=Hide closed services by default
+AllowOnlineSign=Allow online signing
+AllowExternalDownload=Allow external download
ShowClosedServices=Show Closed Services
HideClosedServices=Hide Closed Services
UserStartingService=User starting service
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 09745ec5eac..893b910186f 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -927,6 +927,7 @@ DirectDownloadInternalLink=Private download link
PrivateDownloadLinkDesc=You need to be logged and you need permissions to view or download the file
Download=Download
DownloadDocument=Download document
+DownloadSignedDocument=Download signed document
ActualizeCurrency=Update currency rate
Fiscalyear=Fiscal year
ModuleBuilder=Module and Application Builder
diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang
index aa5ef73f7dc..d07d6d2efba 100644
--- a/htdocs/langs/en_US/propal.lang
+++ b/htdocs/langs/en_US/propal.lang
@@ -103,11 +103,13 @@ IdProposal=Proposal ID
IdProduct=Product ID
LineBuyPriceHT=Buy Price Amount net of tax for line
SignPropal=Accept proposal
+SignContract=Sign contract
RefusePropal=Refuse proposal
Sign=Sign
NoSign=Refuse
PropalAlreadySigned=Proposal already accepted
PropalAlreadyRefused=Proposal already refused
PropalSigned=Proposal accepted
+ContractSigned=Contract signed
PropalRefused=Proposal refused
ConfirmRefusePropal=Are you sure you want to refuse this commercial proposal?
diff --git a/htdocs/langs/fr_FR/commercial.lang b/htdocs/langs/fr_FR/commercial.lang
index d663185936b..84bb1364386 100644
--- a/htdocs/langs/fr_FR/commercial.lang
+++ b/htdocs/langs/fr_FR/commercial.lang
@@ -74,8 +74,12 @@ StatusProsp=Status prospection
DraftPropals=Propositions brouillons
NoLimit=Pas de limite
ToOfferALinkForOnlineSignature=Lien pour signature en ligne
-WelcomeOnOnlineSignaturePage=Bienvenue sur la page pour accepter les propositions commerciales de %s
-ThisScreenAllowsYouToSignDocFrom=Cet écran vous permet d'accepter et signer en ligne, ou de refuser, le devis ou la proposition commerciale
-ThisIsInformationOnDocumentToSign=Voici les informations sur le document à accepter ou refuser
+WelcomeOnOnlineSignaturePageProposal=Bienvenue sur la page pour accepter les propositions commerciales de %s
+WelcomeOnOnlineSignaturePageContract=Bienvenue sur la page de signature en ligne de contrats au format PDF de %s
+ThisScreenAllowsYouToSignDocFromProposal=Cet écran vous permet d'accepter et signer en ligne, ou de refuser, le devis ou la proposition commerciale
+ThisScreenAllowsYouToSignDocFromContract=Cet écran vous permet de signer en ligne des contrats au format PDF.
+ThisIsInformationOnDocumentToSignProposal=Voici les informations sur le document à accepter ou refuser
+ThisIsInformationOnDocumentToSignContract=Voici les informations sur le contrat a signer
SignatureProposalRef=Signature du devis ou proposition commerciale %s
+SignatureContractRef=Signature du contrat %s
FeatureOnlineSignDisabled=Fonctionnalité pour la signature en ligne désactivée ou document généré avant l'activation de la fonctionnalité
diff --git a/htdocs/langs/fr_FR/contracts.lang b/htdocs/langs/fr_FR/contracts.lang
index 8d89487c5cf..bb7bf18da67 100644
--- a/htdocs/langs/fr_FR/contracts.lang
+++ b/htdocs/langs/fr_FR/contracts.lang
@@ -100,5 +100,7 @@ TypeContact_contrat_external_BILLING=Contact client facturation contrat
TypeContact_contrat_external_CUSTOMER=Contact client suivi contrat
TypeContact_contrat_external_SALESREPSIGN=Contact client signataire contrat
HideClosedServiceByDefault=Masquer les services fermés par défaut
+AllowOnlineSign=Autoriser la signature en ligne
+AllowExternalDownload=Autoriser le téléchargement externe
ShowClosedServices=Afficher les services fermés
HideClosedServices=Masquer les services fermés
diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang
index 6d852468492..33a30382ef0 100644
--- a/htdocs/langs/fr_FR/main.lang
+++ b/htdocs/langs/fr_FR/main.lang
@@ -565,7 +565,7 @@ None=Aucun
NoneF=Aucune
NoneOrSeveral=Aucun ou plusieurs
Late=Retard
-LateDesc=Le délai qui définit si un enregistrement est en retard ou non dépend de votre configuration. Demandez à votre administrateur pour changer ce délai depuis Accueil - Configuration - Alertes
+LateDesc=Le délai qui définit si un enregistrement est en retard ou non dépend de votre configuration. Demandez à votre administrateur pour changer ce délai depuis Accueil - Configuration - Alertes
NoItemLate=Aucun élément en retard
Photo=Photo
Photos=Photos
@@ -927,6 +927,7 @@ DirectDownloadInternalLink=Lien de téléchargement privé
PrivateDownloadLinkDesc=Vous devez être connecté et vous avez besoin d’autorisations pour afficher ou télécharger le fichier
Download=Téléchargement
DownloadDocument=Télécharger le document
+DownloadSignedDocument=Télécharger le document signé
ActualizeCurrency=Mettre à jour le taux de devise
Fiscalyear=Exercice fiscal
ModuleBuilder=Générateur de Module et Application
diff --git a/htdocs/langs/fr_FR/propal.lang b/htdocs/langs/fr_FR/propal.lang
index 41483196a39..4c44d0691c3 100644
--- a/htdocs/langs/fr_FR/propal.lang
+++ b/htdocs/langs/fr_FR/propal.lang
@@ -47,7 +47,7 @@ SendPropalByMail=Envoyer proposition commerciale par email
DatePropal=Date de proposition
DateEndPropal=Date de fin de validité
ValidityDuration=Durée de validité
-SetAcceptedRefused=Accepter/Refuser
+SetAcceptedRefused=Accepter/Refuser
ErrorPropalNotFound=Propale %s inexistante
AddToDraftProposals=Ajouter à proposition brouillon
NoDraftProposals=Pas de propositions brouillons
@@ -103,11 +103,13 @@ IdProposal=ID de la proposition commerciale
IdProduct=ID produit
LineBuyPriceHT=Prix d'achat HT de la ligne
SignPropal=Accepter la proposition
+SignContract=Signer le contrat
RefusePropal=Refuser la proposition
Sign=Signer
NoSign=Mettre à Non signé
PropalAlreadySigned=Proposition déjà acceptée
PropalAlreadyRefused=Proposition déjà refusée
PropalSigned=Proposition acceptée
+ContractSigned=Contrat signé
PropalRefused=Proposition refusée
ConfirmRefusePropal=Êtes-vous sûr de vouloir refuser cette proposition ?
diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php
index fe1b71423ce..91c3ec2ce73 100644
--- a/htdocs/public/onlinesign/newonlinesign.php
+++ b/htdocs/public/onlinesign/newonlinesign.php
@@ -128,8 +128,9 @@ if (!$action) {
$securekeyseed = '';
if ($source == 'proposal') {
$securekeyseed = getDolGlobalString('PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN');
+} elseif ($source == 'contract') {
+ $securekeyseed = getDolGlobalString('CONTRACT_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);
}
@@ -138,6 +139,10 @@ if ($source == 'proposal') {
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
$object = new Propal($db);
$result= $object->fetch(0, $ref, '', $entity);
+} elseif ($source == 'contract') {
+ require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
+ $object = new Contrat($db);
+ $result= $object->fetch(0, $ref);
} else {
httponly_accessforbidden($langs->trans('ErrorBadParameters')." - Bad value for source", 400, 1);
}
@@ -278,16 +283,24 @@ if (!empty($conf->global->ONLINE_SIGN_NEWFORM_TEXT)) {
$text = '
'.$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('contract');
+ 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 '