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