Store payment after invoice is confirmed paid

This commit is contained in:
David Bomba 2019-09-25 15:55:52 +10:00
parent 5090c963d3
commit 362f197fbb
6 changed files with 167 additions and 23 deletions

View File

@ -24,6 +24,7 @@ use App\Models\Filterable;
use App\Models\GatewayType;
use App\Models\GroupSetting;
use App\Models\Timezone;
use App\Models\User;
use App\Utils\Traits\CompanyGatewaySettings;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\MakesDates;
@ -137,6 +138,11 @@ class Client extends BaseModel
return $this->belongsTo(Company::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function country()
{
return $this->belongsTo(Country::class);

View File

@ -19,4 +19,61 @@ class PaymentType extends StaticModel
* @var bool
*/
public $timestamps = false;
const CREDIT = 1;
const ACH = 5;
const VISA = 6;
const MASTERCARD = 7;
const AMERICAN_EXPRESS = 8;
const DISCOVER = 9;
const DINERS = 10;
const EUROCARD = 11;
const NOVA = 12;
const CREDIT_CARD_OTHER = 13;
const PAYPAL = 14;
const CARTE_BLANCHE = 17;
const UNIONPAY = 18;
const JCB = 19;
const LASER = 20;
const MAESTRO = 21;
const SOLO = 22;
const SWITCH = 23;
const ALIPAY = 28;
const SOFORT = 29;
const SEPA = 30;
const GOCARDLESS = 31;
const BITCOIN = 32;
public static function parseCardType($cardName)
{
$cardTypes = [
'visa' => self::VISA,
'americanexpress' => self::AMERICAN_EXPRESS,
'amex' => self::AMERICAN_EXPRESS,
'mastercard' => self::MASTERCARD,
'discover' => self::DISCOVER,
'jcb' => self::JCB,
'dinersclub' => self::DINERS,
'carteblanche' => self::CARTE_BLANCHE,
'chinaunionpay' => self::UNIONPAY,
'unionpay' => self::UNIONPAY,
'laser' => self::LASER,
'maestro' => self::MAESTRO,
'solo' => self::SOLO,
'switch' => self::SWITCH,
];
$cardName = strtolower(str_replace([' ', '-', '_'], '', $cardName));
if (empty($cardTypes[$cardName]) && 1 == preg_match('/^('.implode('|', array_keys($cardTypes)).')/', $cardName, $matches)) {
// Some gateways return extra stuff after the card name
$cardName = $matches[1];
}
if (! empty($cardTypes[$cardName])) {
return $cardTypes[$cardName];
} else {
return self::CREDIT_CARD_OTHER;
}
}
}

View File

@ -12,8 +12,10 @@
namespace App\PaymentDrivers;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\CompanyGateway;
use App\Models\GatewayType;
use Illuminate\Support\Facades\Auth;
use Omnipay\Omnipay;
@ -123,6 +125,16 @@ class BasePaymentDriver
public function processPaymentResponse($request) {}
public function getContact()
{
if($this->invitation)
return ClientContact::find($this->invitation->client_contact_id);
elseif(auth()->guard('contact')->user())
return auth()->user();
else
return false;
}
/************************************* Omnipay ******************************************
authorize($options) - authorize an amount on the customer's card
completeAuthorize($options) - handle return from off-site gateways after authorization

View File

@ -11,34 +11,31 @@
namespace App\PaymentDrivers;
use App\Factory\PaymentFactory;
use App\Models\ClientGatewayToken;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentType;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Stripe\PaymentIntent;
use Stripe\SetupIntent;
use Stripe\Stripe;
class StripePaymentDriver extends BasePaymentDriver
{
use MakesHash;
protected $refundable = true;
protected $token_billing = true;
protected $can_authorise_credit_card = true;
protected $can_authorise_credit_card = true;
protected $customer_reference = 'customerReferenceParam';
/**
* Payments
* \Stripe\PaymentIntent::create([
'payment_method_types' => ['card'],
'amount' => 1099,
'currency' => 'aud',
'customer' => 'cus_Fow2nmVJX1EsQw',
'payment_method' => 'card_1FJIAjKmol8YQE9DxWb9kMpR',
]);
*/
/**
* Methods in this class are divided into
* two separate streams
@ -128,6 +125,14 @@ class StripePaymentDriver extends BasePaymentDriver
}
}
/**
*
* Authorises a credit card for future use
* @param array $data Array of variables needed for the view
*
* @return view The gateway specific partial to be rendered
*
*/
public function authorizeCreditCardView(array $data)
{
@ -137,6 +142,11 @@ class StripePaymentDriver extends BasePaymentDriver
}
/**
* Processes the gateway response for credti card authorization
* @param Request $request The returning request object
* @return view Returns the user to payment methods screen.
*/
public function authorizeCreditCardResponse($request)
{
@ -203,7 +213,7 @@ class StripePaymentDriver extends BasePaymentDriver
public function processPaymentView(array $data)
{
$payment_intent_data = [
'amount' => $data['amount_with_fee']*100,
'amount' => $this->convertToStripeAmount($data['amount_with_fee'], $this->client->currency->precision),
'currency' => $this->client->getCurrencyCode(),
'customer' => $this->findOrCreateCustomer(),
'description' => $data['invoices']->pluck('id'), //todo more meaningful description here:
@ -260,18 +270,40 @@ class StripePaymentDriver extends BasePaymentDriver
$payment_method = $server_response->payment_method;
$payment_status = $server_response->status;
$save_card = $request->input('store_card');
$gateway_type_id = $request->input('gateway_type_id');
$this->init()
$gateway_type_id = $request->input('payment_method_id');
$hashed_ids = $request->input('hashed_ids');
$invoices = Invoice::whereIn('id', $this->transformKeys(explode(",",$hashed_ids)))
->whereClientId($this->client->id)
->get();
/**
* Potential statuses that can be returned
*
* requires_action
* processing
* canceled
* requires_action
* requires_confirmation
* requires_payment_method
*
*/
if($this->getContact()){
$client_contact = $this->getContact();
}
else{
$client_contact = $invoices->first()->invitations->first()->contact;
}
$this->init();
$payment_intent = \Stripe\PaymentIntent::retrieve($server_response->id);
$customer = $payment_intent->customer;
if($save_card)
if($payment_status == 'succeeded')
{
$this->init()
$this->init();
$stripe_payment_method = \Stripe\PaymentMethod::retrieve($payment_method);
$stripe_payment_method_obj = $stripe_payment_method->jsonSerialize();
$stripe_payment_method->attach(['customer' => $customer]);
$payment_meta = new \stdClass;
@ -281,8 +313,15 @@ class StripePaymentDriver extends BasePaymentDriver
$payment_meta->brand = $stripe_payment_method_obj['card']['brand'];
$payment_meta->last4 = $stripe_payment_method_obj['card']['last4'];
$payment_meta->type = $stripe_payment_method_obj['type'];
$payment_type = PaymentType::parseCardType($stripe_payment_method_obj['card']['brand']);
}
if($save_card == 'true')
{
$stripe_payment_method->attach(['customer' => $customer]);
$cgt = new ClientGatewayToken;
$cgt->company_id = $this->client->company->id;
$cgt->client_id = $this->client->id;
@ -293,16 +332,46 @@ class StripePaymentDriver extends BasePaymentDriver
$cgt->meta = $payment_meta;
$cgt->save();
if($is_default == 'true' || $this->client->gateway_tokens->count() == 1)
if($this->client->gateway_tokens->count() == 1)
{
$this->client->gateway_tokens()->update(['is_default'=>0]);
$cgt->is_default = 1;
$cgt->save();
}
}
//todo need to fix this to support payment types other than credit card.... sepa etc etc
if(!$payment_type)
$payment_type = PaymentType::CREDIT_CARD_OTHER;
$payment = PaymentFactory::create($this->client->company->id, $this->client->user->id);
$payment->client_id = $this->client->id;
$payment->client_contact_id = $client_contact->id;
$payment->company_gateway_id = $this->company_gateway->id;
$payment->status_id = Payment::STATUS_COMPLETED;
$payment->amount = $this->convertFromStripeAmount($server_response->amount, $this->client->currency->precision);
$payment->payment_date = Carbon::now();
$payment->payment_type_id = $payment_type;
$payment->transaction_reference = $payment_method;
$payment->save();
$payment->invoices()->sync($invoices);
$payment->save();
}
}
private function convertFromStripeAmount($amount, $precision)
{
return $amount / pow(10, $precision);
}
private function convertToStripeAmount($amount, $precision)
{
return $amount * pow(10, $precision);
}
/**
* Creates a new String Payment Intent
*
@ -377,7 +446,7 @@ class StripePaymentDriver extends BasePaymentDriver
}
if(!$customer)
throw Exception('Unable to create gateway customer');
throw new Exception('Unable to create gateway customer');
return $customer;
}

View File

@ -76,8 +76,7 @@
$("#card-button").removeAttr("disabled");
} else {
// The setup has succeeded. Display a success message.
console.log(result);
The card has been successfullly stored.
postResult(result);
}
});

View File

@ -80,6 +80,7 @@
$("#card-errors").empty();
$("#card-errors").append("<b>" + result.error.message + "</b>");
$("#card-button").removeAttr("disabled");
$("#store_card").val(0);
} else {
// The setup has succeeded. Display a success message.