From 48b2cb83af29a9d54b333d224e6847faa3e6a969 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 16 Jun 2019 17:08:23 +0200 Subject: [PATCH] Close #11152 by a manual merge to keep only required things --- .../interface_80_modStripe_Stripe.class.php | 30 +++++-- htdocs/public/stripe/ipn.php | 89 ++++++++++++++++++- .../class/companypaymentmode.class.php | 20 ++--- htdocs/societe/class/societeaccount.class.php | 36 +++++++- htdocs/societe/paymentmodes.php | 3 +- htdocs/stripe/class/stripe.class.php | 64 +++++++++---- 6 files changed, 205 insertions(+), 37 deletions(-) diff --git a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php index 8282a09a43d..f9d28a0b984 100644 --- a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php +++ b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php @@ -148,32 +148,50 @@ class InterfaceStripe { $namecleaned = $object->name ? $object->name : null; $vatcleaned = $object->tva_intra ? $object->tva_intra : null; - - $taxinfo = array('type'=>'vat'); + $desccleaned = $object->name_alias ? $object->name_alias : null; + $taxexemptcleaned = $object->tva_assuj ? 'none' : 'exempt'; + $langcleaned = $object->default_lang ? array(substr($object->default_lang, 0, 2)) : null; + /*$taxinfo = array('type'=>'vat'); if ($vatcleaned) { $taxinfo["tax_id"] = $vatcleaned; } // We force data to "null" if not defined as expected by Stripe - if (empty($vatcleaned)) $taxinfo=null; + if (empty($vatcleaned)) $taxinfo=null;*/ // Detect if we change a Stripe info (email, description, vat id) $changerequested = 0; if (! empty($object->email) && $object->email != $customer->email) $changerequested++; - if ($namecleaned != $customer->description) $changerequested++; + /* if ($namecleaned != $customer->description) $changerequested++; if (! isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned)) $changerequested++; elseif (isset($customer->tax_info['tax_id']) && is_null($vatcleaned)) $changerequested++; elseif (isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned)) { if ($vatcleaned != $customer->tax_info['tax_id']) $changerequested++; + } */ + if ($namecleaned != $customer->name) $changerequested++; + if ($desccleaned != $customer->description) $changerequested++; + if (($customer->tax_exempt == 'exempt' && ! $object->tva_assuj) || (! $customer->tax_exempt == 'exempt' && empty($object->tva_assuj))) $changerequested++; + if (! isset($customer->tax_ids['data']) && ! is_null($vatcleaned)) $changerequested++; + elseif (isset($customer->tax_ids['data']) && is_null($vatcleaned)) $changerequested++; + elseif (isset($customer->tax_ids['data']) && ! is_null($vatcleaned)) + { + $taxinfo = reset($customer->tax_ids['data']); + if (isset($taxinfo->value) && $vatcleaned != $taxinfo->value) $changerequested++; } if ($changerequested) { - if (! empty($object->email)) $customer->email = $object->email; + /*if (! empty($object->email)) $customer->email = $object->email; $customer->description = $namecleaned; if (empty($taxinfo)) $customer->tax_info = array('type'=>'vat', 'tax_id'=>null); - else $customer->tax_info = $taxinfo; + else $customer->tax_info = $taxinfo; */ + $customer->name = $namecleaned; + $customer->description = $desccleaned; + $customer->preferred_locales = $langcleaned; + $customer->tax_exempt = $taxexemptcleaned; + if (! empty($vatcleaned)) $customer->tax_ids = array('object'=>'list', 'data'=>array('value'=>$vatcleaned)); + else $customer->tax_ids = null; $customer->save(); } diff --git a/htdocs/public/stripe/ipn.php b/htdocs/public/stripe/ipn.php index 8795031592a..bfd1788e12f 100644 --- a/htdocs/public/stripe/ipn.php +++ b/htdocs/public/stripe/ipn.php @@ -293,7 +293,6 @@ elseif ($event->type == 'customer.source.delete') { elseif ($event->type == 'customer.deleted') { $db->begin(); $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_account WHERE key_account = '".$db->escape($event->data->object->id)."' and site='stripe'"; - dol_syslog(get_class($this) . "::delete sql=" . $sql, LOG_DEBUG); $db->query($sql); $db->commit(); } @@ -309,6 +308,94 @@ elseif ($event->type == 'checkout.session.completed') // Called when making pay // TODO: create fees // TODO: Redirect to paymentok.php } +elseif ($event->type == 'payment_method.attached') { + require_once DOL_DOCUMENT_ROOT.'/societe/class/companypaymentmode.class.php'; + require_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php'; + $societeaccount = new SocieteAccount($db); + + $companypaymentmode = new CompanyPaymentMode($db); + + $idthirdparty = $societeaccount->getThirdPartyID($db->escape($event->data->object->customer), 'stripe', $servicestatus); + if ($idthirdparty > 0) // If the payment mode is on an external customer that is known in societeaccount, we can create the payment mode + { + $companypaymentmode->stripe_card_ref = $db->escape($event->data->object->id); + $companypaymentmode->fk_soc = $idthirdparty; + $companypaymentmode->bank = null; + $companypaymentmode->label = null; + $companypaymentmode->number = $db->escape($event->data->object->id); + $companypaymentmode->last_four = $db->escape($event->data->object->card->last4); + $companypaymentmode->card_type = $db->escape($event->data->object->card->branding); + $companypaymentmode->proprio = $db->escape($event->data->object->billing_details->name); + $companypaymentmode->exp_date_month = $db->escape($event->data->object->card->exp_month); + $companypaymentmode->exp_date_year = $db->escape($event->data->object->card->exp_year); + $companypaymentmode->cvn = null; + $companypaymentmode->datec = $db->escape($event->data->object->created); + $companypaymentmode->default_rib = 0; + $companypaymentmode->type = $db->escape($event->data->object->type); + $companypaymentmode->country_code = $db->escape($event->data->object->card->country); + $companypaymentmode->status = $servicestatus; + + $db->begin(); + if (! $error) + { + $result = $companypaymentmode->create($user); + if ($result < 0) + { + $error++; + } + } + if (! $error) + { + $db->commit(); + } + else + { + $db->rollback(); + } + } +} +elseif ($event->type == 'payment_method.updated') { + require_once DOL_DOCUMENT_ROOT.'/societe/class/companypaymentmode.class.php'; + $companypaymentmode = new CompanyPaymentMode($db); + $companypaymentmode->fetch(0, '', 0, '', " AND stripe_card_ref = '".$db->escape($event->data->object->id)."'"); + $companypaymentmode->bank = null; + $companypaymentmode->label = null; + $companypaymentmode->number = $db->escape($event->data->object->id); + $companypaymentmode->last_four = $db->escape($event->data->object->card->last4); + $companypaymentmode->proprio = $db->escape($event->data->object->billing_details->name); + $companypaymentmode->exp_date_month = $db->escape($event->data->object->card->exp_month); + $companypaymentmode->exp_date_year = $db->escape($event->data->object->card->exp_year); + $companypaymentmode->cvn = null; + $companypaymentmode->datec = $db->escape($event->data->object->created); + $companypaymentmode->default_rib = 0; + $companypaymentmode->type = $db->escape($event->data->object->type); + $companypaymentmode->country_code = $db->escape($event->data->object->card->country); + $companypaymentmode->status = $servicestatus; + + $db->begin(); + if (! $error) + { + $result = $companypaymentmode->update($user); + if ($result < 0) + { + $error++; + } + } + if (! $error) + { + $db->commit(); + } + else + { + $db->rollback(); + } +} +elseif ($event->type == 'payment_method.detached') { + $db->begin(); + $sql = "DELETE FROM ".MAIN_DB_PREFIX."societe_rib WHERE ref = '".$db->escape($event->data->object->id)."' and status = ".$servicestatus; + $db->query($sql); + $db->commit(); +} elseif ($event->type == 'charge.succeeded') { // TODO: create fees // TODO: Redirect to paymentok.php diff --git a/htdocs/societe/class/companypaymentmode.class.php b/htdocs/societe/class/companypaymentmode.class.php index ae9f0a44b32..e3e86e2cf4a 100644 --- a/htdocs/societe/class/companypaymentmode.class.php +++ b/htdocs/societe/class/companypaymentmode.class.php @@ -169,21 +169,21 @@ class CompanyPaymentMode extends CommonObject public $starting_date; public $ending_date; - + /** * Date creation record (datec) * * @var integer */ public $datec; - + /** * Date modification record (tms) * * @var integer */ public $tms; - + public $import_key; // END MODULEBUILDER PROPERTIES @@ -297,15 +297,15 @@ class CompanyPaymentMode extends CommonObject /** * Load object in memory from the database * - * @param int $id Id object - * @param string $ref Ref - * @param int $socid Id of company to get first default payment mode - * @param string $type Filter on type ('ban', 'card', ...) - * @return int <0 if KO, 0 if not found, >0 if OK + * @param int $id Id object + * @param string $ref Ref + * @param int $socid Id of company to get first default payment mode + * @param string $type Filter on type ('ban', 'card', ...) + * @param string $morewhere More SQL filters (' AND ...') + * @return int <0 if KO, 0 if not found, >0 if OK */ - public function fetch($id, $ref = null, $socid = 0, $type = '') + public function fetch($id, $ref = null, $socid = 0, $type = '', $morewhere = '') { - $morewhere = ''; if ($socid) $morewhere.= " AND fk_soc = ".$this->db->escape($socid)." AND default_rib = 1"; if ($type) $morewhere.= " AND type = '".$this->db->escape($type)."'"; diff --git a/htdocs/societe/class/societeaccount.class.php b/htdocs/societe/class/societeaccount.class.php index 6f24471a295..3fc7b225c77 100644 --- a/htdocs/societe/class/societeaccount.class.php +++ b/htdocs/societe/class/societeaccount.class.php @@ -3,7 +3,6 @@ * Copyright (C) 2014-2016 Juanjo Menent * Copyright (C) 2015 Florian Henry * Copyright (C) 2015 Raphaƫl Doursenaud - * Copyright (C) ---Put here your own copyright and developer email--- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -281,12 +280,13 @@ class SocieteAccount extends CommonObject } /** - * Try to find the external customer id of a thirdparty for an another site/system. + * Try to find the external customer id of a thirdparty for another site/system. * * @param int $id Id of third party * @param string $site Site (example: 'stripe', '...') * @param int $status Status (0=test, 1=live) * @return string Stripe customer ref 'cu_xxxxxxxxxxxxx' or '' + * @see getThirdPartyID() */ public function getCustomerAccount($id, $site, $status = 0) { @@ -314,6 +314,38 @@ class SocieteAccount extends CommonObject return $key; } + /** + * Try to find the thirdparty id for an another site/system external id. + * + * @param string $id Id of customer in external system (example: 'cu_xxxxxxxxxxxxx', ...) + * @param string $site Site (example: 'stripe', '...') + * @param int $status Status (0=test, 1=live) + * @return string Id of third party + * @see getCustomerAccount() + */ + public function getThirdPartyID($id, $site, $status = 0) + { + $socid = 0; + + $sql = "SELECT sa.fk_soc as fk_soc, sa.key_account, sa.entity"; + $sql.= " FROM " . MAIN_DB_PREFIX . "societe_account as sa"; + $sql.= " WHERE sa.key_account = '".$this->db->escape($id)."'"; + $sql.= " AND sa.entity IN (".getEntity('societe').")"; + $sql.= " AND sa.site = '".$this->db->escape($site)."' AND sa.status = ".((int) $status); + $sql.= " AND sa.fk_soc > 0"; + + dol_syslog(get_class($this) . "::getCustomerAccount Try to find the first thirdparty id for ".$site." for external id=".$id, LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $socid = $obj->fk_soc; + } + } + + return $socid; + } + /** * Update object into database * diff --git a/htdocs/societe/paymentmodes.php b/htdocs/societe/paymentmodes.php index 3b1a2dd0459..24329a48a33 100644 --- a/htdocs/societe/paymentmodes.php +++ b/htdocs/societe/paymentmodes.php @@ -1123,7 +1123,8 @@ if ($socid && $action != 'edit' && $action != 'create' && $action != 'editcard' print ''; // Default print ''; - if (($customerstripe->default_source != $src->id)) + if ((empty($customerstripe->invoice_settings) && $customerstripe->default_source != $src->id) || + (! empty($customerstripe->invoice_settings) && $customerstripe->invoice_settings->default_payment_method != $src->id)) { print ''; print img_picto($langs->trans("Default"), 'off'); diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index de43c063922..dd66c7607e5 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -237,6 +237,33 @@ class Stripe extends CommonObject return $customer; } + /** + * Get the Stripe payment method Object from its ID + * + * @param string $paymentmethod Payment Method ID + * @param string $key ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect + * @param int $status Status (0=test, 1=live) + * @return \Stripe\PaymentMethod|null Stripe PaymentMethod or null if not found + */ + public function getPaymentMethodStripe($paymentmethod, $key = '', $status = 0) + { + try { + // Force to use the correct API key + global $stripearrayofkeysbyenv; + \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']); + if (empty($key)) { // If the Stripe connect account not set, we use common API usage + $stripepaymentmethod = \Stripe\PaymentMethod::retrieve(''.$paymentmethod->id.''); + } else { + $stripepaymentmethod = \Stripe\PaymentMethod::retrieve(''.$paymentmethod->id.'', array("stripe_account" => $key)); + } + } + catch(Exception $e) + { + $this->error = $e->getMessage(); + } + return $stripepaymentmethod; + } + /** * Get the Stripe payment intent. Create it with confirm=false * Warning. If a payment was tried and failed, a payment intent was created. @@ -259,7 +286,7 @@ class Stripe extends CommonObject */ public function getPaymentIntent($amount, $currency_code, $tag, $description = '', $object = null, $customer = null, $key = null, $status = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic', $confirmnow = false) { - global $conf, $user, $mysoc; + global $conf; dol_syslog("getPaymentIntent"); @@ -272,12 +299,14 @@ class Stripe extends CommonObject if (! in_array($currency_code, $arrayzerounitcurrency)) $stripeamount = $amount * 100; else $stripeamount = $amount; - $fee = round(($$stripeamount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE) * 100); - if ($fee >= ($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100) && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL>$conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { - $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100); - } elseif ($fee < ($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100)) { - $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100); + $fee = round($amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE); + if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { + $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL); + } elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { + $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL); } + if (! in_array($currency_code, $arrayzerounitcurrency)) $stripefee = $fee * 100; + else $stripefee = $fee; $paymentintent = null; @@ -352,9 +381,9 @@ class Stripe extends CommonObject // payment_method_types = array('card') //var_dump($dataforintent); - if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $fee>0) + if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $stripefee > 0) { - $dataforintent["application_fee"] = $fee; + $dataforintent["application_fee"] = $stripefee; } if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) { @@ -461,8 +490,7 @@ class Stripe extends CommonObject $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.exp_date_month, sa.exp_date_year, sa.number, sa.cvn"; // stripe_card_ref is card_.... $sql.= " FROM " . MAIN_DB_PREFIX . "societe_rib as sa"; - $sql.= " WHERE sa.rowid = " . $object->id; - //$sql.= " AND sa.entity IN (".getEntity('societe').")"; + $sql.= " WHERE sa.rowid = " . $object->id; // We get record from ID, no need for filter on entity $sql.= " AND sa.type = 'card'"; dol_syslog(get_class($this) . "::fetch search stripe card id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG); @@ -660,13 +688,15 @@ class Stripe extends CommonObject $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description")); } } else { - $fee = round(($object->total_ttc * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE) * 100); - if ($fee >= ($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100) && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL>$conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { - $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100); + $fee = round($amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE); + if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { + $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL); } - elseif ($fee < ($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100)) { - $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100); + elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { + $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL); } + if (! in_array($currency, $arrayzerounitcurrency)) $stripefee = $fee * 100; + else $stripefee = $fee; $paymentarray = array( "amount" => "$stripeamount", @@ -678,9 +708,9 @@ class Stripe extends CommonObject "source" => "$source", "customer" => "$customer" ); - if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $fee>0) + if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $stripefee > 0) { - $paymentarray["application_fee"] = $fee; + $paymentarray["application_fee"] = $stripefee; } if ($societe->email && $usethirdpartyemailforreceiptemail) {