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