diff --git a/htdocs/compta/facture/prelevement.php b/htdocs/compta/facture/prelevement.php index 365fa59fdcb..39e6446b573 100644 --- a/htdocs/compta/facture/prelevement.php +++ b/htdocs/compta/facture/prelevement.php @@ -807,13 +807,13 @@ if ($object->id > 0) { print ''.$langs->trans("User").''; print ''.$langs->trans("Amount").''; print ''.$langs->trans("DateProcess").''; - print ' '; if ($type == 'bank-transfer') { print ''.$langs->trans("BankTransferReceipt").''; } else { print ''.$langs->trans("WithdrawalReceipt").''; } print ' '; + print ' '; print ''; $sql = "SELECT pfd.rowid, pfd.traite, pfd.date_demande as date_demande,"; @@ -864,9 +864,10 @@ if ($object->id > 0) { // Amount print ''.price($obj->amount).''; - // Ref of SEPA request + // Date process print ''.$langs->trans("OrderWaiting").''; + // Link to make payment now print ''; if (!empty($conf->global->STRIPE_SEPA_DIRECT_DEBIT)) { $langs->load("stripe"); @@ -874,8 +875,10 @@ if ($object->id > 0) { } print ''; + // print '-'; + // Actions print ''; print ''; print img_delete(); @@ -929,14 +932,21 @@ if ($object->id > 0) { print ''; + // Date print ''.dol_print_date($db->jdate($obj->date_demande), 'day')."\n"; + // User print ''; print $tmpuser->getNomUrl(1, '', 0, 0, 0, 0, 'login'); print ''; + // Amount print ''.price($obj->amount).''; + // Date process + print ''.dol_print_date($db->jdate($obj->date_traite), 'day')."\n"; + + // Link to payment request done print ''; if ($obj->fk_prelevement_bons > 0) { $withdrawreceipt = new BonPrelevement($db); @@ -946,10 +956,10 @@ if ($object->id > 0) { } print "\n"; + // print ' '; - print ''.dol_print_date($db->jdate($obj->date_traite), 'day')."\n"; - + // Actions print ' '; print "\n"; diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 3f53c3c4e94..7a8b5e3cbf7 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -865,7 +865,7 @@ abstract class CommonInvoice extends CommonObject /** - * Create a withdrawal request for a direct debit order or a credit transfer order. + * Create a withdrawal request at Stripe for a direct debit order or a credit transfer order. * Use the remain to pay excluding all existing open direct debit requests. * * @param User $fuser User asking the direct debit transfer @@ -900,6 +900,7 @@ abstract class CommonInvoice extends CommonObject $sql = "SELECT rowid, date_demande, amount, fk_facture, fk_facture_fourn"; $sql .= " FROM ".$this->db->prefix()."prelevement_demande"; + $sql .= " AND fk_facture = ".((int) $this->fk_facture); // Add a protection to not pay another invoice than current one $sql .= " WHERE rowid = ".((int) $did); dol_syslog(get_class($this)."::makeStripeSepaRequest 1", LOG_DEBUG); @@ -1035,9 +1036,9 @@ abstract class CommonInvoice extends CommonObject } - dol_syslog("makeStripeSepaRequest get stripe account", LOG_DEBUG); + dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG); $stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here) - dol_syslog("makeStripeSepaRequest get stripe account return " . json_encode($stripeacc), LOG_DEBUG); + dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG); if ($foundalternativestripeaccount) { if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage @@ -1072,101 +1073,64 @@ abstract class CommonInvoice extends CommonObject } if (!$error) { // Payment was not canceled - //erics card or sepa ? $sepaMode = false; + $stripecard = null; if ($companypaymentmode->type == 'ban') { $sepaMode = true; $stripecard = $stripe->sepaStripe($customer, $companypaymentmode, $stripeacc, $servicestatus, 0); - } else { - $stripecard = $stripe->cardStripe($customer, $companypaymentmode, $stripeacc, $servicestatus, 0); } - if ($stripecard) { // Can be card_... (old mode) or pm_... (new mode) + if ($stripecard) { // Can be src_... (for sepa) - Other card_... (old mode) or pm_... (new mode) should not happen here. $FULLTAG = 'INV=' . $this->id . '-CUS=' . $thirdparty->id; - $description = 'Stripe payment from doTakePaymentStripeForThirdparty: ' . $FULLTAG . ' ref=' . $this->ref; + $description = 'Stripe payment from makeStripeSepaRequest: ' . $FULLTAG . ' ref=' . $this->ref; $stripefailurecode = ''; $stripefailuremessage = ''; $stripefailuredeclinecode = ''; - if (preg_match('/^card_/', $stripecard->id)) { // Using old method - dol_syslog("* Create charge on card " . $stripecard->id . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG); + // Using new SCA method + dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG); - $ipaddress = getUserRemoteIP(); + // Create payment intent and charge payment (confirmnow = true) + $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $this, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1); - $charge = null; // Force reset of $charge, so, if already set from a previous fetch, it will be empty even if there is an exception at next step - try { - $charge = \Stripe\Charge::create([ - 'amount' => price2num($amountstripe, 'MU'), - 'currency' => $currency, - 'capture' => true, // Charge immediatly - 'description' => $description, - 'metadata' => ["FULLTAG" => $FULLTAG, 'Recipient' => $mysoc->name, 'dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress], - 'customer' => $customer->id, - //'customer' => 'bidon_to_force_error', // To use to force a stripe error - 'source' => $stripecard, - 'statement_descriptor' => dol_trunc('INV=' . $this->id, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description) - ]); - } catch (\Stripe\Error\Card $e) { - // Since it's a decline, Stripe_CardError will be caught - $body = $e->getJsonBody(); - $err = $body['error']; + $charge = new stdClass(); + //erics add processing sepa is like success ? + if ($paymentintent->status === 'succeeded' || $paymentintent->status === 'processing') { + $charge->status = 'ok'; + $charge->id = $paymentintent->id; + $charge->customer = $customer->id; + } elseif ($paymentintent->status === 'requires_action') { + //paymentintent->status may be => 'requires_action' (no error in such a case) + dol_syslog(var_export($paymentintent, true), LOG_DEBUG); - $stripefailurecode = $err['code']; - $stripefailuremessage = $err['message']; - $stripefailuredeclinecode = $err['decline_code']; - } catch (Exception $e) { - $stripefailurecode = 'UnknownChargeError'; - $stripefailuremessage = $e->getMessage(); - } - } else { // Using new SCA method - if ($sepaMode) { - dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG); - } else { - dol_syslog("* Create payment on card " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG); - } + $charge->status = 'failed'; + $charge->customer = $customer->id; + $charge->failure_code = $stripe->code; + $charge->failure_message = $stripe->error; + $charge->failure_declinecode = $stripe->declinecode; + $stripefailurecode = $stripe->code; + $stripefailuremessage = 'Action required. Contact the support at ';// . $conf->global->SELLYOURSAAS_MAIN_EMAIL; + $stripefailuredeclinecode = $stripe->declinecode; + } else { + dol_syslog(var_export($paymentintent, true), LOG_DEBUG); - // Create payment intent and charge payment (confirmnow = true) - $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1); - - $charge = new stdClass(); - //erics add processing sepa is like success ? - if ($paymentintent->status === 'succeeded' || $paymentintent->status === 'processing') { - $charge->status = 'ok'; - $charge->id = $paymentintent->id; - $charge->customer = $customer->id; - } elseif ($paymentintent->status === 'requires_action') { - //paymentintent->status may be => 'requires_action' (no error in such a case) - dol_syslog(var_export($paymentintent, true), LOG_DEBUG); - - $charge->status = 'failed'; - $charge->customer = $customer->id; - $charge->failure_code = $stripe->code; - $charge->failure_message = $stripe->error; - $charge->failure_declinecode = $stripe->declinecode; - $stripefailurecode = $stripe->code; - $stripefailuremessage = 'Action required. Contact the support at ';// . $conf->global->SELLYOURSAAS_MAIN_EMAIL; - $stripefailuredeclinecode = $stripe->declinecode; - } else { - dol_syslog(var_export($paymentintent, true), LOG_DEBUG); - - $charge->status = 'failed'; - $charge->customer = $customer->id; - $charge->failure_code = $stripe->code; - $charge->failure_message = $stripe->error; - $charge->failure_declinecode = $stripe->declinecode; - $stripefailurecode = $stripe->code; - $stripefailuremessage = $stripe->error; - $stripefailuredeclinecode = $stripe->declinecode; - } - - //var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode); - //exit; + $charge->status = 'failed'; + $charge->customer = $customer->id; + $charge->failure_code = $stripe->code; + $charge->failure_message = $stripe->error; + $charge->failure_declinecode = $stripe->declinecode; + $stripefailurecode = $stripe->code; + $stripefailuremessage = $stripe->error; + $stripefailuredeclinecode = $stripe->declinecode; } + //var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode); + //exit; + // Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...) if (empty($charge) || $charge->status == 'failed') { - dol_syslog('Failed to charge card or payment mode ' . $stripecard->id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode, LOG_WARNING); + dol_syslog('Failed to charge payment mode ' . $stripecard->id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode, LOG_WARNING); // Save a stripe payment was in error $this->stripechargeerror++; @@ -1202,20 +1166,20 @@ abstract class CommonInvoice extends CommonObject $errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : ''); } - $description = 'Stripe payment ERROR from doTakePaymentStripeForThirdparty: ' . $FULLTAG; + $description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG; $postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')'; $this->errors[] = $errmsg; } else { - dol_syslog('Successfuly charge card ' . $stripecard->id); + dol_syslog('Successfuly charge direct debit ' . $stripecard->id); - $postactionmessages[] = 'Success to charge card (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')'; + $postactionmessages[] = 'Success to charge direct debit (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')'; // Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments // even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit. $this->stripechargedone++; // Default description used for label of event. Will be overwrite by another value later. - $description = 'Stripe payment OK (' . $charge->id . ') from doTakePaymentStripeForThirdparty: ' . $FULLTAG; + $description = 'Stripe payment OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG; $db = $this->db; @@ -1300,13 +1264,8 @@ abstract class CommonInvoice extends CommonObject if (!$errorforinvoice && isModEnabled('banque')) { dol_syslog('* Add payment to bank'); + // The bank used is the one defined into Stripe setup $bankaccountid = 0; - if ($paymentmethod == 'paybox') { - $bankaccountid = $conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS; - } - if ($paymentmethod == 'paypal') { - $bankaccountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS; - } if ($paymentmethod == 'stripe') { $bankaccountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS; } @@ -1323,7 +1282,7 @@ abstract class CommonInvoice extends CommonObject $error++; $errorforinvoice++; } else { - $postactionmessages[] = 'Bank transaction of payment created (by doTakePaymentStripeForThirdparty)'; + $postactionmessages[] = 'Bank transaction of payment created (by makeStripeSepaRequest)'; } } else { $postactionmessages[] = 'Setup of bank account to use in module ' . $paymentmethod . ' was not set. No way to record the payment.'; @@ -1334,55 +1293,24 @@ abstract class CommonInvoice extends CommonObject } if ($ispostactionok < 1) { - $description = 'Stripe payment OK (' . $charge->id . ' - ' . $amounttopay . ' ' . $conf->currency . ') but post action KO from doTakePaymentStripeForThirdparty: ' . $FULLTAG; + $description = 'Stripe payment OK (' . $charge->id . ' - ' . $amounttopay . ' ' . $conf->currency . ') but post action KO from makeStripeSepaRequest: ' . $FULLTAG; } else { - $description = 'Stripe payment+post action OK (' . $charge->id . ' - ' . $amounttopay . ' ' . $conf->currency . ') from doTakePaymentStripeForThirdparty: ' . $FULLTAG; + $description = 'Stripe payment+post action OK (' . $charge->id . ' - ' . $amounttopay . ' ' . $conf->currency . ') from makeStripeSepaRequest: ' . $FULLTAG; } } $object = $invoice; - // Send emails - $labeltouse = 'InvoicePaymentSuccess'; - $sendemailtocustomer = 1; - - if (empty($charge) || $charge->status == 'failed') { - $labeltouse = 'InvoicePaymentFailure'; - if ($noemailtocustomeriferror) { - $sendemailtocustomer = 0; - } // $noemailtocustomeriferror is set when error already reported on myaccount screen - } - - // Track an event - if (empty($charge) || $charge->status == 'failed') { - $actioncode = 'PAYMENT_STRIPE_KO'; - $extraparams = $stripefailurecode; - $extraparams .= (($extraparams && $stripefailuremessage) ? ' - ' : '') . $stripefailuremessage; - $extraparams .= (($extraparams && $stripefailuredeclinecode) ? ' - ' : '') . $stripefailuredeclinecode; - } else { - $actioncode = 'PAYMENT_STRIPE_OK'; - $extraparams = ''; - } + $actioncode = ''; + $extraparams = ''; } else { $error++; $errorforinvoice++; - dol_syslog("No card or payment method found for this stripe customer " . $customer->id, LOG_WARNING); - $this->errors[] = 'Failed to get card | payment method for stripe customer = ' . $customer->id; - - $labeltouse = 'InvoicePaymentFailure'; - $sendemailtocustomer = 1; - if ($noemailtocustomeriferror) { - $sendemailtocustomer = 0; - } // $noemailtocustomeriferror is set when error already reported on myaccount screen - - $description = 'Failed to find or use the payment mode - no credit card defined for the customer account'; - $stripefailurecode = 'BADPAYMENTMODE'; - $stripefailuremessage = 'Failed to find or use the payment mode - no credit card defined for the customer account'; - $postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')'; - + dol_syslog("No direct debit payment method found for this stripe customer " . $customer->id, LOG_WARNING); + $this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id; $object = $invoice; - $actioncode = 'PAYMENT_STRIPE_KO'; + $actioncode = ''; $extraparams = ''; } } else { @@ -1427,6 +1355,7 @@ abstract class CommonInvoice extends CommonObject $extraparams = ''; } + /* // Send email + create action after if ($sendemailtocustomer && $labeltouse) { dol_syslog("* Send email with result of payment - " . $labeltouse); @@ -1537,6 +1466,7 @@ abstract class CommonInvoice extends CommonObject } } } + */ if ($description) { dol_syslog("* Record event for payment result - " . $description); @@ -1588,18 +1518,12 @@ abstract class CommonInvoice extends CommonObject $this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?"; } - $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_demande("; - $sql .= "fk_facture, "; - $sql .= " amount, date_demande, fk_user_demande, ext_payment_id, ext_payment_site, sourcetype, entity)"; - $sql .= " VALUES (".$this->id; - $sql .= ",".((float) price2num($amount)); - $sql .= ",'".$this->db->idate($now)."'"; - $sql .= ",".((int) $fuser->id); - $sql .= ",'".$this->db->escape($stripe_id)."'"; - $sql .= ",'".$this->db->escape($stripe_uri)."'"; - $sql .= ",'".$this->db->escape($sourcetype)."'"; - $sql .= ",".$conf->entity; - $sql .= ")"; + // TODO Create a prelevement_bon ? + // For the moment no + + // We must update the direct debit payment request as "done" + $sql = "UPDATE".MAIN_DB_PREFIX."prelevement_demande SET traite = 1, date_traite = '".$this->db->idate(dol_now())."'"; + $sql .= "WHERE rowid = ".((int) $did); dol_syslog(get_class($this)."::makeStripeSepaRequest", LOG_DEBUG); $resql = $this->db->query($sql);