mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 13:42:49 +01:00
Merge branch 'v5-develop' into v5-stable
This commit is contained in:
commit
ca6468f8d6
@ -1 +1 @@
|
||||
5.2.18
|
||||
5.2.19
|
@ -14,6 +14,7 @@ namespace App\Exceptions;
|
||||
use App\Exceptions\FilePermissionsFailure;
|
||||
use App\Exceptions\InternalPDFFailure;
|
||||
use App\Exceptions\PhantomPDFFailure;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Utils\Ninja;
|
||||
use Exception;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
@ -197,6 +198,8 @@ class Handler extends ExceptionHandler
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof StripeConnectFailure) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
|
10
app/Exceptions/StripeConnectFailure.php
Normal file
10
app/Exceptions/StripeConnectFailure.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class StripeConnectFailure extends Exception
|
||||
{
|
||||
// ..
|
||||
}
|
@ -81,6 +81,8 @@ class InvoiceItemSum
|
||||
|
||||
private function push()
|
||||
{
|
||||
nlog($this->sub_total . " + ". $this->getLineTotal());
|
||||
|
||||
$this->sub_total += $this->getLineTotal();
|
||||
|
||||
$this->line_items[] = $this->item;
|
||||
@ -92,6 +94,7 @@ class InvoiceItemSum
|
||||
private function sumLineItem()
|
||||
{ //todo need to support quantities less than the precision amount
|
||||
// $this->setLineTotal($this->formatValue($this->item->cost, $this->currency->precision) * $this->formatValue($this->item->quantity, $this->currency->precision));
|
||||
|
||||
$this->setLineTotal($this->item->cost * $this->item->quantity);
|
||||
|
||||
return $this;
|
||||
@ -102,7 +105,15 @@ class InvoiceItemSum
|
||||
if ($this->invoice->is_amount_discount) {
|
||||
$this->setLineTotal($this->getLineTotal() - $this->formatValue($this->item->discount, $this->currency->precision));
|
||||
} else {
|
||||
$this->setLineTotal($this->getLineTotal() - $this->formatValue(round($this->item->line_total * ($this->item->discount / 100), 2), $this->currency->precision));
|
||||
|
||||
/*Test 16-08-2021*/
|
||||
$discount = ($this->item->line_total * ($this->item->discount / 100));
|
||||
$this->setLineTotal($this->formatValue(($this->getLineTotal() - $discount), $this->currency->precision));
|
||||
/*Test 16-08-2021*/
|
||||
|
||||
//replaces the following
|
||||
|
||||
// $this->setLineTotal($this->getLineTotal() - $this->formatValue(round($this->item->line_total * ($this->item->discount / 100), 2), $this->currency->precision));
|
||||
}
|
||||
|
||||
$this->item->is_amount_discount = $this->invoice->is_amount_discount;
|
||||
|
@ -433,9 +433,14 @@ class CompanyGatewayController extends BaseController
|
||||
*/
|
||||
public function destroy(DestroyCompanyGatewayRequest $request, CompanyGateway $company_gateway)
|
||||
{
|
||||
|
||||
$company_gateway->driver(new Client)
|
||||
->disconnect();
|
||||
|
||||
$company_gateway->delete();
|
||||
|
||||
return $this->itemResponse($company_gateway->fresh());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -795,6 +795,10 @@ class InvoiceController extends BaseController
|
||||
public function downloadPdf($invitation_key)
|
||||
{
|
||||
$invitation = $this->invoice_repo->getInvitationByKey($invitation_key);
|
||||
|
||||
if(!$invitation)
|
||||
return response()->json(["message" => "no record found"], 400);
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
|
@ -80,6 +80,8 @@ class StripeConnectController extends BaseController
|
||||
nlog($e->getMessage());
|
||||
|
||||
}
|
||||
|
||||
MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']);
|
||||
|
||||
$company = Company::where('company_key', $request->getTokenContent()['company_key'])->first();
|
||||
|
||||
|
@ -14,10 +14,14 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\Util\ImportStripeCustomers;
|
||||
use App\Jobs\Util\StripeUpdatePaymentMethods;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
|
||||
class StripeController extends BaseController
|
||||
{
|
||||
|
||||
private $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
|
||||
|
||||
public function update()
|
||||
{
|
||||
if(auth()->user()->isAdmin())
|
||||
@ -50,4 +54,22 @@ class StripeController extends BaseController
|
||||
return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
public function verify()
|
||||
{
|
||||
|
||||
if(auth()->user()->isAdmin())
|
||||
{
|
||||
|
||||
$company_gateway = CompanyGateway::where('company_id', auth()->user()->company()->id)
|
||||
->where('is_deleted',0)
|
||||
->whereIn('gateway_key', $this->stripe_keys)
|
||||
->first();
|
||||
|
||||
return $company_gateway->driver(new Client)->verifyConnect();
|
||||
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Unauthorized'], 403);
|
||||
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ class ClientTransformer extends BaseTransformer
|
||||
'work_phone' => $this->getString( $data, 'client.phone' ),
|
||||
'address1' => $this->getString( $data, 'client.address1' ),
|
||||
'address2' => $this->getString( $data, 'client.address2' ),
|
||||
'postal_code' => $this->getString( $data, 'client.postal_code'),
|
||||
'city' => $this->getString( $data, 'client.city' ),
|
||||
'state' => $this->getString( $data, 'client.state' ),
|
||||
'shipping_address1' => $this->getString( $data, 'client.shipping_address1' ),
|
||||
|
@ -1506,12 +1506,6 @@ class Import implements ShouldQueue
|
||||
'new' => $expense_category->id,
|
||||
];
|
||||
|
||||
// $this->ids['expense_categories'] = [
|
||||
// "expense_categories_{$old_user_key}" => [
|
||||
// 'old' => $resource['id'],
|
||||
// 'new' => $expense_category->id,
|
||||
// ],
|
||||
// ];
|
||||
}
|
||||
|
||||
ExpenseCategory::reguard();
|
||||
|
@ -49,6 +49,7 @@ class ImportStripeCustomers implements ShouldQueue
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$cgs = CompanyGateway::where('company_id', $this->company->id)
|
||||
->where('is_deleted',0)
|
||||
->whereIn('gateway_key', $this->stripe_keys)
|
||||
->get();
|
||||
|
||||
|
@ -175,7 +175,8 @@ class ReminderJob implements ShouldQueue
|
||||
$invoice->line_items = $invoice_items;
|
||||
|
||||
/**Refresh Invoice values*/
|
||||
$invoice = $invoice->calc()->getInvoice()->save();
|
||||
$invoice->calc()->getInvoice()->save();
|
||||
$invoice->fresh();
|
||||
$invoice->service()->deletePdf();
|
||||
|
||||
nlog("adjusting client balance and invoice balance by ". ($invoice->balance - $temp_invoice_balance));
|
||||
|
@ -53,7 +53,8 @@ class SupportMessageSent extends Mailable
|
||||
$account = auth()->user()->account;
|
||||
|
||||
$priority = '';
|
||||
$plan = $account->plan ?: '';
|
||||
$plan = $account->plan ?: 'customer support';
|
||||
$plan = ucfirst($plan);
|
||||
|
||||
if(strlen($plan) >1)
|
||||
$priority = '[PRIORITY] ';
|
||||
@ -63,9 +64,9 @@ class SupportMessageSent extends Mailable
|
||||
$db = str_replace("db-ninja-", "", $company->db);
|
||||
|
||||
if(Ninja::isHosted())
|
||||
$subject = "{$priority}Hosted-{$db} :: {ucfirst($plan)} :: ".date('M jS, g:ia');
|
||||
$subject = "{$priority}Hosted-{$db} :: {$plan} :: ".date('M jS, g:ia');
|
||||
else
|
||||
$subject = "{$priority}Self Hosted :: {ucfirst($plan)} :: ".date('M jS, g:ia');
|
||||
$subject = "{$priority}Self Hosted :: {$plan} :: ".date('M jS, g:ia');
|
||||
|
||||
return $this->from(config('mail.from.address'), $user->present()->name())
|
||||
->replyTo($user->email, $user->present()->name())
|
||||
|
@ -115,7 +115,7 @@ class AuthorizeCreditCard
|
||||
];
|
||||
|
||||
$logger_message = [
|
||||
'server_response' => $response->getTransactionResponse()->getTransId(),
|
||||
'server_response' => $response->getTransId(),
|
||||
'data' => $this->formatGatewayResponse($data, $vars),
|
||||
];
|
||||
|
||||
@ -130,11 +130,11 @@ class AuthorizeCreditCard
|
||||
];
|
||||
|
||||
$logger_message = [
|
||||
'server_response' => $response->getTransactionResponse()->getTransId(),
|
||||
'server_response' => $response->getTransId(),
|
||||
'data' => $this->formatGatewayResponse($data, $vars),
|
||||
];
|
||||
|
||||
PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransactionResponse()->getTransId(), $this->authorize->client->company, $amount);
|
||||
PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransId(), $this->authorize->client->company, $amount);
|
||||
|
||||
SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_AUTHORIZE, $this->authorize->client, $this->authorize->client->company);
|
||||
|
||||
@ -147,8 +147,8 @@ class AuthorizeCreditCard
|
||||
{
|
||||
$response = $data['response'];
|
||||
|
||||
if ($response != null && $response->getMessages()->getResultCode() == 'Ok') {
|
||||
|
||||
// if ($response != null && $response->getMessages()->getResultCode() == 'Ok') {
|
||||
if ($response != null && $response->getMessages() != null) {
|
||||
return $this->processSuccessfulResponse($data, $request);
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ class AuthorizeCreditCard
|
||||
$payment_record['amount'] = $amount;
|
||||
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||
$payment_record['transaction_reference'] = $response->getTransactionResponse()->getTransId();
|
||||
$payment_record['transaction_reference'] = $response->getTransId();
|
||||
|
||||
$payment = $this->authorize->createPayment($payment_record);
|
||||
|
||||
@ -183,7 +183,7 @@ class AuthorizeCreditCard
|
||||
];
|
||||
|
||||
$logger_message = [
|
||||
'server_response' => $data['response']->getTransactionResponse()->getTransId(),
|
||||
'server_response' => $data['response']->getTransId(),
|
||||
'data' => $this->formatGatewayResponse($data, $vars),
|
||||
];
|
||||
|
||||
@ -204,9 +204,39 @@ class AuthorizeCreditCard
|
||||
$response = $data['response'];
|
||||
$amount = array_key_exists('amount_with_fee', $data) ? $data['amount_with_fee'] : 0;
|
||||
|
||||
PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransactionResponse()->getTransId(), $this->authorize->client->company, $data['amount_with_fee']);
|
||||
$code = "Error";
|
||||
$description = "There was an error processing the payment";
|
||||
|
||||
if ($response->getErrors() != null) {
|
||||
$code = $response->getErrors()[0]->getErrorCode();
|
||||
$description = $response->getErrors()[0]->getErrorText();
|
||||
}
|
||||
|
||||
PaymentFailureMailer::dispatch($this->authorize->client, $response->getTransId(), $this->authorize->client->company, $amount);
|
||||
|
||||
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
|
||||
|
||||
$vars = [
|
||||
'invoices' => $payment_hash->invoices(),
|
||||
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
||||
];
|
||||
|
||||
$logger_message = [
|
||||
'server_response' => $response->getErrors(),
|
||||
'data' => $this->formatGatewayResponse($data, $vars),
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$logger_message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_ERROR,
|
||||
SystemLog::TYPE_AUTHORIZE,
|
||||
$this->authorize->client,
|
||||
$this->authorize->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed($description, $code);
|
||||
|
||||
throw new \Exception(ctrans('texts.error_title'));
|
||||
}
|
||||
|
||||
private function formatGatewayResponse($data, $vars)
|
||||
@ -216,15 +246,20 @@ class AuthorizeCreditCard
|
||||
$code = '';
|
||||
$description = '';
|
||||
|
||||
if($response->getTransactionResponse()->getMessages() !== null){
|
||||
$code = $response->getTransactionResponse()->getMessages()[0]->getCode();
|
||||
$description = $response->getTransactionResponse()->getMessages()[0]->getDescription();
|
||||
if($response->getMessages() !== null){
|
||||
$code = $response->getMessages()[0]->getCode();
|
||||
$description = $response->getMessages()[0]->getDescription();
|
||||
}
|
||||
|
||||
if ($response->getErrors() != null) {
|
||||
$code = $response->getErrors()[0]->getErrorCode();
|
||||
$description = $response->getErrors()[0]->getErrorText();
|
||||
}
|
||||
|
||||
return [
|
||||
'transaction_reference' => $response->getTransactionResponse()->getTransId(),
|
||||
'transaction_reference' => $response->getTransId(),
|
||||
'amount' => $vars['amount'],
|
||||
'auth_code' => $response->getTransactionResponse()->getAuthCode(),
|
||||
'auth_code' => $response->getAuthCode(),
|
||||
'code' => $code,
|
||||
'description' => $description,
|
||||
'invoices' => $vars['invoices'],
|
||||
|
@ -93,7 +93,7 @@ class ChargePaymentProfile
|
||||
}
|
||||
|
||||
return [
|
||||
'response' => $response,
|
||||
'response' => $tresponse,
|
||||
'amount' => $amount,
|
||||
'profile_id' => $profile_id,
|
||||
'payment_profile_id' => $payment_profile_id,
|
||||
|
@ -631,4 +631,9 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ class CreditCard
|
||||
'transaction_reference' => $payment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment($data, Payment::STATUS_COMPLETED);
|
||||
$payment_record = $this->mollie->createPayment($data, $payment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
|
@ -273,6 +273,9 @@ class MolliePaymentDriver extends BaseDriver
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
{
|
||||
// Allow app to catch up with webhook request.
|
||||
sleep(2);
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'id' => ['required', 'starts_with:tr'],
|
||||
]);
|
||||
|
117
app/PaymentDrivers/Stripe/ApplePay.php
Normal file
117
app/PaymentDrivers/Stripe/ApplePay.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\PaymentDrivers\Stripe\CreditCard;
|
||||
use App\Utils\Ninja;
|
||||
|
||||
class ApplePay
|
||||
{
|
||||
/** @var StripePaymentDriver */
|
||||
public $stripe_driver;
|
||||
|
||||
public function __construct(StripePaymentDriver $stripe_driver)
|
||||
{
|
||||
$this->stripe_driver = $stripe_driver;
|
||||
}
|
||||
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
$this->registerDomain();
|
||||
|
||||
$data['gateway'] = $this->stripe_driver;
|
||||
$data['payment_hash'] = $this->stripe_driver->payment_hash->hash;
|
||||
$data['payment_method_id'] = GatewayType::APPLE_PAY;
|
||||
$data['country'] = $this->stripe_driver->client->country;
|
||||
$data['currency'] = $this->stripe_driver->client->currency()->code;
|
||||
$data['stripe_amount'] = $this->stripe_driver->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe_driver->client->currency()->precision, $this->stripe_driver->client->currency());
|
||||
$data['invoices'] = $this->stripe_driver->payment_hash->invoices();
|
||||
|
||||
$data['intent'] = \Stripe\PaymentIntent::create([
|
||||
'amount' => $data['stripe_amount'],
|
||||
'currency' => $this->stripe_driver->client->getCurrencyCode(),
|
||||
], $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
$this->stripe_driver->payment_hash->data = array_merge((array) $this->stripe_driver->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
|
||||
$this->stripe_driver->payment_hash->save();
|
||||
|
||||
return render('gateways.stripe.applepay.pay', $data);
|
||||
}
|
||||
|
||||
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
{
|
||||
|
||||
$this->stripe_driver->init();
|
||||
|
||||
$state = [
|
||||
'server_response' => json_decode($request->gateway_response),
|
||||
'payment_hash' => $request->payment_hash,
|
||||
];
|
||||
|
||||
$state['payment_intent'] = \Stripe\PaymentIntent::retrieve($state['server_response']->id, $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
$state['customer'] = $state['payment_intent']->customer;
|
||||
|
||||
$this->stripe_driver->payment_hash->data = array_merge((array) $this->stripe_driver->payment_hash->data, $state);
|
||||
$this->stripe_driver->payment_hash->save();
|
||||
|
||||
$server_response = $this->stripe_driver->payment_hash->data->server_response;
|
||||
|
||||
$response_handler = new CreditCard($this->stripe_driver);
|
||||
|
||||
if ($server_response->status == 'succeeded') {
|
||||
|
||||
$this->stripe_driver->logSuccessfulGatewayResponse(['response' => json_decode($request->gateway_response), 'data' => $this->stripe_driver->payment_hash], SystemLog::TYPE_STRIPE);
|
||||
|
||||
return $response_handler->processSuccessfulPayment();
|
||||
}
|
||||
|
||||
return $response_handler->processUnsuccessfulPayment($server_response);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function registerDomain()
|
||||
{
|
||||
if(Ninja::isHosted())
|
||||
{
|
||||
|
||||
$domain = isset($this->stripe_driver->company_gateway->company->portal_domain) ? $this->stripe_driver->company_gateway->company->portal_domain : $this->stripe_driver->company_gateway->company->domain();
|
||||
|
||||
\Stripe\ApplePayDomain::create([
|
||||
'domain_name' => $domain,
|
||||
], $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
\Stripe\ApplePayDomain::create([
|
||||
'domain_name' => config('ninja.app_url'),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
76
app/PaymentDrivers/Stripe/Connect/Verify.php
Normal file
76
app/PaymentDrivers/Stripe/Connect/Verify.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Stripe\Connect;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Http\Requests\ClientPortal\PaymentMethod\VerifyPaymentMethodRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Mail\Gateways\ACHVerificationNotification;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Exception;
|
||||
use Stripe\Customer;
|
||||
use Stripe\Exception\CardException;
|
||||
use Stripe\Exception\InvalidRequestException;
|
||||
|
||||
class Verify
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/** @var StripePaymentDriver */
|
||||
|
||||
public $stripe;
|
||||
|
||||
public function __construct(StripePaymentDriver $stripe)
|
||||
{
|
||||
$this->stripe = $stripe;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->stripe->init();
|
||||
|
||||
if($this->stripe->stripe_connect && strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1)
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
|
||||
$customers = Customer::all([], $this->stripe->stripe_connect_auth);
|
||||
|
||||
$stripe_customers = $this->stripe->company_gateway->client_gateway_tokens->map(function ($cgt){
|
||||
|
||||
$customer = Customer::retrieve($cgt->gateway_customer_reference, $this->stripe->stripe_connect_auth);
|
||||
|
||||
return [
|
||||
'customer' => $cgt->gateway_customer_reference,
|
||||
'record' => $customer
|
||||
];
|
||||
|
||||
});
|
||||
|
||||
$data = [
|
||||
'stripe_customer_count' => count($customers),
|
||||
'stripe_customers' => $stripe_customers,
|
||||
];
|
||||
|
||||
return response()->json($data, 200);
|
||||
}
|
||||
}
|
@ -108,7 +108,7 @@ class CreditCard
|
||||
return $this->processUnsuccessfulPayment($server_response);
|
||||
}
|
||||
|
||||
private function processSuccessfulPayment()
|
||||
public function processSuccessfulPayment()
|
||||
{
|
||||
$stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method);
|
||||
|
||||
@ -148,7 +148,7 @@ class CreditCard
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]);
|
||||
}
|
||||
|
||||
private function processUnsuccessfulPayment($server_response)
|
||||
public function processUnsuccessfulPayment($server_response)
|
||||
{
|
||||
PaymentFailureMailer::dispatch($this->stripe->client, $server_response->cancellation_reason, $this->stripe->client->company, $server_response->amount);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Factory\ClientContactFactory;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\ClientGatewayTokenFactory;
|
||||
@ -22,6 +23,7 @@ use App\Models\Currency;
|
||||
use App\Models\GatewayType;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\PaymentDrivers\Stripe\UpdatePaymentMethods;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Stripe\Customer;
|
||||
use Stripe\PaymentMethod;
|
||||
@ -29,6 +31,7 @@ use Stripe\PaymentMethod;
|
||||
class ImportCustomers
|
||||
{
|
||||
use MakesHash;
|
||||
use GeneratesCounter;
|
||||
|
||||
/** @var StripePaymentDriver */
|
||||
public $stripe;
|
||||
@ -48,6 +51,9 @@ class ImportCustomers
|
||||
|
||||
$this->update_payment_methods = new UpdatePaymentMethods($this->stripe);
|
||||
|
||||
if(strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1)
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
|
||||
$customers = Customer::all([], $this->stripe->stripe_connect_auth);
|
||||
|
||||
foreach($customers as $customer)
|
||||
@ -120,6 +126,10 @@ class ImportCustomers
|
||||
|
||||
$client->name = property_exists($customer, 'name') ? $customer->name : $customer->email;
|
||||
|
||||
if (!isset($client->number) || empty($client->number)) {
|
||||
$client->number = $this->getNextClientNumber($client);
|
||||
}
|
||||
|
||||
$client->save();
|
||||
|
||||
$contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||
|
109
app/PaymentDrivers/Stripe/SEPA.php
Normal file
109
app/PaymentDrivers/Stripe/SEPA.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\PaymentDrivers\Stripe\CreditCard;
|
||||
use App\Utils\Ninja;
|
||||
|
||||
class SEPA
|
||||
{
|
||||
/** @var StripePaymentDriver */
|
||||
public $stripe_driver;
|
||||
|
||||
public function __construct(StripePaymentDriver $stripe_driver)
|
||||
{
|
||||
$this->stripe_driver = $stripe_driver;
|
||||
}
|
||||
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
$customer = $this->stripe_driver->findOrCreateCustomer();
|
||||
|
||||
$setup_intent = \Stripe\SetupIntent::create([
|
||||
'payment_method_types' => ['sepa_debit'],
|
||||
'customer' => $customer->id,
|
||||
], $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
$client_secret = $setup_intent->client_secret
|
||||
// Pass the client secret to the client
|
||||
|
||||
|
||||
$data['gateway'] = $this->stripe;
|
||||
|
||||
return render('gateways.stripe.sepa.authorize', array_merge($data));
|
||||
}
|
||||
|
||||
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
{
|
||||
|
||||
// $this->stripe_driver->init();
|
||||
|
||||
// $state = [
|
||||
// 'server_response' => json_decode($request->gateway_response),
|
||||
// 'payment_hash' => $request->payment_hash,
|
||||
// ];
|
||||
|
||||
// $state['payment_intent'] = \Stripe\PaymentIntent::retrieve($state['server_response']->id, $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
// $state['customer'] = $state['payment_intent']->customer;
|
||||
|
||||
// $this->stripe_driver->payment_hash->data = array_merge((array) $this->stripe_driver->payment_hash->data, $state);
|
||||
// $this->stripe_driver->payment_hash->save();
|
||||
|
||||
// $server_response = $this->stripe_driver->payment_hash->data->server_response;
|
||||
|
||||
// $response_handler = new CreditCard($this->stripe_driver);
|
||||
|
||||
// if ($server_response->status == 'succeeded') {
|
||||
|
||||
// $this->stripe_driver->logSuccessfulGatewayResponse(['response' => json_decode($request->gateway_response), 'data' => $this->stripe_driver->payment_hash], SystemLog::TYPE_STRIPE);
|
||||
|
||||
// return $response_handler->processSuccessfulPayment();
|
||||
// }
|
||||
|
||||
// return $response_handler->processUnsuccessfulPayment($server_response);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Searches for a stripe customer by email
|
||||
otherwise searches by gateway tokens in StripePaymentdriver
|
||||
finally creates a new customer if none found
|
||||
*/
|
||||
private function getCustomer()
|
||||
{
|
||||
$searchResults = \Stripe\Customer::all([
|
||||
"email" => $this->stripe_driver->client->present()->email(),
|
||||
"limit" => 1,
|
||||
"starting_after" => null
|
||||
], $this->stripe_driver->stripe_connect_auth);
|
||||
|
||||
|
||||
if(count($searchResults) >= 1)
|
||||
return $searchResults[0];
|
||||
|
||||
return $this->stripe_driver->findOrCreateCustomer();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||
use App\Http\Requests\Request;
|
||||
@ -24,7 +25,9 @@ use App\Models\PaymentHash;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Stripe\ACH;
|
||||
use App\PaymentDrivers\Stripe\Alipay;
|
||||
use App\PaymentDrivers\Stripe\ApplePay;
|
||||
use App\PaymentDrivers\Stripe\Charge;
|
||||
use App\PaymentDrivers\Stripe\Connect\Verify;
|
||||
use App\PaymentDrivers\Stripe\CreditCard;
|
||||
use App\PaymentDrivers\Stripe\ImportCustomers;
|
||||
use App\PaymentDrivers\Stripe\SOFORT;
|
||||
@ -70,7 +73,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
GatewayType::BANK_TRANSFER => ACH::class,
|
||||
GatewayType::ALIPAY => Alipay::class,
|
||||
GatewayType::SOFORT => SOFORT::class,
|
||||
GatewayType::APPLE_PAY => 1, // TODO
|
||||
GatewayType::APPLE_PAY => ApplePay::class,
|
||||
GatewayType::SEPA => 1, // TODO
|
||||
];
|
||||
|
||||
@ -86,7 +89,10 @@ class StripePaymentDriver extends BaseDriver
|
||||
{
|
||||
Stripe::setApiKey(config('ninja.ninja_stripe_key'));
|
||||
|
||||
$this->stripe_connect_auth = ["stripe_account" => $this->company_gateway->getConfigField('account_id')];
|
||||
if(strlen($this->company_gateway->getConfigField('account_id')) > 1)
|
||||
$this->stripe_connect_auth = ["stripe_account" => $this->company_gateway->getConfigField('account_id')];
|
||||
else
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -390,6 +396,9 @@ class StripePaymentDriver extends BaseDriver
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
{
|
||||
// Allow app to catch up with webhook request.
|
||||
sleep(2);
|
||||
|
||||
if ($request->type === 'charge.succeeded' || $request->type === 'source.chargeable') {
|
||||
foreach ($request->data as $transaction) {
|
||||
$payment = Payment::query()
|
||||
@ -533,4 +542,34 @@ class StripePaymentDriver extends BaseDriver
|
||||
//match clients based on the gateway_customer_reference column
|
||||
|
||||
}
|
||||
|
||||
public function verifyConnect()
|
||||
{
|
||||
return (new Verify($this))->run();
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
if(!$this->stripe_connect)
|
||||
return true;
|
||||
|
||||
if(!strlen($this->company_gateway->getConfigField('account_id')) > 1 )
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
|
||||
Stripe::setApiKey(config('ninja.ninja_stripe_key'));
|
||||
|
||||
try {
|
||||
|
||||
\Stripe\OAuth::deauthorize([
|
||||
'client_id' => config('ninja.ninja_stripe_client_id'),
|
||||
'stripe_user_id' => $this->company_gateway->getConfigField('account_id'),
|
||||
]);
|
||||
|
||||
}
|
||||
catch(\Exception $e){
|
||||
throw new StripeConnectFailure('Unable to disconnect Stripe Connect');
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'success'], 200);
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ class HandleReversal extends AbstractService
|
||||
|
||||
/* Generate a credit for the $total_paid amount */
|
||||
$notes = 'Credit for reversal of '.$this->invoice->number;
|
||||
|
||||
$credit = false;
|
||||
|
||||
if ($total_paid > 0) {
|
||||
|
||||
$credit = CreditFactory::create($this->invoice->company_id, $this->invoice->user_id);
|
||||
|
@ -450,7 +450,7 @@ class Design extends BaseDesign
|
||||
['element' => 'img', 'properties' => ['src' => '$invoiceninja.whitelabel', 'style' => 'height: 2.5rem;', 'hidden' => $this->entity->user->account->isPaid() ? 'true' : 'false', 'id' => 'invoiceninja-whitelabel-logo']],
|
||||
]],
|
||||
]],
|
||||
['element' => 'div', 'properties' => ['class' => 'totals-table-right-side'], 'elements' => []],
|
||||
['element' => 'div', 'properties' => ['class' => 'totals-table-right-side', 'dir' => '$dir'], 'elements' => []],
|
||||
];
|
||||
|
||||
if ($this->type == 'delivery_note') {
|
||||
|
@ -433,6 +433,9 @@ class HtmlEngine
|
||||
$data['$paymentLink'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_payment').'</a>', 'label' => ctrans('texts.view_payment')];
|
||||
$data['$portalButton'] = &$data['$paymentLink'];
|
||||
|
||||
$data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => ''];
|
||||
$data['$dir_text_align'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'right' : 'left', 'label' => ''];
|
||||
|
||||
$arrKeysLength = array_map('strlen', array_keys($data));
|
||||
array_multisort($arrKeysLength, SORT_DESC, $data);
|
||||
|
||||
|
@ -55,6 +55,13 @@ trait CleanLineItems
|
||||
//always cast the value!
|
||||
$item[$key] = BaseSettings::castAttribute(InvoiceItem::$casts[$key], $item[$key]);
|
||||
}
|
||||
|
||||
if(array_key_exists('type_id', $item) && $item['type_id'] == '0')
|
||||
$item['type_id'] = '1';
|
||||
|
||||
if(!array_key_exists('type_id', $item))
|
||||
$item['type_id'] = '1';
|
||||
|
||||
}
|
||||
|
||||
if (array_key_exists('id', $item)) {
|
||||
|
@ -44,6 +44,7 @@
|
||||
"fakerphp/faker": "^1.14",
|
||||
"fideloper/proxy": "^4.2",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"gocardless/gocardless-pro": "^4.12",
|
||||
"google/apiclient": "^2.7",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"hashids/hashids": "^4.0",
|
||||
|
59
composer.lock
generated
59
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "275a9dd3910b6ec79607b098406dc6c7",
|
||||
"content-hash": "bcd9405b1978cef268d732794883e91d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm/php-ansible",
|
||||
@ -2221,6 +2221,61 @@
|
||||
],
|
||||
"time": "2021-04-26T11:24:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gocardless/gocardless-pro",
|
||||
"version": "4.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gocardless/gocardless-pro-php.git",
|
||||
"reference": "e63b97b215c27179023dd2e911133ee75e543fbd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/e63b97b215c27179023dd2e911133ee75e543fbd",
|
||||
"reference": "e63b97b215c27179023dd2e911133ee75e543fbd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"guzzlehttp/guzzle": "^6.0 | ^7.0",
|
||||
"php": ">=5.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.2",
|
||||
"phpunit/phpunit": "^7.5",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GoCardlessPro\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "GoCardless and contributors",
|
||||
"homepage": "https://github.com/gocardless/gocardless-pro-php/contributors"
|
||||
}
|
||||
],
|
||||
"description": "GoCardless Pro PHP Client Library",
|
||||
"homepage": "https://gocardless.com/",
|
||||
"keywords": [
|
||||
"api",
|
||||
"direct debit",
|
||||
"gocardless"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/gocardless/gocardless-pro-php/issues",
|
||||
"source": "https://github.com/gocardless/gocardless-pro-php/tree/v4.12.0"
|
||||
},
|
||||
"time": "2021-08-12T15:41:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "google/apiclient",
|
||||
"version": "v2.10.1",
|
||||
@ -14972,5 +15027,5 @@
|
||||
"platform-dev": {
|
||||
"php": "^7.3|^7.4|^8.0"
|
||||
},
|
||||
"plugin-api-version": "2.1.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.2.18',
|
||||
'app_tag' => '5.2.18',
|
||||
'app_version' => '5.2.19',
|
||||
'app_tag' => '5.2.19',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
@ -1 +1 @@
|
||||
{"assets/images/google-icon.png":["assets/images/google-icon.png"],"assets/images/icon.png":["assets/images/icon.png"],"assets/images/logo.png":["assets/images/logo.png"],"assets/images/payment_types/ach.png":["assets/images/payment_types/ach.png"],"assets/images/payment_types/amex.png":["assets/images/payment_types/amex.png"],"assets/images/payment_types/carteblanche.png":["assets/images/payment_types/carteblanche.png"],"assets/images/payment_types/dinerscard.png":["assets/images/payment_types/dinerscard.png"],"assets/images/payment_types/discover.png":["assets/images/payment_types/discover.png"],"assets/images/payment_types/jcb.png":["assets/images/payment_types/jcb.png"],"assets/images/payment_types/laser.png":["assets/images/payment_types/laser.png"],"assets/images/payment_types/maestro.png":["assets/images/payment_types/maestro.png"],"assets/images/payment_types/mastercard.png":["assets/images/payment_types/mastercard.png"],"assets/images/payment_types/other.png":["assets/images/payment_types/other.png"],"assets/images/payment_types/paypal.png":["assets/images/payment_types/paypal.png"],"assets/images/payment_types/solo.png":["assets/images/payment_types/solo.png"],"assets/images/payment_types/switch.png":["assets/images/payment_types/switch.png"],"assets/images/payment_types/unionpay.png":["assets/images/payment_types/unionpay.png"],"assets/images/payment_types/visa.png":["assets/images/payment_types/visa.png"],"packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf":["packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf"]}
|
||||
{"assets/images/google_logo.png":["assets/images/google_logo.png"],"assets/images/icon.png":["assets/images/icon.png"],"assets/images/logo_dark.png":["assets/images/logo_dark.png"],"assets/images/logo_light.png":["assets/images/logo_light.png"],"assets/images/payment_types/ach.png":["assets/images/payment_types/ach.png"],"assets/images/payment_types/amex.png":["assets/images/payment_types/amex.png"],"assets/images/payment_types/carteblanche.png":["assets/images/payment_types/carteblanche.png"],"assets/images/payment_types/dinerscard.png":["assets/images/payment_types/dinerscard.png"],"assets/images/payment_types/discover.png":["assets/images/payment_types/discover.png"],"assets/images/payment_types/jcb.png":["assets/images/payment_types/jcb.png"],"assets/images/payment_types/laser.png":["assets/images/payment_types/laser.png"],"assets/images/payment_types/maestro.png":["assets/images/payment_types/maestro.png"],"assets/images/payment_types/mastercard.png":["assets/images/payment_types/mastercard.png"],"assets/images/payment_types/other.png":["assets/images/payment_types/other.png"],"assets/images/payment_types/paypal.png":["assets/images/payment_types/paypal.png"],"assets/images/payment_types/solo.png":["assets/images/payment_types/solo.png"],"assets/images/payment_types/switch.png":["assets/images/payment_types/switch.png"],"assets/images/payment_types/unionpay.png":["assets/images/payment_types/unionpay.png"],"assets/images/payment_types/visa.png":["assets/images/payment_types/visa.png"],"packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf":["packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf"]}
|
@ -5198,8 +5198,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
cached_network_image
|
||||
cached_network_image_platform_interface
|
||||
cached_network_image_web
|
||||
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -11935,6 +11933,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
js
|
||||
markdown
|
||||
|
||||
Copyright 2012, the Dart project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -13795,6 +13794,31 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
--------------------------------------------------------------------------------
|
||||
linkify
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Charles-William Crete
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
material_design_icons_flutter
|
||||
|
||||
@ -17105,6 +17129,17 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
super_editor
|
||||
|
||||
Copyright (c) 2021 Superlist, SuperDeclarative! and the contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
synchronized
|
||||
|
||||
|
BIN
public/assets/assets/images/google_logo.png
Normal file
BIN
public/assets/assets/images/google_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
public/assets/assets/images/logo_dark.png
Normal file
BIN
public/assets/assets/images/logo_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.0 KiB |
BIN
public/assets/assets/images/logo_light.png
Normal file
BIN
public/assets/assets/images/logo_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
15
public/flutter_service_worker.js
vendored
15
public/flutter_service_worker.js
vendored
@ -19,21 +19,22 @@ const RESOURCES = {
|
||||
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
|
||||
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
|
||||
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
|
||||
"assets/assets/images/google-icon.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/assets/images/logo.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/AssetManifest.json": "753bba1dee0531d5fad970b5ce1d296d",
|
||||
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
|
||||
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
|
||||
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
|
||||
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
|
||||
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
|
||||
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
|
||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
|
||||
"assets/NOTICES": "f44f710ef9af0b68d977d458631873e1",
|
||||
"assets/NOTICES": "4d4db4724f228190d45706dc2890bfff",
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"manifest.json": "ce1b79950eb917ea619a0a30da27c6a3",
|
||||
"manifest.json": "17bae385e59f59be709280b542203f8e",
|
||||
"version.json": "46d4015fc9abcefe5371cafcf2084173",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"main.dart.js": "7bcab146a5f6ade3cd027cc9e429f732",
|
||||
"/": "d389ab59423a76b2aaaa683ed382c78e"
|
||||
"main.dart.js": "870ee0de972245c17e9db71991aecfc1",
|
||||
"/": "24783ba7c9b4ad6d85740d03acd4bf25"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
231637
public/main.dart.js
vendored
231637
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
231209
public/main.foss.dart.js
vendored
231209
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@
|
||||
"display": "standalone",
|
||||
"background_color": "#0175C2",
|
||||
"theme_color": "#0175C2",
|
||||
"description": "The leading open-source invoicing app",
|
||||
"description": "Invoice Clients, Track Work-Time, Get Paid Online.",
|
||||
"orientation": "portrait-primary",
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
@ -19,7 +19,7 @@
|
||||
],
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/logo.png",
|
||||
"src": "images/icon.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
|
@ -4257,7 +4257,7 @@ $LANG = array(
|
||||
'user_duplicate_error' => 'Cannot add the same user to the same company',
|
||||
'user_cross_linked_error' => 'User exists but cannot be crossed linked to multiple accounts',
|
||||
'ach_verification_notification_label' => 'ACH verification',
|
||||
'ach_verification_notification' => 'Connecting bank accounts require verification. Stripe will automatically sends two small deposits for this purpose. These deposits take 1-2 business days to appear on the customer\'s online statement.',
|
||||
'ach_verification_notification' => 'Connecting bank accounts require verification. Payment gateway will automatically send two small deposits for this purpose. These deposits take 1-2 business days to appear on the customer\'s online statement.',
|
||||
'login_link_requested_label' => 'Login link requested',
|
||||
'login_link_requested' => 'There was a request to login using link. If you did not request this, it\'s safe to ignore it.',
|
||||
'invoices_backup_subject' => 'Your invoices are ready for download',
|
||||
|
@ -156,7 +156,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@
|
||||
|
||||
<div class="entity-details-wrapper-right-side">
|
||||
<div class="entity-details-wrapper">
|
||||
<table id="entity-details"></table>
|
||||
<table id="entity-details" dir="$dir"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -193,7 +193,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@
|
||||
<div id="client-details"></div>
|
||||
|
||||
<div class="entity-details-wrapper">
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -156,7 +156,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -248,7 +248,7 @@
|
||||
|
||||
<p class="entity-label">$entity_label</p>
|
||||
<div class="client-and-entity-wrapper">
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
|
||||
<div id="client-details"></div>
|
||||
</div>
|
||||
|
@ -158,7 +158,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -258,7 +258,7 @@
|
||||
<span>#$entity_number</span>
|
||||
</h1>
|
||||
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
|
||||
<table id="product-table" cellspacing="0"></table>
|
||||
|
@ -152,7 +152,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@
|
||||
|
||||
<div class="wrapper-right-side">
|
||||
<h2 class="wrapper-info-text">$details_label</h2>
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -167,7 +167,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -213,6 +213,16 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.entity-details-wrapper > * {
|
||||
direction: $dir;
|
||||
}
|
||||
|
||||
.entity-details-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
direction: $dir;
|
||||
}
|
||||
|
||||
/** Useful snippets, uncomment to enable. **/
|
||||
|
||||
/** Hide company logo **/
|
||||
@ -271,30 +281,31 @@
|
||||
|
||||
<h1 class="entity-label">$entity_label</h1>
|
||||
<div class="entity-details-wrapper">
|
||||
<span>
|
||||
<span
|
||||
class="entity-property-label"
|
||||
data-element="entity-details-wrapper-invoice-number-label"
|
||||
>$entity_number_label:</span
|
||||
>
|
||||
<div>
|
||||
<span class="entity-property-label" data-element="entity-details-wrapper-invoice-number-label">
|
||||
$entity_number_label:
|
||||
</span>
|
||||
<span class="entity-property-value">$entity_number</span>
|
||||
</span>
|
||||
<span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="entity-property-label">$date_label:</span>
|
||||
<span class="entity-property-value">$date</span>
|
||||
</span>
|
||||
<span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="entity-property-label">$payment_due_label:</span>
|
||||
<span class="entity-property-value">$payment_due</span>
|
||||
</span>
|
||||
<span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="entity-property-label">$amount_due_label:</span>
|
||||
<span
|
||||
class="entity-property-value"
|
||||
data-element="entity-details-wrapper-amount-due"
|
||||
>$amount_due</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table id="product-table" cellspacing="0"></table>
|
||||
|
@ -189,7 +189,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -232,7 +232,7 @@
|
||||
|
||||
[data-ref="total_table-footer"] {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 2rem
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
/** Repeating header & footer styling. */
|
||||
@ -307,7 +307,7 @@
|
||||
<td>
|
||||
<div class="header-container" id="header">
|
||||
<h1 class="company-name">$company.name</h1>
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -132,7 +132,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@
|
||||
alt="$company.name logo"
|
||||
/>
|
||||
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -184,7 +184,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@
|
||||
<div></div>
|
||||
|
||||
<div class="entity-details-wrapper">
|
||||
<table id="entity-details" cellspacing="0"></table>
|
||||
<table id="entity-details" cellspacing="0" dir="$dir"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -190,7 +190,7 @@
|
||||
}
|
||||
|
||||
#table-totals>.totals-table-right-side>*> :nth-child(1) {
|
||||
text-align: left;
|
||||
text-align: "$dir_text_align";
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
@ -278,15 +278,15 @@
|
||||
<img class="company-logo" src="$company.logo"
|
||||
alt="$company.name logo">
|
||||
<div class="top-right-side-section">
|
||||
<section>
|
||||
<div dir="$dir">
|
||||
<span class="header-payment-due-label">$payment_due_label:</span>
|
||||
<span>$payment_due</span>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<div dir="$dir">
|
||||
<span class="header-amount-due-label">$amount_due_label:</span>
|
||||
<span class="header-amount-due-value">$amount_due</span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1,122 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Apple Pay', 'card_title' => 'Apple Pay'])
|
||||
|
||||
@section('gateway_head')
|
||||
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payments.response') }}" method="post" id="server-response">
|
||||
@csrf
|
||||
<input type="hidden" name="gateway_response">
|
||||
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->getCompanyGatewayId() }}">
|
||||
<input type="hidden" name="payment_method_id" value="{{ $payment_method_id }}">
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||
|
||||
<div id="payment-request-button">
|
||||
<!-- A Stripe Element will be inserted here. -->
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@if($gateway->company_gateway->getConfigField('account_id'))
|
||||
var stripe = Stripe('{{ config('ninja.ninja_stripe_publishable_key') }}', {
|
||||
apiVersion: "2018-05-21",
|
||||
stripeAccount: '{{ $gateway->company_gateway->getConfigField('account_id') }}',
|
||||
});
|
||||
@else
|
||||
var stripe = Stripe('{{ $gateway->getPublishableKey() }}', {
|
||||
apiVersion: "2018-05-21",
|
||||
});
|
||||
@endif
|
||||
|
||||
var paymentRequest = stripe.paymentRequest({
|
||||
country: '{{ $country->iso_3166_2 }}',
|
||||
currency: '{{ $currency }}',
|
||||
total: {
|
||||
label: '{{ ctrans('texts.payment_amount') }}',
|
||||
amount: {{ $stripe_amount }},
|
||||
},
|
||||
requestPayerName: true,
|
||||
requestPayerEmail: true,
|
||||
});
|
||||
|
||||
var elements = stripe.elements();
|
||||
var prButton = elements.create('paymentRequestButton', {
|
||||
paymentRequest: paymentRequest,
|
||||
});
|
||||
|
||||
// Check the availability of the Payment Request API first.
|
||||
paymentRequest.canMakePayment().then(function(result) {
|
||||
if (result) {
|
||||
prButton.mount('#payment-request-button');
|
||||
} else {
|
||||
document.getElementById('payment-request-button').style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
paymentRequest.on('paymentmethod', function(ev) {
|
||||
// Confirm the PaymentIntent without handling potential next actions (yet).
|
||||
stripe.confirmCardPayment(
|
||||
'{{ $intent->client_secret }}',
|
||||
{payment_method: ev.paymentMethod.id},
|
||||
{handleActions: false}
|
||||
).then(function(confirmResult) {
|
||||
if (confirmResult.error) {
|
||||
// Report to the browser that the payment failed, prompting it to
|
||||
// re-show the payment interface, or show an error message and close
|
||||
// the payment interface.
|
||||
ev.complete('fail');
|
||||
} else {
|
||||
// Report to the browser that the confirmation was successful, prompting
|
||||
// it to close the browser payment method collection interface.
|
||||
ev.complete('success');
|
||||
// Check if the PaymentIntent requires any actions and if so let Stripe.js
|
||||
// handle the flow. If using an API version older than "2019-02-11"
|
||||
// instead check for: `paymentIntent.status === "requires_source_action"`.
|
||||
if (confirmResult.paymentIntent.status === "requires_action") {
|
||||
// Let Stripe.js handle the rest of the payment flow.
|
||||
stripe.confirmCardPayment(clientSecret).then(function(result) {
|
||||
if (result.error) {
|
||||
// The payment failed -- ask your customer for a new payment method.
|
||||
handleFailure(result.error)
|
||||
} else {
|
||||
// The payment has succeeded.
|
||||
handleSuccess(result);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// The payment has succeeded.
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
handleSuccess(result) {
|
||||
document.querySelector(
|
||||
'input[name="gateway_response"]'
|
||||
).value = JSON.stringify(result.paymentIntent);
|
||||
|
||||
document.getElementById('server-response').submit();
|
||||
}
|
||||
|
||||
handleFailure(message) {
|
||||
let errors = document.getElementById('errors');
|
||||
|
||||
errors.textContent = '';
|
||||
errors.textContent = message;
|
||||
errors.hidden = false;
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,82 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'SEPA', 'card_title' => 'SEPA'])
|
||||
|
||||
@section('gateway_head')
|
||||
@if($gateway->company_gateway->getConfigField('account_id'))
|
||||
<meta name="stripe-account-id" content="{{ $gateway->company_gateway->getConfigField('account_id') }}">
|
||||
<meta name="stripe-publishable-key" content="{{ config('ninja.ninja_stripe_publishable_key') }}">
|
||||
@else
|
||||
<meta name="stripe-publishable-key" content="{{ $gateway->company_gateway->getPublishableKey() }}">
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
@if(session()->has('ach_error'))
|
||||
<div class="alert alert-failure mb-4">
|
||||
<p>{{ session('ach_error') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::SEPA]) }}" method="post" id="server_response">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||
<input type="hidden" name="gateway_type_id" value="9">
|
||||
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||
<input type="hidden" name="is_default" id="is_default">
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_type')])
|
||||
<span class="flex items-center mr-4">
|
||||
<input class="form-radio mr-2" type="radio" value="individual" name="account-holder-type" checked>
|
||||
<span>{{ __('texts.individual_account') }}</span>
|
||||
</span>
|
||||
<span class="flex items-center">
|
||||
<input class="form-radio mr-2" type="radio" value="company" name="account-holder-type">
|
||||
<span>{{ __('texts.company_account') }}</span>
|
||||
</span>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_name')])
|
||||
<input class="input w-full" id="account-holder-name" type="text" placeholder="{{ ctrans('texts.name') }}" required>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')])
|
||||
<select name="countries" id="country" class="form-select input w-full" required>
|
||||
@foreach($countries as $country)
|
||||
<option value="{{ $country->iso_3166_2 }}">{{ $country->iso_3166_2 }} ({{ $country->name }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')])
|
||||
<select name="currencies" id="currency" class="form-select input w-full">
|
||||
@foreach($currencies as $currency)
|
||||
<option value="{{ $currency->code }}">{{ $currency->code }} ({{ $currency->name }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.routing_number')])
|
||||
<input class="input w-full" id="routing-number" type="text" required>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_number')])
|
||||
<input class="input w-full" id="account-number" type="text" required>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element-single')
|
||||
<input type="checkbox" class="form-checkbox mr-1" id="accept-terms" required>
|
||||
<label for="accept-terms" class="cursor-pointer">{{ ctrans('texts.ach_authorization', ['company' => auth()->user()->company->present()->name, 'email' => auth('contact')->user()->client->company->settings->email]) }}</label>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'save-button'])
|
||||
{{ ctrans('texts.add_payment_method') }}
|
||||
@endcomponent
|
||||
@endsection
|
||||
|
||||
@section('gateway_footer')
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
<script src="{{ asset('js/clients/payments/stripe-ach.js') }}"></script>
|
||||
@endsection
|
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(optional($payment_method->meta)->state === 'unauthorized' && $payment_method->gateway_type_id === \App\Models\GatewayType::BANK_TRANSFER)
|
||||
@if((optional($payment_method->meta)->state === 'unauthorized' || optional($payment_method->meta)->state === 'pending') && $payment_method->gateway_type_id === \App\Models\GatewayType::BANK_TRANSFER)
|
||||
<div class="mt-4 mb-4 bg-white shadow sm:rounded-lg">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
|
@ -190,6 +190,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::post('stripe/update_payment_methods', 'StripeController@update')->middleware('password_protected')->name('stripe.update');
|
||||
Route::post('stripe/import_customers', 'StripeController@import')->middleware('password_protected')->name('stripe.import');
|
||||
|
||||
Route::post('stripe/verify', 'StripeController@verify')->middleware('password_protected')->name('stripe.verify');
|
||||
|
||||
Route::resource('subscriptions', 'SubscriptionController');
|
||||
Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk');
|
||||
|
||||
|
@ -158,7 +158,8 @@ class CompanyLedgerTest extends TestCase
|
||||
$item = [];
|
||||
$item['quantity'] = 1;
|
||||
$item['cost'] = 10;
|
||||
|
||||
$item['type_id'] = "1";
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
$data = [
|
||||
|
Loading…
Reference in New Issue
Block a user