1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00
invoiceninja/app/Services/PaymentService.php

399 lines
15 KiB
PHP
Raw Normal View History

<?php namespace App\Services;
2015-11-05 23:37:04 +01:00
use Utils;
2016-03-16 00:08:00 +01:00
use Auth;
use URL;
use DateTime;
use Event;
use Omnipay;
use Session;
use CreditCard;
use App\Models\Payment;
use App\Models\Account;
use App\Models\Country;
use App\Models\Client;
use App\Models\Invoice;
use App\Models\AccountGatewayToken;
2015-10-28 20:22:07 +01:00
use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\AccountRepository;
2015-10-28 20:22:07 +01:00
use App\Services\BaseService;
use App\Events\PaymentWasCreated;
2015-10-28 20:22:07 +01:00
class PaymentService extends BaseService
{
public $lastError;
2015-11-05 23:37:04 +01:00
protected $datatableService;
2015-11-05 23:37:04 +01:00
public function __construct(PaymentRepository $paymentRepo, AccountRepository $accountRepo, DatatableService $datatableService)
{
2015-11-05 23:37:04 +01:00
$this->datatableService = $datatableService;
2015-10-28 20:22:07 +01:00
$this->paymentRepo = $paymentRepo;
$this->accountRepo = $accountRepo;
}
2015-10-28 20:22:07 +01:00
protected function getRepo()
{
return $this->paymentRepo;
}
public function createGateway($accountGateway)
{
$gateway = Omnipay::create($accountGateway->gateway->provider);
$gateway->initialize((array) $accountGateway->getConfig());
2015-10-21 06:30:23 +02:00
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
$gateway->setKey($_ENV['DWOLLA_SANDBOX_KEY']);
$gateway->setSecret($_ENV['DWOLLA_SANSBOX_SECRET']);
} elseif (isset($_ENV['DWOLLA_KEY']) && isset($_ENV['DWOLLA_SECRET'])) {
$gateway->setKey($_ENV['DWOLLA_KEY']);
$gateway->setSecret($_ENV['DWOLLA_SECRET']);
}
}
return $gateway;
}
2015-10-21 06:30:23 +02:00
public function getPaymentDetails($invitation, $accountGateway, $input = null)
{
$invoice = $invitation->invoice;
$account = $invoice->account;
$key = $invoice->account_id.'-'.$invoice->invoice_number;
$currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD');
if ($input) {
$data = self::convertInputForOmnipay($input);
2016-04-11 21:09:05 +02:00
$data['email'] = $invitation->contact->email;
Session::put($key, $data);
} elseif (Session::get($key)) {
$data = Session::get($key);
} else {
2015-09-20 23:05:02 +02:00
$data = $this->createDataForClient($invitation);
}
$card = new CreditCard($data);
2015-10-21 06:30:23 +02:00
$data = [
'amount' => $invoice->getRequestedAmount(),
'card' => $card,
'currency' => $currencyCode,
'returnUrl' => URL::to('complete'),
'cancelUrl' => $invitation->getLink(),
'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->invoice_number}",
2015-09-20 23:05:02 +02:00
'transactionId' => $invoice->invoice_number,
'transactionType' => 'Purchase',
];
2015-10-21 06:30:23 +02:00
if ($accountGateway->isGateway(GATEWAY_PAYPAL_EXPRESS) || $accountGateway->isGateway(GATEWAY_PAYPAL_PRO)) {
$data['ButtonSource'] = 'InvoiceNinja_SP';
};
return $data;
}
2015-10-01 22:02:22 +02:00
public function convertInputForOmnipay($input)
{
$data = [
'firstName' => $input['first_name'],
'lastName' => $input['last_name'],
2015-11-29 21:13:50 +01:00
'number' => isset($input['card_number']) ? $input['card_number'] : null,
'expiryMonth' => isset($input['expiration_month']) ? $input['expiration_month'] : null,
'expiryYear' => isset($input['expiration_year']) ? $input['expiration_year'] : null,
'cvv' => isset($input['cvv']) ? $input['cvv'] : '',
];
if (isset($input['country_id'])) {
$country = Country::find($input['country_id']);
$data = array_merge($data, [
'billingAddress1' => $input['address1'],
'billingAddress2' => $input['address2'],
'billingCity' => $input['city'],
'billingState' => $input['state'],
'billingPostcode' => $input['postal_code'],
'billingCountry' => $country->iso_3166_2,
'shippingAddress1' => $input['address1'],
'shippingAddress2' => $input['address2'],
'shippingCity' => $input['city'],
'shippingState' => $input['state'],
'shippingPostcode' => $input['postal_code'],
'shippingCountry' => $country->iso_3166_2
]);
}
return $data;
}
2015-09-20 23:05:02 +02:00
public function createDataForClient($invitation)
{
$invoice = $invitation->invoice;
$client = $invoice->client;
$contact = $invitation->contact ?: $client->contacts()->first();
return [
'email' => $contact->email,
'company' => $client->getDisplayName(),
'firstName' => $contact->first_name,
'lastName' => $contact->last_name,
'billingAddress1' => $client->address1,
'billingAddress2' => $client->address2,
'billingCity' => $client->city,
'billingPostcode' => $client->postal_code,
'billingState' => $client->state,
2015-09-29 12:21:57 +02:00
'billingCountry' => $client->country ? $client->country->iso_3166_2 : '',
2015-09-20 23:05:02 +02:00
'billingPhone' => $contact->phone,
'shippingAddress1' => $client->address1,
'shippingAddress2' => $client->address2,
'shippingCity' => $client->city,
'shippingPostcode' => $client->postal_code,
'shippingState' => $client->state,
2015-09-29 12:21:57 +02:00
'shippingCountry' => $client->country ? $client->country->iso_3166_2 : '',
2015-09-20 23:05:02 +02:00
'shippingPhone' => $contact->phone,
];
}
public function createToken($gateway, $details, $accountGateway, $client, $contactId)
{
$tokenResponse = $gateway->createCard($details)->send();
2015-11-27 13:55:28 +01:00
$cardReference = $tokenResponse->getCustomerReference();
if ($cardReference) {
$token = AccountGatewayToken::where('client_id', '=', $client->id)
->where('account_gateway_id', '=', $accountGateway->id)->first();
if (!$token) {
$token = new AccountGatewayToken();
$token->account_id = $client->account->id;
$token->contact_id = $contactId;
$token->account_gateway_id = $accountGateway->id;
$token->client_id = $client->id;
}
$token->token = $cardReference;
$token->save();
} else {
$this->lastError = $tokenResponse->getMessage();
}
return $cardReference;
}
public function getCheckoutComToken($invitation)
{
$token = false;
$invoice = $invitation->invoice;
$client = $invoice->client;
$account = $invoice->account;
$accountGateway = $account->getGatewayConfig(GATEWAY_CHECKOUT_COM);
$gateway = $this->createGateway($accountGateway);
$response = $gateway->purchase([
'amount' => $invoice->getRequestedAmount(),
'currency' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD')
])->send();
if ($response->isRedirect()) {
$token = $response->getTransactionReference();
}
2016-03-02 14:36:42 +01:00
Session::set($invitation->id . 'payment_type', PAYMENT_TYPE_CREDIT_CARD);
return $token;
}
2015-12-23 12:49:49 +01:00
public function createPayment($invitation, $accountGateway, $ref, $payerId = null)
{
$invoice = $invitation->invoice;
$payment = Payment::createNew($invitation);
$payment->invitation_id = $invitation->id;
$payment->account_gateway_id = $accountGateway->id;
$payment->invoice_id = $invoice->id;
$payment->amount = $invoice->getRequestedAmount();
$payment->client_id = $invoice->client_id;
$payment->contact_id = $invitation->contact_id;
$payment->transaction_reference = $ref;
$payment->payment_date = date_create()->format('Y-m-d');
2016-04-17 00:34:39 +02:00
if ($payerId) {
$payment->payer_id = $payerId;
}
$payment->save();
2016-04-17 00:34:39 +02:00
// enable pro plan for hosted users
if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) {
foreach ($invoice->invoice_items as $invoice_item) {
// Hacky, but invoices don't have meta fields to allow us to store this easily
if (1 == preg_match('/^Plan - (.+) \((.+)\)$/', $invoice_item->product_key, $matches)) {
$plan = strtolower($matches[1]);
$term = strtolower($matches[2]);
} elseif ($invoice_item->product_key == 'Pending Monthly') {
$pending_monthly = true;
}
}
2016-04-17 04:09:01 +02:00
if (!empty($plan)) {
2016-04-17 00:34:39 +02:00
$account = Account::with('users')->find($invoice->client->public_id);
2016-04-17 04:09:01 +02:00
if(
$account->company->plan != $plan
|| DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create('-7 days')
) {
// Either this is a different plan, or the subscription expired more than a week ago
// Reset any grandfathering
$account->company->plan_started = date_create()->format('Y-m-d');
}
if (
$account->company->plan == $plan
&& $account->company->plan_term == $term
&& DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create()
) {
// This is a renewal; mark it paid as of when this term expires
$account->company->plan_paid = $account->company->plan_expires;
} else {
$account->company->plan_paid = date_create()->format('Y-m-d');
}
2016-04-17 00:34:39 +02:00
$account->company->payment_id = $payment->id;
$account->company->plan = $plan;
$account->company->plan_term = $term;
2016-04-17 04:09:01 +02:00
$account->company->plan_expires = DateTime::createFromFormat('Y-m-d', $account->company->plan_paid)
->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d');
2016-04-17 00:34:39 +02:00
if (!empty($pending_monthly)) {
$account->company->pending_plan = $plan;
$account->company->pending_term = PLAN_TERM_MONTHLY;
} else {
$account->company->pending_plan = null;
$account->company->pending_term = null;
}
$account->company->save();
}
}
return $payment;
}
2015-12-21 20:57:55 +01:00
public function completePurchase($gateway, $accountGateway, $details, $token)
{
if ($accountGateway->isGateway(GATEWAY_MOLLIE)) {
$details['transactionReference'] = $token;
$response = $gateway->fetchTransaction($details)->send();
return $gateway->fetchTransaction($details)->send();
} else {
2016-01-18 10:13:39 +01:00
2015-12-21 20:57:55 +01:00
return $gateway->completePurchase($details)->send();
}
}
public function autoBillInvoice($invoice)
{
$client = $invoice->client;
$account = $invoice->account;
$invitation = $invoice->invitations->first();
$accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE);
2015-10-11 16:41:09 +02:00
$token = $client->getGatewayToken();
2015-10-11 16:41:09 +02:00
if (!$invitation || !$accountGateway || !$token) {
return false;
}
// setup the gateway/payment info
$gateway = $this->createGateway($accountGateway);
2015-10-21 14:40:31 +02:00
$details = $this->getPaymentDetails($invitation, $accountGateway);
2015-11-27 13:55:28 +01:00
$details['customerReference'] = $token;
// submit purchase/get response
$response = $gateway->purchase($details)->send();
2016-03-02 14:36:42 +01:00
if ($response->isSuccessful()) {
$ref = $response->getTransactionReference();
return $this->createPayment($invitation, $accountGateway, $ref);
} else {
return false;
}
}
2015-11-05 23:37:04 +01:00
public function getDatatable($clientPublicId, $search)
{
$query = $this->paymentRepo->find($clientPublicId, $search);
2016-03-16 00:08:00 +01:00
if(!Utils::hasPermission('view_all')){
$query->where('payments.user_id', '=', Auth::user()->id);
}
2015-11-05 23:37:04 +01:00
return $this->createDatatable(ENTITY_PAYMENT, $query, !$clientPublicId);
}
protected function getDatatableColumns($entityType, $hideClient)
{
return [
[
'invoice_number',
function ($model) {
if(!Invoice::canEditItemByOwner($model->invoice_user_id)){
return $model->invoice_number;
}
2016-03-02 14:36:42 +01:00
return link_to("invoices/{$model->invoice_public_id}/edit", $model->invoice_number, ['class' => Utils::getEntityRowClass($model)])->toHtml();
2015-11-05 23:37:04 +01:00
}
],
[
'client_name',
function ($model) {
if(!Client::canViewItemByOwner($model->client_user_id)){
return Utils::getClientDisplayName($model);
}
2016-03-02 14:36:42 +01:00
return $model->client_public_id ? link_to("clients/{$model->client_public_id}", Utils::getClientDisplayName($model))->toHtml() : '';
2015-11-05 23:37:04 +01:00
},
! $hideClient
],
[
'transaction_reference',
function ($model) {
return $model->transaction_reference ? $model->transaction_reference : '<i>Manual entry</i>';
}
],
[
'payment_type',
function ($model) {
return $model->payment_type ? $model->payment_type : ($model->account_gateway_id ? $model->gateway_name : '');
}
],
[
'amount',
function ($model) {
return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id);
2015-11-05 23:37:04 +01:00
}
],
[
'payment_date',
function ($model) {
return Utils::dateToString($model->payment_date);
}
]
];
}
protected function getDatatableActions($entityType)
{
return [
[
trans('texts.edit_payment'),
function ($model) {
return URL::to("payments/{$model->public_id}/edit");
2016-03-16 00:08:00 +01:00
},
function ($model) {
return Payment::canEditItem($model);
2015-11-05 23:37:04 +01:00
}
]
];
}
}