';
diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php
index 628313d5fe9..1d788457abe 100644
--- a/htdocs/adherents/type.php
+++ b/htdocs/adherents/type.php
@@ -292,7 +292,7 @@ if (!$rowid && $action != 'create' && $action != 'edit') {
$membertype->amount = $objp->amount;
print '
'.$langs->trans("VoteAllowed").' ';
diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php
index 997ca45f515..746075ab51e 100644
--- a/htdocs/comm/propal/card.php
+++ b/htdocs/comm/propal/card.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2001-2007 Rodolphe Quiedeville
* Copyright (C) 2004-2014 Laurent Destailleur
* Copyright (C) 2004 Eric Seigne
* Copyright (C) 2005 Marc Barilley / Ocebo
@@ -817,7 +817,7 @@ if (empty($reshook)) {
}
}
}
- } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '') {
+ } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
// Define vat_rate
$vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
$vat_rate = str_replace('*', '', $vat_rate);
@@ -835,7 +835,7 @@ if (empty($reshook)) {
$prod_entry_mode = GETPOST('prod_entry_mode');
if ($prod_entry_mode == 'free') {
$idprod = 0;
- $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
+ $tva_tx = (GETPOST('tva_tx') ? price2num(GETPOST('tva_tx')) : 0);
} else {
$idprod = GETPOST('idprod', 'int');
$tva_tx = '';
@@ -2680,7 +2680,7 @@ if ($action == 'create') {
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
// Show online signature link
- $useonlinesignature = 1; // Replace this with 1 when feature to make online signature is ok
+ $useonlinesignature = 1;
if ($object->statut != Propal::STATUS_DRAFT && $useonlinesignature) {
print ' ';
diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php
index 488b5051ea5..bf484dc1c45 100644
--- a/htdocs/core/ajax/onlineSign.php
+++ b/htdocs/core/ajax/onlineSign.php
@@ -51,11 +51,27 @@ if (!defined('NOBROWSERNOTIF')) {
include '../../main.inc.php';
$action = GETPOST('action', 'aZ09');
+
$signature = GETPOST('signaturebase64');
$ref = GETPOST('ref', 'aZ09');
$mode = GETPOST('mode', 'aZ09');
+$SECUREKEY = GETPOST("securekey"); // Secure key
+
$error = 0;
$response = "";
+
+// Check securitykey
+$securekeyseed = $conf->global->PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN;
+$type = $mode;
+$calculatedsecuritykey = dol_hash($securekeyseed.$type.$ref, '0');
+
+if ($calculatedsecuritykey != $SECUREKEY) {
+ http_response_code(403);
+ print 'Bad value for securitykey. Value provided '.dol_escape_htmltag($SECUREKEY).' does not match expected value for ref='.dol_escape_htmltag($ref);
+ exit(-1);
+}
+
+
/*
* Actions
*/
@@ -71,62 +87,76 @@ if ($action == "importSignature") {
if (!empty($signature) && $signature[0] == "image/png;base64") {
$signature = $signature[1];
$data = base64_decode($signature);
- $upload_dir = DOL_DATA_ROOT."/".$mode."/".$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 (!mkdir($upload_dir."signatures/")) {
- $response ="error mkdir";
- $error++;
+
+ if ($mode == "propale" || $mode == 'proposal') {
+ require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
+ $object = new Propal($db);
+ $object->fetch(0, $ref);
+
+ $upload_dir = !empty($conf->propal->multidir_output[$object->entity])?$conf->propal->multidir_output[$object->entity]:$conf->propal->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) {
- $response = 'error file_put_content';
- } else {
- if ($mode == "propale") {
- require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
- require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
- $object = new Propal($db);
- $object->fetch(0, $ref);
- $pdf = pdf_getInstance();
- $pdf->Open();
- $pdf->AddPage();
- $pagecount = $pdf->setSourceFile($upload_dir.$ref.".pdf");
+ if (!$error) {
+ $return = file_put_contents($upload_dir.$filename, $data);
+ if ($return == false) {
+ $error++;
+ $response = 'error file_put_content';
+ }
+ }
- $tppl = $pdf->importPage(1);
- $pdf->useTemplate($tppl);
- $pdf->Image($upload_dir.$filename, 129, 239.6, 60, 15);
- $pdf->Close();
- $pdf->Output($upload_dir.$ref."_signed-".$date.".pdf", "F");
+ if (!$error) {
+ $pdf = pdf_getInstance();
+ $pdf->Open();
+ $pdf->AddPage();
+ $pagecount = $pdf->setSourceFile($upload_dir.$ref.".pdf");
- $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
- $sql .= " SET fk_statut = ".((int) $object::STATUS_SIGNED).", note_private = '".$object->note_private."', date_signature='".$db->idate(dol_now())."'";
- $sql .= " WHERE rowid = ".((int) $object->id);
+ $tppl = $pdf->importPage(1);
+ $pdf->useTemplate($tppl);
+ $pdf->Image($upload_dir.$filename, 129, 239.6, 60, 15);
+ $pdf->Close();
+ $pdf->Output($upload_dir.$ref."_signed-".$date.".pdf", "F");
- dol_syslog(__METHOD__, LOG_DEBUG);
- $resql = $db->query($sql);
- if (!$resql) {
- $error++;
- } else {
- $num = $db->affected_rows($resql);
- }
+ $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
+ $sql .= " SET fk_statut = ".((int) $object::STATUS_SIGNED).", note_private = '".$object->note_private."', date_signature='".$db->idate(dol_now())."'";
+ $sql .= " WHERE rowid = ".((int) $object->id);
- if (!$error) {
- $db->commit();
- $response = "success";
- setEventMessage("PropalSigned");
- } else {
- $db->rollback();
- $response = "error sql";
- }
+ dol_syslog(__METHOD__, LOG_DEBUG);
+ $resql = $db->query($sql);
+ if (!$resql) {
+ $error++;
+ } else {
+ $num = $db->affected_rows($resql);
+ }
+
+ if (!$error) {
+ $db->commit();
+ $response = "success";
+ setEventMessages("PropalSigned", null, 'warnings');
+ } else {
+ $db->rollback();
+ $error++;
+ $response = "error sql";
}
}
}
} else {
+ $error++;
$response = 'error signature_not_found';
}
}
+
+if ($error) {
+ http_response_code(501);
+}
+
echo $response;
diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php
index 7f9e28f5b4a..3539348e35a 100644
--- a/htdocs/core/class/html.formfile.class.php
+++ b/htdocs/core/class/html.formfile.class.php
@@ -761,7 +761,7 @@ class FormFile
$arraykeys = array_keys($modellist);
$modelselected = $arraykeys[0];
}
- $morecss = 'maxwidth200';
+ $morecss = 'minwidth75 maxwidth200';
if ($conf->browser->layout == 'phone') {
$morecss = 'maxwidth100';
}
diff --git a/htdocs/core/lib/signature.lib.php b/htdocs/core/lib/signature.lib.php
index 6bc4a4668a3..5a2fd9dfd8c 100644
--- a/htdocs/core/lib/signature.lib.php
+++ b/htdocs/core/lib/signature.lib.php
@@ -18,7 +18,7 @@
*/
/**
- * Return string with full Url
+ * Return string with full online Url to accept and sign a quote
*
* @param string $type Type of URL ('proposal', ...)
* @param string $ref Ref of object
@@ -58,13 +58,27 @@ function showOnlineSignatureUrl($type, $ref)
*/
function getOnlineSignatureUrl($mode, $type, $ref = '')
{
- global $conf, $db, $langs;
+ global $conf, $db, $langs, $dolibarr_main_url_root;
$ref = str_replace(' ', '', $ref);
$out = '';
+ // Define $urlwithroot
+ $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
+ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
+ //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
+
+ $localorexternal = 1; // external
+
+ $urltouse = DOL_MAIN_URL_ROOT;
+ if ($localorexternal) {
+ $urltouse = $urlwithroot;
+ }
+
+ $securekeyseed = $conf->global->PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN;
+
if ($type == 'proposal') {
- $out = DOL_MAIN_URL_ROOT.'/public/onlinesign/newonlinesign.php?source=proposal&ref='.($mode ? '' : '');
+ $out = $urltouse.'/public/onlinesign/newonlinesign.php?source=proposal&ref='.($mode ? '' : '');
if ($mode == 1) {
$out .= 'proposal_ref';
}
@@ -72,6 +86,12 @@ function getOnlineSignatureUrl($mode, $type, $ref = '')
$out .= urlencode($ref);
}
$out .= ($mode ? ' ' : '');
+ if ($mode == 1) {
+ $out .= "hash('".$securekeyseed."' + '".$type."' + proposal_ref)";
+ } else {
+ $out .= '&securekey='.dol_hash($securekeyseed.$type.$ref, '0');
+ }
+ /*
if ($mode == 1) {
$out .= '&hashp=hash_of_file ';
} else {
@@ -94,13 +114,15 @@ function getOnlineSignatureUrl($mode, $type, $ref = '')
} else {
$out .= '&hashp='.$hashp;
}
- }
+ }*/
}
// For multicompany
+ /*
if (!empty($out)) {
$out .= "&entity=".$conf->entity; // Check the entity because He may be the same reference in several entities
}
+ */
return $out;
}
diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php
index 14a08c675ce..caec61f4a2a 100644
--- a/htdocs/public/onlinesign/newonlinesign.php
+++ b/htdocs/public/onlinesign/newonlinesign.php
@@ -122,6 +122,17 @@ $creditor = $mysoc->name;
$object = new Propal($db);
$object->fetch(0, $ref);
+// Check securitykey
+$securekeyseed = $conf->global->PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN;
+$type = $source;
+$calculatedsecuritykey = dol_hash($securekeyseed.$type.$ref, '0');
+
+if ($calculatedsecuritykey != $SECUREKEY) {
+ http_response_code(403);
+ print 'Bad value for securitykey. Value provided '.dol_escape_htmltag($SECUREKEY).' does not match expected value for ref='.dol_escape_htmltag($ref);
+ exit(-1);
+}
+
/*
* Actions
@@ -144,7 +155,7 @@ if ($action == 'confirm_refusepropal') {
$db->commit();
$message = 'refused';
- setEventMessages("PropalRefused", null, 'warning');
+ setEventMessages("PropalRefused", null, 'warnings');
} else {
$db->rollback();
}
@@ -170,7 +181,7 @@ $replacemainarea = (empty($conf->dol_hide_leftmenu) ? '' : '').'
';
llxHeader($head, $langs->trans("OnlineSignature"), '', '', 0, 0, '', '', '', 'onlinepaymentbody', $replacemainarea, 1);
if ($action == 'refusepropal') {
- print $form->formconfirm($_SERVER["PHP_SELF"].'?ref='.$ref, $langs->trans('RefusePropal'), $langs->trans('ConfirmRefusePropal', $object->ref), 'confirm_refusepropal', '', '', 1);
+ print $form->formconfirm($_SERVER["PHP_SELF"].'?ref='.urlencode($ref).'&securekey='.urlencode($SECUREKEY), $langs->trans('RefusePropal'), $langs->trans('ConfirmRefusePropal', $object->ref), 'confirm_refusepropal', '', '', 1);
}
// Check link validity for param 'source'
@@ -195,7 +206,7 @@ print '
';
print "\n";
print ''."\n";
-print '
'."\n";
+print ''."\n";
// Show logo (search order: logo defined by ONLINE_SIGN_LOGO_suffix, then ONLINE_SIGN_LOGO_, then small company logo, large company logo, theme logo, common logo)
// Define logo and logosmall
@@ -295,6 +306,13 @@ if ($source == 'proposal') {
print ''.$proposal->thirdparty->name.' ';
print ''."\n";
+ // Amount
+
+ print ''.$langs->trans("Amount");
+ print ' ';
+ print ''.price($proposal->total_ttc, 0, $langs, 1, -1, -1, $conf->currency).' ';
+ print ' '."\n";
+
// Object
$text = ''.$langs->trans("SignatureProposalRef", $proposal->ref).' ';
@@ -308,7 +326,7 @@ if ($source == 'proposal') {
print $langs->trans("DownloadDocument").'';
}
} else {
- /* TODO If proposal signed newer than proposal ref, get link of proposal signed
+ /* TODO If the file of proposal signed is newer than the default proposal file, get link of proposal signed
*/
}
@@ -358,7 +376,7 @@ if ($action == "dosign" && empty($cancel)) {
print '