diff --git a/htdocs/adherents/agenda.php b/htdocs/adherents/agenda.php index 3f7114380f3..4b59039d313 100644 --- a/htdocs/adherents/agenda.php +++ b/htdocs/adherents/agenda.php @@ -136,7 +136,11 @@ if ($object->id > 0) { $linkback = ''.$langs->trans("BackToList").''; - dol_banner_tab($object, 'rowid', $linkback); + $morehtmlref = ''; + $morehtmlref .= img_picto($langs->trans("Download").' '.$langs->trans("VCard"), 'vcard.png', 'class="valignmiddle marginleftonly paddingrightonly"'); + $morehtmlref .= ''; + + dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref); print '
'; diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php index 9dcb514cc36..df258e104a7 100644 --- a/htdocs/adherents/card.php +++ b/htdocs/adherents/card.php @@ -918,12 +918,8 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { // When used in standard mode // ----------------------------------------- + // Create mode if ($action == 'create') { - /* ************************************************************************** */ - /* */ - /* Creation mode */ - /* */ - /* ************************************************************************** */ $object->canvas = $canvas; $object->state_id = GETPOST('state_id', 'int'); @@ -1145,13 +1141,8 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print "\n"; } + // Edit mode if ($action == 'edit') { - /******************************************** - * - * Edition mode - * - ********************************************/ - $res = $object->fetch($id); if ($res < 0) { dol_print_error($db, $object->error); exit; @@ -1412,13 +1403,8 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print ''; } + // View if ($id > 0 && $action != 'edit') { - /* ************************************************************************** */ - /* */ - /* View mode */ - /* */ - /* ************************************************************************** */ - $res = $object->fetch($id); if ($res < 0) { dol_print_error($db, $object->error); exit; @@ -1707,7 +1693,12 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $linkback = ''.$langs->trans("BackToList").''; - dol_banner_tab($object, 'rowid', $linkback); + $morehtmlref = ''; + $morehtmlref .= img_picto($langs->trans("Download").' '.$langs->trans("VCard"), 'vcard.png', 'class="valignmiddle marginleftonly paddingrightonly"'); + $morehtmlref .= ''; + + + dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref); print '
'; print '
'; @@ -1862,13 +1853,16 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { print ''; // VCard + /* print ''; print $langs->trans("VCard").''; print ''; - print img_picto($langs->trans("Download"), 'vcard.png', 'class="paddingrightonly"'); + print img_picto($langs->trans("Download").' vcard', 'vcard.png', 'class="paddingrightonly"'); print $langs->trans("Download"); + print img_picto($langs->trans("Download").' vcard', 'download', 'class="paddingleft"'); print ''; print ''; + */ print "\n"; diff --git a/htdocs/adherents/document.php b/htdocs/adherents/document.php index 98c0e026139..49a1654120f 100644 --- a/htdocs/adherents/document.php +++ b/htdocs/adherents/document.php @@ -138,7 +138,11 @@ if ($id > 0) { $linkback = ''.$langs->trans("BackToList").''; - dol_banner_tab($object, 'rowid', $linkback); + $morehtmlref = ''; + $morehtmlref .= img_picto($langs->trans("Download").' '.$langs->trans("VCard"), 'vcard.png', 'class="valignmiddle marginleftonly paddingrightonly"'); + $morehtmlref .= ''; + + dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref); print '
'; diff --git a/htdocs/adherents/note.php b/htdocs/adherents/note.php index 0444d03b2ff..2d98dfe5fbc 100644 --- a/htdocs/adherents/note.php +++ b/htdocs/adherents/note.php @@ -107,7 +107,11 @@ if ($id) { $linkback = ''.$langs->trans("BackToList").''; - dol_banner_tab($object, 'id', $linkback); + $morehtmlref = ''; + $morehtmlref .= img_picto($langs->trans("Download").' '.$langs->trans("VCard"), 'vcard.png', 'class="valignmiddle marginleftonly paddingrightonly"'); + $morehtmlref .= ''; + + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref); print '
'; diff --git a/htdocs/adherents/subscription.php b/htdocs/adherents/subscription.php index ef406b02561..e26db90c4ff 100644 --- a/htdocs/adherents/subscription.php +++ b/htdocs/adherents/subscription.php @@ -485,7 +485,11 @@ if ($rowid > 0) { $linkback = ''.$langs->trans("BackToList").''; - dol_banner_tab($object, 'rowid', $linkback); + $morehtmlref = ''; + $morehtmlref .= img_picto($langs->trans("Download").' '.$langs->trans("VCard"), 'vcard.png', 'class="valignmiddle marginleftonly paddingrightonly"'); + $morehtmlref .= ''; + + dol_banner_tab($object, 'rowid', $linkback, 1, 'rowid', 'ref', $morehtmlref); print '
'; print '
'; 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/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 b6638daba51..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' @@ -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 */ } @@ -374,12 +392,13 @@ if ($action == "dosign" && empty($cancel)) { "action" : "importSignature", "signaturebase64" : signature, "ref" : \''.dol_escape_js($REF).'\', - "mode" : "propale", + "securekey" : \''.dol_escape_js($SECUREKEY).'\', + "mode" : \''.dol_escape_htmltag($source).'\', }, success: function(response) { if(response == "success"){ console.log("Success on saving signature"); - window.location.replace("'.$_SERVER["SELF"].'?ref='.urlencode($ref).'&message=signed"); + window.location.replace("'.$_SERVER["PHP_SELF"].'?ref='.urlencode($ref).'&message=signed&securekey='.urlencode($SECUREKEY).'"); }else{ console.error(response); } diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index 7786f88c2f4..2cb5a7e9076 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -1525,10 +1525,13 @@ if ($source == 'member' || $source == 'membersubscription') { // Debitor print ''.$langs->trans("Member"); - print ''; - if ($member->morphy == 'mor' && !empty($member->societe)) { - print $member->societe; + print ''; + print ''; + if ($member->morphy == 'mor' && !empty($member->company)) { + print img_picto('', 'company', 'class="pictofixedwidth"'); + print $member->company; } else { + print img_picto('', 'member', 'class="pictofixedwidth"'); print $member->getFullName($langs); } print ''; diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index a586593de49..b42a6813a30 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -3630,16 +3630,19 @@ div.refidpadding { } div.refid { font-weight: bold; - color: var(--colortexttitlenotab); - font-size: 1.2em; - word-break: break-word; + color: var(--colortexttitlenotab); + font-size: 1.2em; + word-break: break-word; +} +a.refid { + color: var(--colortexttitlenotab) !important; } div.refidno { padding-top: 3px; font-weight: normal; - color: var(--refidnocolor); - font-size: ; - line-height: 1.4em; + color: var(--refidnocolor); + font-size: ; + line-height: 1.4em; } div.refidno form { display: inline-block; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index c1a79584b6c..8f5fc141b32 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -3662,14 +3662,17 @@ div.refidpadding { div.refid { font-weight: bold; color: rgb(--colortexttitlenotab); - font-size: 160%; + font-size: 160%; +} +a.refid { + color: var(--colortexttitlenotab) !important; } div.refidno { padding-top: 8px; font-weight: normal; - color: #444; - font-size: px; - line-height: 21px; + color: #444; + font-size: px; + line-height: 21px; } div.refidno form { display: inline-block;