dolibarr 23.0.4
newpayment.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2002 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2006-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2018 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2018-2021 Thibault FOUCART <support@ptibogxiv.net>
7 * Copyright (C) 2021 Waël Almoman <info@almoman.com>
8 * Copyright (C) 2021 Dorian Vabre <dorian.vabre@gmail.com>
9 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
10 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 *
25 * For Paypal test: https://developer.paypal.com/
26 * For Paybox test: ???
27 * For Stripe test: Use credit card 4242424242424242 .More example on https://stripe.com/docs/testing
28 *
29 * Variants:
30 * - When option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION is on, we use the new PaymentIntent API
31 * - When option STRIPE_USE_NEW_CHECKOUT is on, we use the new checkout API
32 * - If no option set, we use old APIS (charge)
33 */
34
41if (!defined('NOLOGIN')) {
42 define("NOLOGIN", 1); // This means this output page does not require to be logged.
43}
44if (!defined('NOCSRFCHECK')) {
45 define("NOCSRFCHECK", 1); // We accept to go on this page from external web site.
46}
47if (!defined('NOIPCHECK')) {
48 define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
49}
50if (!defined('NOBROWSERNOTIF')) {
51 define('NOBROWSERNOTIF', '1');
52}
53
54if (!defined('XFRAMEOPTIONS_ALLOWALL')) {
55 define('XFRAMEOPTIONS_ALLOWALL', '1');
56}
57
58// For MultiCompany module.
59// Do not use GETPOST here, function is not defined and get of entity must be done before including main.inc.php
60// Because 2 entities can have the same ref.
61$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : (!empty($_GET['e']) ? (int) $_GET['e'] : (!empty($_POST['e']) ? (int) $_POST['e'] : 1))));
62if (is_numeric($entity)) {
63 define("DOLENTITY", $entity);
64}
65
66// Load Dolibarr environment
67require '../../main.inc.php';
78require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
79require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
80require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
81require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
82require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
83require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorboothattendee.class.php';
84require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
85require_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
86require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
87require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
88
89// Load translation files
90$langs->loadLangs(array("main", "other", "dict", "bills", "companies", "errors", "paypal", "stripe")); // File with generic data
91
92// Hook to be used by external payment modules (ie Payzen, ...)
93$hookmanager = new HookManager($db);
94$hookmanager->initHooks(array('newpayment'));
95
96
97// Security check
98// No check on module enabled. Done later according to $validpaymentmethod
99
100$action = GETPOST('action', 'aZ09');
101
102// Input are:
103// type ('invoice','order','contractline'),
104// id (object id),
105// amount (required if id is empty),
106// tag (a free text, required if type is empty)
107// currency (iso code)
108
109$suffix = GETPOST("suffix", 'aZ09');
110$amount = price2num(GETPOST("amount", 'alpha'));
111if (!GETPOST("currency", 'alpha')) {
112 $currency = getDolCurrency();
113} else {
114 $currency = GETPOST("currency", 'aZ09');
115}
116$source = GETPOST("s", 'aZ09') ? GETPOST("s", 'aZ09') : GETPOST("source", 'aZ09');
117$getpostlang = GETPOST('lang', 'aZ09');
118$ws = GETPOST("ws", "aZ09"); // Website reference where the newpayment page is embedded or from where the newpayment page is called
119
120if (!$action) {
121 if (!GETPOST("amount", 'alpha') && !$source) {
122 print $langs->trans('ErrorBadParameters')." - amount or source";
123 exit;
124 }
125 if (is_numeric($amount) && !GETPOST("tag", 'alpha') && !$source) {
126 print $langs->trans('ErrorBadParameters')." - tag or source";
127 exit;
128 }
129 if ($source && !GETPOST("ref", 'alpha')) {
130 print $langs->trans('ErrorBadParameters')." - ref";
131 exit;
132 }
133}
134
135
136$thirdparty = null; // Init for static analysis
137$stripecu = null; // Init for static analysis
138$paymentintent = null; // Init for static analysis
139
140// Load data required later for actions and view
141
142if ($source == 'organizedeventregistration') { // Test on permission not required here (anonymous action protected by mitigation of /public/... urls)
143 // Finding the Attendee
144 $attendee = new ConferenceOrBoothAttendee($db);
145
146 $invoiceid = GETPOSTINT('ref');
147 $invoice = new Facture($db);
148
149 $resultinvoice = $invoice->fetch($invoiceid);
150
151 if ($resultinvoice <= 0) {
152 setEventMessages(null, $invoice->errors, "errors");
153 } else {
154 /*
155 $attendeeid = 0;
156
157 $invoice->fetchObjectLinked();
158 $linkedAttendees = $invoice->linkedObjectsIds['conferenceorboothattendee'];
159
160 if (is_array($linkedAttendees)) {
161 $linkedAttendees = array_values($linkedAttendees);
162 $attendeeid = $linkedAttendees[0];
163 }*/
164 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."eventorganization_conferenceorboothattendee";
165 $sql .= " WHERE fk_invoice = ".((int) $invoiceid);
166 $attendeeid = 0;
167 $resql = $db->query($sql);
168 if ($resql) {
169 $obj = $db->fetch_object($resql);
170 if ($obj) {
171 $attendeeid = $obj->rowid;
172 }
173 }
174
175 if ($attendeeid > 0) {
176 $resultattendee = $attendee->fetch($attendeeid);
177
178 if ($resultattendee <= 0) {
179 setEventMessages(null, $attendee->errors, "errors");
180 } else {
181 $attendee->fetch_projet();
182
183 $amount = price2num($invoice->total_ttc);
184 // Finding the associated thirdparty
185 $thirdparty = new Societe($db);
186 $resultthirdparty = $thirdparty->fetch($invoice->socid);
187 if ($resultthirdparty <= 0) {
188 setEventMessages(null, $thirdparty->errors, "errors");
189 }
190 $object = $thirdparty;
191 }
192 }
193 }
194} elseif ($source == 'boothlocation') { // Test on permission not required here (anonymous action protected by mitigation of /public/... urls)
195 // Getting the amount to pay, the invoice, finding the thirdparty
196 $invoiceid = GETPOSTINT('ref');
197 $invoice = new Facture($db);
198 $resultinvoice = $invoice->fetch($invoiceid);
199 if ($resultinvoice <= 0) {
200 setEventMessages(null, $invoice->errors, "errors");
201 } else {
202 $amount = price2num($invoice->total_ttc);
203 // Finding the associated thirdparty
204 $thirdparty = new Societe($db);
205 $resultthirdparty = $thirdparty->fetch($invoice->socid);
206 if ($resultthirdparty <= 0) {
207 setEventMessages(null, $thirdparty->errors, "errors");
208 }
209 $object = $thirdparty;
210 }
211}
212
213
214$paymentmethod = GETPOST('paymentmethod', 'alphanohtml') ? GETPOST('paymentmethod', 'alphanohtml') : ''; // Empty in most cases. Defined when a payment mode is forced
215$validpaymentmethod = array();
216
217// Detect $paymentmethod
218foreach ($_POST as $key => $val) {
219 $reg = array();
220 if (preg_match('/^dopayment_(.*)$/', $key, $reg)) {
221 $paymentmethod = $reg[1];
222 break;
223 }
224}
225
226// Complete urls for post treatment
227$ref = $REF = GETPOST('ref', 'alpha');
228$TAG = GETPOST("tag", 'alpha');
229$FULLTAG = GETPOST("fulltag", 'alpha'); // fulltag is tag with more information
230$SECUREKEY = GETPOST("securekey"); // Secure key
231$PAYPAL_API_OK = "";
232$PAYPAL_API_KO = "";
233$PAYPAL_API_SANDBOX = "";
234$PAYPAL_API_USER = "";
235$PAYPAL_API_PASSWORD = "";
236$PAYPAL_API_SIGNATURE = "";
237
238$reg = array();
239if (empty($ws) && preg_match('/WS=([^=&]+)/', $FULLTAG, $reg)) {
240 $ws = $reg[1];
241}
242
243// Define $urlwithroot
244//$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
245//$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
246$urlwithroot = DOL_MAIN_URL_ROOT; // This is to use same domain name than current. For Paypal payment, we can use internal URL like localhost.
247
248$urlok = $urlwithroot.'/public/payment/paymentok.php?';
249$urlko = $urlwithroot.'/public/payment/paymentko.php?';
250
251if ($ws && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) { // So defined('USEEXTERNALSERVER') should be set but is not always
252 if (!empty($_SERVER["HTTP_X_FORWARDED_HOST"])) {
253 // Page is called after a proxy
254 $tmphosts = explode(',', $_SERVER["HTTP_X_FORWARDED_HOST"]);
255 $tmphosts = array_map('trim', $tmphosts);
256 $lastproxy = end($tmphosts);
257
258 include_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
259 $tmpwebsite = new Website($db);
260 $tmpwebsite->fetch(0, $ws);
261
262 if (preg_replace('/https?:\/\//i', '', $tmpwebsite->virtualhost) == $lastproxy) {
263 // If the newpayment.php page was called from a proxy with same domain than the website virtual host, we must use this one as the redirect domain url.
264 $urlok = $tmpwebsite->virtualhost.'/public/payment/paymentok.php?';
265 $urlko = $tmpwebsite->virtualhost.'/public/payment/paymentko.php?';
266 }
267 }
268}
269
270if ($paymentmethod && !preg_match('/'.preg_quote('PM='.$paymentmethod, '/').'/', $FULLTAG)) {
271 $FULLTAG .= ($FULLTAG ? '.' : '').'PM='.$paymentmethod;
272}
273
274if ($ws && !preg_match('/'.preg_quote('WS='.$ws, '/').'/', $FULLTAG)) {
275 $FULLTAG .= ($FULLTAG ? '.' : '').'WS='.$ws;
276}
277
278if (!empty($suffix)) {
279 $urlok .= 'suffix='.urlencode($suffix).'&';
280 $urlko .= 'suffix='.urlencode($suffix).'&';
281}
282if ($source) {
283 $urlok .= 's='.urlencode($source).'&';
284 $urlko .= 's='.urlencode($source).'&';
285}
286if (!empty($REF)) {
287 $urlok .= 'ref='.urlencode($REF).'&';
288 $urlko .= 'ref='.urlencode($REF).'&';
289}
290if (!empty($TAG)) {
291 $urlok .= 'tag='.urlencode($TAG).'&';
292 $urlko .= 'tag='.urlencode($TAG).'&';
293}
294if (!empty($FULLTAG)) {
295 $urlok .= 'fulltag='.urlencode($FULLTAG).'&';
296 $urlko .= 'fulltag='.urlencode($FULLTAG).'&';
297}
298if (!empty($SECUREKEY)) {
299 $urlok .= 'securekey='.urlencode($SECUREKEY).'&';
300 $urlko .= 'securekey='.urlencode($SECUREKEY).'&';
301}
302if (!empty($entity)) {
303 $urlok .= 'e='.urlencode((string) ($entity)).'&';
304 $urlko .= 'e='.urlencode((string) ($entity)).'&';
305}
306if (!empty($getpostlang)) {
307 $urlok .= 'lang='.urlencode($getpostlang).'&';
308 $urlko .= 'lang='.urlencode($getpostlang).'&';
309}
310$urlok = preg_replace('/&$/', '', $urlok); // Remove last &
311$urlko = preg_replace('/&$/', '', $urlko); // Remove last &
312
313
314// Make special controls
315
316// From paypal.lib - reused across 'if' bodies
317'
318@phan-var-force string $PAYPAL_API_SANDBOX
319@phan-var-force string $PAYPAL_API_OK
320@phan-var-force string $PAYPAL_API_KO
321';
322
323if ((empty($paymentmethod) || $paymentmethod == 'paypal') && isModEnabled('paypal')) {
324 global $PAYPAL_API_SANDBOX, $PAYPAL_API_OK, $PAYPAL_API_KO, $PAYPAL_API_USER, $PAYPAL_API_PASSWORD, $PAYPAL_API_SIGNATURE;
325 require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypal.lib.php';
326 require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php';
327
328
329 // Check parameters
330 $PAYPAL_API_OK = "";
331 if ($urlok) {
332 $PAYPAL_API_OK = $urlok;
333 }
334 $PAYPAL_API_KO = "";
335 if ($urlko) {
336 $PAYPAL_API_KO = $urlko;
337 }
338 if (empty($PAYPAL_API_USER)) {
339 print 'Paypal parameter PAYPAL_API_USER is not defined. Please <a href="'.DOL_URL_ROOT.'/paypal/admin/paypal.php">complete the setup of module PayPal first</a>.';
340 exit;
341 }
342 if (empty($PAYPAL_API_PASSWORD)) {
343 print 'Paypal parameter PAYPAL_API_PASSWORD is not defined. Please <a href="'.DOL_URL_ROOT.'/paypal/admin/paypal.php">complete the setup of module PayPal first</a>.';
344 exit;
345 }
346 if (empty($PAYPAL_API_SIGNATURE)) {
347 print 'Paypal parameter PAYPAL_API_SIGNATURE is not defined. Please <a href="'.DOL_URL_ROOT.'/paypal/admin/paypal.php">complete the setup of module PayPal first</a>.';
348 exit;
349 }
350}
351//if ((empty($paymentmethod) || $paymentmethod == 'paybox') && isModEnabled('paybox')) {
352// No specific test for the moment
353//}
354if ((empty($paymentmethod) || $paymentmethod == 'stripe') && isModEnabled('stripe')) {
355 require_once DOL_DOCUMENT_ROOT.'/stripe/config.php'; // This include also /stripe/lib/stripe.lib.php, /includes/stripe/stripe-php/init.php, ...
360}
361
362// Initialize $validpaymentmethod
363// The list can be complete by the hook 'doValidatePayment' executed inside getValidOnlinePaymentMethods()
364$validpaymentmethod = getValidOnlinePaymentMethods($paymentmethod);
365
366// Check security token
367$tmpsource = $source;
368if ($tmpsource == 'membersubscription') {
369 $tmpsource = 'member';
370}
371$valid = true;
372if (getDolGlobalString('PAYMENT_SECURITY_TOKEN')) {
373 $tokenisok = false;
374 if (getDolGlobalString('PAYMENT_SECURITY_TOKEN_UNIQUE')) {
375 if ($tmpsource && $REF) {
376 // Use the source in the hash to avoid duplicates if the references are identical
377 $tokenisok = dol_verifyHash(getDolGlobalString('PAYMENT_SECURITY_TOKEN') . $tmpsource.$REF, $SECUREKEY, '2');
378 // Do a second test for retro-compatibility (token may have been hashed with membersubscription in external module)
379 if ($tmpsource != $source) {
380 $tokenisok = dol_verifyHash(getDolGlobalString('PAYMENT_SECURITY_TOKEN') . $source.$REF, $SECUREKEY, '2');
381 }
382 } else {
383 $tokenisok = dol_verifyHash(getDolGlobalString('PAYMENT_SECURITY_TOKEN'), $SECUREKEY, '2');
384 }
385 } else {
386 $tokenisok = (getDolGlobalString('PAYMENT_SECURITY_TOKEN') == $SECUREKEY);
387 }
388
389 if (! $tokenisok) {
390 if (!getDolGlobalString('PAYMENT_SECURITY_ACCEPT_ANY_TOKEN')) {
391 $valid = false; // PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is for backward compatibility
392 } else {
393 dol_syslog("Warning: PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is on", LOG_WARNING);
394 dol_syslog("Warning: PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is on", LOG_WARNING, 0, '_payment');
395 }
396 }
397
398 if (!$valid) {
399 print '<div class="error">Bad value for key.</div>';
400 //print 'SECUREKEY='.$SECUREKEY.' valid='.$valid;
401 exit;
402 }
403}
404
405if (!empty($paymentmethod) && empty($validpaymentmethod[$paymentmethod])) {
406 print 'Payment module for payment method '.$paymentmethod.' is not active';
407 exit;
408}
409if (empty($validpaymentmethod)) {
410 print 'No active payment module (Paypal, Stripe, Paybox, ...)';
411 exit;
412}
413
414// Common variables
415$creditor = $mysoc->name;
416$paramcreditor = 'ONLINE_PAYMENT_CREDITOR';
417$paramcreditorlong = 'ONLINE_PAYMENT_CREDITOR_'.$suffix;
418if (getDolGlobalString($paramcreditorlong)) {
419 $creditor = getDolGlobalString($paramcreditorlong); // use label long of the seller to show
420} elseif (getDolGlobalString($paramcreditor)) {
421 $creditor = getDolGlobalString($paramcreditor); // use label short of the seller to show
422}
423
424$mesg = '';
425
426
427/*
428 * Actions
429 */
430
431// First log into the dolibarr_payment.log file
432dol_syslog("--- newpayment.php action=".$action." paymentmethod=".$paymentmethod.' amount='.$amount.' newamount='.GETPOST("newamount", 'alpha'), LOG_DEBUG, 0, '_payment');
433
434dol_syslog("fulltag=".GETPOST("fulltag", 'alpha')." ws=".$ws." urlok=".$urlok, LOG_DEBUG, 0, '_payment');
435
436// Action dopayment is called after clicking/choosing the payment mode
437if ($action == 'dopayment') { // Test on permission not required here (anonymous action protected by mitigation of /public/... urls)
438 if ($paymentmethod == 'paypal') {
439 $PAYPAL_API_PRICE = price2num(GETPOST("newamount", 'alpha'), 'MT');
440 $PAYPAL_PAYMENT_TYPE = 'Sale';
441
442 // Vars that are used as global var later in print_paypal_redirect()
443 $origfulltag = GETPOST("fulltag", 'alpha');
444 $shipToName = GETPOST("shipToName", 'alpha');
445 $shipToStreet = GETPOST("shipToStreet", 'alpha');
446 $shipToCity = GETPOST("shipToCity", 'alpha');
447 $shipToState = GETPOST("shipToState", 'alpha');
448 $shipToCountryCode = GETPOST("shipToCountryCode", 'alpha');
449 $shipToZip = GETPOST("shipToZip", 'alpha');
450 $shipToStreet2 = GETPOST("shipToStreet2", 'alpha');
451 $phoneNum = GETPOST("phoneNum", 'alpha');
452 $email = GETPOST("email", 'alpha');
453 $desc = GETPOST("desc", 'alpha');
454 $thirdparty_id = GETPOSTINT('thirdparty_id');
455
456 // Special case for Paypal-Indonesia
457 if ($shipToCountryCode == 'ID' && !preg_match('/\-/', $shipToState)) {
458 $shipToState = 'ID-'.$shipToState;
459 }
460
461 if (empty($PAYPAL_API_PRICE) || !is_numeric($PAYPAL_API_PRICE)) {
462 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount"));
463 $action = '';
464 // } elseif (empty($EMAIL)) { $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("YourEMail"));
465 // } elseif (! isValidEmail($EMAIL)) { $mesg=$langs->trans("ErrorBadEMail",$EMAIL);
466 } elseif (!$origfulltag) {
467 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PaymentCode"));
468 $action = '';
469 }
470
471 if (empty($mesg)) {
472 dol_syslog("newpayment.php call paypal api and do redirect", LOG_DEBUG);
473 dol_syslog("newpayment.php call paypal api and do redirect", LOG_DEBUG, 0, '_payment');
474
475 // Other
476 $PAYPAL_API_DEVISE = "USD";
477 if (!empty($currency)) {
478 $PAYPAL_API_DEVISE = $currency;
479 }
480
481 // Show var initialized by inclusion of paypal lib at start of this file
482 dol_syslog("Submit Paypal form", LOG_DEBUG);
483 dol_syslog("Submit Paypal form", LOG_DEBUG, 0, '_payment');
484
485 dol_syslog("PAYPAL_API_USER: $PAYPAL_API_USER", LOG_DEBUG, 0, '_payment');
486 dol_syslog("PAYPAL_API_PASSWORD: ".preg_replace('/./', '*', $PAYPAL_API_PASSWORD), LOG_DEBUG, 0, '_payment'); // No password into log files
487 dol_syslog("PAYPAL_API_SIGNATURE: $PAYPAL_API_SIGNATURE", LOG_DEBUG, 0, '_payment');
488 dol_syslog("PAYPAL_API_SANDBOX: $PAYPAL_API_SANDBOX", LOG_DEBUG, 0, '_payment');
489 dol_syslog("PAYPAL_API_OK: $PAYPAL_API_OK", LOG_DEBUG, 0, '_payment');
490 dol_syslog("PAYPAL_API_KO: $PAYPAL_API_KO", LOG_DEBUG, 0, '_payment');
491 dol_syslog("PAYPAL_API_PRICE: $PAYPAL_API_PRICE", LOG_DEBUG, 0, '_payment');
492 dol_syslog("PAYPAL_API_DEVISE: $PAYPAL_API_DEVISE", LOG_DEBUG, 0, '_payment');
493 // All those fields may be empty when making a payment for a free amount for example
494 dol_syslog("shipToName: $shipToName", LOG_DEBUG, 0, '_payment');
495 dol_syslog("shipToStreet: $shipToStreet", LOG_DEBUG, 0, '_payment');
496 dol_syslog("shipToCity: $shipToCity", LOG_DEBUG, 0, '_payment');
497 dol_syslog("shipToState: $shipToState", LOG_DEBUG, 0, '_payment');
498 dol_syslog("shipToCountryCode: $shipToCountryCode", LOG_DEBUG, 0, '_payment');
499 dol_syslog("shipToZip: $shipToZip", LOG_DEBUG, 0, '_payment');
500 dol_syslog("shipToStreet2: $shipToStreet2", LOG_DEBUG, 0, '_payment');
501 dol_syslog("phoneNum: $phoneNum", LOG_DEBUG, 0, '_payment');
502 dol_syslog("email: $email", LOG_DEBUG, 0, '_payment');
503 dol_syslog("desc: $desc", LOG_DEBUG, 0, '_payment');
504
505 dol_syslog("SCRIPT_URI: ".(empty($_SERVER["SCRIPT_URI"]) ? '' : $_SERVER["SCRIPT_URI"]), LOG_DEBUG, 0, '_payment'); // If defined script uri must match domain of PAYPAL_API_OK and PAYPAL_API_KO
506
507 // A redirect is added if API call successful
508 $mesg = print_paypal_redirect((float) $PAYPAL_API_PRICE, $PAYPAL_API_DEVISE, $PAYPAL_PAYMENT_TYPE, $PAYPAL_API_OK, $PAYPAL_API_KO, $FULLTAG);
509
510 // If we are here, it means the Paypal redirect was not done, so we show error message
511 $action = '';
512 }
513 }
514
515 if ($paymentmethod == 'paybox') {
516 $PRICE = price2num(GETPOST("newamount"), 'MT');
517 $email = getDolGlobalString('ONLINE_PAYMENT_SENDEMAIL');
518 $thirdparty_id = GETPOSTINT('thirdparty_id');
519
520 $origfulltag = GETPOST("fulltag", 'alpha');
521
522 // Securekey into back url useless for back url and we need an url lower than 150.
523 $urlok = preg_replace('/securekey=[^&]+&?/', '', $urlok);
524 $urlko = preg_replace('/securekey=[^&]+&?/', '', $urlko);
525
526 if (empty($PRICE) || !is_numeric($PRICE)) {
527 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount"));
528 } elseif (empty($email)) {
529 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ONLINE_PAYMENT_SENDEMAIL"));
530 } elseif (!isValidEmail($email)) {
531 $mesg = $langs->trans("ErrorBadEMail", $email);
532 } elseif (!$origfulltag) {
533 $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PaymentCode"));
534 } elseif (dol_strlen($urlok) > 150) {
535 $mesg = 'Error urlok too long '.$urlok.' (Paybox requires 150, found '.strlen($urlok).')';
536 } elseif (dol_strlen($urlko) > 150) {
537 $mesg = 'Error urlko too long '.$urlko.' (Paybox requires 150, found '.strlen($urlok).')';
538 }
539
540 if (empty($mesg)) {
541 dol_syslog("newpayment.php call paybox api and do redirect", LOG_DEBUG, 0, '_payment');
542
543 include_once DOL_DOCUMENT_ROOT.'/paybox/lib/paybox.lib.php';
544 print_paybox_redirect((float) $PRICE, getDolCurrency(), $email, $urlok, $urlko, $FULLTAG);
545
546 session_destroy();
547 exit;
548 }
549 }
550
551 if ($paymentmethod == 'stripe') {
552 if (GETPOST('newamount', 'alpha')) {
553 $amount = price2num(GETPOST('newamount', 'alpha'), 'MT');
554 } else {
555 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")), null, 'errors');
556 $action = '';
557 }
558 }
559}
560
561
562// Called when choosing Stripe mode.
563// When using the old Charge API architecture, this code is called after clicking the 'dopayment' with the Charge API architecture.
564// When using the PaymentIntent API architecture, the Stripe customer was already created when creating PaymentIntent when showing payment page, and the payment is already ok when action=charge.
565if ($action == 'charge' && isModEnabled('stripe')) { // Test on permission not required here (anonymous action protected by mitigation of /public/... urls)
566 $amountstripe = (float) $amount;
567
568 // Correct the amount according to unit of currency
569 // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
570 $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
571 if (!in_array($currency, $arrayzerounitcurrency)) {
572 $amountstripe *= 100;
573 }
574
575 dol_syslog("newpayment.php execute action = ".$action." STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION=".getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION'), LOG_DEBUG, 0, '_payment');
576 dol_syslog("GET=".var_export($_GET, true), LOG_DEBUG, 0, '_payment');
577 dol_syslog("POST=".var_export($_POST, true), LOG_DEBUG, 0, '_payment');
578
579 $stripeToken = GETPOST("stripeToken", 'alpha');
580 $email = GETPOST("email", 'alpha');
581 $thirdparty_id = GETPOSTINT('thirdparty_id'); // Note that for payment following online registration for members, this is empty because thirdparty is created once payment is confirmed by paymentok.php
582 $dol_type = (GETPOST('s', 'alpha') ? GETPOST('s', 'alpha') : GETPOST('source', 'alpha'));
583 $dol_id = GETPOSTINT('dol_id');
584 $vatnumber = GETPOST('vatnumber', 'alpha');
585 $savesource = GETPOSTISSET('savesource') ? GETPOSTINT('savesource') : 1;
586
587 dol_syslog("POST stripeToken = ".$stripeToken, LOG_DEBUG, 0, '_payment');
588 dol_syslog("POST email = ".$email, LOG_DEBUG, 0, '_payment');
589 dol_syslog("POST thirdparty_id = ".$thirdparty_id, LOG_DEBUG, 0, '_payment');
590 dol_syslog("POST vatnumber = ".$vatnumber, LOG_DEBUG, 0, '_payment');
591
592 $error = 0;
593 $errormessage = '';
594 $stripeacc = null;
595 $customer = null;
596 $charge = null;
597 $paymentintent = null;
598
599 // When using the old Charge API architecture
600 if (!getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
601 try {
602 $metadata = array(
603 'dol_version' => DOL_VERSION,
604 'dol_entity' => $conf->entity,
605 'dol_company' => $mysoc->name, // Useful when using multicompany
606 'dol_tax_num' => $vatnumber,
607 'ipaddress' => getUserRemoteIP()
608 );
609
610 if (!empty($thirdparty_id)) {
611 $metadata["dol_thirdparty_id"] = $thirdparty_id;
612 }
613
614 if ($thirdparty_id > 0) {
615 dol_syslog("Search existing Stripe customer profile for thirdparty_id=".$thirdparty_id, LOG_DEBUG, 0, '_payment');
616
617 $service = 'StripeTest';
618 $servicestatus = 0;
619 if (getDolGlobalString('STRIPE_LIVE')/* && !GETPOSTINT('forcesandbox') */) {
620 $service = 'StripeLive';
621 $servicestatus = 1;
622 }
623
624 $thirdparty = new Societe($db);
625 $thirdparty->fetch($thirdparty_id);
626
627 // Create Stripe customer
628 include_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
629 $stripe = new Stripe($db);
630 $stripeacc = $stripe->getStripeAccount($service);
631 $customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 1);
632 if (empty($customer)) {
633 $error++;
634 dol_syslog('Failed to get/create stripe customer for thirdparty id = '.$thirdparty_id.' and servicestatus = '.$servicestatus.': '.$stripe->error, LOG_ERR, 0, '_payment');
635 setEventMessages('Failed to get/create stripe customer for thirdparty id = '.$thirdparty_id.' and servicestatus = '.$servicestatus.': '.$stripe->error, null, 'errors');
636 $action = '';
637 }
638
639 // Create Stripe card from Token
640 if (!$error) {
641 if ($savesource) {
642 $card = $customer->sources->create(array("source" => $stripeToken, "metadata" => $metadata));
643 } else {
644 $card = $stripeToken;
645 }
646
647 if (empty($card)) {
648 $error++;
649 dol_syslog('Failed to create card record', LOG_WARNING, 0, '_payment');
650 setEventMessages('Failed to create card record', null, 'errors');
651 $action = '';
652 } else {
653 if (!empty($FULLTAG)) {
654 $metadata["FULLTAG"] = $FULLTAG;
655 }
656 if (!empty($dol_id)) {
657 $metadata["dol_id"] = $dol_id;
658 }
659 if (!empty($dol_type)) {
660 $metadata["dol_type"] = $dol_type;
661 }
662
663 dol_syslog("Create charge on card ".$card->id, LOG_DEBUG, 0, '_payment');
664 $charge = \Stripe\Charge::create(array(
665 'amount' => price2num($amountstripe, 'MU'),
666 'currency' => $currency,
667 'capture' => true, // Charge immediately
668 'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
669 'metadata' => $metadata,
670 'customer' => $customer->id,
671 'source' => $card,
672 'statement_descriptor_suffix' => dol_trunc($FULLTAG, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
673 ), array("idempotency_key" => "$FULLTAG", "stripe_account" => "$stripeacc"));
674 // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
675 if (empty($charge)) {
676 $error++;
677 dol_syslog('Failed to charge card', LOG_WARNING, 0, '_payment');
678 setEventMessages('Failed to charge card', null, 'errors');
679 $action = '';
680 }
681 }
682 }
683 } else {
684 $vatcleaned = $vatnumber ? $vatnumber : null;
685
686 /*$taxinfo = array('type'=>'vat');
687 if ($vatcleaned)
688 {
689 $taxinfo["tax_id"] = $vatcleaned;
690 }
691 // We force data to "null" if not defined as expected by Stripe
692 if (empty($vatcleaned)) $taxinfo=null;
693 */
694
695 dol_syslog("Create anonymous customer card profile", LOG_DEBUG, 0, '_payment');
696
697 $customer = \Stripe\Customer::create(array(
698 'email' => $email,
699 'description' => ($email ? 'Anonymous customer for '.$email : 'Anonymous customer'),
700 'metadata' => $metadata,
701 'source' => $stripeToken // source can be a token OR array('object'=>'card', 'exp_month'=>xx, 'exp_year'=>xxxx, 'number'=>xxxxxxx, 'cvc'=>xxx, 'name'=>'Cardholder's full name', zip ?)
702 ));
703 // Return $customer = array('id'=>'cus_XXXX', ...)
704
705 // Create the VAT record in Stripe
706 /* We don't know country of customer, so we can't create tax
707 if (getDolGlobalString('STRIPE_SAVE_TAX_IDS')) { // We setup to save Tax info on Stripe side. Warning: This may result in error when saving customer
708 if (!empty($vatcleaned))
709 {
710 $isineec=isInEEC($object);
711 if ($object->country_code && $isineec)
712 {
713 //$taxids = $customer->allTaxIds($customer->id);
714 $customer->createTaxId($customer->id, array('type'=>'eu_vat', 'value'=>$vatcleaned));
715 }
716 }
717 }*/
718
719 if (!empty($FULLTAG)) {
720 $metadata["FULLTAG"] = $FULLTAG;
721 }
722 if (!empty($dol_id)) {
723 $metadata["dol_id"] = $dol_id;
724 }
725 if (!empty($dol_type)) {
726 $metadata["dol_type"] = $dol_type;
727 }
728
729 // The customer was just created with a source, so we can make a charge
730 // with no card defined, the source just used for customer creation will be used.
731 dol_syslog("Create charge", LOG_DEBUG, 0, '_payment');
732 $charge = \Stripe\Charge::create(array(
733 'customer' => $customer->id,
734 'amount' => price2num($amountstripe, 'MU'),
735 'currency' => $currency,
736 'capture' => true, // Charge immediately
737 'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
738 'metadata' => $metadata,
739 'statement_descriptor' => dol_trunc($FULLTAG, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
740 ), array("idempotency_key" => (string) $FULLTAG, "stripe_account" => (string) $stripeacc));
741 // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
742 if (empty($charge)) {
743 $error++;
744 dol_syslog('Failed to charge card', LOG_WARNING, 0, '_payment');
745 setEventMessages('Failed to charge card', null, 'errors');
746 $action = '';
747 }
748 }
749 } catch (\Stripe\Exception\CardException $e) {
750 // Since it's a decline, \Stripe\Exception\Card will be caught
751 $body = $e->getJsonBody();
752 $err = $body['error'];
753
754 print('Status is:'.$e->getHttpStatus()."\n");
755 print('Type is:'.$err['type']."\n");
756 print('Code is:'.$err['code']."\n");
757 // param is '' in this case
758 print('Param is:'.$err['param']."\n");
759 print('Message is:'.$err['message']."\n");
760
761 $error++;
762 $errormessage = "ErrorCard ".$e->getMessage()." err=".var_export($err, true);
763 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
764 setEventMessages($e->getMessage(), null, 'errors');
765 $action = '';
766 } catch (\Stripe\Exception\RateLimitException $e) {
767 // Too many requests made to the API too quickly
768 $error++;
769 $errormessage = "ErrorRateLimit ".$e->getMessage();
770 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
771 setEventMessages($e->getMessage(), null, 'errors');
772 $action = '';
773 } catch (\Stripe\Exception\InvalidRequestException $e) {
774 // Invalid parameters were supplied to Stripe's API
775 $error++;
776 $errormessage = "ErrorInvalidRequest ".$e->getMessage();
777 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
778 setEventMessages($e->getMessage(), null, 'errors');
779 $action = '';
780 } catch (\Stripe\Exception\AuthenticationException $e) {
781 // Authentication with Stripe's API failed
782 // (maybe you changed API keys recently)
783 $error++;
784 $errormessage = "ErrorAuthentication ".$e->getMessage();
785 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
786 setEventMessages($e->getMessage(), null, 'errors');
787 $action = '';
788 } catch (\Stripe\Exception\ApiConnectionException $e) {
789 // Network communication with Stripe failed
790 $error++;
791 $errormessage = "ErrorApiConnection ".$e->getMessage();
792 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
793 setEventMessages($e->getMessage(), null, 'errors');
794 $action = '';
795 } catch (\Stripe\Exception\ExceptionInterface $e) {
796 // Display a very generic error to the user, and maybe send
797 // yourself an email
798 $error++;
799 $errormessage = "ErrorBase ".$e->getMessage();
800 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
801 setEventMessages($e->getMessage(), null, 'errors');
802 $action = '';
803 } catch (Exception $e) {
804 // Something else happened, completely unrelated to Stripe
805 $error++;
806 $errormessage = "ErrorException ".$e->getMessage();
807 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
808 setEventMessages($e->getMessage(), null, 'errors');
809 $action = '';
810 }
811
812 if ($error) {
813 $randomseckey = getRandomPassword(true, null, 20); // TODO Generate a key including fulltag to avoid forging URL.
814 $_SESSION['paymentkosessioncode'] = $randomseckey; // key between newpayment.php to paymentko.php
815
816 $urlko .= '&paymentkosessioncode='.urlencode($randomseckey);
817 } else {
818 $randomseckey = getRandomPassword(true, null, 20); // TODO Generate a key including fulltag to avoid forging URL.
819 $_SESSION['paymentoksessioncode'] = $randomseckey; // key between newpayment.php to paymentok.php
820
821 $urlok .= '&paymentoksessioncode='.urlencode($randomseckey);
822 }
823 }
824
825 // When using the PaymentIntent API architecture (mode set on by default into conf.class.php)
826 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
827 $service = 'StripeTest';
828 $servicestatus = 0;
829 if (getDolGlobalString('STRIPE_LIVE')/* && !GETPOSTINT('forcesandbox') */) {
830 $service = 'StripeLive';
831 $servicestatus = 1;
832 }
833 include_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
834 $stripe = new Stripe($db);
835 $stripeacc = $stripe->getStripeAccount($service);
836
837 // We go here if getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') is set.
838 // In such a case, payment is always ok when we call the "charge" action.
839 $paymentintent_id = GETPOST("paymentintent_id", "alpha");
840
841 // Force to use the correct API key
842 global $stripearrayofkeysbyenv;
843 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$servicestatus]['secret_key']);
844
845 try {
846 if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
847 $paymentintent = \Stripe\PaymentIntent::retrieve($paymentintent_id);
848 } else {
849 $paymentintent = \Stripe\PaymentIntent::retrieve($paymentintent_id, array("stripe_account" => $stripeacc));
850 }
851 } catch (Exception $e) {
852 $error++;
853 $errormessage = "CantRetrievePaymentIntent ".$e->getMessage();
854 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
855 setEventMessages($e->getMessage(), null, 'errors');
856 $action = '';
857 }
858
859 // Security: a succeeded PaymentIntent must not be reusable to record a payment on more than one Dolibarr object.
860 // Without this check, a PaymentIntent id obtained for one invoice/order/... could be resubmitted here with a
861 // different fulltag/ref to fraudulently record (and validate) a payment on a different object that was never
862 // really paid for, since Dolibarr never re-checks that a "succeeded" PaymentIntent is bound to a specific target.
863 $paymentintentalreadyused = 0;
864 if (!$error && is_object($paymentintent) && $paymentintent->status == 'succeeded') {
865 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."paiement";
866 $sql .= " WHERE ext_payment_id = '".$db->escape($paymentintent_id)."'";
867 $sql .= " OR ext_payment_id LIKE '".$db->escape($paymentintent_id).":%'";
868 $resql = $db->query($sql);
869 if ($resql) {
870 if ($db->num_rows($resql) > 0) {
871 $paymentintentalreadyused = 1;
872 }
873 $db->free($resql);
874 }
875 }
876
877 if ($paymentintent->status != 'succeeded' || $paymentintentalreadyused) {
878 $error++;
879 if ($paymentintentalreadyused) {
880 $errormessage = "PaymentIntent ".$paymentintent_id." was already used to record a payment, it cannot be reused for another object";
881 } else {
882 $errormessage = "StatusOfRetrievedIntent is not succeeded: ".$paymentintent->status;
883 }
884 dol_syslog($errormessage, LOG_WARNING, 0, '_payment');
885 setEventMessages($errormessage, null, 'errors');
886 $action = '';
887
888 $randomseckey = getRandomPassword(true, null, 20); // TODO Generate a key including fulltag to avoid forging URL.
889 $_SESSION['paymentkosessioncode'] = $randomseckey; // key between newpayment.php to paymentko.php
890
891 $urlko .= '&paymentkosessioncode='.urlencode($randomseckey);
892 } else {
893 // We can also record the payment mode into llx_societe_rib with stripe $paymentintent->payment_method
894 // Note that with other old Stripe architecture (using Charge API), the payment mode was not recorded, so it is not mandatory to do it here.
895 // dol_syslog("Create payment_method for ".$paymentintent->payment_method, LOG_DEBUG, 0, '_payment');
896
897 // Get here amount and currency used for payment and force value into $amount and $currency so the real amount is saved into session instead
898 // of the amount and currency retrieved from the POST.
899 $amount = $paymentintent->amount;
900 $currency = '';
901
902 if (!empty($paymentintent->currency)) {
903 $currency = strtoupper($paymentintent->currency);
904
905 // Correct the amount according to unit of currency
906 // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
907 $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
908 if (!in_array($currency, $arrayzerounitcurrency)) {
909 $amount /= 100;
910 }
911 }
912
913 dol_syslog("StatusOfRetrievedIntent is succeeded for amount = ".$amount." currency = ".$currency, LOG_DEBUG, 0, '_payment');
914
915 $randomseckey = getRandomPassword(true, null, 20); // TODO Generate a key including fulltag to avoid forging URL.
916 $_SESSION['paymentoksessioncode'] = $randomseckey; // key between newpayment.php to paymentok.php
917
918 $urlok .= '&paymentoksessioncode='.urlencode($randomseckey);
919 }
920 }
921
922
923 $remoteip = getUserRemoteIP();
924
925 $_SESSION["onlinetoken"] = $stripeToken;
926 $_SESSION["FinalPaymentAmt"] = $amount; // amount really paid (coming from Stripe). Will be used for check in paymentok.php.
927 $_SESSION["currencyCodeType"] = $currency; // currency really used for payment (coming from Stripe). Will be used for check in paymentok.php.
928 $_SESSION["paymentType"] = '';
929 $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip
930 $_SESSION['TRANSACTIONID'] = (is_object($charge) ? $charge->id : (is_object($paymentintent) ? $paymentintent->id : ''));
931 $_SESSION['errormessage'] = $errormessage;
932 if (!getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
933 $_SESSION['payerID'] = is_object($customer) ? $customer->id : '';
934 } else {
935 $_SESSION['payerID'] = '';
936 }
937
938 dol_syslog("Action charge stripe STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION=".getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')." ip=".$remoteip, LOG_DEBUG, 0, '_payment');
939 dol_syslog("_SERVER[HTTP_X_FORWARDED_HOST] = ".(empty($_SERVER["HTTP_X_FORWARDED_HOST"]) ? '' : dol_escape_htmltag($_SERVER["HTTP_X_FORWARDED_HOST"])), LOG_DEBUG, 0, '_payment');
940 dol_syslog("_SERVER[SERVER_NAME] = ".(empty($_SERVER["SERVER_NAME"]) ? '' : dol_escape_htmltag($_SERVER["SERVER_NAME"])), LOG_DEBUG, 0, '_payment');
941 dol_syslog("_SERVER[SERVER_ADDR] = ".(empty($_SERVER["SERVER_ADDR"]) ? '' : dol_escape_htmltag($_SERVER["SERVER_ADDR"])), LOG_DEBUG, 0, '_payment');
942 dol_syslog("session_id=".session_id(), LOG_DEBUG, 0, '_payment');
943 dol_syslog("onlinetoken=".$_SESSION["onlinetoken"]." paymentoksessioncode=".$_SESSION["paymentoksessioncode"]." paymentkosessioncode=".($_SESSION["paymentkosessioncode"] ?? ''), LOG_DEBUG, 0, '_payment');
944 dol_syslog("FinalPaymentAmt=".$_SESSION["FinalPaymentAmt"]." currencyCodeType=".$_SESSION["currencyCodeType"]." payerID=".$_SESSION['payerID']." TRANSACTIONID=".$_SESSION['TRANSACTIONID'], LOG_DEBUG, 0, '_payment');
945 dol_syslog("FULLTAG=".$FULLTAG, LOG_DEBUG, 0, '_payment');
946 dol_syslog("error=".$error." errormessage=".$errormessage, LOG_DEBUG, 0, '_payment');
947 dol_syslog("Now call the redirect to paymentok or paymentko, URL = ".($error ? $urlko : $urlok), LOG_DEBUG, 0, '_payment');
948
949 if ($error) {
950 header("Location: ".$urlko);
951 exit;
952 } else {
953 header("Location: ".$urlok);
954 exit;
955 }
956}
957
958// This hook is used to push to $validpaymentmethod by external payment modules (ie Payzen, ...)
959$parameters = array(
960 'paymentmethod' => $paymentmethod,
961 'validpaymentmethod' => &$validpaymentmethod
962);
963$reshook = $hookmanager->executeHooks('doPayment', $parameters, $object, $action);
964if ($reshook < 0) {
965 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
966} elseif ($reshook > 0) {
967 print $hookmanager->resPrint;
968}
969
970
971
972/*
973 * View
974 */
975
976$form = new Form($db);
977
978$head = '';
979if (getDolGlobalString('ONLINE_PAYMENT_CSS_URL')) {
980 $head = '<link rel="stylesheet" type="text/css" href="' . getDolGlobalString('ONLINE_PAYMENT_CSS_URL').'?lang='.(!empty($getpostlang) ? $getpostlang : $langs->defaultlang).'">'."\n";
981}
982
983$conf->dol_hide_topmenu = 1;
984$conf->dol_hide_leftmenu = 1;
985
986$replacemainarea = (empty($conf->dol_hide_leftmenu) ? '<div>' : '').'<div>';
987llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody', $replacemainarea);
988
989dol_syslog("newpayment.php show page source=".$source." paymentmethod=".$paymentmethod.' amount='.$amount.' newamount='.GETPOST("newamount", 'alpha')." ref=".$ref, LOG_DEBUG, 0, '_payment');
990dol_syslog("_SERVER[HTTP_X_FORWARDED_HOST] = ".(empty($_SERVER["HTTP_X_FORWARDED_HOST"]) ? '' : dol_escape_htmltag($_SERVER["HTTP_X_FORWARDED_HOST"])), LOG_DEBUG, 0, '_payment');
991dol_syslog("_SERVER[SERVER_NAME] = ".(empty($_SERVER["SERVER_NAME"]) ? '' : dol_escape_htmltag($_SERVER["SERVER_NAME"])), LOG_DEBUG, 0, '_payment');
992dol_syslog("_SERVER[SERVER_ADDR] = ".(empty($_SERVER["SERVER_ADDR"]) ? '' : dol_escape_htmltag($_SERVER["SERVER_ADDR"])), LOG_DEBUG, 0, '_payment');
993dol_syslog("session_id=".session_id(), LOG_DEBUG, 0, '_payment');
994
995// Check link validity
996if ($source && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', 'donation_ref', ''))) {
997 $langs->load("errors");
998 dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $source, $ref));
999 // End of page
1000 llxFooter();
1001 $db->close();
1002 exit;
1003}
1004
1005
1006// Show sandbox warning
1007if ((empty($paymentmethod) || $paymentmethod == 'paypal') && isModEnabled('paypal') && (getDolGlobalString('PAYPAL_API_SANDBOX')/* || GETPOSTINT('forcesandbox')*/)) { // We can force sand box with param 'forcesandbox'
1008 dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode', 'Paypal'), array(), 'warning');
1009}
1010if ((empty($paymentmethod) || $paymentmethod == 'stripe') && isModEnabled('stripe') && (!getDolGlobalString('STRIPE_LIVE')/* || GETPOSTINT('forcesandbox')*/)) {
1011 dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode', 'Stripe'), array(), 'warning');
1012}
1013
1014
1015print '<span id="dolpaymentspan"></span>'."\n";
1016print '<div class="center">'."\n";
1017print '<form id="dolpaymentform" class="center" name="paymentform" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
1018print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
1019print '<input type="hidden" name="action" value="dopayment">'."\n";
1020print '<input type="hidden" name="tag" value="'.GETPOST("tag", 'alpha').'">'."\n";
1021print '<input type="hidden" name="suffix" value="'.dol_escape_htmltag($suffix).'">'."\n";
1022print '<input type="hidden" name="securekey" value="'.dol_escape_htmltag($SECUREKEY).'">'."\n";
1023print '<input type="hidden" name="e" value="'.$entity.'" />';
1024//print '<input type="hidden" name="forcesandbox" value="'.GETPOSTINT('forcesandbox').'" />';
1025print '<input type="hidden" name="lang" value="'.$getpostlang.'">';
1026print '<input type="hidden" name="ws" value="'.$ws.'">';
1027print '<input type="hidden" name="reload" id="reload" value="0">';
1028print "\n";
1029
1030
1031// Show logo (search order: logo defined by PAYMENT_LOGO_suffix, then PAYMENT_LOGO, then small company logo, large company logo, theme logo, common logo)
1032// Define logo and logosmall
1033$logosmall = $mysoc->logo_small;
1034$logo = $mysoc->logo;
1035$paramlogo = 'ONLINE_PAYMENT_LOGO_'.$suffix;
1036if (getDolGlobalString($paramlogo)) {
1037 $logosmall = getDolGlobalString($paramlogo);
1038} elseif (getDolGlobalString('ONLINE_PAYMENT_LOGO')) {
1039 $logosmall = getDolGlobalString('ONLINE_PAYMENT_LOGO');
1040}
1041//print '<!-- Show logo (logosmall='.$logosmall.' logo='.$logo.') -->'."\n";
1042// Define urllogo
1043$urllogo = '';
1044$urllogofull = '';
1045if (!empty($logosmall) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$logosmall)) {
1046 $urllogo = DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;entity='.$conf->entity.'&amp;file='.urlencode('logos/thumbs/'.$logosmall);
1047 $urllogofull = $dolibarr_main_url_root.'/viewimage.php?modulepart=mycompany&entity='.$conf->entity.'&file='.urlencode('logos/thumbs/'.$logosmall);
1048} elseif (!empty($logo) && is_readable($conf->mycompany->dir_output.'/logos/'.$logo)) {
1049 $urllogo = DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;entity='.$conf->entity.'&amp;file='.urlencode('logos/'.$logo);
1050 $urllogofull = $dolibarr_main_url_root.'/viewimage.php?modulepart=mycompany&entity='.$conf->entity.'&file='.urlencode('logos/'.$logo);
1051}
1052
1053// Output html code for logo
1054if ($ws) {
1055 // Look for a personalized header file (htmlheaderpayment.html) if the payment system is called from a website
1056 $filehtmlheader = dol_sanitizePathName(DOL_DATA_ROOT . ($conf->entity > 1 ? '/' . $conf->entity : '') . '/website/' . $ws . '/htmlheaderpayment.html');
1057 if (dol_is_file($filehtmlheader)) {
1058 print file_get_contents(dol_osencode($filehtmlheader));
1059 }
1060}
1061
1062if ($urllogo && !$ws) {
1063 print '<div class="backgreypublicpayment">';
1064 print '<div class="logopublicpayment">';
1065 print '<img id="dolpaymentlogo" src="'.$urllogo.'"';
1066 print '>';
1067 print '</div>';
1068 if (!getDolGlobalString('MAIN_HIDE_POWERED_BY')) {
1069 print '<div class="poweredbypublicpayment opacitymedium right"><a class="poweredbyhref" href="https://www.dolibarr.org?utm_medium=website&utm_source=poweredby" target="dolibarr" rel="noopener">'.$langs->trans("PoweredBy").'<br><img class="poweredbyimg" src="'.DOL_URL_ROOT.'/theme/dolibarr_logo.svg" width="80px"></a></div>';
1070 }
1071 print '</div>';
1072} elseif ($creditor && !$ws) {
1073 print '<div class="backgreypublicpayment">';
1074 print '<div class="logopublicpayment">';
1075 print $creditor;
1076 print '</div>';
1077 print '</div>';
1078}
1079if (getDolGlobalString('MAIN_IMAGE_PUBLIC_PAYMENT')) {
1080 print '<div class="backimagepublicpayment">';
1081 print '<img id="idMAIN_IMAGE_PUBLIC_PAYMENT" src="'.getDolGlobalString('MAIN_IMAGE_PUBLIC_PAYMENT').'">';
1082 print '</div>';
1083}
1084
1085
1086
1087
1088print '<!-- Form to send a payment -->'."\n";
1089print '<!-- creditor = '.dol_escape_htmltag((string) $creditor).' -->'."\n";
1090// Additional information for each payment system
1091if (isModEnabled('paypal')) {
1092 print '<!-- PAYPAL_API_SANDBOX = '.getDolGlobalString('PAYPAL_API_SANDBOX').' -->'."\n";
1093 print '<!-- PAYPAL_API_INTEGRAL_OR_PAYPALONLY = '.getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY').' -->'."\n";
1094}
1095if (isModEnabled('paybox')) {
1096 print '<!-- PAYBOX_CGI_URL = '.getDolGlobalString('PAYBOX_CGI_URL_V2').' -->'."\n";
1097}
1098if (isModEnabled('stripe')) {
1099 print '<!-- STRIPE_LIVE = '.getDolGlobalString('STRIPE_LIVE').' -->'."\n";
1100 print '<!-- STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION = '.getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION').' -->'."\n";
1101}
1102print '<!-- urlok = '.$urlok.' -->'."\n";
1103print '<!-- urlko = '.$urlko.' -->'."\n";
1104print "\n";
1105
1106// Section with payment informationsummary
1107print '<table id="dolpublictable" summary="Payment form" class="center">'."\n";
1108
1109// Output introduction text
1110$text = '';
1111if (getDolGlobalString('PAYMENT_NEWFORM_TEXT')) {
1112 $langs->load("members");
1113 $reg = array();
1114 if (preg_match('/^\‍((.*)\‍)$/', getDolGlobalString('PAYMENT_NEWFORM_TEXT'), $reg)) {
1115 $text .= $langs->trans($reg[1])."<br>\n";
1116 } else {
1117 $text .= getDolGlobalString('PAYMENT_NEWFORM_TEXT') . "<br>\n";
1118 }
1119 $text = '<tr><td class="center"><br>'.$text.'<br></td></tr>'."\n";
1120}
1121if (empty($text)) {
1122 $text .= '<tr><td class="textpublicpayment"><br><strong>'.$langs->trans("WelcomeOnPaymentPage").'</strong></td></tr>'."\n";
1123 $text .= '<tr><td class="textpublicpayment"><span class="opacitymedium">'.$langs->trans("ThisScreenAllowsYouToPay", (string) $creditor).'</span><br><br></td></tr>'."\n";
1124}
1125print $text;
1126
1127// Output payment summary form
1128print '<tr><td align="center">'; // class=center does not have the payment button centered so we keep align here.
1129print '<table class="centpercent left" id="tablepublicpayment">';
1130print '<tr class="hideonsmartphone"><td colspan="2" class="opacitymedium">'.$langs->trans("ThisIsInformationOnPayment").'...<br><br></td></tr>'."\n";
1131
1132$found = false;
1133$error = 0;
1134
1135$object = null;
1136$tag = null;
1137$fulltag = null;
1138
1139
1140// Free payment
1141if (!$source) {
1142 dol_syslog("newpayment.php no source", LOG_DEBUG);
1143
1144 $found = true;
1145 $tag = GETPOST("tag", 'alpha');
1146 if (GETPOST('fulltag', 'alpha')) {
1147 $fulltag = GETPOST('fulltag', 'alpha');
1148 } else {
1149 $fulltag = "TAG=".$tag;
1150 }
1151
1152 // Creditor
1153 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
1154 print '</td><td class="CTableRow2">';
1155 print img_picto('', 'company', 'class="pictofixedwidth"');
1156 print '<b>'.$creditor.'</b>';
1157 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1158 print '</td></tr>'."\n";
1159
1160 // Amount
1161 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
1162 if (empty($amount)) {
1163 print ' ('.$langs->trans("ToComplete").')';
1164 }
1165 print '</td><td class="CTableRow2">';
1166 if (empty($amount) || !is_numeric($amount)) {
1167 print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1168 print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1169 // Currency
1170 print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1171 } else {
1172 print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
1173 print '<input type="hidden" name="amount" value="'.$amount.'">';
1174 print '<input type="hidden" name="newamount" value="'.$amount.'">';
1175 }
1176 print '<input type="hidden" name="currency" value="'.$currency.'">';
1177 print '</td></tr>'."\n";
1178
1179 // Tag
1180 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
1181 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
1182 print '<input type="hidden" name="tag" value="'.$tag.'">';
1183 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1184 print '</td></tr>'."\n";
1185
1186 // We do not add fields shipToName, shipToStreet, shipToCity, shipToState, shipToCountryCode, shipToZip, shipToStreet2, phoneNum
1187 // as they don't exists (buyer is unknown, tag is free).
1188}
1189
1190
1191// Payment on a Sale Order
1192if ($source == 'order') {
1193 dol_syslog("newpayment.php source=order", LOG_DEBUG);
1194
1195 $found = true;
1196 $langs->load("orders");
1197
1198 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
1199
1200 $order = new Commande($db);
1201 $result = $order->fetch(0, $ref);
1202 if ($result <= 0) {
1203 $mesg = $order->error;
1204 $error++;
1205 } else {
1206 $result = $order->fetch_thirdparty($order->socid);
1207 }
1208 $object = $order;
1209
1210 if ($action != 'dopayment') { // Do not change amount if we just click on first dopayment
1211 $amount = $order->total_ttc;
1212 if (GETPOST("amount", 'alpha')) {
1213 $amount = GETPOST("amount", 'alpha');
1214 }
1215 $amount = price2num($amount);
1216 }
1217
1218 $tag = '';
1219 if (GETPOST('fulltag', 'alpha')) {
1220 $fulltag = GETPOST('fulltag', 'alpha');
1221 } else {
1222 $fulltag = 'ORD='.$order->id.'.CUS='.$order->thirdparty->id;
1223 if (!empty($TAG)) {
1224 $tag = $TAG;
1225 $fulltag .= '.TAG='.$TAG;
1226 }
1227 }
1228 $fulltag = dol_string_unaccent($fulltag);
1229
1230 // Creditor
1231 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
1232 print '</td><td class="CTableRow2"';
1233 print ' title="'.dolPrintHTMLForAttribute($langs->transnoentitiesnoconv("Country").'='.$mysoc->country_code.' - '.$langs->transnoentitiesnoconv("VATIntra").'='.$mysoc->tva_intra).'"';
1234 print '>';
1235 print img_picto('', 'company', 'class="pictofixedwidth"');
1236 print '<b>'.$creditor.'</b>';
1237 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1238 print '</td></tr>'."\n";
1239
1240 // Debitor
1241 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("ThirdParty");
1242 print '</td><td class="CTableRow2"';
1243 print ' title="'.dolPrintHTMLForAttribute($langs->transnoentitiesnoconv("Country").'='.$order->thirdparty->country_code.' - '.$langs->transnoentitiesnoconv("VATIntra").'='.$order->thirdparty->tva_intra).'"';
1244 print '>';
1245 print img_picto('', 'company', 'class="pictofixedwidth"');
1246 print '<b>'.$order->thirdparty->name.'</b>';
1247 print '</td></tr>'."\n";
1248
1249 // Object
1250 $text = '<b>'.$langs->trans("PaymentOrderRef", $order->ref).'</b>';
1251 if (GETPOST('desc', 'alpha')) {
1252 $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1253 }
1254 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
1255 print '</td><td class="CTableRow2">'.$text;
1256 print '<input type="hidden" name="s" value="'.dol_escape_htmltag($source).'">';
1257 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($order->ref).'">';
1258 print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag((string) $order->id).'">';
1259 $directdownloadlink = $order->getLastMainDocLink('commande');
1260 if ($directdownloadlink) {
1261 print '<br><a href="'.$directdownloadlink.'" rel="nofollow noopener">';
1262 print img_mime($order->last_main_doc, '');
1263 print $langs->trans("DownloadDocument").'</a>';
1264 }
1265 print '</td></tr>'."\n";
1266
1267 // Amount
1268 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
1269 if (empty($amount)) {
1270 print ' ('.$langs->trans("ToComplete").')';
1271 }
1272 print '</td><td class="CTableRow2">';
1273 if (empty($amount) || !is_numeric($amount)) {
1274 print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1275 print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1276 // Currency
1277 print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1278 } else {
1279 print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
1280 print '<input type="hidden" name="amount" value="'.$amount.'">';
1281 print '<input type="hidden" name="newamount" value="'.$amount.'">';
1282 }
1283 print '<input type="hidden" name="currency" value="'.$currency.'">';
1284 print '</td></tr>'."\n";
1285
1286 // Tag
1287 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
1288 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
1289 print '<input type="hidden" name="tag" value="'.dol_escape_htmltag($tag).'">';
1290 print '<input type="hidden" name="fulltag" value="'.dol_escape_htmltag($fulltag).'">';
1291 print '</td></tr>'."\n";
1292
1293 // Shipping address
1294 $shipToName = $order->thirdparty->name;
1295 $shipToStreet = $order->thirdparty->address;
1296 $shipToCity = $order->thirdparty->town;
1297 $shipToState = $order->thirdparty->state_code;
1298 $shipToCountryCode = $order->thirdparty->country_code;
1299 $shipToZip = $order->thirdparty->zip;
1300 $shipToStreet2 = '';
1301 $phoneNum = $order->thirdparty->phone;
1302 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
1303 print '<input type="hidden" name="shipToName" value="'.dol_escape_htmltag($shipToName).'">'."\n";
1304 print '<input type="hidden" name="shipToStreet" value="'.dol_escape_htmltag($shipToStreet).'">'."\n";
1305 print '<input type="hidden" name="shipToCity" value="'.dol_escape_htmltag($shipToCity).'">'."\n";
1306 print '<input type="hidden" name="shipToState" value="'.dol_escape_htmltag($shipToState).'">'."\n";
1307 print '<input type="hidden" name="shipToCountryCode" value="'.dol_escape_htmltag($shipToCountryCode).'">'."\n";
1308 print '<input type="hidden" name="shipToZip" value="'.dol_escape_htmltag($shipToZip).'">'."\n";
1309 print '<input type="hidden" name="shipToStreet2" value="'.dol_escape_htmltag($shipToStreet2).'">'."\n";
1310 print '<input type="hidden" name="phoneNum" value="'.dol_escape_htmltag($phoneNum).'">'."\n";
1311 } else {
1312 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1313 }
1314 if (is_object($order->thirdparty)) {
1315 print '<input type="hidden" name="thirdparty_id" value="'.$order->thirdparty->id.'">'."\n";
1316 }
1317 print '<input type="hidden" name="email" value="'.$order->thirdparty->email.'">'."\n";
1318 print '<input type="hidden" name="vatnumber" value="'.dol_escape_htmltag($order->thirdparty->tva_intra).'">'."\n";
1319 $labeldesc = $langs->trans("Order").' '.$order->ref;
1320 if (GETPOST('desc', 'alpha')) {
1321 $labeldesc = GETPOST('desc', 'alpha');
1322 }
1323 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1324}
1325
1326
1327// Payment on a Customer Invoice
1328if ($source == 'invoice') {
1329 dol_syslog("newpayment.php source=invoice", LOG_DEBUG);
1330
1331 $found = true;
1332 $langs->load("bills");
1333 $form->load_cache_types_paiements();
1334
1335 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
1336
1337 $invoice = new Facture($db);
1338 $result = $invoice->fetch(0, $ref);
1339 if ($result <= 0) {
1340 $mesg = $invoice->error;
1341 $error++;
1342 } else {
1343 $result = $invoice->fetch_thirdparty($invoice->socid);
1344 }
1345 $object = $invoice;
1346
1347 if ($action != 'dopayment') { // Do not change amount if we just click on first dopayment
1348 $amount = price2num($invoice->total_ttc - ($invoice->getSommePaiement() + $invoice->getSumCreditNotesUsed() + $invoice->getSumDepositsUsed()));
1349 if (GETPOST("amount", 'alpha')) {
1350 $amount = GETPOST("amount", 'alpha');
1351 }
1352 $amount = price2num($amount);
1353 }
1354
1355 if (GETPOST('fulltag', 'alpha')) {
1356 $fulltag = GETPOST('fulltag', 'alpha');
1357 } else {
1358 $fulltag = 'INV='.$invoice->id.'.CUS='.$invoice->thirdparty->id;
1359 if (!empty($TAG)) {
1360 $tag = $TAG;
1361 $fulltag .= '.TAG='.$TAG;
1362 }
1363 }
1364 $fulltag = dol_string_unaccent($fulltag);
1365
1366 // Creditor (seller)
1367 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
1368 print '</td><td class="CTableRow2"';
1369 print ' title="'.dolPrintHTMLForAttribute($langs->transnoentitiesnoconv("Country").'='.$mysoc->country_code.' - '.$langs->transnoentitiesnoconv("VATIntra").'='.$mysoc->tva_intra).'"';
1370 print '>';
1371 print img_picto('', 'company', 'class="pictofixedwidth"');
1372 print '<b>'.$creditor.'</b>';
1373 print '<input type="hidden" name="creditor" value="'.dol_escape_htmltag((string) $creditor).'">';
1374 print '</td></tr>'."\n";
1375
1376 // Debitor (buyer)
1377 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("ThirdParty");
1378 print '</td><td class="CTableRow2"';
1379 print ' title="'.dolPrintHTMLForAttribute($langs->transnoentitiesnoconv("Country").'='.$invoice->thirdparty->country_code.' - '.$langs->transnoentitiesnoconv("VATIntra").'='.$invoice->thirdparty->tva_intra).'"';
1380 print '>';
1381 print img_picto('', 'company', 'class="pictofixedwidth"');
1382 print '<b>'.$invoice->thirdparty->name.'</b>';
1383 print '</td></tr>'."\n";
1384
1385 // Object
1386 $text = '<b>'.$langs->trans("PaymentInvoiceRef", $invoice->ref).'</b>';
1387 if (GETPOST('desc', 'alpha')) {
1388 $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1389 }
1390 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
1391 print '</td><td class="CTableRow2">'.$text;
1392 print '<input type="hidden" name="s" value="'.dol_escape_htmltag($source).'">';
1393 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($invoice->ref).'">';
1394 print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag((string) $invoice->id).'">';
1395 $directdownloadlink = $invoice->getLastMainDocLink('facture');
1396 if ($directdownloadlink) {
1397 print '<br><a href="'.$directdownloadlink.'">';
1398 print img_mime($invoice->last_main_doc, '');
1399 print $langs->trans("DownloadDocument").'</a>';
1400 }
1401 print '</td></tr>'."\n";
1402
1403 // Amount
1404 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentAmount");
1405 if (empty($amount) && empty($object->paye)) {
1406 print ' ('.$langs->trans("ToComplete").')';
1407 }
1408 print '</td><td class="CTableRow2">';
1409 if ($object->type == $object::TYPE_CREDIT_NOTE) {
1410 print '<b>'.$langs->trans("CreditNote").'</b>';
1411 } elseif (empty($object->paye)) {
1412 if (empty($amount) || !is_numeric($amount)) {
1413 print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1414 print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1415 print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1416 } else {
1417 print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
1418 print '<input type="hidden" name="amount" value="'.$amount.'">';
1419 print '<input type="hidden" name="newamount" value="'.$amount.'">';
1420 }
1421 } else {
1422 print '<b class="amount">'.price($object->total_ttc, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
1423 }
1424 print '<input type="hidden" name="currency" value="'.$currency.'">';
1425 print '</td></tr>'."\n";
1426
1427 // Tag
1428 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
1429 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
1430 print '<input type="hidden" name="tag" value="'.(empty($tag) ? '' : $tag).'">';
1431 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1432 print '</td></tr>'."\n";
1433
1434 // Add a warning if we try to pay an invoice set to be paid in credit transfer
1435 if ($invoice->status == $invoice::STATUS_VALIDATED && $invoice->mode_reglement_id > 0 && $form->cache_types_paiements[$invoice->mode_reglement_id]["code"] == "VIR") {
1436 print '<tr class="CTableRow2 center"><td class="CTableRow2" colspan="2">';
1437 print '<div class="warning maxwidth1000">';
1438 print $langs->trans("PayOfBankTransferInvoice");
1439 print '</div>';
1440 print '</td></tr>'."\n";
1441 }
1442
1443 // Shipping address
1444 $shipToName = $invoice->thirdparty->name;
1445 $shipToStreet = $invoice->thirdparty->address;
1446 $shipToCity = $invoice->thirdparty->town;
1447 $shipToState = $invoice->thirdparty->state_code;
1448 $shipToCountryCode = $invoice->thirdparty->country_code;
1449 $shipToZip = $invoice->thirdparty->zip;
1450 $shipToStreet2 = '';
1451 $phoneNum = $invoice->thirdparty->phone;
1452 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
1453 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1454 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1455 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1456 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1457 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1458 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1459 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1460 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1461 } else {
1462 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1463 }
1464 if (is_object($invoice->thirdparty)) {
1465 print '<input type="hidden" name="thirdparty_id" value="'.$invoice->thirdparty->id.'">'."\n";
1466 }
1467 print '<input type="hidden" name="email" value="'.$invoice->thirdparty->email.'">'."\n";
1468 print '<input type="hidden" name="vatnumber" value="'.$invoice->thirdparty->tva_intra.'">'."\n";
1469 $labeldesc = $langs->trans("Invoice").' '.$invoice->ref;
1470 if (GETPOST('desc', 'alpha')) {
1471 $labeldesc = GETPOST('desc', 'alpha');
1472 }
1473 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1474}
1475
1476// Payment on a Contract line
1477if ($source == 'contractline') {
1478 dol_syslog("newpayment.php source=contractline", LOG_DEBUG);
1479
1480 $found = true;
1481 $langs->load("contracts");
1482
1483 require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
1484
1485 $contract = new Contrat($db);
1486 $contractline = new ContratLigne($db);
1487
1488 $result = $contractline->fetch(0, $ref);
1489 if ($result <= 0) {
1490 $mesg = $contractline->error;
1491 $error++;
1492 } else {
1493 if ($contractline->fk_contrat > 0) {
1494 $result = $contract->fetch($contractline->fk_contrat);
1495 if ($result > 0) {
1496 $result = $contract->fetch_thirdparty($contract->socid);
1497 } else {
1498 $mesg = $contract->error;
1499 $error++;
1500 }
1501 } else {
1502 $mesg = 'ErrorRecordNotFound';
1503 $error++;
1504 }
1505 }
1506 $object = $contractline;
1507
1508 if ($action != 'dopayment') { // Do not change amount if we just click on first dopayment
1509 $amount = $contractline->total_ttc;
1510
1511 if ($contractline->fk_product && getDolGlobalString('PAYMENT_USE_NEW_PRICE_FOR_CONTRACTLINES')) {
1512 $product = new Product($db);
1513 $result = $product->fetch($contractline->fk_product);
1514
1515 // We define price for product (TODO Put this in a method in product class)
1516 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
1517 $pu_ht = $product->multiprices[$contract->thirdparty->price_level];
1518 $pu_ttc = $product->multiprices_ttc[$contract->thirdparty->price_level];
1519 $price_base_type = $product->multiprices_base_type[$contract->thirdparty->price_level];
1520 } else {
1521 $pu_ht = $product->price;
1522 $pu_ttc = $product->price_ttc;
1523 $price_base_type = $product->price_base_type;
1524 }
1525
1526 $amount = $pu_ttc;
1527 if (empty($amount)) {
1528 dol_print_error(null, 'ErrorNoPriceDefinedForThisProduct');
1529 exit;
1530 }
1531 }
1532
1533 if (GETPOST("amount", 'alpha')) {
1534 $amount = GETPOST("amount", 'alpha');
1535 }
1536 $amount = price2num($amount);
1537 }
1538
1539 if (GETPOST('fulltag', 'alpha')) {
1540 $fulltag = GETPOST('fulltag', 'alpha');
1541 } else {
1542 $fulltag = 'COL='.$contractline->id.'.CON='.$contract->id.'.CUS='.$contract->thirdparty->id.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1543 if (!empty($TAG)) {
1544 $tag = $TAG;
1545 $fulltag .= '.TAG='.$TAG;
1546 }
1547 }
1548 $fulltag = dol_string_unaccent($fulltag);
1549
1550 $qty = 1;
1551 if (GETPOST('qty')) {
1552 $qty = price2num(GETPOST('qty', 'alpha'), 'MS');
1553 }
1554
1555 // Creditor
1556 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
1557 print '</td><td class="CTableRow2"><b>'.$creditor.'</b>';
1558 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1559 print '</td></tr>'."\n";
1560
1561 // Debitor
1562 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("ThirdParty");
1563 print '</td><td class="CTableRow2"><b>'.$contract->thirdparty->name.'</b>';
1564 print '</td></tr>'."\n";
1565
1566 // Object
1567 $text = '<b>'.$langs->trans("PaymentRenewContractId", $contract->ref, $contractline->ref).'</b>';
1568 if ($contractline->fk_product > 0) {
1569 $contractline->fetch_product();
1570 $text .= '<br>'.$contractline->product->ref.($contractline->product->label ? ' - '.$contractline->product->label : '');
1571 }
1572 if ($contractline->description) {
1573 $text .= '<br>'.dol_htmlentitiesbr($contractline->description);
1574 }
1575 if ($contractline->date_end) {
1576 $text .= '<br>'.$langs->trans("ExpiredSince").': '.dol_print_date($contractline->date_end);
1577 }
1578 if (GETPOST('desc', 'alpha')) {
1579 $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1580 }
1581 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
1582 print '</td><td class="CTableRow2">'.$text;
1583 print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
1584 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($contractline->ref).'">';
1585 print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag((string) $contractline->id).'">';
1586 $directdownloadlink = $contract->getLastMainDocLink('contract');
1587 if ($directdownloadlink) {
1588 print '<br><a href="'.$directdownloadlink.'">';
1589 print img_mime($contract->last_main_doc, '');
1590 print $langs->trans("DownloadDocument").'</a>';
1591 }
1592 print '</td></tr>'."\n";
1593
1594 // Quantity
1595 $label = $langs->trans("Quantity");
1596 $qty = 1;
1597 $duration = '';
1598 if ($contractline->fk_product) {
1599 if ($contractline->product->isService() && $contractline->product->duration_value > 0) {
1600 $label = $langs->trans("Duration");
1601
1602 // TODO Put this in a global method
1603 if ($contractline->product->duration_value > 1) {
1604 $dur = array("h" => $langs->trans("Hours"), "d" => $langs->trans("DurationDays"), "w" => $langs->trans("DurationWeeks"), "m" => $langs->trans("DurationMonths"), "y" => $langs->trans("DurationYears"));
1605 } else {
1606 $dur = array("h" => $langs->trans("Hour"), "d" => $langs->trans("DurationDay"), "w" => $langs->trans("DurationWeek"), "m" => $langs->trans("DurationMonth"), "y" => $langs->trans("DurationYear"));
1607 }
1608 $duration = $contractline->product->duration_value.' '.$dur[$contractline->product->duration_unit];
1609 }
1610 }
1611 print '<tr class="CTableRow2"><td class="CTableRow2">'.$label.'</td>';
1612 print '<td class="CTableRow2"><b>'.($duration ? $duration : $qty).'</b>';
1613 print '<input type="hidden" name="newqty" value="'.dol_escape_htmltag((string) $qty).'">';
1614 print '</b></td></tr>'."\n";
1615
1616 // Amount
1617 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
1618 if (empty($amount)) {
1619 print ' ('.$langs->trans("ToComplete").')';
1620 }
1621 print '</td><td class="CTableRow2">';
1622 if (empty($amount) || !is_numeric($amount)) {
1623 print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1624 print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1625 // Currency
1626 print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1627 } else {
1628 print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
1629 print '<input type="hidden" name="amount" value="'.$amount.'">';
1630 print '<input type="hidden" name="newamount" value="'.$amount.'">';
1631 }
1632 print '<input type="hidden" name="currency" value="'.$currency.'">';
1633 print '</td></tr>'."\n";
1634
1635 // Tag
1636 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
1637 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
1638 print '<input type="hidden" name="tag" value="'.$tag.'">';
1639 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1640 print '</td></tr>'."\n";
1641
1642 // Shipping address
1643 $shipToName = $contract->thirdparty->name;
1644 $shipToStreet = $contract->thirdparty->address;
1645 $shipToCity = $contract->thirdparty->town;
1646 $shipToState = $contract->thirdparty->state_code;
1647 $shipToCountryCode = $contract->thirdparty->country_code;
1648 $shipToZip = $contract->thirdparty->zip;
1649 $shipToStreet2 = '';
1650 $phoneNum = $contract->thirdparty->phone;
1651 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
1652 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1653 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1654 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1655 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1656 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1657 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1658 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1659 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1660 } else {
1661 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1662 }
1663 if (is_object($contract->thirdparty)) {
1664 print '<input type="hidden" name="thirdparty_id" value="'.$contract->thirdparty->id.'">'."\n";
1665 }
1666 print '<input type="hidden" name="email" value="'.$contract->thirdparty->email.'">'."\n";
1667 print '<input type="hidden" name="vatnumber" value="'.$contract->thirdparty->tva_intra.'">'."\n";
1668 $labeldesc = $langs->trans("Contract").' '.$contract->ref;
1669 if (GETPOST('desc', 'alpha')) {
1670 $labeldesc = GETPOST('desc', 'alpha');
1671 }
1672 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1673}
1674
1675// Payment on a Member subscription
1676if ($source == 'member' || $source == 'membersubscription') {
1677 dol_syslog("newpayment.php source=".$source, LOG_DEBUG);
1678
1679 $newsource = 'member';
1680
1681 $tag = "";
1682 $found = true;
1683 $langs->load("members");
1684
1685 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1686 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php';
1687 require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
1688
1689 $member = new Adherent($db);
1690 $adht = new AdherentType($db);
1691
1692 $result = $member->fetch(0, $ref, 0, '', true, true); // This fetch also ->last_subscription_amount
1693 if ($result <= 0) {
1694 $mesg = $member->error;
1695 $error++;
1696 } else {
1697 $member->fetch_thirdparty();
1698
1699 $adht->fetch($member->typeid);
1700 }
1701 $object = $member;
1702
1703 if ($action != 'dopayment') { // Do not change amount if we just click on first dopayment
1704 $amount = $member->last_subscription_amount;
1705 if (GETPOST("amount", 'alpha')) {
1706 $amount = price2num(GETPOST("amount", 'alpha'), 'MT', 2);
1707 }
1708 // If amount still not defined, we take amount of the type of member
1709 if (empty($amount)) {
1710 $amount = $adht->amount;
1711 }
1712
1713 $amount = max(0, price2num($amount, 'MT'));
1714 }
1715
1716 if (GETPOST('fulltag', 'alpha')) {
1717 $fulltag = GETPOST('fulltag', 'alpha');
1718 } else {
1719 $fulltag = 'MEM='.$member->id.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1720 if (!empty($TAG)) {
1721 $tag = $TAG;
1722 $fulltag .= '.TAG='.$TAG;
1723 }
1724 }
1725 $fulltag = dol_string_unaccent($fulltag);
1726
1727 // Creditor
1728 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
1729 print '</td><td class="CTableRow2"><b>'.$creditor.'</b>';
1730 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1731 print '</td></tr>'."\n";
1732
1733 // Debitor
1734 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Member");
1735 print '</td><td class="CTableRow2">';
1736 print '<b>';
1737 if ($member->morphy == 'mor' && !empty($member->company)) {
1738 print img_picto('', 'company', 'class="pictofixedwidth"');
1739 print $member->company;
1740 } else {
1741 print img_picto('', 'member', 'class="pictofixedwidth"');
1742 print $member->getFullName($langs);
1743 }
1744 print '</b>';
1745 print '</td></tr>'."\n";
1746
1747 // Object
1748 $text = '<b>'.$langs->trans("PaymentSubscription").'</b>';
1749 if (GETPOST('desc', 'alpha')) {
1750 $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1751 }
1752 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
1753 print '</td><td class="CTableRow2">'.$text;
1754 print '<input type="hidden" name="source" value="'.dol_escape_htmltag($newsource).'">';
1755 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($member->ref).'">';
1756 print '</td></tr>'."\n";
1757
1758 if ($object->datefin > 0) {
1759 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("DateEndSubscription");
1760 print '</td><td class="CTableRow2">'.dol_print_date($member->datefin, 'day');
1761 print '</td></tr>'."\n";
1762 }
1763
1764 if ($member->last_subscription_date || $member->last_subscription_amount) {
1765 // Last subscription date
1766
1767 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("LastSubscriptionDate");
1768 print '</td><td class="CTableRow2">'.dol_print_date($member->last_subscription_date, 'day');
1769 print '</td></tr>'."\n";
1770
1771 // Last subscription amount
1772
1773 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("LastSubscriptionAmount");
1774 print '</td><td class="CTableRow2">'.price($member->last_subscription_amount);
1775 print '</td></tr>'."\n";
1776
1777 if (empty($amount) && !GETPOST('newamount', 'alpha')) {
1778 $_GET['newamount'] = $member->last_subscription_amount;
1779 $_GET['amount'] = $member->last_subscription_amount;
1780 }
1781 if (!empty($member->last_subscription_amount) && !GETPOSTISSET('newamount') && is_numeric($amount)) {
1782 $amount = max($member->last_subscription_amount, $amount);
1783 }
1784 }
1785
1786 $amountbytype = $adht->amountByType(1);
1787
1788 $typeid = $adht->id;
1789 $caneditamount = $adht->caneditamount;
1790
1791 if ($member->type) {
1792 $oldtypeid = $member->typeid;
1793 $newtypeid = (int) (GETPOSTISSET("typeid") ? GETPOSTINT("typeid") : $member->typeid);
1794 if (getDolGlobalString('MEMBER_ALLOW_CHANGE_OF_TYPE')) {
1795 $typeid = $newtypeid;
1796 $adht->fetch($typeid); // Reload with the new type id
1797 }
1798
1799 $caneditamount = $adht->caneditamount;
1800
1801 if (getDolGlobalString('MEMBER_ALLOW_CHANGE_OF_TYPE')) {
1802 // Last member type
1803 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("LastMemberType");
1804 print '</td><td class="CTableRow2">'.dol_escape_htmltag($member->type);
1805 print "</td></tr>\n";
1806
1807 // Set the new member type
1808 $member->typeid = $newtypeid;
1809 $member->type = (string) dol_getIdFromCode($db, $newtypeid, 'adherent_type', 'rowid', 'libelle');
1810
1811 // list member type
1812 if (!$action) {
1813 // Set amount for the subscription.
1814 // If we change the type, we use the amount of the new type and not the amount of last subscription.
1815 $amount = (!empty($amountbytype[$member->typeid])) ? $amountbytype[$member->typeid] : $member->last_subscription_amount;
1816
1817 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("NewSubscription");
1818 print '</td><td class="CTableRow2">';
1819 print $form->selectarray("typeid", $adht->liste_array(1), $member->typeid, 0, 0, 0, 'onchange="window.location.replace(\''.$urlwithroot.'/public/payment/newpayment.php?source='.urlencode($source).'&ref='.urlencode($ref).'&amount='.urlencode($amount).'&typeid=\' + this.value + \'&securekey='.urlencode($SECUREKEY).'\');"', 0, 0, 0, '', '', 1);
1820 print "</td></tr>\n";
1821 } elseif ($action == 'dopayment') {
1822 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("NewMemberType");
1823 print '</td><td class="CTableRow2">'.dol_escape_htmltag($member->type);
1824 print '<input type="hidden" name="membertypeid" value="'.$member->typeid.'">';
1825 print "</td></tr>\n";
1826 }
1827 } else {
1828 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("MemberType");
1829 print '</td><td class="CTableRow2">'.dol_escape_htmltag($member->type);
1830 print "</td></tr>\n";
1831 }
1832 }
1833
1834
1835 // Add hook to complete the form
1836 $parameters = array('mode' => 'renewal');
1837 $reshook = $hookmanager->executeHooks('membershipNewSubscriptionPublicForm', $parameters, $object, $action);
1838 if ($reshook < 0) {
1839 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1840 $error++;
1841 }
1842
1843 // TODO Move this into previous hook
1844 if (getDolGlobalString('MEMBER_NEWFORM_DOLIBARRTURNOVER') && $action != 'dopayment') {
1845 $country_id = 0;
1846 if ($member->thirdparty instanceOf Societe) {
1847 $country_id = $member->thirdparty->country_id;
1848 }
1849 $checkednature = $member->morphy;
1850 print '<input type="hidden" name="moralinput" id="moralinput" value="'.$checkednature.'">';
1851
1852 // Is it a Preferred Partner
1853 $pp = 0;
1854 include_once DOL_DOCUMENT_ROOT.'/partnership/class/partnership.class.php';
1855 $partnership = new Partnership($db);
1856 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
1857 $result = $partnership->fetch(0, null, null, $member->thirdparty->id);
1858 if ($result > 0) {
1859 $pp = 1;
1860 }
1861
1862 // Do not set a default amount MEMBER_NEWFORM_AMOUNT if you use MEMBER_NEWFORM_DOLIBARRTURNOVER
1863 $s = $langs->trans("AreYouAPreferredPartner", '<a href="https://partners.dolibarr.org" target="_blank">{s1}</a>');
1864 $s = str_replace('{s1}', 'Preferred Partner', $s);
1865 print '<tr id="trbudget" class="trcompany"><td><label for="pp" class="small">'.$s.'</label></td><td>';
1866 print '<input type="checkbox" name="pp" id="pp" value="1"'.((GETPOST('reload') ? GETPOST('pp') : $pp) ? ' checked="checked"' : '').' class="reposition">';
1867 print '</td></tr>';
1868
1869 print '<tr id="trbudget" class="trcompany"><td class=""><span class="small">'.$langs->trans("TurnoverOrBudget").'</span></td><td>';
1870
1871 $country_code = dol_getIdFromCode($db, $country_id, 'c_country', 'rowid', 'code');
1872 if ($country_code === 'FR' && $checkednature === 'mor' && (GETPOST('reload') ? GETPOST('pp') : $pp)) {
1873 print '<input type="text" name="budget" id="budget" class="flat turnover right width100" value="'.GETPOST('budget').'"'.($action != 'dopayment' ? ' required autofocus' : '').'>';
1874 } else {
1875 $arraybudget = array('50' => '<= 100 000', '100' => '<= 200 000', '200' => '<= 500 000', '300' => '<= 1 500 000', '600' => '<= 3 000 000', '1000' => '<= 5 000 000', '2000' => '5 000 000+');
1876 print $form->selectarray('budget', $arraybudget, GETPOSTINT('budget'), 1, 0, 0, ($checkednature === 'mor' ? 'required' :''), 0, 0, 0, '');
1877 }
1878 print ' € or $';
1879
1880 print '<script type="text/javascript">
1881 jQuery(document).ready(function() {
1882 firstload = true;
1883
1884 newamount = initturnover();
1885 jQuery("#amount").val(newamount);
1886 jQuery("#newamount").val(newamount);
1887
1888 firstload = false;
1889
1890 jQuery("#selectcountry_id").change(function() {
1891 console.log("We change country (code added for association, replace common code), so we reload page");
1892 jQuery("#budget").val(\'\');
1893 jQuery("#amount").val(\'\');
1894 jQuery("#newamount").val(\'\');
1895 jQuery("#amounthidden").val(\'\');
1896 });
1897 jQuery("#pp").change(function() {
1898 console.log("We change the preferred partner status");
1899 selectcountry_id = jQuery("#selectcountry_id").val();
1900 morphy = jQuery("#moralinput").is(\':checked\') ? \'mor\' : \'phy\';
1901 jQuery("#budget").val(\'\');
1902 jQuery("#amount").val(\'\');
1903 jQuery("#amounthidden").val(\'\');
1904 jQuery("#newamount").val(\'\');
1905 jQuery("#reload").val(\'1\');
1906 document.paymentform.action.value="";
1907 jQuery("#dolpaymentform").submit();
1908 });
1909 jQuery("#budget").change(function() {
1910 console.log("Turnover amount has been modified on change");
1911 newamount = initturnover();
1912 jQuery("#amount").val(newamount);
1913 jQuery("#amounthidden").val(newamount);
1914 jQuery("#newamount").val(newamount);
1915 });
1916 jQuery("#budget").keyup(function() {
1917 console.log("Turnover amount has been modified on keyup");
1918 newamount = initturnover();
1919 jQuery("#amount").val(newamount);
1920 jQuery("#amounthidden").val(newamount);
1921 jQuery("#newamount").val(newamount);
1922 });
1923
1924 function initturnover() {
1925 newamount = 0;
1926
1927 //morphy = jQuery("#moralinput").is(\':checked\') ? \'mor\' : \'phy\';
1928 morphy = jQuery("#moralinput").val();
1929 selectcountry_id = '.((int) $country_id).';
1930 pp = jQuery("#pp").is(\':checked\') ? true : false;
1931 console.log("Set fields according to nature and other properties");
1932 console.log("morphy="+morphy);
1933 console.log("selectcountry_id="+selectcountry_id);
1934 console.log("pp="+pp);
1935
1936 if (morphy == \'phy\') {
1937 jQuery(".amount").val('.((float) $amount).');
1938 jQuery("#trbirth").show();
1939 jQuery(".trcompany").hide();
1940 jQuery(".trbudget").hide();
1941 newamount = '.((float) $amount).';
1942 } else {
1943 jQuery(".amount").val(\'\');
1944 jQuery("#trbirth").hide();
1945 jQuery(".trcompany").show();
1946 jQuery(".trbudget").show();
1947 jQuery(".hideifautoturnover").hide();
1948 if (firstload) {
1949 jQuery("#budget").val(\'\');
1950 }
1951
1952 if (selectcountry_id == 1) {
1953 if (jQuery("#budget").val() == \'\') {
1954 return null;
1955 }
1956 if (pp) {
1957 console.log("value selected in input text field is "+jQuery("#budget").val());
1958 newamount = Math.max(Math.round(price2numjs(jQuery("#budget").val()) * 0.005), 50);
1959 console.log("newamount = "+newamount);
1960 } else {
1961 console.log("not a pp");
1962 if (jQuery("#budget").val() > 0) {
1963 console.log("value found in budget is "+jQuery("#budget").val());
1964 newamount = jQuery("#budget").val();
1965 } else {
1966 jQuery("#budget").val(\'\');
1967 newamount = \'\';
1968 }
1969 }
1970 } else {
1971 if (jQuery("#budget").val() > 0) {
1972 newamount = jQuery("#budget").val();
1973 } else {
1974 jQuery("#budget").val(\'\');
1975 newamount = \'\';
1976 }
1977 }
1978 }
1979
1980 return newamount;
1981 }
1982 });
1983 </script>';
1984 print '</td></tr>'."\n";
1985 }
1986
1987
1988 // Set amount for the subscription from the the type and options:
1989 // - First check the amount of the member type if there is no previous payment.
1990 $amount = ($member->last_subscription_amount ? $member->last_subscription_amount : (empty($amountbytype[$typeid]) ? 0 : $amountbytype[$typeid]));
1991 // - If not found, take the default amount
1992 if (empty($amount) && getDolGlobalString('MEMBER_NEWFORM_AMOUNT')) {
1993 $amount = getDolGlobalString('MEMBER_NEWFORM_AMOUNT');
1994 }
1995
1996 // - If an amount was posted from the form (for example from page with types of membership)
1997 if ($caneditamount && !GETPOST('reload') && GETPOSTISSET('amount') && GETPOSTFLOAT('amount', 'MT') > 0) {
1998 $amount = GETPOSTFLOAT('amount', 'MT');
1999 }
2000 // - If a new amount was posted from the form
2001 if ($caneditamount && !GETPOST('reload') && GETPOSTISSET('newamount') && GETPOSTFLOAT('newamount', 'MT') > 0) {
2002 $amount = GETPOSTFLOAT('newamount', 'MT');
2003 }
2004 // - If a min is set or an amount from the posted form, we take them into account
2005 $amount = max(0, (float) $amount, (float) getDolGlobalInt("MEMBER_MIN_AMOUNT"));
2006
2007 // Amount
2008 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
2009 // This place no longer allows amount edition
2010 if (getDolGlobalString('MEMBER_EXT_URL_SUBSCRIPTION_INFO')) {
2011 print ' - <a href="' . getDolGlobalString('MEMBER_EXT_URL_SUBSCRIPTION_INFO').'" rel="external" target="_blank" rel="noopener noreferrer">'.img_picto('', 'url', 'class="pictofixedwidth"').$langs->trans("SeeHere").'</a>';
2012 }
2013 print '</td><td class="CTableRow2">';
2014
2015 $caneditamount = $adht->caneditamount;
2016 $minimumamount = !getDolGlobalString('MEMBER_MIN_AMOUNT') ? $adht->amount : max(getDolGlobalString('MEMBER_MIN_AMOUNT'), $adht->amount, $amount);
2017
2018 if ($caneditamount && ($action != 'dopayment' || GETPOST('reload'))) {
2019 if (GETPOSTISSET('newamount')) {
2020 print '<input type="text" class="width75 amount" name="newamount" id="newamount" value="'.price(price2num(GETPOST('newamount'), '', 2), 1, $langs, 1, -1, -1).'">';
2021 } else {
2022 print '<input type="text" class="width75 amount" name="newamount" id="newamount" value="'.price($amount, 1, $langs, 1, -1, -1).'">';
2023 }
2024 } else {
2025 print '<b class="amount">'.price($amount, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
2026 if ($minimumamount > $amount) {
2027 print ' &nbsp; <span class="opacitymedium small">'. $langs->trans("AmountIsLowerToMinimumNotice", price($minimumamount, 1, $langs, 1, -1, -1, $currency)).'</span>';
2028 }
2029 print '<input type="hidden" name="newamount" value="'.$amount.'">';
2030 }
2031 print '<input type="hidden" name="amount" value="'.$amount.'">';
2032 print '<input type="hidden" name="currency" value="'.$currency.'">';
2033 print '</td></tr>'."\n";
2034
2035 // Tag
2036 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
2037 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
2038 print '<input type="hidden" name="tag" value="'.$tag.'">';
2039 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
2040 print '</td></tr>'."\n";
2041
2042 // Shipping address
2043 $shipToName = $member->getFullName($langs);
2044 $shipToStreet = $member->address;
2045 $shipToCity = $member->town;
2046 $shipToState = $member->state_code;
2047 $shipToCountryCode = $member->country_code;
2048 $shipToZip = $member->zip;
2049 $shipToStreet2 = '';
2050 $phoneNum = $member->phone;
2051 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
2052 print '<!-- Shipping address information -->';
2053 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
2054 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
2055 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
2056 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
2057 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
2058 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
2059 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
2060 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
2061 } else {
2062 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
2063 }
2064 if (is_object($member->thirdparty)) {
2065 print '<input type="hidden" name="thirdparty_id" value="'.$member->thirdparty->id.'">'."\n";
2066 }
2067 print '<input type="hidden" name="email" value="'.$member->email.'">'."\n";
2068 $labeldesc = $langs->trans("PaymentSubscription");
2069 if (GETPOST('desc', 'alpha')) {
2070 $labeldesc = GETPOST('desc', 'alpha');
2071 }
2072 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
2073}
2074
2075// Payment on donation
2076if ($source == 'donation') {
2077 dol_syslog("newpayment.php source=donation", LOG_DEBUG);
2078
2079 $found = true;
2080 $langs->load("don");
2081
2082 require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
2083
2084 $don = new Don($db);
2085 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2086 $result = $don->fetch((int) $ref);
2087 if ($result <= 0) {
2088 $mesg = $don->error;
2089 $error++;
2090 } else {
2091 $don->fetch_thirdparty();
2092 }
2093 $object = $don;
2094
2095 if ($action != 'dopayment') { // Do not change amount if we just click on first dopayment
2096 if (GETPOST("amount", 'alpha')) {
2097 $amount = GETPOST("amount", 'alpha');
2098 } else {
2099 $amount = $don->getRemainToPay();
2100 }
2101 $amount = price2num($amount);
2102 }
2103
2104 if (GETPOST('fulltag', 'alpha')) {
2105 $fulltag = GETPOST('fulltag', 'alpha');
2106 } else {
2107 $fulltag = 'DON='.$don->ref.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
2108 if (!empty($TAG)) {
2109 $tag = $TAG;
2110 $fulltag .= '.TAG='.$TAG;
2111 }
2112 }
2113 $fulltag = dol_string_unaccent($fulltag);
2114
2115 // Creditor
2116 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
2117 print '</td><td class="CTableRow2"><b>'.$creditor.'</b>';
2118 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
2119 print '</td></tr>'."\n";
2120
2121 // Debitor
2122 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("ThirdParty");
2123 print '</td><td class="CTableRow2"><b>';
2124 if (!empty($don->societe)) {
2125 print $don->societe;
2126 } else {
2127 print $don->getFullName($langs);
2128 }
2129 print '</b>';
2130 print '</td></tr>'."\n";
2131
2132 // Object
2133 $text = '<b>'.$langs->trans("PaymentDonation").'</b>';
2134 if (GETPOST('desc', 'alpha')) {
2135 $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
2136 }
2137 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
2138 print '</td><td class="CTableRow2">'.$text;
2139 print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
2140 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($don->ref).'">';
2141 print '</td></tr>'."\n";
2142
2143 // Amount
2144 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
2145 if (empty($amount)) {
2146 if (!getDolGlobalString('DONATION_NEWFORM_AMOUNT')) {
2147 print ' ('.$langs->trans("ToComplete");
2148 }
2149 if (getDolGlobalString('DONATION_EXT_URL_SUBSCRIPTION_INFO')) {
2150 print ' - <a href="' . getDolGlobalString('DONATION_EXT_URL_SUBSCRIPTION_INFO').'" rel="external" target="_blank" rel="noopener noreferrer">'.$langs->trans("SeeHere").'</a>';
2151 }
2152 if (!getDolGlobalString('DONATION_NEWFORM_AMOUNT')) {
2153 print ')';
2154 }
2155 }
2156 print '</td><td class="CTableRow2">';
2157 $valtoshow = '';
2158 if (empty($amount) || !is_numeric($amount)) {
2159 $valtoshow = price2num(GETPOST("newamount", 'alpha'), 'MT');
2160 // force default subscription amount to value defined into constant...
2161 if (empty($valtoshow)) {
2162 if (getDolGlobalString('DONATION_NEWFORM_EDITAMOUNT')) {
2163 if (getDolGlobalString('DONATION_NEWFORM_AMOUNT')) {
2164 $valtoshow = getDolGlobalString('DONATION_NEWFORM_AMOUNT');
2165 }
2166 } else {
2167 if (getDolGlobalString('DONATION_NEWFORM_AMOUNT')) {
2168 $amount = getDolGlobalString('DONATION_NEWFORM_AMOUNT');
2169 }
2170 }
2171 }
2172 }
2173 if (empty($amount) || !is_numeric($amount)) {
2174 //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT');
2175 if (getDolGlobalString('DONATION_MIN_AMOUNT') && $valtoshow) {
2176 $valtoshow = max(getDolGlobalString('DONATION_MIN_AMOUNT'), $valtoshow);
2177 }
2178 print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
2179 print '<input class="flat maxwidth75" type="text" name="newamount" value="'.$valtoshow.'">';
2180 // Currency
2181 print ' <b>'.$langs->trans("Currency".$currency).'</b>';
2182 } else {
2183 $valtoshow = $amount;
2184 if (getDolGlobalString('DONATION_MIN_AMOUNT') && $valtoshow) {
2185 $valtoshow = max(getDolGlobalString('DONATION_MIN_AMOUNT'), $valtoshow);
2186 $amount = $valtoshow;
2187 }
2188 print '<b class="amount">'.price($valtoshow, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
2189 print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
2190 print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
2191 }
2192 print '<input type="hidden" name="currency" value="'.$currency.'">';
2193 print '</td></tr>'."\n";
2194
2195 // Tag
2196 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
2197 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
2198 print '<input type="hidden" name="tag" value="'.$tag.'">';
2199 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
2200 print '</td></tr>'."\n";
2201
2202 // Shipping address
2203 $shipToName = $don->getFullName($langs);
2204 $shipToStreet = $don->address;
2205 $shipToCity = $don->town;
2206 $shipToState = $don->state_code;
2207 $shipToCountryCode = $don->country_code;
2208 $shipToZip = $don->zip;
2209 $shipToStreet2 = '';
2210 $phoneNum = $don->phone;
2211 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
2212 print '<!-- Shipping address information -->';
2213 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
2214 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
2215 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
2216 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
2217 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
2218 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
2219 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
2220 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
2221 } else {
2222 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
2223 }
2224 if (is_object($don->thirdparty)) {
2225 print '<input type="hidden" name="thirdparty_id" value="'.$don->thirdparty->id.'">'."\n";
2226 }
2227 print '<input type="hidden" name="email" value="'.$don->email.'">'."\n";
2228 $labeldesc = $langs->trans("PaymentSubscription");
2229 if (GETPOST('desc', 'alpha')) {
2230 $labeldesc = GETPOST('desc', 'alpha');
2231 }
2232 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
2233}
2234
2235if ($source == 'organizedeventregistration' && is_object($thirdparty)) {
2236 dol_syslog("newpayment.php source=organizedeventregistration", LOG_DEBUG);
2237
2238 $found = true;
2239 $langs->loadLangs(array("members", "eventorganization"));
2240
2241 if (GETPOST('fulltag', 'alpha')) {
2242 $fulltag = GETPOST('fulltag', 'alpha');
2243 } else {
2244 $fulltag = 'ATT='.$attendee->id.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
2245 if (!empty($TAG)) {
2246 $tag = $TAG;
2247 $fulltag .= '.TAG='.$TAG;
2248 }
2249 }
2250 $fulltag = dol_string_unaccent($fulltag);
2251
2252 // Creditor
2253 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
2254 print '</td><td class="CTableRow2"><b>'.$creditor.'</b>';
2255 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
2256 print '</td></tr>'."\n";
2257
2258 // Debitor
2259 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Attendee");
2260 print '</td><td class="CTableRow2"><b>';
2261 print $attendee->email;
2262 print($thirdparty->name ? ' ('.$thirdparty->name.')' : '');
2263 print '</b>';
2264 print '</td></tr>'."\n";
2265
2266 if (! is_object($attendee->project)) {
2267 $text = 'ErrorProjectNotFound';
2268 } else {
2269 $text = $langs->trans("PaymentEvent").' - '.$attendee->project->title;
2270 }
2271
2272 // Object
2273 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
2274 print '</td><td class="CTableRow2"><b>'.$text.'</b>';
2275 print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
2276 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag((string) $invoice->id).'">';
2277 print '</td></tr>'."\n";
2278
2279 // Amount
2280 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
2281 print '</td><td class="CTableRow2">';
2282 $valtoshow = $amount;
2283 print '<b class="amount">'.price($valtoshow, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
2284 print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
2285 print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
2286 print '<input type="hidden" name="currency" value="'.$currency.'">';
2287 print '</td></tr>'."\n";
2288
2289 // Tag
2290 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
2291 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
2292 print '<input type="hidden" name="tag" value="'.$tag.'">';
2293 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
2294 print '</td></tr>'."\n";
2295
2296 // Shipping address
2297 $shipToName = $thirdparty->getFullName($langs);
2298 $shipToStreet = $thirdparty->address;
2299 $shipToCity = $thirdparty->town;
2300 $shipToState = $thirdparty->state_code;
2301 $shipToCountryCode = $thirdparty->country_code;
2302 $shipToZip = $thirdparty->zip;
2303 $shipToStreet2 = '';
2304 $phoneNum = $thirdparty->phone;
2305 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
2306 print '<!-- Shipping address information -->';
2307 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
2308 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
2309 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
2310 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
2311 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
2312 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
2313 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
2314 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
2315 } else {
2316 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
2317 }
2318 print '<input type="hidden" name="thirdparty_id" value="'.$thirdparty->id.'">'."\n";
2319 print '<input type="hidden" name="email" value="'.$thirdparty->email.'">'."\n";
2320 $labeldesc = $langs->trans("PaymentSubscription");
2321 if (GETPOST('desc', 'alpha')) {
2322 $labeldesc = GETPOST('desc', 'alpha');
2323 }
2324 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
2325}
2326
2327if ($source == 'boothlocation') {
2328 dol_syslog("newpayment.php source=boothlocation", LOG_DEBUG);
2329
2330 $found = true;
2331 $langs->load("members");
2332
2333 if (GETPOST('fulltag', 'alpha')) {
2334 $fulltag = GETPOST('fulltag', 'alpha');
2335 } else {
2336 $fulltag = 'BOO='.GETPOST("booth").'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
2337 if (!empty($TAG)) {
2338 $tag = $TAG;
2339 $fulltag .= '.TAG='.$TAG;
2340 }
2341 }
2342 $fulltag = dol_string_unaccent($fulltag);
2343
2344 // Creditor
2345 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Creditor");
2346 print '</td><td class="CTableRow2"><b>'.$creditor.'</b>';
2347 print '<input type="hidden" name="creditor" value="'.$creditor.'">';
2348 print '</td></tr>'."\n";
2349
2350 // Debitor
2351 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Attendee");
2352 print '</td><td class="CTableRow2"><b>';
2353 print $thirdparty->name;
2354 print '</b>';
2355 print '</td></tr>'."\n";
2356
2357 // Object
2358 $text = '<b>'.$langs->trans("PaymentBoothLocation").'</b>';
2359 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Designation");
2360 print '</td><td class="CTableRow2">'.$text;
2361 print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
2362 print '<input type="hidden" name="ref" value="'.dol_escape_htmltag((string) $invoice->id).'">';
2363 print '</td></tr>'."\n";
2364
2365 // Amount
2366 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("Amount");
2367 print '</td><td class="CTableRow2">';
2368 $valtoshow = $amount;
2369 print '<b class="amount">'.price($valtoshow, 1, $langs, 1, -1, -1, $currency).'</b>'; // Price with currency
2370 print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
2371 print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
2372 print '<input type="hidden" name="currency" value="'.$currency.'">';
2373 print '</td></tr>'."\n";
2374
2375 // Tag
2376 print '<tr class="CTableRow2"><td class="CTableRow2">'.$langs->trans("PaymentCode");
2377 print '</td><td class="CTableRow2"><b style="word-break: break-all;">'.$fulltag.'</b>';
2378 print '<input type="hidden" name="tag" value="'.$tag.'">';
2379 print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
2380 print '</td></tr>'."\n";
2381
2382 // Shipping address
2383 $shipToName = $thirdparty->getFullName($langs);
2384 $shipToStreet = $thirdparty->address;
2385 $shipToCity = $thirdparty->town;
2386 $shipToState = $thirdparty->state_code;
2387 $shipToCountryCode = $thirdparty->country_code;
2388 $shipToZip = $thirdparty->zip;
2389 $shipToStreet2 = '';
2390 $phoneNum = $thirdparty->phone;
2391 if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip) {
2392 print '<!-- Shipping address information -->';
2393 print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
2394 print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
2395 print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
2396 print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
2397 print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
2398 print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
2399 print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
2400 print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
2401 } else {
2402 print '<!-- Shipping address not complete, so we don t use it -->'."\n";
2403 }
2404 print '<input type="hidden" name="thirdparty_id" value="'.$thirdparty->id.'">'."\n";
2405 print '<input type="hidden" name="email" value="'.$thirdparty->email.'">'."\n";
2406 $labeldesc = $langs->trans("PaymentSubscription");
2407 if (GETPOST('desc', 'alpha')) {
2408 $labeldesc = GETPOST('desc', 'alpha');
2409 }
2410 print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
2411}
2412
2413if (!$found && !$mesg) {
2414 $mesg = $langs->trans("ErrorBadParameters");
2415}
2416
2417if ($mesg) {
2418 print '<tr><td align="center" colspan="2"><br><div class="warning">'.dol_escape_htmltag($mesg, 1, 1, 'br').'</div></td></tr>'."\n";
2419}
2420
2421print '</table>'."\n";
2422print "\n";
2423
2424
2425// Show all payment mode buttons (Stripe, Paypal, ...)
2426if ($action != 'dopayment') {
2427 dol_syslog("newpayment.php action is not dopayment so we show all payment modes", LOG_DEBUG);
2428
2429 if ($found && !$error) { // We are in a management option and no error
2430 // Check status of the object (Invoice) to verify if it is paid by external payment modules (ie Payzen, ...)
2431 $parameters = [
2432 'source' => $source,
2433 'object' => $object
2434 ];
2435 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
2436 $reshook = $hookmanager->executeHooks('doCheckStatus', $parameters, $object, $action);
2437 if ($reshook < 0) {
2438 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2439 } elseif ($reshook > 0) {
2440 print $hookmanager->resPrint;
2441 }
2442
2443 if ($source == 'order' && $object->billed) {
2444 print '<br><br><div class="amountpaymentcomplete size12x wrapimp">'.$langs->trans("OrderBilled").'</div>';
2445 } elseif ($source == 'invoice' && $object->paye) {
2446 print '<br><br><div class="amountpaymentcomplete size12x wrapimp">'.$langs->trans("InvoicePaid").'</div>';
2447 } elseif ($source == 'invoice' && $object->status == Facture::STATUS_ABANDONED && ($object->close_code == Facture::CLOSECODE_REPLACED || getDolGlobalString('INVOICE_ONLINE_PAYMENT_REFUSED_WHATEVER_IS_ABANDON_REASON'))) {
2448 // Only refuse the payment when the invoice was closed because it has been replaced: the amount is
2449 // then claimed by the replacement invoice and paying this link would pay it twice. An invoice
2450 // abandoned for any other reason, a bad debt for instance, keeps its link usable, since a customer
2451 // paying it anyway is a good outcome.
2452 // INVOICE_ONLINE_PAYMENT_REFUSED_WHATEVER_IS_ABANDON_REASON extends the refusal to every
2453 // abandoned invoice, for jurisdictions where collecting is no longer allowed once a
2454 // receivable has been written off or sent to collections (#39327).
2455 print '<br><br><div class="amountpaymentcomplete size12x wrapimp">'.$langs->trans("Abandoned").'</div>';
2456 } elseif ($source == 'donation' && $object->paid) {
2457 print '<br><br><div class="amountpaymentcomplete size12x wrapimp">'.$langs->trans("DonationPaid").'</div>';
2458 } else {
2459 // Membership can be paid and we still allow to make renewal
2460 if (($source == 'member' || $source == 'membersubscription') && $object->datefin > dol_now()) {
2461 $langs->load("members");
2462 print '<br><div class="amountpaymentcomplete size12x wrapimp">';
2463 $s = $langs->trans("MembershipPaid", '{s1}');
2464 print str_replace('{s1}', '<span class="nobold">'.dol_print_date($object->datefin, 'day').'</span>', $s);
2465 print '</div>';
2466 print '<div class="opacitymedium margintoponly">'.$langs->trans("PaymentWillBeRecordedForNextPeriod").'</div>';
2467 print '<br>';
2468 }
2469
2470 // Buttons for all payments registration methods
2471
2472 // This hook is used to add Button to newpayment.php for external payment modules (ie Payzen, ...)
2473 $parameters = [
2474 'paymentmethod' => $paymentmethod
2475 ];
2476 $reshook = $hookmanager->executeHooks('doAddButton', $parameters, $object, $action);
2477 if ($reshook < 0) {
2478 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2479 } elseif ($reshook >= 0) {
2480 print $hookmanager->resPrint;
2481 }
2482
2483 if ((empty($paymentmethod) || $paymentmethod == 'paybox') && isModEnabled('paybox')) {
2484 print '<div class="button buttonpayment" id="div_dopayment_paybox"><span class="fa fa-credit-card"></span> <input class="" type="submit" id="dopayment_paybox" name="dopayment_paybox" value="'.$langs->trans("PayBoxDoPayment").'">';
2485 print '<br>';
2486 print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span>';
2487 print '</div>';
2488 print '<script>
2489 $( document ).ready(function() {
2490 $("#div_dopayment_paybox").click(function(){
2491 $("#dopayment_paybox").click();
2492 });
2493 $("#dopayment_paybox").click(function(e){
2494 $("#div_dopayment_paybox").css( \'cursor\', \'wait\' );
2495 e.stopPropagation();
2496 });
2497 });
2498 </script>
2499 ';
2500 }
2501
2502 if ((empty($paymentmethod) || $paymentmethod == 'stripe') && isModEnabled('stripe')) {
2503 $showbutton = 1;
2504 if (getDolGlobalString(strtoupper($source).'_FORCE_DISABLE_STRIPE')) { // Example: MEMBER_FORCE_DISABLE_STRIPE
2505 $showbutton = 0;
2506 }
2507
2508 if ($showbutton) {
2509 // By default noidempotency is set to 1, to avoid the error "Keys for idempotant requests...". It means we can pay several times the same tag/ref.
2510 // If STRIPE_USE_IDEMPOTENCY_BY_DEFAULT is set or param noidempotency=0 is added, then with add an idempotent key, so we must use a different tag/ref for each payment (if not we will get an error).
2511 $noidempotency_key = (GETPOSTISSET('noidempotency') ? GETPOSTINT('noidempotency') : (getDolGlobalInt('STRIPE_USE_IDEMPOTENCY_BY_DEFAULT') ? 0 : 1));
2512
2513 print '<div class="button buttonpayment" id="div_dopayment_stripe">';
2514 print '<span class="fa fa-credit-card"></span> ';
2515 print '<input class="" type="submit" id="dopayment_stripe" name="dopayment_stripe" value="'.$langs->trans("StripeDoPayment").'">';
2516 print '<input type="hidden" name="noidempotency" value="'.$noidempotency_key.'">';
2517 print '<br>';
2518 print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span>';
2519 print '</div>';
2520 print '<script>
2521 $( document ).ready(function() {
2522 $("#div_dopayment_stripe").click(function(){
2523 $("#dopayment_stripe").click();
2524 });
2525 $("#dopayment_stripe").click(function(e){
2526 $("#div_dopayment_stripe").css( \'cursor\', \'wait\' );
2527 e.stopPropagation();
2528 return true;
2529 });
2530 });
2531 </script>
2532 ';
2533 }
2534 }
2535
2536 if ((empty($paymentmethod) || $paymentmethod == 'paypal') && isModEnabled('paypal')) {
2537 if (!getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY')) {
2538 $conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY = 'integral';
2539 }
2540
2541 $showbutton = 1;
2542 if (getDolGlobalString(strtoupper($source).'_FORCE_DISABLE_PAYPAL')) { // Example: MEMBER_FORCE_DISABLE_PAYPAL
2543 $showbutton = 0;
2544 }
2545
2546 if ($showbutton) {
2547 print '<div class="button buttonpayment" id="div_dopayment_paypal">';
2548 if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') != 'integral') {
2549 print '<div style="line-height: 1em">&nbsp;</div>';
2550 }
2551 print '<span class="fab fa-paypal"></span> <input class="" type="submit" id="dopayment_paypal" name="dopayment_paypal" value="'.$langs->trans("PaypalDoPayment").'">';
2552 if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') == 'integral') {
2553 print '<br>';
2554 print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span><span class="buttonpaymentsmall"> - </span>';
2555 print '<span class="buttonpaymentsmall">'.$langs->trans("PayPalBalance").'</span>';
2556 }
2557 //if (getDolGlobalString('PAYPAL_API_INTEGRAL_OR_PAYPALONLY') == 'paypalonly') {
2558 //print '<br>';
2559 //print '<span class="buttonpaymentsmall">'.$langs->trans("PayPalBalance").'"></span>';
2560 //}
2561 print '</div>';
2562 print '<script>
2563 $( document ).ready(function() {
2564 $("#div_dopayment_paypal").click(function(){
2565 $("#dopayment_paypal").click();
2566 });
2567 $("#dopayment_paypal").click(function(e){
2568 $("#div_dopayment_paypal").css( \'cursor\', \'wait\' );
2569 e.stopPropagation();
2570 return true;
2571 });
2572 });
2573 </script>
2574 ';
2575 }
2576 }
2577 }
2578 } else {
2579 dol_print_error_email('ERRORNEWPAYMENT');
2580 }
2581} else {
2582 // Print
2583}
2584
2585print '</td></tr>'."\n";
2586
2587print '</table>'."\n";
2588
2589print '</form>'."\n";
2590print '</div>'."\n";
2591
2592print '<br>';
2593
2594
2595
2596// Add more content on page for some services
2597if (preg_match('/^dopayment/', $action)) { // If we choose/clicked on the payment mode
2598 dol_syslog("newpayment.php action is dopayment... because we clicked on a payment mode - amount = ".$amount);
2599
2600 // Save some data for the paymentok
2601 $remoteip = getUserRemoteIP();
2602 $_SESSION["currencyCodeType"] = $currency;
2603 $_SESSION["FinalPaymentAmt"] = $amount;
2604 $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip
2605 $_SESSION["paymentType"] = '';
2606
2607 $stripecu = null;
2608
2609 // For Stripe
2610 if (GETPOST('dopayment_stripe', 'alpha')) {
2611 // Personalized checkout
2612 print '<style>
2617 .StripeElement {
2618 background-color: white;
2619 padding: 8px 12px;
2620 border-radius: 4px;
2621 border: 1px solid transparent;
2622 box-shadow: 0 1px 3px 0 #e6ebf1;
2623 -webkit-transition: box-shadow 150ms ease;
2624 transition: box-shadow 150ms ease;
2625 }
2626
2627 .StripeElement--focus {
2628 box-shadow: 0 1px 3px 0 #cfd7df;
2629 }
2630
2631 .StripeElement--invalid {
2632 border-color: #fa755a;
2633 }
2634
2635 .StripeElement--webkit-autofill {
2636 background-color: #fefde5 !important;
2637 }
2638 </style>';
2639
2640 //print '<br>';
2641
2642 print '<!-- Show Stripe form payment-form STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION = ' . getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION').' STRIPE_USE_NEW_CHECKOUT = ' . getDolGlobalString('STRIPE_USE_NEW_CHECKOUT').' -->'."\n";
2643 print '<form action="'.$_SERVER['REQUEST_URI'].'" method="POST" id="payment-form">'."\n";
2644
2645 print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
2646 print '<input type="hidden" name="dopayment_stripe" value="1">'."\n";
2647 print '<input type="hidden" name="action" value="charge">'."\n";
2648 print '<input type="hidden" name="tag" value="'.$TAG.'">'."\n";
2649 print '<input type="hidden" name="s" value="'.$source.'">'."\n";
2650 print '<input type="hidden" name="ref" value="'.$REF.'">'."\n";
2651 print '<input type="hidden" name="fulltag" value="'.$FULLTAG.'">'."\n";
2652 print '<input type="hidden" name="suffix" value="'.$suffix.'">'."\n";
2653 print '<input type="hidden" name="securekey" value="'.$SECUREKEY.'">'."\n";
2654 print '<input type="hidden" name="e" value="'.$entity.'" />'."\n";
2655 print '<input type="hidden" name="amount" value="'.$amount.'">'."\n";
2656 print '<input type="hidden" name="currency" value="'.$currency.'">'."\n";
2657 //print '<input type="hidden" name="forcesandbox" value="'.GETPOSTINT('forcesandbox').'" />';
2658 print '<input type="hidden" name="email" value="'.GETPOST('email', 'alpha').'" />';
2659 print '<input type="hidden" name="thirdparty_id" value="'.GETPOSTINT('thirdparty_id').'" />';
2660 print '<input type="hidden" name="lang" value="'.$getpostlang.'">';
2661
2662 // Make some check on amount: We accept an amount that is different to allow to pay an existing invoice partially or
2663 // to allow to pay a membership with open amount, but for a payment of an order, we have no reason to accept partial payment.
2664 $checkamount = 1;
2665 $tmptag = dolExplodeIntoArray($fulltag, '.', '=');
2666 if (array_key_exists('ORD', $tmptag) && (int) $tmptag['ORD'] > 0) {
2667 include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
2668 $object = new Commande($db);
2669 $result = $object->fetch((int) $tmptag['ORD']);
2670 if ($result > 0) {
2671 if ($object->total_ttc != $amount) {
2672 $checkamount = 0;
2673 }
2674 } else {
2675 $checkamount = 0;
2676 }
2677 }
2678 if (!$checkamount) {
2679 dol_syslog("Hack attempt detected", LOG_WARNING);
2680 setEventMessages('Bad value for amount. Reported as a hack attempt.', null, 'errors');
2681 }
2682
2683 if ($checkamount && (getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') || getDolGlobalString('STRIPE_USE_NEW_CHECKOUT'))) { // Use a SCA ready method
2684 require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
2685
2686 $service = 'StripeLive';
2687 $servicestatus = 1;
2688 if (!getDolGlobalString('STRIPE_LIVE')/* || GETPOST('forcesandbox', 'alpha') */) {
2689 $service = 'StripeTest';
2690 $servicestatus = 0;
2691 }
2692
2693 $stripe = new Stripe($db);
2694 $stripeacc = $stripe->getStripeAccount($service);
2695 if (is_object($object) && is_object($object->thirdparty)) {
2696 $stripecu = $stripe->customerStripe($object->thirdparty, $stripeacc, $servicestatus, 1);
2697 }
2698
2699 if (getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
2700 dol_syslog("newpayment.php Create a Paymentintent for amount=".$amount, LOG_DEBUG);
2701
2702 // By default noidempotency is set to 1, to avoid the error "Keys for idempotant requests...". It means we can pay several times the same tag/ref.
2703 // If STRIPE_USE_IDEMPOTENCY_BY_DEFAULT is set or param noidempotency=0 is added, then with add an idempotent key, so we must use a different tag/ref for each payment (if not we will get an error).
2704 $noidempotency_key = (GETPOSTISSET('noidempotency') ? GETPOSTINT('noidempotency') : (getDolGlobalInt('STRIPE_USE_IDEMPOTENCY_BY_DEFAULT') ? 0 : 1));
2705
2706 $paymentintent = $stripe->getPaymentIntent($amount, $currency, ($tag ? $tag : $fulltag), 'Stripe payment: '.$fulltag.(is_object($object) ? ' ref='.$object->ref : ''), $object, $stripecu, $stripeacc, $servicestatus, 0, 'automatic', false, null, 0, $noidempotency_key);
2707 // The paymentintnent has status 'requires_payment_method' (even if paymentintent was already paid)
2708 //var_dump($paymentintent);
2709 if ($stripe->error) {
2710 setEventMessages($stripe->error, null, 'errors');
2711 }
2712 }
2713 }
2714
2715 // Note:
2716 // $conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION = 1 = use intent object (default value, suggest card payment mode only)
2717 // $conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION = 2 = use payment object (suggest both card payment mode but also sepa, ...)
2718
2719 print '
2720 <table id="dolpaymenttable" summary="Payment form" class="center centpercent">
2721 <tbody><tr><td class="textpublicpayment">';
2722
2723 if (getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
2724 print '<div id="payment-request-button"><!-- A Stripe Element will be inserted here. --></div>';
2725 }
2726
2727 print '<div class="form-row '.(getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 2 ? 'center' : 'left').'">';
2728 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 1) {
2729 print '<label for="card-element">'.$langs->trans("CreditOrDebitCard").'</label>';
2730 print '<br><input id="cardholder-name" class="marginbottomonly" name="cardholder-name" value="" type="text" placeholder="'.$langs->trans("CardOwner").'" autocomplete="off" spellcheck="false" autofocus required>';
2731 }
2732
2733 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 1) {
2734 print '<div id="card-element">
2735 <!-- a Stripe Element will be inserted here. -->
2736 </div>';
2737 }
2738 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 2) {
2739 print '<div id="payment-element">
2740 <!-- a Stripe Element will be inserted here. -->
2741 </div>';
2742 }
2743
2744 print '<!-- Used to display form errors -->
2745 <div id="card-errors" role="alert"></div>
2746 </div>';
2747
2748 print '<br>';
2749 print '<button class="button buttonpayment" style="text-align: center; padding-left: 0; padding-right: 0;" id="buttontopay" data-secret="'.(is_object($paymentintent) ? $paymentintent->client_secret : '').'">'.$langs->trans("ValidatePayment").'</button>';
2750 print '<img id="hourglasstopay" class="hidden" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/working.gif">';
2751
2752 print '</td></tr></tbody>';
2753 print '</table>';
2754 //}
2755
2756 if (getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
2757 if (empty($paymentintent)) {
2758 print '<center>'.$langs->trans("Error").' - Failed to get PaymentIntent</center>';
2759 } else {
2760 print '<input type="hidden" name="paymentintent_id" value="'.$paymentintent->id.'">';
2761 //$_SESSION["paymentintent_id"] = $paymentintent->id;
2762 }
2763 }
2764
2765 print '</form>'."\n";
2766
2767
2768 // JS Code for Stripe
2769 if (empty($stripearrayofkeys['publishable_key'])) {
2770 $langs->load("errors");
2771 print info_admin($langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("Stripe")), 0, 0, 'error marginleftonly marginrightonly');
2772 } else {
2773 print '<!-- JS Code for Stripe components -->';
2774 print '<script src="https://js.stripe.com/v3/"></script>'."\n";
2775 print '<!-- urllogofull = '.$urllogofull.' -->'."\n";
2776
2777 // Code to ask the credit card. This use the default "API version". No way to force API version when using JS code.
2778 print '<script type="text/javascript">'."\n";
2779
2780 if (getDolGlobalString('STRIPE_USE_NEW_CHECKOUT')) {
2781 $amountstripe = $amount;
2782
2783 // Correct the amount according to unit of currency
2784 // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
2785 $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
2786 if (!in_array($currency, $arrayzerounitcurrency)) {
2787 $amountstripe *= 100;
2788 }
2789
2790 $ipaddress = getUserRemoteIP();
2791 $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress);
2792 if (is_object($object)) {
2793 $metadata['dol_type'] = $object->element;
2794 $metadata['dol_id'] = $object->id;
2795
2796 $ref = $object->ref;
2797 }
2798
2799 try {
2800 $arrayforpaymentintent = array(
2801 'description' => 'Stripe payment: '.$FULLTAG.($ref ? ' ref='.$ref : ''),
2802 "metadata" => $metadata
2803 );
2804 if ($TAG) {
2805 $arrayforpaymentintent["statement_descriptor"] = dol_trunc($TAG, 10, 'right', 'UTF-8', 1); // 22 chars that appears on bank receipt (company + description)
2806 }
2807
2808 $arrayforcheckout = array(
2809 'payment_method_types' => array('card'),
2810 'line_items' => array(array(
2811 'price_data' => array(
2812 'currency' => $currency,
2813 'unit_amount' => $amountstripe,
2814 'product_data' => array(
2815 'name' => $langs->transnoentitiesnoconv("Payment").' '.$TAG, // Label of product line
2816 'description' => 'Stripe payment: '.$FULLTAG.($ref ? ' ref='.$ref : ''),
2817 //'images' => array($urllogofull),
2818 ),
2819 ),
2820 'quantity' => 1,
2821 )),
2822 'mode' => 'payment',
2823 'client_reference_id' => $FULLTAG,
2824 'success_url' => $urlok,
2825 'cancel_url' => $urlko,
2826 'payment_intent_data' => $arrayforpaymentintent
2827 );
2828 if ($stripecu) {
2829 $arrayforcheckout['customer'] = $stripecu;
2830 } elseif (GETPOST('email', 'alpha') && isValidEmail(GETPOST('email', 'alpha'))) {
2831 $arrayforcheckout['customer_email'] = GETPOST('email', 'alpha');
2832 }
2833
2834 dol_syslog("We create a stripe session with \Stripe\Checkout\Session::create for amountstripe=".$amountstripe);
2835
2836 $sessionstripe = \Stripe\Checkout\Session::create($arrayforcheckout);
2837
2838 dol_syslog("sessionstripe=".$sessionstripe->id);
2839
2840
2841 $remoteip = getUserRemoteIP();
2842
2843 // Save some data for the paymentok
2844 $_SESSION["currencyCodeType"] = $currency;
2845 $_SESSION["paymentType"] = '';
2846 $_SESSION["FinalPaymentAmt"] = $amount;
2847 $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip
2848 $_SESSION['payerID'] = is_object($stripecu) ? $stripecu->id : '';
2849 $_SESSION['TRANSACTIONID'] = $sessionstripe->id;
2850 } catch (Exception $e) {
2851 print $e->getMessage();
2852 } ?>
2853 // Code for payment with option STRIPE_USE_NEW_CHECKOUT set
2854
2855 // Create a Stripe client.
2856 <?php
2857 if (empty($stripeacc)) {
2858 ?>
2859 var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php?>');
2860 <?php
2861 } else {
2862 ?>
2863 var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php?>', { stripeAccount: '<?php echo $stripeacc; ?>' });
2864 <?php
2865 } ?>
2866
2867 // Create an instance of Elements
2868 var elements = stripe.elements();
2869
2870 // Custom styling can be passed to options when creating an Element.
2871 // (Note that this demo uses a wider set of styles than the guide below.)
2872 var style = {
2873 base: {
2874 color: '#32325d',
2875 lineHeight: '24px',
2876 fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
2877 fontSmoothing: 'antialiased',
2878 fontSize: '16px',
2879 '::placeholder': {
2880 color: '#aab7c4'
2881 }
2882 },
2883 invalid: {
2884 color: '#fa755a',
2885 iconColor: '#fa755a'
2886 }
2887 }
2888
2889 var cardElement = elements.create('card', {style: style});
2890
2891 <?php if (!empty($sessionstripe)) { ?>
2892 // Comment this to avoid the redirect
2893 stripe.redirectToCheckout({
2894 // Make the id field from the Checkout Session creation API response
2895 // available to this file, so you can provide it as parameter here
2896 // instead of the {{CHECKOUT_SESSION_ID}} placeholder.
2897 sessionId: '<?php print $sessionstripe->id; ?>'
2898 }).then(function (result) {
2899 // If `redirectToCheckout` fails due to a browser or network
2900 // error, display the localized error message to your customer
2901 // using `result.error.message`.
2902 });
2903 <?php } else { ?>
2904 // $sessionstripe was not created (Stripe API call failed, see the error message printed above)
2905 console.error('Failed to create Stripe Checkout Session');
2906 <?php } ?>
2907
2908
2909 <?php
2910 } elseif (getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) { // default value is 1
2911 ?>
2912 // Code for payment with option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION set to 1 or 2
2913
2914 // Create a Stripe client.
2915 <?php
2916 if (empty($stripeacc)) {
2917 ?>
2918 var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php?>');
2919 <?php
2920 } else {
2921 ?>
2922 var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php?>', { stripeAccount: '<?php echo $stripeacc; ?>' });
2923 <?php
2924 } ?>
2925
2926 <?php
2927 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 2) { // default is 1
2928 ?>
2929 var cardButton = document.getElementById('buttontopay');
2930 var clientSecret = cardButton.dataset.secret;
2931 var options = { clientSecret: clientSecret };
2932
2933 // Create an instance of Elements
2934 var elements = stripe.elements(options);
2935 <?php
2936 } else {
2937 ?>
2938 // Create an instance of Elements
2939 var elements = stripe.elements();
2940 <?php
2941 } ?>
2942
2943 // Custom styling can be passed to options when creating an Element.
2944 // (Note that this demo uses a wider set of styles than the guide below.)
2945 var style = {
2946 base: {
2947 color: '#32325d',
2948 lineHeight: '24px',
2949 fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
2950 fontSmoothing: 'antialiased',
2951 fontSize: '16px',
2952 '::placeholder': {
2953 color: '#aab7c4'
2954 }
2955 },
2956 invalid: {
2957 color: '#fa755a',
2958 iconColor: '#fa755a'
2959 }
2960 }
2961
2962 <?php
2963 if (getDolGlobalInt('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION') == 2) { // Default is 1.
2964 ?>
2965 var paymentElement = elements.create("payment");
2966
2967 // Add an instance of the card Element into the div #payment-element
2968 paymentElement.mount("#payment-element");
2969
2970 // Handle form submission
2971 var cardButton = document.getElementById('buttontopay');
2972
2973 cardButton.addEventListener('click', function(event) {
2974 console.log("We click on buttontopay");
2975 event.preventDefault();
2976
2977 /* Disable button to pay and show hourglass cursor */
2978 jQuery('#hourglasstopay').show();
2979 jQuery('#buttontopay').hide();
2980
2981 stripe.confirmPayment({
2982 elements,confirmParams: {
2983 return_url: '<?php echo $urlok; ?>',
2984 payment_method_data: {
2985 billing_details: {
2986 name: 'test'
2987 <?php if (GETPOST('email', 'alpha') || (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->email))) {
2988 ?>, email: '<?php echo dol_escape_js(GETPOST('email', 'alpha') ? GETPOST('email', 'alpha') : $object->thirdparty->email); ?>'<?php
2989 } ?>
2990 <?php if (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->phone)) {
2991 ?>, phone: '<?php echo dol_escape_js($object->thirdparty->phone); ?>'<?php
2992 } ?>
2993 <?php if (is_object($object) && is_object($object->thirdparty)) {
2994 ?>, address: {
2995 city: '<?php echo dol_escape_js($object->thirdparty->town); ?>',
2996 <?php if ($object->thirdparty->country_code) {
2997 ?>country: '<?php echo dol_escape_js($object->thirdparty->country_code); ?>',<?php
2998 } ?>
2999 line1: '<?php echo dol_escape_js(preg_replace('/\s\s+/', ' ', $object->thirdparty->address)); ?>',
3000 postal_code: '<?php echo dol_escape_js($object->thirdparty->zip); ?>'
3001 }
3002 <?php
3003 } ?>
3004 }
3005 },
3006 save_payment_method:<?php if ($stripecu) {
3007 print 'true';
3008 } else {
3009 print 'false';
3010 } ?> /* true when a customer was provided when creating payment intent. true ask to save the card */
3011 },
3012 }
3013 ).then(function(result) {
3014 console.log(result);
3015 if (result.error) {
3016 console.log("Error on result of handleCardPayment");
3017 jQuery('#buttontopay').show();
3018 jQuery('#hourglasstopay').hide();
3019 // Inform the user if there was an error
3020 var errorElement = document.getElementById('card-errors');
3021 console.log(result);
3022 errorElement.textContent = result.error.message;
3023 } else {
3024 // The payment has succeeded. Display a success message.
3025 console.log("No error on result of handleCardPayment, so we submit the form");
3026 // Submit the form
3027 jQuery('#buttontopay').hide();
3028 jQuery('#hourglasstopay').show();
3029 // Send form (action=charge that will do nothing)
3030 jQuery('#payment-form').submit();
3031 }
3032 });
3033
3034 });
3035 <?php
3036 } else {
3037 ?>
3038 var cardElement = elements.create('card', {style: style});
3039
3040 // Add an instance of the card Element into the div #card-element
3041 cardElement.mount('#card-element');
3042
3043 // Handle real-time validation errors from the card Element.
3044 cardElement.addEventListener('change', function(event) {
3045 var displayError = document.getElementById('card-errors');
3046 if (event.error) {
3047 console.log("Show event error (like 'Incorrect card number', ...)");
3048 displayError.textContent = event.error.message;
3049 } else {
3050 console.log("Reset error message");
3051 displayError.textContent = '';
3052 }
3053 });
3054
3055 // Handle form submission
3056 var cardholderName = document.getElementById('cardholder-name');
3057 var cardButton = document.getElementById('buttontopay');
3058 var clientSecret = cardButton.dataset.secret;
3059
3060 cardButton.addEventListener('click', function(event) {
3061 console.log("We click on buttontopay");
3062 event.preventDefault();
3063
3064 if (cardholderName.value == '')
3065 {
3066 console.log("Field Card holder is empty");
3067 var displayError = document.getElementById('card-errors');
3068 displayError.textContent = '<?php print dol_escape_js($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CardOwner"))); ?>';
3069 }
3070 else
3071 {
3072 /* Disable button to pay and show hourglass cursor */
3073 jQuery('#hourglasstopay').show();
3074 jQuery('#buttontopay').hide();
3075
3076 stripe.handleCardPayment(
3077 clientSecret, cardElement, {
3078 payment_method_data: {
3079 billing_details: {
3080 name: cardholderName.value
3081 <?php if (GETPOST('email', 'alpha') || (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->email))) {
3082 ?>, email: '<?php echo dol_escape_js(GETPOST('email', 'alpha') ? GETPOST('email', 'alpha') : $object->thirdparty->email); ?>'<?php
3083 } ?>
3084 <?php if (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->phone)) {
3085 ?>, phone: '<?php echo dol_escape_js($object->thirdparty->phone); ?>'<?php
3086 } ?>
3087 <?php if (is_object($object) && is_object($object->thirdparty)) {
3088 ?>, address: {
3089 city: '<?php echo dol_escape_js($object->thirdparty->town); ?>',
3090 <?php if ($object->thirdparty->country_code) {
3091 ?>country: '<?php echo dol_escape_js($object->thirdparty->country_code); ?>',<?php
3092 } ?>
3093 line1: '<?php echo dol_escape_js(preg_replace('/\s\s+/', ' ', $object->thirdparty->address)); ?>',
3094 postal_code: '<?php echo dol_escape_js($object->thirdparty->zip); ?>'
3095 }
3096 <?php
3097 } ?>
3098 }
3099 },
3100 save_payment_method:<?php if ($stripecu) {
3101 print 'true';
3102 } else {
3103 print 'false';
3104 } ?> /* true when a customer was provided when creating payment intent. true ask to save the card */
3105 }
3106 ).then(function(result) {
3107 console.log(result);
3108 if (result.error) {
3109 console.log("Error on result of handleCardPayment");
3110 jQuery('#buttontopay').show();
3111 jQuery('#hourglasstopay').hide();
3112 // Inform the user if there was an error
3113 var errorElement = document.getElementById('card-errors');
3114 errorElement.textContent = result.error.message;
3115 } else {
3116 // The payment has succeeded. Display a success message.
3117 console.log("No error on result of handleCardPayment, so we submit the form");
3118 // Submit the form
3119 jQuery('#buttontopay').hide();
3120 jQuery('#hourglasstopay').show();
3121 // Send form (action=charge that will do nothing)
3122 jQuery('#payment-form').submit();
3123 }
3124 });
3125 }
3126 });
3127 <?php
3128 } ?>
3129
3130 <?php
3131 }
3132
3133 print '</script>';
3134 }
3135 }
3136
3137 // For any other payment services
3138 // This hook can be used to show the embedded form to make payments with external payment modules (ie Payzen, ...)
3139 $parameters = [
3140 'paymentmethod' => $paymentmethod,
3141 'amount' => $amount,
3142 'currency' => $currency,
3143 'tag' => GETPOST("tag", 'alpha'),
3144 'dopayment' => GETPOST('dopayment', 'alpha')
3145 ];
3146 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
3147 $reshook = $hookmanager->executeHooks('doPayment', $parameters, $object, $action);
3148 if ($reshook < 0) {
3149 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3150 } elseif ($reshook > 0) {
3151 print $hookmanager->resPrint;
3152 }
3153}
3154
3155if (!$ws) {
3156 htmlPrintOnlineFooter($mysoc, $langs, 1, $suffix, $object);
3157}
3158
3159llxFooter('', 'public');
3160
3161$db->close();
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
global $dolibarr_main_url_root
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
$object ref
Definition info.php:90
Class to manage members of a foundation.
Class to manage members type.
Class to manage customers orders.
Class for ConferenceOrBoothAttendee.
Class to manage lines of contracts.
Class to manage donations.
Definition don.class.php:41
Class to manage invoices.
const STATUS_ABANDONED
Classified abandoned and no payment done.
Class to manage generation of HTML components Only common components must be here.
Class to manage hooks.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
Stripe class @TODO No reason to extend CommonObject.
Class Website.
htmlPrintOnlineFooter($fromcompany, $langs, $addformmessage=0, $suffix='', $object=null)
Show footer of company in HTML public pages.
global $mysoc
dol_is_file($pathoffile)
Return if path is a file.
dol_now($mode='gmt')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dolExplodeIntoArray($string, $delimiter=';', $kv='=')
Split a string with 2 keys into key array.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_sanitizePathName($str, $newstr='_', $unaccent=0, $allowdash=0)
Clean a string to use it as a path name.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formatted messages to output (Used to show messages on html output).
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Abort invoice creation with a given error message.
print_paybox_redirect($PRICE, $CURRENCY, $EMAIL, $urlok, $urlko, $TAG)
Create a redirect form to paybox form.
print_paypal_redirect($paymentAmount, $currencyCodeType, $paymentType, $returnURL, $cancelURL, $tag)
Send redirect to paypal to browser.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:135
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...