dolibarr  13.0.2
newpayment.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001-2002 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2006-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2009-2012 Regis Houssin <regis.houssin@inodbox.com>
5  * Copyright (C) 2018 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2018-2019 Thibault FOUCART <support@ptibogxiv.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  *
21  * For Paypal test: https://developer.paypal.com/
22  * For Paybox test: ???
23  * For Stripe test: Use credit card 4242424242424242 .More example on https://stripe.com/docs/testing
24  *
25  * Variants:
26  * - When option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION is on, we use the new PaymentIntent API
27  * - When option STRIPE_USE_NEW_CHECKOUT is on, we use the new checkout API
28  * - If no option set, we use old APIS (charge)
29  */
30 
37 if (!defined('NOLOGIN')) define("NOLOGIN", 1); // This means this output page does not require to be logged.
38 if (!defined('NOCSRFCHECK')) define("NOCSRFCHECK", 1); // We accept to go on this page from external web site.
39 if (!defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
40 if (!defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1');
41 
42 // For MultiCompany module.
43 // Do not use GETPOST here, function is not defined and get of entity must be done before including main.inc.php
44 $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))));
45 if (is_numeric($entity)) define("DOLENTITY", $entity);
46 
47 require '../../main.inc.php';
48 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
49 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
50 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
51 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
52 require_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
53 // Hook to be used by external payment modules (ie Payzen, ...)
54 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
55 $hookmanager = new HookManager($db);
56 $hookmanager->initHooks(array('newpayment'));
57 
58 // Load translation files
59 $langs->loadLangs(array("main", "other", "dict", "bills", "companies", "errors", "paybox", "paypal", "stripe")); // File with generic data
60 
61 // Security check
62 // No check on module enabled. Done later according to $validpaymentmethod
63 
64 $action = GETPOST('action', 'aZ09');
65 
66 // Input are:
67 // type ('invoice','order','contractline'),
68 // id (object id),
69 // amount (required if id is empty),
70 // tag (a free text, required if type is empty)
71 // currency (iso code)
72 
73 $suffix = GETPOST("suffix", 'aZ09');
74 $amount = price2num(GETPOST("amount", 'alpha'));
75 if (!GETPOST("currency", 'alpha')) $currency = $conf->currency;
76 else $currency = GETPOST("currency", 'aZ09');
77 $source = GETPOST("s", 'aZ09') ?GETPOST("s", 'aZ09') : GETPOST("source", 'aZ09');
78 $download = GETPOST('d', 'int') ?GETPOST('d', 'int') : GETPOST('download', 'int');
79 
80 if (!$action)
81 {
82  if (!GETPOST("amount", 'alpha') && !$source)
83  {
84  print $langs->trans('ErrorBadParameters')." - amount or source";
85  exit;
86  }
87  if (is_numeric($amount) && !GETPOST("tag", 'alpha') && !$source)
88  {
89  print $langs->trans('ErrorBadParameters')." - tag or source";
90  exit;
91  }
92  if ($source && !GETPOST("ref", 'alpha'))
93  {
94  print $langs->trans('ErrorBadParameters')." - ref";
95  exit;
96  }
97 }
98 
99 
100 $paymentmethod = GETPOST('paymentmethod', 'alphanohtml') ?GETPOST('paymentmethod', 'alphanohtml') : ''; // Empty in most cases. Defined when a payment mode is forced
101 $validpaymentmethod = array();
102 
103 // Detect $paymentmethod
104 foreach ($_POST as $key => $val)
105 {
106  if (preg_match('/^dopayment_(.*)$/', $key, $reg))
107  {
108  $paymentmethod = $reg[1];
109  break;
110  }
111 }
112 
113 
114 // Define $urlwithroot
115 //$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
116 //$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
117 $urlwithroot = DOL_MAIN_URL_ROOT; // This is to use same domain name than current. For Paypal payment, we can use internal URL like localhost.
118 
119 $urlok = $urlwithroot.'/public/payment/paymentok.php?';
120 $urlko = $urlwithroot.'/public/payment/paymentko.php?';
121 
122 // Complete urls for post treatment
123 $ref = $REF = GETPOST('ref', 'alpha');
124 $TAG = GETPOST("tag", 'alpha');
125 $FULLTAG = GETPOST("fulltag", 'alpha'); // fulltag is tag with more informations
126 $SECUREKEY = GETPOST("securekey"); // Secure key
127 if ($paymentmethod && !preg_match('/'.preg_quote('PM='.$paymentmethod, '/').'/', $FULLTAG)) $FULLTAG .= ($FULLTAG ? '.' : '').'PM='.$paymentmethod;
128 
129 if (!empty($suffix))
130 {
131  $urlok .= 'suffix='.urlencode($suffix).'&';
132  $urlko .= 'suffix='.urlencode($suffix).'&';
133 }
134 if ($source)
135 {
136  $urlok .= 's='.urlencode($source).'&';
137  $urlko .= 's='.urlencode($source).'&';
138 }
139 if (!empty($REF))
140 {
141  $urlok .= 'ref='.urlencode($REF).'&';
142  $urlko .= 'ref='.urlencode($REF).'&';
143 }
144 if (!empty($TAG))
145 {
146  $urlok .= 'tag='.urlencode($TAG).'&';
147  $urlko .= 'tag='.urlencode($TAG).'&';
148 }
149 if (!empty($FULLTAG))
150 {
151  $urlok .= 'fulltag='.urlencode($FULLTAG).'&';
152  $urlko .= 'fulltag='.urlencode($FULLTAG).'&';
153 }
154 if (!empty($SECUREKEY))
155 {
156  $urlok .= 'securekey='.urlencode($SECUREKEY).'&';
157  $urlko .= 'securekey='.urlencode($SECUREKEY).'&';
158 }
159 if (!empty($entity))
160 {
161  $urlok .= 'e='.urlencode($entity).'&';
162  $urlko .= 'e='.urlencode($entity).'&';
163 }
164 $urlok = preg_replace('/&$/', '', $urlok); // Remove last &
165 $urlko = preg_replace('/&$/', '', $urlko); // Remove last &
166 
167 
168 
169 // Make special controls
170 
171 if ((empty($paymentmethod) || $paymentmethod == 'paypal') && !empty($conf->paypal->enabled))
172 {
173  require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypal.lib.php';
174  require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php';
175 
176  // Check parameters
177  $PAYPAL_API_OK = "";
178  if ($urlok) $PAYPAL_API_OK = $urlok;
179  $PAYPAL_API_KO = "";
180  if ($urlko) $PAYPAL_API_KO = $urlko;
181  if (empty($PAYPAL_API_USER))
182  {
183  dol_print_error('', "Paypal setup param PAYPAL_API_USER not defined");
184  return -1;
185  }
186  if (empty($PAYPAL_API_PASSWORD))
187  {
188  dol_print_error('', "Paypal setup param PAYPAL_API_PASSWORD not defined");
189  return -1;
190  }
191  if (empty($PAYPAL_API_SIGNATURE))
192  {
193  dol_print_error('', "Paypal setup param PAYPAL_API_SIGNATURE not defined");
194  return -1;
195  }
196 }
197 if ((empty($paymentmethod) || $paymentmethod == 'paybox') && !empty($conf->paybox->enabled))
198 {
199  // No specific test for the moment
200 }
201 if ((empty($paymentmethod) || $paymentmethod == 'stripe') && !empty($conf->stripe->enabled))
202 {
203  require_once DOL_DOCUMENT_ROOT.'/stripe/config.php'; // This include also /stripe/lib/stripe.lib.php, /includes/stripe/stripe-php/init.php, ...
204 }
205 
206 // Initialize $validpaymentmethod
207 $validpaymentmethod = getValidOnlinePaymentMethods($paymentmethod);
208 
209 // This hook is used to push to $validpaymentmethod by external payment modules (ie Payzen, ...)
210 $parameters = [
211  'paymentmethod' => $paymentmethod,
212  'validpaymentmethod' => &$validpaymentmethod
213 ];
214 $reshook = $hookmanager->executeHooks('doValidatePayment', $parameters, $object, $action);
215 
216 // Check security token
217 $valid = true;
218 if (!empty($conf->global->PAYMENT_SECURITY_TOKEN))
219 {
220  if (!empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE))
221  {
222  if ($source && $REF) $token = dol_hash($conf->global->PAYMENT_SECURITY_TOKEN.$source.$REF, 2); // Use the source in the hash to avoid duplicates if the references are identical
223  else $token = dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2);
224  } else {
225  $token = $conf->global->PAYMENT_SECURITY_TOKEN;
226  }
227  if ($SECUREKEY != $token)
228  {
229  if (empty($conf->global->PAYMENT_SECURITY_ACCEPT_ANY_TOKEN)) $valid = false; // PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is for backward compatibility
230  else dol_syslog("Warning: PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is on", LOG_WARNING);
231  }
232 
233  if (!$valid)
234  {
235  print '<div class="error">Bad value for key.</div>';
236  //print 'SECUREKEY='.$SECUREKEY.' token='.$token.' valid='.$valid;
237  exit;
238  }
239 }
240 
241 if (!empty($paymentmethod) && empty($validpaymentmethod[$paymentmethod]))
242 {
243  print 'Payment module for payment method '.$paymentmethod.' is not active';
244  exit;
245 }
246 if (empty($validpaymentmethod))
247 {
248  print 'No active payment module (Paypal, Stripe, Paybox, ...)';
249  exit;
250 }
251 
252 // Common variables
253 $creditor = $mysoc->name;
254 $paramcreditor = 'ONLINE_PAYMENT_CREDITOR';
255 $paramcreditorlong = 'ONLINE_PAYMENT_CREDITOR_'.$suffix;
256 if (!empty($conf->global->$paramcreditorlong)) $creditor = $conf->global->$paramcreditorlong;
257 elseif (!empty($conf->global->$paramcreditor)) $creditor = $conf->global->$paramcreditor;
258 
259 
260 
261 /*
262  * Actions
263  */
264 
265 // Action dopayment is called after clicking/choosing the payment mode
266 if ($action == 'dopayment')
267 {
268  if ($paymentmethod == 'paypal')
269  {
270  $PAYPAL_API_PRICE = price2num(GETPOST("newamount", 'alpha'), 'MT');
271  $PAYPAL_PAYMENT_TYPE = 'Sale';
272 
273  // Vars that are used as global var later in print_paypal_redirect()
274  $origfulltag = GETPOST("fulltag", 'alpha');
275  $shipToName = GETPOST("shipToName", 'alpha');
276  $shipToStreet = GETPOST("shipToStreet", 'alpha');
277  $shipToCity = GETPOST("shipToCity", 'alpha');
278  $shipToState = GETPOST("shipToState", 'alpha');
279  $shipToCountryCode = GETPOST("shipToCountryCode", 'alpha');
280  $shipToZip = GETPOST("shipToZip", 'alpha');
281  $shipToStreet2 = GETPOST("shipToStreet2", 'alpha');
282  $phoneNum = GETPOST("phoneNum", 'alpha');
283  $email = GETPOST("email", 'alpha');
284  $desc = GETPOST("desc", 'alpha');
285  $thirdparty_id = GETPOST('thirdparty_id', 'int');
286 
287  // Special case for Paypal-Indonesia
288  if ($shipToCountryCode == 'ID' && !preg_match('/\-/', $shipToState))
289  {
290  $shipToState = 'ID-'.$shipToState;
291  }
292 
293  $mesg = '';
294  if (empty($PAYPAL_API_PRICE) || !is_numeric($PAYPAL_API_PRICE))
295  {
296  $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount"));
297  $action = '';
298  }
299  //elseif (empty($EMAIL)) $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("YourEMail"));
300  //elseif (! isValidEMail($EMAIL)) $mesg=$langs->trans("ErrorBadEMail",$EMAIL);
301  elseif (!$origfulltag)
302  {
303  $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PaymentCode"));
304  $action = '';
305  }
306 
307  //var_dump($_POST);
308  if (empty($mesg))
309  {
310  dol_syslog("newpayment.php call paypal api and do redirect", LOG_DEBUG);
311 
312  // Other
313  $PAYPAL_API_DEVISE = "USD";
314  if (!empty($currency)) $PAYPAL_API_DEVISE = $currency;
315 
316  // Show var initialized by include fo paypal lib at begin of this file
317  dol_syslog("Submit Paypal form", LOG_DEBUG);
318  dol_syslog("PAYPAL_API_USER: $PAYPAL_API_USER", LOG_DEBUG);
319  dol_syslog("PAYPAL_API_PASSWORD: ".preg_replace('/./', '*', $PAYPAL_API_PASSWORD), LOG_DEBUG); // No password into log files
320  dol_syslog("PAYPAL_API_SIGNATURE: $PAYPAL_API_SIGNATURE", LOG_DEBUG);
321  dol_syslog("PAYPAL_API_SANDBOX: $PAYPAL_API_SANDBOX", LOG_DEBUG);
322  dol_syslog("PAYPAL_API_OK: $PAYPAL_API_OK", LOG_DEBUG);
323  dol_syslog("PAYPAL_API_KO: $PAYPAL_API_KO", LOG_DEBUG);
324  dol_syslog("PAYPAL_API_PRICE: $PAYPAL_API_PRICE", LOG_DEBUG);
325  dol_syslog("PAYPAL_API_DEVISE: $PAYPAL_API_DEVISE", LOG_DEBUG);
326  // All those fields may be empty when making a payment for a free amount for example
327  dol_syslog("shipToName: $shipToName", LOG_DEBUG);
328  dol_syslog("shipToStreet: $shipToStreet", LOG_DEBUG);
329  dol_syslog("shipToCity: $shipToCity", LOG_DEBUG);
330  dol_syslog("shipToState: $shipToState", LOG_DEBUG);
331  dol_syslog("shipToCountryCode: $shipToCountryCode", LOG_DEBUG);
332  dol_syslog("shipToZip: $shipToZip", LOG_DEBUG);
333  dol_syslog("shipToStreet2: $shipToStreet2", LOG_DEBUG);
334  dol_syslog("phoneNum: $phoneNum", LOG_DEBUG);
335  dol_syslog("email: $email", LOG_DEBUG);
336  dol_syslog("desc: $desc", LOG_DEBUG);
337 
338  dol_syslog("SCRIPT_URI: ".(empty($_SERVER["SCRIPT_URI"]) ? '' : $_SERVER["SCRIPT_URI"]), LOG_DEBUG); // If defined script uri must match domain of PAYPAL_API_OK and PAYPAL_API_KO
339 
340  // A redirect is added if API call successfull
341  $mesg = print_paypal_redirect($PAYPAL_API_PRICE, $PAYPAL_API_DEVISE, $PAYPAL_PAYMENT_TYPE, $PAYPAL_API_OK, $PAYPAL_API_KO, $FULLTAG);
342 
343  // If we are here, it means the Paypal redirect was not done, so we show error message
344  $action = '';
345  }
346  }
347 
348  if ($paymentmethod == 'paybox')
349  {
350  $PRICE = price2num(GETPOST("newamount"), 'MT');
351  $email = $conf->global->ONLINE_PAYMENT_SENDEMAIL;
352  $thirdparty_id = GETPOST('thirdparty_id', 'int');
353 
354  $origfulltag = GETPOST("fulltag", 'alpha');
355 
356  // Securekey into back url useless for back url and we need an url lower than 150.
357  $urlok = preg_replace('/securekey=[^&]+/', '', $urlok);
358  $urlko = preg_replace('/securekey=[^&]+/', '', $urlko);
359 
360  $mesg = '';
361  if (empty($PRICE) || !is_numeric($PRICE)) $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount"));
362  elseif (empty($email)) $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("YourEMail"));
363  elseif (!isValidEMail($email)) $mesg = $langs->trans("ErrorBadEMail", $email);
364  elseif (!$origfulltag) $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PaymentCode"));
365  elseif (dol_strlen($urlok) > 150) $mesg = 'Error urlok too long '.$urlok.'( Paybox requires 150, found '.strlen($urlok).')';
366  elseif (dol_strlen($urlko) > 150) $mesg = 'Error urlko too long '.$urlko.'( Paybox requires 150, found '.strlen($urlok).')';
367 
368  if (empty($mesg))
369  {
370  dol_syslog("newpayment.php call paybox api and do redirect", LOG_DEBUG);
371 
372  include_once DOL_DOCUMENT_ROOT.'/paybox/lib/paybox.lib.php';
373  print_paybox_redirect($PRICE, $conf->currency, $email, $urlok, $urlko, $FULLTAG);
374 
375  session_destroy();
376  exit;
377  }
378  }
379 
380  if ($paymentmethod == 'stripe')
381  {
382  if (GETPOST('newamount', 'alpha')) $amount = price2num(GETPOST('newamount', 'alpha'), 'MT');
383  else {
384  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")), null, 'errors');
385  $action = '';
386  }
387  }
388 }
389 
390 
391 // Called when choosing Stripe mode.
392 // When using the Charge API architecture, this code is called after clicking the 'dopayment' with the Charge API architecture.
393 // When using the PaymentIntent API architecture, the Stripe customer is already created when creating PaymentIntent when showing payment page and the payment is already ok.
394 if ($action == 'charge' && !empty($conf->stripe->enabled))
395 {
396  $amountstripe = $amount;
397 
398  // Correct the amount according to unit of currency
399  // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
400  $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
401  if (!in_array($currency, $arrayzerounitcurrency)) $amountstripe = $amountstripe * 100;
402 
403  dol_syslog("--- newpayment.php Execute action = ".$action, LOG_DEBUG, 0, '_stripe');
404  dol_syslog("POST keys : ".join(',', array_keys($_POST)), LOG_DEBUG, 0, '_stripe');
405  dol_syslog("POST values: ".join(',', $_POST), LOG_DEBUG, 0, '_stripe');
406 
407  $stripeToken = GETPOST("stripeToken", 'alpha');
408  $email = GETPOST("email", 'alpha');
409  $thirdparty_id = GETPOST('thirdparty_id', 'int'); // Note that for payment following online registration for members, this is empty because thirdparty is created once payment is confirmed by paymentok.php
410  $dol_type = (GETPOST('s', 'alpha') ? GETPOST('s', 'alpha') : GETPOST('source', 'alpha'));
411  $dol_id = GETPOST('dol_id', 'int');
412  $vatnumber = GETPOST('vatnumber', 'alpha');
413  $savesource = GETPOSTISSET('savesource') ?GETPOST('savesource', 'int') : 1;
414 
415  dol_syslog("POST stripeToken = ".$stripeToken, LOG_DEBUG, 0, '_stripe');
416  dol_syslog("POST email = ".$email, LOG_DEBUG, 0, '_stripe');
417  dol_syslog("POST thirdparty_id = ".$thirdparty_id, LOG_DEBUG, 0, '_stripe');
418  dol_syslog("POST vatnumber = ".$vatnumber, LOG_DEBUG, 0, '_stripe');
419 
420  $error = 0;
421  $errormessage = '';
422 
423  // When using the old Charge API architecture
424  if (empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
425  {
426  try {
427  $metadata = array(
428  'dol_version' => DOL_VERSION,
429  'dol_entity' => $conf->entity,
430  'dol_company' => $mysoc->name, // Usefull when using multicompany
431  'dol_tax_num' => $vatnumber,
432  'ipaddress'=> getUserRemoteIP()
433  );
434 
435  if (!empty($thirdparty_id)) $metadata["dol_thirdparty_id"] = $thirdparty_id;
436 
437  if ($thirdparty_id > 0)
438  {
439  dol_syslog("Search existing Stripe customer profile for thirdparty_id=".$thirdparty_id, LOG_DEBUG, 0, '_stripe');
440 
441  $service = 'StripeTest';
442  $servicestatus = 0;
443  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'int'))
444  {
445  $service = 'StripeLive';
446  $servicestatus = 1;
447  }
448 
449  $thirdparty = new Societe($db);
450  $thirdparty->fetch($thirdparty_id);
451 
452  // Create Stripe customer
453  include_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
454  $stripe = new Stripe($db);
455  $stripeacc = $stripe->getStripeAccount($service);
456  $customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 1);
457  if (empty($customer))
458  {
459  $error++;
460  dol_syslog('Failed to get/create stripe customer for thirdparty id = '.$thirdparty_id.' and servicestatus = '.$servicestatus.': '.$stripe->error, LOG_ERR, 0, '_stripe');
461  setEventMessages('Failed to get/create stripe customer for thirdparty id = '.$thirdparty_id.' and servicestatus = '.$servicestatus.': '.$stripe->error, null, 'errors');
462  $action = '';
463  }
464 
465  // Create Stripe card from Token
466  if (!$error)
467  {
468  if ($savesource) {
469  $card = $customer->sources->create(array("source" => $stripeToken, "metadata" => $metadata));
470  } else {
471  $card = $stripeToken;
472  }
473 
474  if (empty($card))
475  {
476  $error++;
477  dol_syslog('Failed to create card record', LOG_WARNING, 0, '_stripe');
478  setEventMessages('Failed to create card record', null, 'errors');
479  $action = '';
480  } else {
481  if (!empty($FULLTAG)) $metadata["FULLTAG"] = $FULLTAG;
482  if (!empty($dol_id)) $metadata["dol_id"] = $dol_id;
483  if (!empty($dol_type)) $metadata["dol_type"] = $dol_type;
484 
485  dol_syslog("Create charge on card ".$card->id, LOG_DEBUG, 0, '_stripe');
486  $charge = \Stripe\Charge::create(array(
487  'amount' => price2num($amountstripe, 'MU'),
488  'currency' => $currency,
489  'capture' => true, // Charge immediatly
490  'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
491  'metadata' => $metadata,
492  'customer' => $customer->id,
493  'source' => $card,
494  'statement_descriptor_suffix' => dol_trunc($FULLTAG, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
495  ), array("idempotency_key" => "$FULLTAG", "stripe_account" => "$stripeacc"));
496  // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
497  if (empty($charge))
498  {
499  $error++;
500  dol_syslog('Failed to charge card', LOG_WARNING, 0, '_stripe');
501  setEventMessages('Failed to charge card', null, 'errors');
502  $action = '';
503  }
504  }
505  }
506  } else {
507  $vatcleaned = $vatnumber ? $vatnumber : null;
508 
509  /*$taxinfo = array('type'=>'vat');
510  if ($vatcleaned)
511  {
512  $taxinfo["tax_id"] = $vatcleaned;
513  }
514  // We force data to "null" if not defined as expected by Stripe
515  if (empty($vatcleaned)) $taxinfo=null;
516  */
517 
518  dol_syslog("Create anonymous customer card profile", LOG_DEBUG, 0, '_stripe');
519 
520  $customer = \Stripe\Customer::create(array(
521  'email' => $email,
522  'description' => ($email ? 'Anonymous customer for '.$email : 'Anonymous customer'),
523  'metadata' => $metadata,
524  '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 ?)
525  ));
526  // Return $customer = array('id'=>'cus_XXXX', ...)
527 
528  // Create the VAT record in Stripe
529  /* We don't know country of customer, so we can't create tax
530  if (! empty($conf->global->STRIPE_SAVE_TAX_IDS)) // We setup to save Tax info on Stripe side. Warning: This may result in error when saving customer
531  {
532  if (! empty($vatcleaned))
533  {
534  $isineec=isInEEC($object);
535  if ($object->country_code && $isineec)
536  {
537  //$taxids = $customer->allTaxIds($customer->id);
538  $customer->createTaxId($customer->id, array('type'=>'eu_vat', 'value'=>$vatcleaned));
539  }
540  }
541  }*/
542 
543  if (!empty($FULLTAG)) $metadata["FULLTAG"] = $FULLTAG;
544  if (!empty($dol_id)) $metadata["dol_id"] = $dol_id;
545  if (!empty($dol_type)) $metadata["dol_type"] = $dol_type;
546 
547  // The customer was just created with a source, so we can make a charge
548  // with no card defined, the source just used for customer creation will be used.
549  dol_syslog("Create charge", LOG_DEBUG, 0, '_stripe');
550  $charge = \Stripe\Charge::create(array(
551  'customer' => $customer->id,
552  'amount' => price2num($amountstripe, 'MU'),
553  'currency' => $currency,
554  'capture' => true, // Charge immediatly
555  'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
556  'metadata' => $metadata,
557  'statement_descriptor' => dol_trunc($FULLTAG, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
558  ), array("idempotency_key" => "$FULLTAG", "stripe_account" => "$stripeacc"));
559  // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
560  if (empty($charge))
561  {
562  $error++;
563  dol_syslog('Failed to charge card', LOG_WARNING, 0, '_stripe');
564  setEventMessages('Failed to charge card', null, 'errors');
565  $action = '';
566  }
567  }
568  } catch (\Stripe\Error\Card $e) {
569  // Since it's a decline, \Stripe\Error\Card will be caught
570  $body = $e->getJsonBody();
571  $err = $body['error'];
572 
573  print('Status is:'.$e->getHttpStatus()."\n");
574  print('Type is:'.$err['type']."\n");
575  print('Code is:'.$err['code']."\n");
576  // param is '' in this case
577  print('Param is:'.$err['param']."\n");
578  print('Message is:'.$err['message']."\n");
579 
580  $error++;
581  $errormessage = "ErrorCard ".$e->getMessage()." err=".var_export($err, true);
582  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
583  setEventMessages($e->getMessage(), null, 'errors');
584  $action = '';
585  } catch (\Stripe\Error\RateLimit $e) {
586  // Too many requests made to the API too quickly
587  $error++;
588  $errormessage = "ErrorRateLimit ".$e->getMessage();
589  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
590  setEventMessages($e->getMessage(), null, 'errors');
591  $action = '';
592  } catch (\Stripe\Error\InvalidRequest $e) {
593  // Invalid parameters were supplied to Stripe's API
594  $error++;
595  $errormessage = "ErrorInvalidRequest ".$e->getMessage();
596  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
597  setEventMessages($e->getMessage(), null, 'errors');
598  $action = '';
599  } catch (\Stripe\Error\Authentication $e) {
600  // Authentication with Stripe's API failed
601  // (maybe you changed API keys recently)
602  $error++;
603  $errormessage = "ErrorAuthentication ".$e->getMessage();
604  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
605  setEventMessages($e->getMessage(), null, 'errors');
606  $action = '';
607  } catch (\Stripe\Error\ApiConnection $e) {
608  // Network communication with Stripe failed
609  $error++;
610  $errormessage = "ErrorApiConnection ".$e->getMessage();
611  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
612  setEventMessages($e->getMessage(), null, 'errors');
613  $action = '';
614  } catch (\Stripe\Error\Base $e) {
615  // Display a very generic error to the user, and maybe send
616  // yourself an email
617  $error++;
618  $errormessage = "ErrorBase ".$e->getMessage();
619  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
620  setEventMessages($e->getMessage(), null, 'errors');
621  $action = '';
622  } catch (Exception $e) {
623  // Something else happened, completely unrelated to Stripe
624  $error++;
625  $errormessage = "ErrorException ".$e->getMessage();
626  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
627  setEventMessages($e->getMessage(), null, 'errors');
628  $action = '';
629  }
630  }
631 
632  // When using the PaymentIntent API architecture
633  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
634  {
635  $service = 'StripeTest';
636  $servicestatus = 0;
637  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'int'))
638  {
639  $service = 'StripeLive';
640  $servicestatus = 1;
641  }
642  include_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
643  $stripe = new Stripe($db);
644  $stripeacc = $stripe->getStripeAccount($service);
645 
646  // We go here if $conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION is set.
647  // In such a case, payment is always ok when we call the "charge" action.
648  $paymentintent_id = GETPOST("paymentintent_id", "alpha");
649 
650  // Force to use the correct API key
651  global $stripearrayofkeysbyenv;
652  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$servicestatus]['secret_key']);
653 
654  try {
655  if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
656  $paymentintent = \Stripe\PaymentIntent::retrieve($paymentintent_id);
657  } else {
658  $paymentintent = \Stripe\PaymentIntent::retrieve($paymentintent_id, array("stripe_account" => $stripeacc));
659  }
660  } catch (Exception $e)
661  {
662  $error++;
663  $errormessage = "CantRetrievePaymentIntent ".$e->getMessage();
664  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
665  setEventMessages($e->getMessage(), null, 'errors');
666  $action = '';
667  }
668 
669  if ($paymentintent->status != 'succeeded')
670  {
671  $error++;
672  $errormessage = "StatusOfRetrievedIntent is not succeeded: ".$paymentintent->status;
673  dol_syslog($errormessage, LOG_WARNING, 0, '_stripe');
674  setEventMessages($paymentintent->status, null, 'errors');
675  $action = '';
676  } else {
677  // TODO We can alse record the payment mode into llx_societe_rib with stripe $paymentintent->payment_method
678  // 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.
679  //dol_syslog("Create payment_method for ".$paymentintent->payment_method, LOG_DEBUG, 0, '_stripe');
680  }
681  }
682 
683 
684  $remoteip = getUserRemoteIP();
685 
686  $_SESSION["onlinetoken"] = $stripeToken;
687  $_SESSION["FinalPaymentAmt"] = $amount;
688  $_SESSION["currencyCodeType"] = $currency;
689  $_SESSION["paymentType"] = '';
690  $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip
691  $_SESSION['payerID'] = is_object($customer) ? $customer->id : '';
692  $_SESSION['TRANSACTIONID'] = (is_object($charge) ? $charge->id : (is_object($paymentintent) ? $paymentintent->id : ''));
693  $_SESSION['errormessage'] = $errormessage;
694 
695  dol_syslog("Action charge stripe ip=".$remoteip, LOG_DEBUG, 0, '_stripe');
696  dol_syslog("onlinetoken=".$_SESSION["onlinetoken"]." FinalPaymentAmt=".$_SESSION["FinalPaymentAmt"]." currencyCodeType=".$_SESSION["currencyCodeType"]." payerID=".$_SESSION['payerID']." TRANSACTIONID=".$_SESSION['TRANSACTIONID'], LOG_DEBUG, 0, '_stripe');
697  dol_syslog("FULLTAG=".$FULLTAG, LOG_DEBUG, 0, '_stripe');
698  dol_syslog("error=".$error." errormessage=".$errormessage, LOG_DEBUG, 0, '_stripe');
699  dol_syslog("Now call the redirect to paymentok or paymentko, URL = ".($error ? $urlko : $urlok), LOG_DEBUG, 0, '_stripe');
700 
701  if ($error)
702  {
703  header("Location: ".$urlko);
704  exit;
705  } else {
706  header("Location: ".$urlok);
707  exit;
708  }
709 }
710 
711 
712 /*
713  * View
714  */
715 
716 $head = '';
717 if (!empty($conf->global->ONLINE_PAYMENT_CSS_URL)) $head = '<link rel="stylesheet" type="text/css" href="'.$conf->global->ONLINE_PAYMENT_CSS_URL.'?lang='.$langs->defaultlang.'">'."\n";
718 
719 $conf->dol_hide_topmenu = 1;
720 $conf->dol_hide_leftmenu = 1;
721 
722 $replacemainarea = (empty($conf->dol_hide_leftmenu) ? '<div>' : '').'<div>';
723 llxHeader($head, $langs->trans("PaymentForm"), '', '', 0, 0, '', '', '', 'onlinepaymentbody', $replacemainarea);
724 
725 // Check link validity
726 if ($source && in_array($ref, array('member_ref', 'contractline_ref', 'invoice_ref', 'order_ref', '')))
727 {
728  $langs->load("errors");
729  dol_print_error_email('BADREFINPAYMENTFORM', $langs->trans("ErrorBadLinkSourceSetButBadValueForRef", $source, $ref));
730  // End of page
731  llxFooter();
732  $db->close();
733  exit;
734 }
735 
736 
737 // Show sandbox warning
738 if ((empty($paymentmethod) || $paymentmethod == 'paypal') && !empty($conf->paypal->enabled) && (!empty($conf->global->PAYPAL_API_SANDBOX) || GETPOST('forcesandbox', 'int'))) // We can force sand box with param 'forcesandbox'
739 {
740  dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode', 'Paypal'), '', 'warning');
741 }
742 if ((empty($paymentmethod) || $paymentmethod == 'stripe') && !empty($conf->stripe->enabled) && (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'int')))
743 {
744  dol_htmloutput_mesg($langs->trans('YouAreCurrentlyInSandboxMode', 'Stripe'), '', 'warning');
745 }
746 
747 
748 print '<span id="dolpaymentspan"></span>'."\n";
749 print '<div class="center">'."\n";
750 print '<form id="dolpaymentform" class="center" name="paymentform" action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
751 print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
752 print '<input type="hidden" name="action" value="dopayment">'."\n";
753 print '<input type="hidden" name="tag" value="'.GETPOST("tag", 'alpha').'">'."\n";
754 print '<input type="hidden" name="suffix" value="'.dol_escape_htmltag($suffix).'">'."\n";
755 print '<input type="hidden" name="securekey" value="'.dol_escape_htmltag($SECUREKEY).'">'."\n";
756 print '<input type="hidden" name="e" value="'.$entity.'" />';
757 print '<input type="hidden" name="forcesandbox" value="'.GETPOST('forcesandbox', 'int').'" />';
758 print "\n";
759 
760 
761 // Show logo (search order: logo defined by PAYMENT_LOGO_suffix, then PAYMENT_LOGO, then small company logo, large company logo, theme logo, common logo)
762 // Define logo and logosmall
763 $logosmall = $mysoc->logo_small;
764 $logo = $mysoc->logo;
765 $paramlogo = 'ONLINE_PAYMENT_LOGO_'.$suffix;
766 if (!empty($conf->global->$paramlogo)) $logosmall = $conf->global->$paramlogo;
767 elseif (!empty($conf->global->ONLINE_PAYMENT_LOGO)) $logosmall = $conf->global->ONLINE_PAYMENT_LOGO;
768 //print '<!-- Show logo (logosmall='.$logosmall.' logo='.$logo.') -->'."\n";
769 // Define urllogo
770 $urllogo = '';
771 $urllogofull = '';
772 if (!empty($logosmall) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$logosmall))
773 {
774  $urllogo = DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;entity='.$conf->entity.'&amp;file='.urlencode('logos/thumbs/'.$logosmall);
775  $urllogofull = $dolibarr_main_url_root.'/viewimage.php?modulepart=mycompany&entity='.$conf->entity.'&file='.urlencode('logos/thumbs/'.$logosmall);
776 } elseif (!empty($logo) && is_readable($conf->mycompany->dir_output.'/logos/'.$logo))
777 {
778  $urllogo = DOL_URL_ROOT.'/viewimage.php?modulepart=mycompany&amp;entity='.$conf->entity.'&amp;file='.urlencode('logos/'.$logo);
779  $urllogofull = $dolibarr_main_url_root.'/viewimage.php?modulepart=mycompany&entity='.$conf->entity.'&file='.urlencode('logos/'.$logo);
780 }
781 
782 // Output html code for logo
783 if ($urllogo)
784 {
785  print '<div class="backgreypublicpayment">';
786  print '<div class="logopublicpayment">';
787  print '<img id="dolpaymentlogo" src="'.$urllogo.'"';
788  print '>';
789  print '</div>';
790  if (empty($conf->global->MAIN_HIDE_POWERED_BY)) {
791  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>';
792  }
793  print '</div>';
794 }
795 
796 
797 
798 
799 print '<!-- Form to send a payment -->'."\n";
800 print '<!-- creditor = '.$creditor.' -->'."\n";
801 // Additionnal information for each payment system
802 if (!empty($conf->paypal->enabled))
803 {
804  print '<!-- PAYPAL_API_SANDBOX = '.$conf->global->PAYPAL_API_SANDBOX.' -->'."\n";
805  print '<!-- PAYPAL_API_INTEGRAL_OR_PAYPALONLY = '.$conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY.' -->'."\n";
806 }
807 if (!empty($conf->paybox->enabled))
808 {
809  print '<!-- PAYBOX_CGI_URL = '.$conf->global->PAYBOX_CGI_URL_V2.' -->'."\n";
810 }
811 if (!empty($conf->stripe->enabled))
812 {
813  print '<!-- STRIPE_LIVE = '.$conf->global->STRIPE_LIVE.' -->'."\n";
814 }
815 print '<!-- urlok = '.$urlok.' -->'."\n";
816 print '<!-- urlko = '.$urlko.' -->'."\n";
817 print "\n";
818 
819 print '<table id="dolpaymenttable" summary="Payment form" class="center">'."\n";
820 
821 // Output introduction text
822 $text = '';
823 if (!empty($conf->global->PAYMENT_NEWFORM_TEXT))
824 {
825  $langs->load("members");
826  if (preg_match('/^\((.*)\)$/', $conf->global->PAYMENT_NEWFORM_TEXT, $reg)) $text .= $langs->trans($reg[1])."<br>\n";
827  else $text .= $conf->global->PAYMENT_NEWFORM_TEXT."<br>\n";
828  $text = '<tr><td align="center"><br>'.$text.'<br></td></tr>'."\n";
829 }
830 if (empty($text))
831 {
832  $text .= '<tr><td class="textpublicpayment"><br><strong>'.$langs->trans("WelcomeOnPaymentPage").'</strong></td></tr>'."\n";
833  $text .= '<tr><td class="textpublicpayment">'.$langs->trans("ThisScreenAllowsYouToPay", $creditor).'<br><br></td></tr>'."\n";
834 }
835 print $text;
836 
837 // Output payment summary form
838 print '<tr><td align="center">';
839 print '<table with="100%" id="tablepublicpayment">';
840 print '<tr><td align="left" colspan="2" class="opacitymedium">'.$langs->trans("ThisIsInformationOnPayment").' :</td></tr>'."\n";
841 
842 $found = false;
843 $error = 0;
844 $var = false;
845 
846 $object = null;
847 
848 
849 // Free payment
850 if (!$source)
851 {
852  $found = true;
853  $tag = GETPOST("tag", 'alpha');
854  if (GETPOST('fulltag', 'alpha')) {
855  $fulltag = GETPOST('fulltag', 'alpha');
856  } else {
857  $fulltag = "TAG=".$tag;
858  }
859 
860  // Creditor
861  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
862  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
863  print '<input type="hidden" name="creditor" value="'.$creditor.'">';
864  print '</td></tr>'."\n";
865 
866  // Amount
867  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Amount");
868  if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
869  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
870  if (empty($amount) || !is_numeric($amount))
871  {
872  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
873  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
874  } else {
875  print '<b>'.price($amount).'</b>';
876  print '<input type="hidden" name="amount" value="'.$amount.'">';
877  print '<input type="hidden" name="newamount" value="'.$amount.'">';
878  }
879  // Currency
880  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
881  print '<input type="hidden" name="currency" value="'.$currency.'">';
882  print '</td></tr>'."\n";
883 
884  // Tag
885  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
886  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
887  print '<input type="hidden" name="tag" value="'.$tag.'">';
888  print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
889  print '</td></tr>'."\n";
890 
891  // We do not add fields shipToName, shipToStreet, shipToCity, shipToState, shipToCountryCode, shipToZip, shipToStreet2, phoneNum
892  // as they don't exists (buyer is unknown, tag is free).
893 }
894 
895 
896 // Payment on customer order
897 if ($source == 'order')
898 {
899  $found = true;
900  $langs->load("orders");
901 
902  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
903 
904  $order = new Commande($db);
905  $result = $order->fetch('', $ref);
906  if ($result <= 0)
907  {
908  $mesg = $order->error;
909  $error++;
910  } else {
911  $result = $order->fetch_thirdparty($order->socid);
912  }
913  $object = $order;
914 
915  if ($action != 'dopayment') // Do not change amount if we just click on first dopayment
916  {
917  $amount = $order->total_ttc;
918  if (GETPOST("amount", 'alpha')) $amount = GETPOST("amount", 'alpha');
919  $amount = price2num($amount);
920  }
921 
922  if (GETPOST('fulltag', 'alpha')) {
923  $fulltag = GETPOST('fulltag', 'alpha');
924  } else {
925  $fulltag = 'ORD='.$order->id.'.CUS='.$order->thirdparty->id;
926  if (!empty($TAG)) { $tag = $TAG; $fulltag .= '.TAG='.$TAG; }
927  }
928  $fulltag = dol_string_unaccent($fulltag);
929 
930  // Creditor
931  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
932  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
933  print '<input type="hidden" name="creditor" value="'.$creditor.'">';
934  print '</td></tr>'."\n";
935 
936  // Debitor
937  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("ThirdParty");
938  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$order->thirdparty->name.'</b>';
939  print '</td></tr>'."\n";
940 
941  // Object
942  $text = '<b>'.$langs->trans("PaymentOrderRef", $order->ref).'</b>';
943  if (GETPOST('desc', 'alpha')) $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
944  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Designation");
945  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.$text;
946  print '<input type="hidden" name="s" value="'.dol_escape_htmltag($source).'">';
947  print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($order->ref).'">';
948  print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag($order->id).'">';
949  $directdownloadlink = $order->getLastMainDocLink('commande');
950  if ($directdownloadlink)
951  {
952  print '<br><a href="'.$directdownloadlink.'" rel="nofollow noopener">';
953  print img_mime($order->last_main_doc, '');
954  print $langs->trans("DownloadDocument").'</a>';
955  }
956  print '</td></tr>'."\n";
957 
958  // Amount
959  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Amount");
960  if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
961  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
962  if (empty($amount) || !is_numeric($amount))
963  {
964  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
965  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
966  } else {
967  print '<b>'.price($amount).'</b>';
968  print '<input type="hidden" name="amount" value="'.$amount.'">';
969  print '<input type="hidden" name="newamount" value="'.$amount.'">';
970  }
971  // Currency
972  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
973  print '<input type="hidden" name="currency" value="'.$currency.'">';
974  print '</td></tr>'."\n";
975 
976  // Tag
977  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
978  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
979  print '<input type="hidden" name="tag" value="'.dol_escape_htmltag($tag).'">';
980  print '<input type="hidden" name="fulltag" value="'.dol_escape_htmltag($fulltag).'">';
981  print '</td></tr>'."\n";
982 
983  // Shipping address
984  $shipToName = $order->thirdparty->name;
985  $shipToStreet = $order->thirdparty->address;
986  $shipToCity = $order->thirdparty->town;
987  $shipToState = $order->thirdparty->state_code;
988  $shipToCountryCode = $order->thirdparty->country_code;
989  $shipToZip = $order->thirdparty->zip;
990  $shipToStreet2 = '';
991  $phoneNum = $order->thirdparty->phone;
992  if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip)
993  {
994  print '<input type="hidden" name="shipToName" value="'.dol_escape_htmltag($shipToName).'">'."\n";
995  print '<input type="hidden" name="shipToStreet" value="'.dol_escape_htmltag($shipToStreet).'">'."\n";
996  print '<input type="hidden" name="shipToCity" value="'.dol_escape_htmltag($shipToCity).'">'."\n";
997  print '<input type="hidden" name="shipToState" value="'.dol_escape_htmltag($shipToState).'">'."\n";
998  print '<input type="hidden" name="shipToCountryCode" value="'.dol_escape_htmltag($shipToCountryCode).'">'."\n";
999  print '<input type="hidden" name="shipToZip" value="'.dol_escape_htmltag($shipToZip).'">'."\n";
1000  print '<input type="hidden" name="shipToStreet2" value="'.dol_escape_htmltag($shipToStreet2).'">'."\n";
1001  print '<input type="hidden" name="phoneNum" value="'.dol_escape_htmltag($phoneNum).'">'."\n";
1002  } else {
1003  print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1004  }
1005  if (is_object($order->thirdparty)) print '<input type="hidden" name="thirdparty_id" value="'.$order->thirdparty->id.'">'."\n";
1006  print '<input type="hidden" name="email" value="'.$order->thirdparty->email.'">'."\n";
1007  print '<input type="hidden" name="vatnumber" value="'.dol_escape_htmltag($order->thirdparty->tva_intra).'">'."\n";
1008  $labeldesc = $langs->trans("Order").' '.$order->ref;
1009  if (GETPOST('desc', 'alpha')) $labeldesc = GETPOST('desc', 'alpha');
1010  print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1011 }
1012 
1013 
1014 // Payment on customer invoice
1015 if ($source == 'invoice')
1016 {
1017  $found = true;
1018  $langs->load("bills");
1019 
1020  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
1021 
1022  $invoice = new Facture($db);
1023  $result = $invoice->fetch('', $ref);
1024  if ($result <= 0)
1025  {
1026  $mesg = $invoice->error;
1027  $error++;
1028  } else {
1029  $result = $invoice->fetch_thirdparty($invoice->socid);
1030  }
1031  $object = $invoice;
1032 
1033  if ($action != 'dopayment') // Do not change amount if we just click on first dopayment
1034  {
1035  $amount = price2num($invoice->total_ttc - ($invoice->getSommePaiement() + $invoice->getSumCreditNotesUsed() + $invoice->getSumDepositsUsed()));
1036  if (GETPOST("amount", 'int')) $amount = GETPOST("amount", 'alpha');
1037  $amount = price2num($amount);
1038  }
1039 
1040  if (GETPOST('fulltag', 'alpha')) {
1041  $fulltag = GETPOST('fulltag', 'alpha');
1042  } else {
1043  $fulltag = 'INV='.$invoice->id.'.CUS='.$invoice->thirdparty->id;
1044  if (!empty($TAG)) { $tag = $TAG; $fulltag .= '.TAG='.$TAG; }
1045  }
1046  $fulltag = dol_string_unaccent($fulltag);
1047 
1048  // Creditor
1049  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
1050  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
1051  print '<input type="hidden" name="creditor" value="'.dol_escape_htmltag($creditor).'">';
1052  print '</td></tr>'."\n";
1053 
1054  // Debitor
1055  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("ThirdParty");
1056  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$invoice->thirdparty->name.'</b>';
1057  print '</td></tr>'."\n";
1058 
1059  // Object
1060  $text = '<b>'.$langs->trans("PaymentInvoiceRef", $invoice->ref).'</b>';
1061  if (GETPOST('desc', 'alpha')) $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1062  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Designation");
1063  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.$text;
1064  print '<input type="hidden" name="s" value="'.dol_escape_htmltag($source).'">';
1065  print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($invoice->ref).'">';
1066  print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag($invoice->id).'">';
1067  $directdownloadlink = $invoice->getLastMainDocLink('facture');
1068  if ($directdownloadlink)
1069  {
1070  print '<br><a href="'.$directdownloadlink.'">';
1071  print img_mime($invoice->last_main_doc, '');
1072  print $langs->trans("DownloadDocument").'</a>';
1073  }
1074  print '</td></tr>'."\n";
1075 
1076  // Amount
1077  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentAmount");
1078  if (empty($amount) && empty($object->paye)) print ' ('.$langs->trans("ToComplete").')';
1079  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
1080  if ($object->type == $object::TYPE_CREDIT_NOTE) {
1081  print '<b>'.$langs->trans("CreditNote").'</b>';
1082  } elseif (empty($object->paye)) {
1083  if (empty($amount) || !is_numeric($amount))
1084  {
1085  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1086  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1087  } else {
1088  print '<b>'.price($amount).'</b>';
1089  print '<input type="hidden" name="amount" value="'.$amount.'">';
1090  print '<input type="hidden" name="newamount" value="'.$amount.'">';
1091  }
1092  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1093  print '<input type="hidden" name="currency" value="'.$currency.'">';
1094  } else {
1095  print '<b>'.price($object->total_ttc, 1, $langs).'</b>';
1096  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1097  print '<input type="hidden" name="currency" value="'.$currency.'">';
1098  }
1099  print '</td></tr>'."\n";
1100 
1101  // Tag
1102  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
1103  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
1104  print '<input type="hidden" name="tag" value="'.$tag.'">';
1105  print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1106  print '</td></tr>'."\n";
1107 
1108  // Shipping address
1109  $shipToName = $invoice->thirdparty->name;
1110  $shipToStreet = $invoice->thirdparty->address;
1111  $shipToCity = $invoice->thirdparty->town;
1112  $shipToState = $invoice->thirdparty->state_code;
1113  $shipToCountryCode = $invoice->thirdparty->country_code;
1114  $shipToZip = $invoice->thirdparty->zip;
1115  $shipToStreet2 = '';
1116  $phoneNum = $invoice->thirdparty->phone;
1117  if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip)
1118  {
1119  print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1120  print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1121  print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1122  print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1123  print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1124  print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1125  print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1126  print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1127  } else {
1128  print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1129  }
1130  if (is_object($invoice->thirdparty)) print '<input type="hidden" name="thirdparty_id" value="'.$invoice->thirdparty->id.'">'."\n";
1131  print '<input type="hidden" name="email" value="'.$invoice->thirdparty->email.'">'."\n";
1132  print '<input type="hidden" name="vatnumber" value="'.$invoice->thirdparty->tva_intra.'">'."\n";
1133  $labeldesc = $langs->trans("Invoice").' '.$invoice->ref;
1134  if (GETPOST('desc', 'alpha')) $labeldesc = GETPOST('desc', 'alpha');
1135  print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1136 }
1137 
1138 // Payment on contract line
1139 if ($source == 'contractline')
1140 {
1141  $found = true;
1142  $langs->load("contracts");
1143 
1144  require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
1145 
1146  $contract = new Contrat($db);
1147  $contractline = new ContratLigne($db);
1148 
1149  $result = $contractline->fetch('', $ref);
1150  if ($result <= 0)
1151  {
1152  $mesg = $contractline->error;
1153  $error++;
1154  } else {
1155  if ($contractline->fk_contrat > 0)
1156  {
1157  $result = $contract->fetch($contractline->fk_contrat);
1158  if ($result > 0)
1159  {
1160  $result = $contract->fetch_thirdparty($contract->socid);
1161  } else {
1162  $mesg = $contract->error;
1163  $error++;
1164  }
1165  } else {
1166  $mesg = 'ErrorRecordNotFound';
1167  $error++;
1168  }
1169  }
1170  $object = $contractline;
1171 
1172  if ($action != 'dopayment') // Do not change amount if we just click on first dopayment
1173  {
1174  $amount = $contractline->total_ttc;
1175 
1176  if ($contractline->fk_product && !empty($conf->global->PAYMENT_USE_NEW_PRICE_FOR_CONTRACTLINES))
1177  {
1178  $product = new Product($db);
1179  $result = $product->fetch($contractline->fk_product);
1180 
1181  // We define price for product (TODO Put this in a method in product class)
1182  if (!empty($conf->global->PRODUIT_MULTIPRICES))
1183  {
1184  $pu_ht = $product->multiprices[$contract->thirdparty->price_level];
1185  $pu_ttc = $product->multiprices_ttc[$contract->thirdparty->price_level];
1186  $price_base_type = $product->multiprices_base_type[$contract->thirdparty->price_level];
1187  } else {
1188  $pu_ht = $product->price;
1189  $pu_ttc = $product->price_ttc;
1190  $price_base_type = $product->price_base_type;
1191  }
1192 
1193  $amount = $pu_ttc;
1194  if (empty($amount))
1195  {
1196  dol_print_error('', 'ErrorNoPriceDefinedForThisProduct');
1197  exit;
1198  }
1199  }
1200 
1201  if (GETPOST("amount", 'alpha')) $amount = GETPOST("amount", 'alpha');
1202  $amount = price2num($amount);
1203  }
1204 
1205  if (GETPOST('fulltag', 'alpha')) {
1206  $fulltag = GETPOST('fulltag', 'alpha');
1207  } else {
1208  $fulltag = 'COL='.$contractline->id.'.CON='.$contract->id.'.CUS='.$contract->thirdparty->id.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1209  if (!empty($TAG)) { $tag = $TAG; $fulltag .= '.TAG='.$TAG; }
1210  }
1211  $fulltag = dol_string_unaccent($fulltag);
1212 
1213  $qty = 1;
1214  if (GETPOST('qty')) $qty = GETPOST('qty');
1215 
1216  // Creditor
1217  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
1218  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
1219  print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1220  print '</td></tr>'."\n";
1221 
1222  // Debitor
1223  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("ThirdParty");
1224  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$contract->thirdparty->name.'</b>';
1225  print '</td></tr>'."\n";
1226 
1227  // Object
1228  $text = '<b>'.$langs->trans("PaymentRenewContractId", $contract->ref, $contractline->ref).'</b>';
1229  if ($contractline->fk_product)
1230  {
1231  $contractline->fetch_product();
1232  $text .= '<br>'.$contractline->product->ref.($contractline->product->label ? ' - '.$contractline->product->label : '');
1233  }
1234  if ($contractline->description) $text .= '<br>'.dol_htmlentitiesbr($contractline->description);
1235  //if ($contractline->date_fin_validite) {
1236  // $text.='<br>'.$langs->trans("DateEndPlanned").': ';
1237  // $text.=dol_print_date($contractline->date_fin_validite);
1238  //}
1239  if ($contractline->date_fin_validite)
1240  {
1241  $text .= '<br>'.$langs->trans("ExpiredSince").': '.dol_print_date($contractline->date_fin_validite);
1242  }
1243  if (GETPOST('desc', 'alpha')) $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1244  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Designation");
1245  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.$text;
1246  print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
1247  print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($contractline->ref).'">';
1248  print '<input type="hidden" name="dol_id" value="'.dol_escape_htmltag($contractline->id).'">';
1249  $directdownloadlink = $contract->getLastMainDocLink('contract');
1250  if ($directdownloadlink)
1251  {
1252  print '<br><a href="'.$directdownloadlink.'">';
1253  print img_mime($contract->last_main_doc, '');
1254  print $langs->trans("DownloadDocument").'</a>';
1255  }
1256  print '</td></tr>'."\n";
1257 
1258  // Quantity
1259  $label = $langs->trans("Quantity");
1260  $qty = 1;
1261  $duration = '';
1262  if ($contractline->fk_product)
1263  {
1264  if ($contractline->product->isService() && $contractline->product->duration_value > 0)
1265  {
1266  $label = $langs->trans("Duration");
1267 
1268  // TODO Put this in a global method
1269  if ($contractline->product->duration_value > 1)
1270  {
1271  $dur = array("h"=>$langs->trans("Hours"), "d"=>$langs->trans("DurationDays"), "w"=>$langs->trans("DurationWeeks"), "m"=>$langs->trans("DurationMonths"), "y"=>$langs->trans("DurationYears"));
1272  } else {
1273  $dur = array("h"=>$langs->trans("Hour"), "d"=>$langs->trans("DurationDay"), "w"=>$langs->trans("DurationWeek"), "m"=>$langs->trans("DurationMonth"), "y"=>$langs->trans("DurationYear"));
1274  }
1275  $duration = $contractline->product->duration_value.' '.$dur[$contractline->product->duration_unit];
1276  }
1277  }
1278  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$label.'</td>';
1279  print '<td class="CTableRow'.($var ? '1' : '2').'"><b>'.($duration ? $duration : $qty).'</b>';
1280  print '<input type="hidden" name="newqty" value="'.dol_escape_htmltag($qty).'">';
1281  print '</b></td></tr>'."\n";
1282 
1283  // Amount
1284  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Amount");
1285  if (empty($amount)) print ' ('.$langs->trans("ToComplete").')';
1286  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
1287  if (empty($amount) || !is_numeric($amount))
1288  {
1289  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1290  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.price2num(GETPOST("newamount", "alpha"), 'MT').'">';
1291  } else {
1292  print '<b>'.price($amount).'</b>';
1293  print '<input type="hidden" name="amount" value="'.$amount.'">';
1294  print '<input type="hidden" name="newamount" value="'.$amount.'">';
1295  }
1296  // Currency
1297  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1298  print '<input type="hidden" name="currency" value="'.$currency.'">';
1299  print '</td></tr>'."\n";
1300 
1301  // Tag
1302  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
1303  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
1304  print '<input type="hidden" name="tag" value="'.$tag.'">';
1305  print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1306  print '</td></tr>'."\n";
1307 
1308  // Shipping address
1309  $shipToName = $contract->thirdparty->name;
1310  $shipToStreet = $contract->thirdparty->address;
1311  $shipToCity = $contract->thirdparty->town;
1312  $shipToState = $contract->thirdparty->state_code;
1313  $shipToCountryCode = $contract->thirdparty->country_code;
1314  $shipToZip = $contract->thirdparty->zip;
1315  $shipToStreet2 = '';
1316  $phoneNum = $contract->thirdparty->phone;
1317  if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip)
1318  {
1319  print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1320  print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1321  print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1322  print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1323  print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1324  print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1325  print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1326  print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1327  } else {
1328  print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1329  }
1330  if (is_object($contract->thirdparty)) print '<input type="hidden" name="thirdparty_id" value="'.$contract->thirdparty->id.'">'."\n";
1331  print '<input type="hidden" name="email" value="'.$contract->thirdparty->email.'">'."\n";
1332  print '<input type="hidden" name="vatnumber" value="'.$contract->thirdparty->tva_intra.'">'."\n";
1333  $labeldesc = $langs->trans("Contract").' '.$contract->ref;
1334  if (GETPOST('desc', 'alpha')) $labeldesc = GETPOST('desc', 'alpha');
1335  print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1336 }
1337 
1338 // Payment on member subscription
1339 if ($source == 'membersubscription')
1340 {
1341  $found = true;
1342  $langs->load("members");
1343 
1344  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1345  require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
1346 
1347  $member = new Adherent($db);
1348  $result = $member->fetch('', $ref);
1349  if ($result <= 0)
1350  {
1351  $mesg = $member->error;
1352  $error++;
1353  } else {
1354  $member->fetch_thirdparty();
1355  $subscription = new Subscription($db);
1356  }
1357  $object = $member;
1358 
1359  if ($action != 'dopayment') // Do not change amount if we just click on first dopayment
1360  {
1361  $amount = $subscription->total_ttc;
1362  if (GETPOST("amount", 'alpha')) $amount = GETPOST("amount", 'alpha');
1363  $amount = price2num($amount, 'MT');
1364  }
1365 
1366  if (GETPOST('fulltag', 'alpha')) {
1367  $fulltag = GETPOST('fulltag', 'alpha');
1368  } else {
1369  $fulltag = 'MEM='.$member->id.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1370  if (!empty($TAG)) { $tag = $TAG; $fulltag .= '.TAG='.$TAG; }
1371  }
1372  $fulltag = dol_string_unaccent($fulltag);
1373 
1374  // Creditor
1375  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
1376  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
1377  print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1378  print '</td></tr>'."\n";
1379 
1380  // Debitor
1381  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Member");
1382  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>';
1383  if ($member->morphy == 'mor' && !empty($member->societe)) print $member->societe;
1384  else print $member->getFullName($langs);
1385  print '</b>';
1386  print '</td></tr>'."\n";
1387 
1388  // Object
1389  $text = '<b>'.$langs->trans("PaymentSubscription").'</b>';
1390  if (GETPOST('desc', 'alpha')) $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1391  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Designation");
1392  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.$text;
1393  print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
1394  print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($member->ref).'">';
1395  print '</td></tr>'."\n";
1396 
1397  if ($object->datefin > 0) {
1398  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("DateEndSubscription");
1399  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.dol_print_date($member->datefin, 'day');
1400  print '</td></tr>'."\n";
1401  }
1402 
1403  if ($member->last_subscription_date || $member->last_subscription_amount)
1404  {
1405  // Last subscription date
1406 
1407  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("LastSubscriptionDate");
1408  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.dol_print_date($member->last_subscription_date, 'day');
1409  print '</td></tr>'."\n";
1410 
1411  // Last subscription amount
1412 
1413  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("LastSubscriptionAmount");
1414  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.price($member->last_subscription_amount);
1415  print '</td></tr>'."\n";
1416 
1417  if (empty($amount) && !GETPOST('newamount', 'alpha')) $_GET['newamount'] = $member->last_subscription_amount;
1418  }
1419 
1420  // Amount
1421  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Amount");
1422  if (empty($amount))
1423  {
1424  if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) print ' ('.$langs->trans("ToComplete");
1425  if (!empty($conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO)) print ' - <a href="'.$conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO.'" rel="external" target="_blank">'.$langs->trans("SeeHere").'</a>';
1426  if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) print ')';
1427  }
1428  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
1429  $valtoshow = '';
1430  if (empty($amount) || !is_numeric($amount))
1431  {
1432  $valtoshow = price2num(GETPOST("newamount", 'alpha'), 'MT');
1433  // force default subscription amount to value defined into constant...
1434  if (empty($valtoshow))
1435  {
1436  if (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) {
1437  if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
1438  $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT;
1439  }
1440  } else {
1441  if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
1442  $amount = $conf->global->MEMBER_NEWFORM_AMOUNT;
1443  }
1444  }
1445  }
1446  }
1447  if (empty($amount) || !is_numeric($amount))
1448  {
1449  //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT');
1450  if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
1451  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1452  if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) {
1453  print '<input class="flat maxwidth75" type="text" name="newamountbis" value="'.$valtoshow.'" disabled>';
1454  print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
1455  } else {
1456  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.$valtoshow.'">';
1457  }
1458  } else {
1459  $valtoshow = $amount;
1460  if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) {
1461  $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
1462  $amount = $valtoshow;
1463  }
1464  print '<b>'.price($valtoshow).'</b>';
1465  print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
1466  print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
1467  }
1468  // Currency
1469  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1470  print '<input type="hidden" name="currency" value="'.$currency.'">';
1471  print '</td></tr>'."\n";
1472 
1473  // Tag
1474  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
1475  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
1476  print '<input type="hidden" name="tag" value="'.$tag.'">';
1477  print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1478  print '</td></tr>'."\n";
1479 
1480  // Shipping address
1481  $shipToName = $member->getFullName($langs);
1482  $shipToStreet = $member->address;
1483  $shipToCity = $member->town;
1484  $shipToState = $member->state_code;
1485  $shipToCountryCode = $member->country_code;
1486  $shipToZip = $member->zip;
1487  $shipToStreet2 = '';
1488  $phoneNum = $member->phone;
1489  if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip)
1490  {
1491  print '<!-- Shipping address information -->';
1492  print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1493  print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1494  print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1495  print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1496  print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1497  print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1498  print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1499  print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1500  } else {
1501  print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1502  }
1503  if (is_object($member->thirdparty)) print '<input type="hidden" name="thirdparty_id" value="'.$member->thirdparty->id.'">'."\n";
1504  print '<input type="hidden" name="email" value="'.$member->email.'">'."\n";
1505  $labeldesc = $langs->trans("PaymentSubscription");
1506  if (GETPOST('desc', 'alpha')) $labeldesc = GETPOST('desc', 'alpha');
1507  print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1508 }
1509 
1510 // Payment on donation
1511 if ($source == 'donation')
1512 {
1513  $found = true;
1514  $langs->load("don");
1515 
1516  require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
1517 
1518  $don = new Don($db);
1519  $result = $don->fetch($ref);
1520  if ($result <= 0)
1521  {
1522  $mesg = $don->error;
1523  $error++;
1524  } else {
1525  $don->fetch_thirdparty();
1526  }
1527  $object = $don;
1528 
1529  if ($action != 'dopayment') // Do not change amount if we just click on first dopayment
1530  {
1531  $amount = $subscription->total_ttc;
1532  if (GETPOST("amount", 'alpha')) $amount = GETPOST("amount", 'alpha');
1533  $amount = price2num($amount);
1534  }
1535 
1536  if (GETPOST('fulltag', 'alpha')) {
1537  $fulltag = GETPOST('fulltag', 'alpha');
1538  } else {
1539  $fulltag = 'DON='.$don->ref.'.DAT='.dol_print_date(dol_now(), '%Y%m%d%H%M%S');
1540  if (!empty($TAG)) { $tag = $TAG; $fulltag .= '.TAG='.$TAG; }
1541  }
1542  $fulltag = dol_string_unaccent($fulltag);
1543 
1544  // Creditor
1545  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Creditor");
1546  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>'.$creditor.'</b>';
1547  print '<input type="hidden" name="creditor" value="'.$creditor.'">';
1548  print '</td></tr>'."\n";
1549 
1550  // Debitor
1551  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("ThirdParty");
1552  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b>';
1553  if ($don->morphy == 'mor' && !empty($don->societe)) print $don->societe;
1554  else print $don->getFullName($langs);
1555  print '</b>';
1556  print '</td></tr>'."\n";
1557 
1558  // Object
1559  $text = '<b>'.$langs->trans("PaymentDonation").'</b>';
1560  if (GETPOST('desc', 'alpha')) $text = '<b>'.$langs->trans(GETPOST('desc', 'alpha')).'</b>';
1561  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Designation");
1562  print '</td><td class="CTableRow'.($var ? '1' : '2').'">'.$text;
1563  print '<input type="hidden" name="source" value="'.dol_escape_htmltag($source).'">';
1564  print '<input type="hidden" name="ref" value="'.dol_escape_htmltag($don->ref).'">';
1565  print '</td></tr>'."\n";
1566 
1567  // Amount
1568  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("Amount");
1569  if (empty($amount))
1570  {
1571  if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) print ' ('.$langs->trans("ToComplete");
1572  if (!empty($conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO)) print ' - <a href="'.$conf->global->MEMBER_EXT_URL_SUBSCRIPTION_INFO.'" rel="external" target="_blank">'.$langs->trans("SeeHere").'</a>';
1573  if (empty($conf->global->MEMBER_NEWFORM_AMOUNT)) print ')';
1574  }
1575  print '</td><td class="CTableRow'.($var ? '1' : '2').'">';
1576  $valtoshow = '';
1577  if (empty($amount) || !is_numeric($amount))
1578  {
1579  $valtoshow = price2num(GETPOST("newamount", 'alpha'), 'MT');
1580  // force default subscription amount to value defined into constant...
1581  if (empty($valtoshow))
1582  {
1583  if (!empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) {
1584  if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
1585  $valtoshow = $conf->global->MEMBER_NEWFORM_AMOUNT;
1586  }
1587  } else {
1588  if (!empty($conf->global->MEMBER_NEWFORM_AMOUNT)) {
1589  $amount = $conf->global->MEMBER_NEWFORM_AMOUNT;
1590  }
1591  }
1592  }
1593  }
1594  if (empty($amount) || !is_numeric($amount))
1595  {
1596  //$valtoshow=price2num(GETPOST("newamount",'alpha'),'MT');
1597  if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
1598  print '<input type="hidden" name="amount" value="'.price2num(GETPOST("amount", 'alpha'), 'MT').'">';
1599  print '<input class="flat maxwidth75" type="text" name="newamount" value="'.$valtoshow.'">';
1600  } else {
1601  $valtoshow = $amount;
1602  if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) {
1603  $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow);
1604  $amount = $valtoshow;
1605  }
1606  print '<b>'.price($valtoshow).'</b>';
1607  print '<input type="hidden" name="amount" value="'.$valtoshow.'">';
1608  print '<input type="hidden" name="newamount" value="'.$valtoshow.'">';
1609  }
1610  // Currency
1611  print ' <b>'.$langs->trans("Currency".$currency).'</b>';
1612  print '<input type="hidden" name="currency" value="'.$currency.'">';
1613  print '</td></tr>'."\n";
1614 
1615  // Tag
1616  print '<tr class="CTableRow'.($var ? '1' : '2').'"><td class="CTableRow'.($var ? '1' : '2').'">'.$langs->trans("PaymentCode");
1617  print '</td><td class="CTableRow'.($var ? '1' : '2').'"><b style="word-break: break-all;">'.$fulltag.'</b>';
1618  print '<input type="hidden" name="tag" value="'.$tag.'">';
1619  print '<input type="hidden" name="fulltag" value="'.$fulltag.'">';
1620  print '</td></tr>'."\n";
1621 
1622  // Shipping address
1623  $shipToName = $don->getFullName($langs);
1624  $shipToStreet = $don->address;
1625  $shipToCity = $don->town;
1626  $shipToState = $don->state_code;
1627  $shipToCountryCode = $don->country_code;
1628  $shipToZip = $don->zip;
1629  $shipToStreet2 = '';
1630  $phoneNum = $don->phone;
1631  if ($shipToName && $shipToStreet && $shipToCity && $shipToCountryCode && $shipToZip)
1632  {
1633  print '<!-- Shipping address information -->';
1634  print '<input type="hidden" name="shipToName" value="'.$shipToName.'">'."\n";
1635  print '<input type="hidden" name="shipToStreet" value="'.$shipToStreet.'">'."\n";
1636  print '<input type="hidden" name="shipToCity" value="'.$shipToCity.'">'."\n";
1637  print '<input type="hidden" name="shipToState" value="'.$shipToState.'">'."\n";
1638  print '<input type="hidden" name="shipToCountryCode" value="'.$shipToCountryCode.'">'."\n";
1639  print '<input type="hidden" name="shipToZip" value="'.$shipToZip.'">'."\n";
1640  print '<input type="hidden" name="shipToStreet2" value="'.$shipToStreet2.'">'."\n";
1641  print '<input type="hidden" name="phoneNum" value="'.$phoneNum.'">'."\n";
1642  } else {
1643  print '<!-- Shipping address not complete, so we don t use it -->'."\n";
1644  }
1645  if (is_object($don->thirdparty)) print '<input type="hidden" name="thirdparty_id" value="'.$don->thirdparty->id.'">'."\n";
1646  print '<input type="hidden" name="email" value="'.$don->email.'">'."\n";
1647  $labeldesc = $langs->trans("PaymentSubscription");
1648  if (GETPOST('desc', 'alpha')) $labeldesc = GETPOST('desc', 'alpha');
1649  print '<input type="hidden" name="desc" value="'.dol_escape_htmltag($labeldesc).'">'."\n";
1650 }
1651 
1652 
1653 if (!$found && !$mesg) $mesg = $langs->trans("ErrorBadParameters");
1654 
1655 if ($mesg) print '<tr><td align="center" colspan="2"><br><div class="warning">'.dol_escape_htmltag($mesg).'</div></td></tr>'."\n";
1656 
1657 print '</table>'."\n";
1658 print "\n";
1659 
1660 
1661 // Show all payment mode buttons (Stripe, Paypal, ...)
1662 if ($action != 'dopayment')
1663 {
1664  if ($found && !$error) // We are in a management option and no error
1665  {
1666  // Check status of the object (Invoice) to verify if it is paid by external payment modules (ie Payzen, ...)
1667  $parameters = [
1668  'source' => $source,
1669  'object' => $object
1670  ];
1671  $reshook = $hookmanager->executeHooks('doCheckStatus', $parameters, $object, $action);
1672  if ($source == 'order' && $object->billed)
1673  {
1674  print '<br><br><span class="amountpaymentcomplete size15x">'.$langs->trans("OrderBilled").'</span>';
1675  } elseif ($source == 'invoice' && $object->paye)
1676  {
1677  print '<br><br><span class="amountpaymentcomplete size15x">'.$langs->trans("InvoicePaid").'</span>';
1678  } elseif ($source == 'donation' && $object->paid)
1679  {
1680  print '<br><br><span class="amountpaymentcomplete size15x">'.$langs->trans("DonationPaid").'</span>';
1681  } else {
1682  // Membership can be paid and we still allow to make renewal
1683  if ($source == 'membersubscription' && $object->datefin > dol_now())
1684  {
1685  $langs->load("members");
1686  print '<br><span class="amountpaymentcomplete size15x">'.$langs->trans("MembershipPaid", dol_print_date($object->datefin, 'day')).'</span><br>';
1687  print '<div class="opacitymedium margintoponly">'.$langs->trans("PaymentWillBeRecordedForNextPeriod").'</div>';
1688  }
1689 
1690  // Buttons for all payments registration methods
1691 
1692  // This hook is used to add Button to newpayment.php for external payment modules (ie Payzen, ...)
1693  $parameters = [
1694  'paymentmethod' => $paymentmethod
1695  ];
1696  $reshook = $hookmanager->executeHooks('doAddButton', $parameters, $object, $action);
1697  if ((empty($paymentmethod) || $paymentmethod == 'paybox') && !empty($conf->paybox->enabled))
1698  {
1699  print '<div class="button buttonpayment" id="div_dopayment_paybox"><span class="fa fa-credit-card"></span> <input class="" type="submit" id="dopayment_paybox" name="dopayment_paybox" value="'.$langs->trans("PayBoxDoPayment").'">';
1700  print '<br>';
1701  print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span>';
1702  print '</div>';
1703  print '<script>
1704  $( document ).ready(function() {
1705  $("#div_dopayment_paybox").click(function(){
1706  $("#dopayment_paybox").click();
1707  });
1708  $("#dopayment_paybox").click(function(e){
1709  $("#div_dopayment_paybox").css( \'cursor\', \'wait\' );
1710  e.stopPropagation();
1711  });
1712  });
1713  </script>
1714  ';
1715  }
1716 
1717  if ((empty($paymentmethod) || $paymentmethod == 'stripe') && !empty($conf->stripe->enabled))
1718  {
1719  print '<div class="button buttonpayment" id="div_dopayment_stripe"><span class="fa fa-credit-card"></span> <input class="" type="submit" id="dopayment_stripe" name="dopayment_stripe" value="'.$langs->trans("StripeDoPayment").'">';
1720  print '<input type="hidden" name="noidempotency" value="'.GETPOST('noidempotency', 'int').'">';
1721  print '<br>';
1722  print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span>';
1723  print '</div>';
1724  print '<script>
1725  $( document ).ready(function() {
1726  $("#div_dopayment_stripe").click(function(){
1727  $("#dopayment_stripe").click();
1728  });
1729  $("#dopayment_stripe").click(function(e){
1730  $("#div_dopayment_stripe").css( \'cursor\', \'wait\' );
1731  e.stopPropagation();
1732  return true;
1733  });
1734  });
1735  </script>
1736  ';
1737  }
1738 
1739  if ((empty($paymentmethod) || $paymentmethod == 'paypal') && !empty($conf->paypal->enabled))
1740  {
1741  if (empty($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY)) $conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY = 'integral';
1742 
1743  print '<div class="button buttonpayment" id="div_dopayment_paypal">';
1744  if ($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY != 'integral') {
1745  print '<div style="line-height: 1em">&nbsp;</div>';
1746  }
1747  print '<span class="fa fa-paypal"></span> <input class="" type="submit" id="dopayment_paypal" name="dopayment_paypal" value="'.$langs->trans("PaypalDoPayment").'">';
1748  if ($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY == 'integral')
1749  {
1750  print '<br>';
1751  print '<span class="buttonpaymentsmall">'.$langs->trans("CreditOrDebitCard").'</span><span class="buttonpaymentsmall"> - </span>';
1752  print '<span class="buttonpaymentsmall">'.$langs->trans("PayPalBalance").'</span>';
1753  }
1754  if ($conf->global->PAYPAL_API_INTEGRAL_OR_PAYPALONLY == 'paypalonly')
1755  {
1756  //print '<br>';
1757  //print '<span class="buttonpaymentsmall">'.$langs->trans("PayPalBalance").'"></span>';
1758  }
1759  print '</div>';
1760  print '<script>
1761  $( document ).ready(function() {
1762  $("#div_dopayment_paypal").click(function(){
1763  $("#dopayment_paypal").click();
1764  });
1765  $("#dopayment_paypal").click(function(e){
1766  $("#div_dopayment_paypal").css( \'cursor\', \'wait\' );
1767  e.stopPropagation();
1768  return true;
1769  });
1770  });
1771  </script>
1772  ';
1773  }
1774  }
1775  } else {
1776  dol_print_error_email('ERRORNEWPAYMENT');
1777  }
1778 } else {
1779  // Print
1780 }
1781 
1782 print '</td></tr>'."\n";
1783 
1784 print '</table>'."\n";
1785 
1786 print '</form>'."\n";
1787 print '</div>'."\n";
1788 print '<br>';
1789 
1790 
1791 
1792 // Add more content on page for some services
1793 if (preg_match('/^dopayment/', $action)) // If we choosed/click on the payment mode
1794 {
1795  // Stripe
1796  if (GETPOST('dopayment_stripe', 'alpha'))
1797  {
1798  // Personalized checkout
1799  print '<style>
1804  .StripeElement {
1805  background-color: white;
1806  padding: 8px 12px;
1807  border-radius: 4px;
1808  border: 1px solid transparent;
1809  box-shadow: 0 1px 3px 0 #e6ebf1;
1810  -webkit-transition: box-shadow 150ms ease;
1811  transition: box-shadow 150ms ease;
1812  }
1813 
1814  .StripeElement--focus {
1815  box-shadow: 0 1px 3px 0 #cfd7df;
1816  }
1817 
1818  .StripeElement--invalid {
1819  border-color: #fa755a;
1820  }
1821 
1822  .StripeElement--webkit-autofill {
1823  background-color: #fefde5 !important;
1824  }
1825  </style>';
1826 
1827  print '<br>';
1828 
1829  print '<!-- Form payment-form STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION = '.$conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION.' STRIPE_USE_NEW_CHECKOUT = '.$conf->global->STRIPE_USE_NEW_CHECKOUT.' -->'."\n";
1830  print '<form action="'.$_SERVER['REQUEST_URI'].'" method="POST" id="payment-form">'."\n";
1831 
1832  print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
1833  print '<input type="hidden" name="dopayment_stripe" value="1">'."\n";
1834  print '<input type="hidden" name="action" value="charge">'."\n";
1835  print '<input type="hidden" name="tag" value="'.$TAG.'">'."\n";
1836  print '<input type="hidden" name="s" value="'.$source.'">'."\n";
1837  print '<input type="hidden" name="ref" value="'.$REF.'">'."\n";
1838  print '<input type="hidden" name="fulltag" value="'.$FULLTAG.'">'."\n";
1839  print '<input type="hidden" name="suffix" value="'.$suffix.'">'."\n";
1840  print '<input type="hidden" name="securekey" value="'.$SECUREKEY.'">'."\n";
1841  print '<input type="hidden" name="e" value="'.$entity.'" />';
1842  print '<input type="hidden" name="amount" value="'.$amount.'">'."\n";
1843  print '<input type="hidden" name="currency" value="'.$currency.'">'."\n";
1844  print '<input type="hidden" name="forcesandbox" value="'.GETPOST('forcesandbox', 'int').'" />';
1845  print '<input type="hidden" name="email" value="'.GETPOST('email', 'alpha').'" />';
1846  print '<input type="hidden" name="thirdparty_id" value="'.GETPOST('thirdparty_id', 'int').'" />';
1847 
1848  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION) || !empty($conf->global->STRIPE_USE_NEW_CHECKOUT)) // Use a SCA ready method
1849  {
1850  require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
1851 
1852  $service = 'StripeLive';
1853  $servicestatus = 1;
1854  if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
1855  {
1856  $service = 'StripeTest';
1857  $servicestatus = 0;
1858  }
1859 
1860  $stripe = new Stripe($db);
1861  $stripeacc = $stripe->getStripeAccount($service);
1862  $stripecu = null;
1863  if (is_object($object) && is_object($object->thirdparty)) $stripecu = $stripe->customerStripe($object->thirdparty, $stripeacc, $servicestatus, 1);
1864 
1865  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
1866  {
1867  $noidempotency_key = (GETPOSTISSET('noidempotency') ? GETPOST('noidempotency', 'int') : 0); // By default noidempotency is unset, so we must use a different tag/ref for each payment. If set, we can pay several times the same tag/ref.
1868  $paymentintent = $stripe->getPaymentIntent($amount, $currency, $tag, 'Stripe payment: '.$fulltag.(is_object($object) ? ' ref='.$object->ref : ''), $object, $stripecu, $stripeacc, $servicestatus, 0, 'automatic', false, null, 0, $noidempotency_key);
1869  // The paymentintnent has status 'requires_payment_method' (even if paymentintent was already paid)
1870  //var_dump($paymentintent);
1871  if ($stripe->error) setEventMessages($stripe->error, null, 'errors');
1872  }
1873  }
1874 
1875  //if (empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION) || ! empty($paymentintent))
1876  //{
1877  print '
1878  <table id="dolpaymenttable" summary="Payment form" class="center">
1879  <tbody><tr><td class="textpublicpayment">';
1880 
1881  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
1882  {
1883  print '<div id="payment-request-button"><!-- A Stripe Element will be inserted here. --></div>';
1884  }
1885 
1886  print '<div class="form-row left">';
1887  print '<label for="card-element">'.$langs->trans("CreditOrDebitCard").'</label>';
1888 
1889  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
1890  {
1891  print '<br><input id="cardholder-name" class="marginbottomonly" name="cardholder-name" value="" type="text" placeholder="'.$langs->trans("CardOwner").'" autocomplete="off" autofocus required>';
1892  }
1893 
1894  print '<div id="card-element">
1895  <!-- a Stripe Element will be inserted here. -->
1896  </div>';
1897 
1898  print '<!-- Used to display form errors -->
1899  <div id="card-errors" role="alert"></div>
1900  </div>';
1901 
1902  print '<br>';
1903  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>';
1904  print '<img id="hourglasstopay" class="hidden" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/working.gif">';
1905 
1906  print '</td></tr></tbody>';
1907  print '</table>';
1908  //}
1909 
1910  if (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
1911  {
1912  if (empty($paymentintent))
1913  {
1914  print '<center>'.$langs->trans("Error").'</center>';
1915  } else {
1916  print '<input type="hidden" name="paymentintent_id" value="'.$paymentintent->id.'">';
1917  //$_SESSION["paymentintent_id"] = $paymentintent->id;
1918  }
1919  }
1920 
1921  print '</form>'."\n";
1922 
1923 
1924  // JS Code for Stripe
1925  if (empty($stripearrayofkeys['publishable_key']))
1926  {
1927  $langs->load("errors");
1928  print info_admin($langs->trans("ErrorModuleSetupNotComplete", $langs->transnoentitiesnoconv("Stripe")), 0, 0, 'error');
1929  } else {
1930  print '<!-- JS Code for Stripe components -->';
1931  print '<script src="https://js.stripe.com/v3/"></script>'."\n";
1932  print '<!-- urllogofull = '.$urllogofull.' -->'."\n";
1933 
1934  // Code to ask the credit card. This use the default "API version". No way to force API version when using JS code.
1935  print '<script type="text/javascript" language="javascript">'."\n";
1936 
1937  if (!empty($conf->global->STRIPE_USE_NEW_CHECKOUT))
1938  {
1939  $amountstripe = $amount;
1940 
1941  // Correct the amount according to unit of currency
1942  // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
1943  $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
1944  if (!in_array($currency, $arrayzerounitcurrency)) $amountstripe = $amountstripe * 100;
1945 
1946  $ipaddress = getUserRemoteIP();
1947  $metadata = array('dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress);
1948  if (is_object($object))
1949  {
1950  $metadata['dol_type'] = $object->element;
1951  $metadata['dol_id'] = $object->id;
1952 
1953  $ref = $object->ref;
1954  }
1955 
1956  try {
1957  $arrayforpaymentintent = array(
1958  'description'=>'Stripe payment: '.$FULLTAG.($ref ? ' ref='.$ref : ''),
1959  "metadata" => $metadata
1960  );
1961  if ($TAG) $arrayforpaymentintent["statement_descriptor"] = dol_trunc($TAG, 10, 'right', 'UTF-8', 1); // 22 chars that appears on bank receipt (company + description)
1962 
1963  $arrayforcheckout = array(
1964  'payment_method_types' => array('card'),
1965  'line_items' => array(array(
1966  'name' => $langs->transnoentitiesnoconv("Payment").' '.$TAG, // Label of product line
1967  'description' => 'Stripe payment: '.$FULLTAG.($ref ? ' ref='.$ref : ''),
1968  'amount' => $amountstripe,
1969  'currency' => $currency,
1970  //'images' => array($urllogofull),
1971  'quantity' => 1,
1972  )),
1973  'client_reference_id' => $FULLTAG,
1974  'success_url' => $urlok,
1975  'cancel_url' => $urlko,
1976  'payment_intent_data' => $arrayforpaymentintent
1977  );
1978  if ($stripecu) $arrayforcheckout['customer'] = $stripecu;
1979  elseif (GETPOST('email', 'alpha') && isValidEmail(GETPOST('email', 'alpha'))) $arrayforcheckout['customer_email'] = GETPOST('email', 'alpha');
1980  $sessionstripe = \Stripe\Checkout\Session::create($arrayforcheckout);
1981 
1982  $remoteip = getUserRemoteIP();
1983 
1984  // Save some data for the paymentok
1985  $_SESSION["currencyCodeType"] = $currency;
1986  $_SESSION["paymentType"] = '';
1987  $_SESSION["FinalPaymentAmt"] = $amount;
1988  $_SESSION['ipaddress'] = ($remoteip ? $remoteip : 'unknown'); // Payer ip
1989  $_SESSION['payerID'] = is_object($stripecu) ? $stripecu->id : '';
1990  $_SESSION['TRANSACTIONID'] = $sessionstripe->id;
1991  } catch (Exception $e)
1992  {
1993  print $e->getMessage();
1994  }
1995  ?>
1996  // Code for payment with option STRIPE_USE_NEW_CHECKOUT set
1997 
1998  // Create a Stripe client.
1999  var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php ?>');
2000 
2001  // Create an instance of Elements
2002  var elements = stripe.elements();
2003 
2004  // Custom styling can be passed to options when creating an Element.
2005  // (Note that this demo uses a wider set of styles than the guide below.)
2006  var style = {
2007  base: {
2008  color: '#32325d',
2009  lineHeight: '24px',
2010  fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
2011  fontSmoothing: 'antialiased',
2012  fontSize: '16px',
2013  '::placeholder': {
2014  color: '#aab7c4'
2015  }
2016  },
2017  invalid: {
2018  color: '#fa755a',
2019  iconColor: '#fa755a'
2020  }
2021  };
2022 
2023  var cardElement = elements.create('card', {style: style});
2024 
2025  // Comment this to avoid the redirect
2026  stripe.redirectToCheckout({
2027  // Make the id field from the Checkout Session creation API response
2028  // available to this file, so you can provide it as parameter here
2029  // instead of the {{CHECKOUT_SESSION_ID}} placeholder.
2030  sessionId: '<?php print $sessionstripe->id; ?>'
2031  }).then(function (result) {
2032  // If `redirectToCheckout` fails due to a browser or network
2033  // error, display the localized error message to your customer
2034  // using `result.error.message`.
2035  });
2036 
2037 
2038  <?php
2039  } elseif (!empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
2040  {
2041  ?>
2042  // Code for payment with option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION set
2043 
2044  // Create a Stripe client.
2045  var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php ?>');
2046 
2047  // Create an instance of Elements
2048  var elements = stripe.elements();
2049 
2050  // Custom styling can be passed to options when creating an Element.
2051  // (Note that this demo uses a wider set of styles than the guide below.)
2052  var style = {
2053  base: {
2054  color: '#32325d',
2055  lineHeight: '24px',
2056  fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
2057  fontSmoothing: 'antialiased',
2058  fontSize: '16px',
2059  '::placeholder': {
2060  color: '#aab7c4'
2061  }
2062  },
2063  invalid: {
2064  color: '#fa755a',
2065  iconColor: '#fa755a'
2066  }
2067  };
2068 
2069  var cardElement = elements.create('card', {style: style});
2070 
2071  // Add an instance of the card Element into the `card-element` <div>
2072  cardElement.mount('#card-element');
2073 
2074  // Handle real-time validation errors from the card Element.
2075  cardElement.addEventListener('change', function(event) {
2076  var displayError = document.getElementById('card-errors');
2077  if (event.error) {
2078  console.log("Show event error (like 'Incorrect card number', ...)");
2079  displayError.textContent = event.error.message;
2080  } else {
2081  console.log("Reset error message");
2082  displayError.textContent = '';
2083  }
2084  });
2085 
2086  // Handle form submission
2087  var cardholderName = document.getElementById('cardholder-name');
2088  var cardButton = document.getElementById('buttontopay');
2089  var clientSecret = cardButton.dataset.secret;
2090 
2091  cardButton.addEventListener('click', function(event) {
2092  console.log("We click on buttontopay");
2093  event.preventDefault();
2094 
2095  if (cardholderName.value == '')
2096  {
2097  console.log("Field Card holder is empty");
2098  var displayError = document.getElementById('card-errors');
2099  displayError.textContent = '<?php print dol_escape_js($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CardOwner"))); ?>';
2100  }
2101  else
2102  {
2103  /* Disable button to pay and show hourglass cursor */
2104  jQuery('#hourglasstopay').show();
2105  jQuery('#buttontopay').hide();
2106 
2107  stripe.handleCardPayment(
2108  clientSecret, cardElement, {
2109  payment_method_data: {
2110  billing_details: {
2111  name: cardholderName.value
2112  <?php if (GETPOST('email', 'alpha') || (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->email))) { ?>, email: '<?php echo dol_escape_js(GETPOST('email', 'alpha') ? GETPOST('email', 'alpha') : $object->thirdparty->email); ?>'<?php } ?>
2113  <?php if (is_object($object) && is_object($object->thirdparty) && !empty($object->thirdparty->phone)) { ?>, phone: '<?php echo dol_escape_js($object->thirdparty->phone); ?>'<?php } ?>
2114  <?php if (is_object($object) && is_object($object->thirdparty)) { ?>, address: {
2115  city: '<?php echo dol_escape_js($object->thirdparty->town); ?>',
2116  <?php if ($object->thirdparty->country_code) { ?>country: '<?php echo dol_escape_js($object->thirdparty->country_code); ?>',<?php } ?>
2117  line1: '<?php echo dol_escape_js(preg_replace('/\s\s+/', ' ', $object->thirdparty->address)); ?>',
2118  postal_code: '<?php echo dol_escape_js($object->thirdparty->zip); ?>'
2119  }
2120  <?php } ?>
2121  }
2122  },
2123  save_payment_method: <?php if ($stripecu) { print 'true'; } else { print 'false'; } ?> /* true when a customer was provided when creating payment intent. true ask to save the card */
2124  }
2125  ).then(function(result) {
2126  console.log(result);
2127  if (result.error) {
2128  console.log("Error on result of handleCardPayment");
2129  jQuery('#buttontopay').show();
2130  jQuery('#hourglasstopay').hide();
2131  // Inform the user if there was an error
2132  var errorElement = document.getElementById('card-errors');
2133  errorElement.textContent = result.error.message;
2134  } else {
2135  // The payment has succeeded. Display a success message.
2136  console.log("No error on result of handleCardPayment, so we submit the form");
2137  // Submit the form
2138  jQuery('#buttontopay').hide();
2139  jQuery('#hourglasstopay').show();
2140  // Send form (action=charge that will do nothing)
2141  jQuery('#payment-form').submit();
2142  }
2143  });
2144  }
2145  });
2146 
2147  <?php
2148  } else // Old method (not SCA ready)
2149  {
2150  ?>
2151  // Old code for payment with option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION off and STRIPE_USE_NEW_CHECKOUT off
2152 
2153  // Create a Stripe client.
2154  var stripe = Stripe('<?php echo $stripearrayofkeys['publishable_key']; // Defined into config.php ?>');
2155 
2156  // Create an instance of Elements
2157  var elements = stripe.elements();
2158 
2159  // Custom styling can be passed to options when creating an Element.
2160  // (Note that this demo uses a wider set of styles than the guide below.)
2161  var style = {
2162  base: {
2163  color: '#32325d',
2164  lineHeight: '24px',
2165  fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
2166  fontSmoothing: 'antialiased',
2167  fontSize: '16px',
2168  '::placeholder': {
2169  color: '#aab7c4'
2170  }
2171  },
2172  invalid: {
2173  color: '#fa755a',
2174  iconColor: '#fa755a'
2175  }
2176  };
2177 
2178  // Create an instance of the card Element
2179  var card = elements.create('card', {style: style});
2180 
2181  // Add an instance of the card Element into the `card-element` <div>
2182  card.mount('#card-element');
2183 
2184  // Handle real-time validation errors from the card Element.
2185  card.addEventListener('change', function(event) {
2186  var displayError = document.getElementById('card-errors');
2187  if (event.error) {
2188  displayError.textContent = event.error.message;
2189  } else {
2190  displayError.textContent = '';
2191  }
2192  });
2193 
2194  // Handle form submission
2195  var form = document.getElementById('payment-form');
2196  console.log(form);
2197  form.addEventListener('submit', function(event) {
2198  event.preventDefault();
2199  <?php
2200  if (empty($conf->global->STRIPE_USE_3DSECURE)) // Ask credit card directly, no 3DS test
2201  {
2202  ?>
2203  /* Use token */
2204  stripe.createToken(card).then(function(result) {
2205  if (result.error) {
2206  // Inform the user if there was an error
2207  var errorElement = document.getElementById('card-errors');
2208  errorElement.textContent = result.error.message;
2209  } else {
2210  // Send the token to your server
2211  stripeTokenHandler(result.token);
2212  }
2213  });
2214  <?php
2215  } else // Ask credit card with 3DS test
2216  {
2217  ?>
2218  /* Use 3DS source */
2219  stripe.createSource(card).then(function(result) {
2220  if (result.error) {
2221  // Inform the user if there was an error
2222  var errorElement = document.getElementById('card-errors');
2223  errorElement.textContent = result.error.message;
2224  } else {
2225  // Send the source to your server
2226  stripeSourceHandler(result.source);
2227  }
2228  });
2229  <?php
2230  }
2231  ?>
2232  });
2233 
2234 
2235  /* Insert the Token into the form so it gets submitted to the server */
2236  function stripeTokenHandler(token) {
2237  // Insert the token ID into the form so it gets submitted to the server
2238  var form = document.getElementById('payment-form');
2239 
2240  var hiddenInput = document.createElement('input');
2241  hiddenInput.setAttribute('type', 'hidden');
2242  hiddenInput.setAttribute('name', 'stripeToken');
2243  hiddenInput.setAttribute('value', token.id);
2244  form.appendChild(hiddenInput);
2245 
2246  var hiddenInput2 = document.createElement('input');
2247  hiddenInput2.setAttribute('type', 'hidden');
2248  hiddenInput2.setAttribute('name', 'token');
2249  hiddenInput2.setAttribute('value', '<?php echo newToken(); ?>');
2250  form.appendChild(hiddenInput2);
2251 
2252  // Submit the form
2253  jQuery('#buttontopay').hide();
2254  jQuery('#hourglasstopay').show();
2255  console.log("submit token");
2256  form.submit();
2257  }
2258 
2259  /* Insert the Source into the form so it gets submitted to the server */
2260  function stripeSourceHandler(source) {
2261  // Insert the source ID into the form so it gets submitted to the server
2262  var form = document.getElementById('payment-form');
2263 
2264  var hiddenInput = document.createElement('input');
2265  hiddenInput.setAttribute('type', 'hidden');
2266  hiddenInput.setAttribute('name', 'stripeSource');
2267  hiddenInput.setAttribute('value', source.id);
2268  form.appendChild(hiddenInput);
2269 
2270  var hiddenInput2 = document.createElement('input');
2271  hiddenInput2.setAttribute('type', 'hidden');
2272  hiddenInput2.setAttribute('name', 'token');
2273  hiddenInput2.setAttribute('value', '<?php echo newToken(); ?>');
2274  form.appendChild(hiddenInput2);
2275 
2276  // Submit the form
2277  jQuery('#buttontopay').hide();
2278  jQuery('#hourglasstopay').show();
2279  console.log("submit source");
2280  form.submit();
2281  }
2282 
2283  <?php
2284  }
2285 
2286  print '</script>';
2287  }
2288  }
2289  // This hook is used to show the embedded form to make payments with external payment modules (ie Payzen, ...)
2290  $parameters = [
2291  'paymentmethod' => $paymentmethod,
2292  'amount' => price2num(GETPOST("newamount"), 'MT'),
2293  'tag' => GETPOST("tag", 'alpha'),
2294  'dopayment' => GETPOST('dopayment', 'alpha')
2295  ];
2296  $reshook = $hookmanager->executeHooks('doPayment', $parameters, $object, $action);
2297 }
2298 
2299 
2300 htmlPrintOnlinePaymentFooter($mysoc, $langs, 1, $suffix, $object);
2301 
2302 llxFooter('', 'public');
2303 
2304 $db->close();
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_hash($chain, $type= '0')
Returns a hash of a string.
getUserRemoteIP()
Return the IP of remote user.
Class to manage products or services.
dol_now($mode= 'auto')
Return date for now.
Class to manage contracts.
print_paybox_redirect($PRICE, $CURRENCY, $EMAIL, $urlok, $urlko, $TAG)
Create a redirect form to paybox form.
Definition: paybox.lib.php:39
Class to manage lines of contracts.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:108
Stripe class.
dol_print_error_email($prefixcode, $errormessage= '', $errormessages=array(), $morecss= 'error', $email= '')
Show a public email and error code to contact if technical error.
img_mime($file, $titlealt= '', $morecss= '')
Show MIME img of a file.
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...
llxHeader()
Empty header.
Definition: wrapper.php:45
Class to manage hooks.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
Class to manage customers orders.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
Class to manage members of a foundation.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
Class to manage subscriptions of foundation members.
print $_SERVER["PHP_SELF"]
Edit parameters.
dol_htmloutput_mesg($mesgstring= '', $mesgarray=array(), $style= 'ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
print
Draft customers invoices.
Definition: index.php:89
Class to manage donations.
Definition: don.class.php:37
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc= 'right', $stringencoding= 'UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding &#39;...&#39; if string larger than length.
Class to manage invoices.
llxFooter()
Empty footer.
Definition: wrapper.php:59
isValidEmail($address, $acceptsupervisorkey=0)
Return true if email syntax is ok.
if(!defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN'
Draft customers invoices.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin= '1', $morecss= '', $textfordropdown= '')
Show information for admin users or standard users.
print_paypal_redirect($paymentAmount, $currencyCodeType, $paymentType, $returnURL, $cancelURL, $tag)
Send redirect to paypal to browser.
Definition: paypal.lib.php:70