Merge pull request #6821 from turbo124/v5-stable

v5.2.23
This commit is contained in:
David Bomba 2021-10-11 17:26:45 +11:00 committed by GitHub
commit 6eb2cc3e18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 609855 additions and 600646 deletions

View File

@ -1 +1 @@
5.3.22
5.3.23

View File

@ -630,7 +630,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.stripe'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -653,7 +653,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.paypal'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -716,7 +716,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.wepay'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -737,7 +737,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.braintree'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -761,7 +761,7 @@ class CreateSingleAccount extends Command
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -782,7 +782,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.mollie'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
@ -803,7 +803,7 @@ class CreateSingleAccount extends Command
$cg->config = encrypt(config('ninja.testvars.square'));
$cg->save();
$gateway_types = $cg->driver(new Client)->gatewayTypes();
$gateway_types = $cg->driver()->gatewayTypes();
$fees_and_limits = new stdClass;
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;

View File

@ -23,6 +23,7 @@ use App\Jobs\Util\SchedulerCheck;
use App\Jobs\Util\SendFailedEmails;
use App\Jobs\Util\UpdateExchangeRates;
use App\Jobs\Util\VersionCheck;
use App\Models\Account;
use App\Utils\Ninja;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -69,6 +70,10 @@ class Kernel extends ConsoleKernel
$schedule->job(new SchedulerCheck)->daily()->withoutOverlapping();
$schedule->call(function () {
Account::whereNotNull('id')->update(['is_scheduler_running' => true]);
})->everyFiveMinutes();
/* Run hosted specific jobs */
if (Ninja::isHosted()) {

View File

@ -28,9 +28,9 @@ class CloneQuoteToInvoiceFactory
unset($quote_array['invoice_id']);
unset($quote_array['id']);
unset($quote_array['invitations']);
//unset($quote_array['terms']);
//unset($quote_array['public_notes']);
//unset($quote_array['footer']);
unset($quote_array['terms']);
unset($quote_array['public_notes']);
unset($quote_array['footer']);
unset($quote_array['design_id']);
foreach ($quote_array as $key => $value) {

View File

@ -67,9 +67,10 @@ class ContactResetPasswordController extends Controller
$account_id = $request->get('account_id');
$account = Account::find($account_id);
$db = $account->companies->first()->db;
$company = $account->companies->first();
return $this->render('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email, 'account' => $account, 'db' => $db]
['token' => $token, 'email' => $request->email, 'account' => $account, 'db' => $db, 'company' => $company]
);
}

View File

@ -75,7 +75,10 @@ class InvitationController extends Controller
$entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation';
$invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key])
$invitation = $entity_obj::where('key', $invitation_key)
->whereHas($entity, function ($query) {
$query->where('is_deleted',0);
})
->with('contact.client')
->firstOrFail();

View File

@ -491,7 +491,7 @@ class DesignController extends BaseController
public function default(DefaultDesignRequest $request)
{
$design_id = $request->int('design_id');
$design_id = $request->input('design_id');
$entity = $request->input('entity');
$company = auth()->user()->getCompany();

View File

@ -216,7 +216,7 @@ class PreviewController extends BaseController
if(!$request->has('entity_id'))
$entity_obj->service()->fillDefaults()->save();
$entity_obj->load('client');
$entity_obj->load('client.contacts','company');
App::forgetInstance('translator');
$t = app('translator');
@ -345,7 +345,7 @@ class PreviewController extends BaseController
$invoice->setRelation('invitations', $invitation);
$invoice->setRelation('client', $client);
$invoice->setRelation('company', auth()->user()->company());
$invoice->load('client');
$invoice->load('client.company');
// nlog(print_r($invoice->toArray(),1));
@ -380,11 +380,11 @@ class PreviewController extends BaseController
return $maker->getCompiledHTML();
}
if (config('ninja.phantomjs_pdf_generation')) {
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
return (new Phantom)->convertHtmlToPdf($maker->getCompiledHTML(true));
}
if(config('ninja.invoiceninja_hosted_pdf_generation')){
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){
return (new NinjaPdf())->build($maker->getCompiledHTML(true));
}

View File

@ -17,9 +17,11 @@ use App\Jobs\Util\StripeUpdatePaymentMethods;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\CompanyGateway;
use App\Utils\Traits\MakesHash;
class StripeController extends BaseController
{
use MakesHash;
private $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
@ -75,4 +77,16 @@ class StripeController extends BaseController
return response()->json(['message' => 'Unauthorized'], 403);
}
public function disconnect(string $company_gateway_id)
{
$company_gateway = CompanyGateway::where('company_id', auth()->user()->company()->id)
->where('id', $this->decodePrimaryKey($company_gateway_id))
->whereIn('gateway_key', $this->stripe_keys)
->firstOrFail();
return $company_gateway->driver()->disconnect();
}
}

View File

@ -52,7 +52,7 @@ class QueryLogging
$timeEnd = microtime(true);
$time = $timeEnd - $timeStart;
// nlog("Query count = {$count}");
// info("Query count = {$count}");
if($count > 175){
nlog("Query count = {$count}");

View File

@ -58,6 +58,10 @@ class StoreDesignRequest extends Request
$input['design']['header'] = '';
}
if (! array_key_exists('body', $input['design']) || is_null($input['design']['body'])) {
$input['design']['body'] = '';
}
$this->replace($input);
}
}

View File

@ -57,6 +57,10 @@ class UpdateDesignRequest extends Request
$input['design']['header'] = '';
}
if (! array_key_exists('body', $input['design']) || is_null($input['design']['body'])) {
$input['design']['body'] = '';
}
$this->replace($input);
}
}

View File

@ -59,6 +59,8 @@ class CreateEntityPdf implements ShouldQueue
public $entity_string = '';
public $client;
/**
* Create a new job instance.
*
@ -69,15 +71,19 @@ class CreateEntityPdf implements ShouldQueue
$this->invitation = $invitation;
if ($invitation instanceof InvoiceInvitation) {
// $invitation->load('contact.client.company','invoice.client','invoice.user.account');
$this->entity = $invitation->invoice;
$this->entity_string = 'invoice';
} elseif ($invitation instanceof QuoteInvitation) {
// $invitation->load('contact.client.company','quote.client','quote.user.account');
$this->entity = $invitation->quote;
$this->entity_string = 'quote';
} elseif ($invitation instanceof CreditInvitation) {
// $invitation->load('contact.client.company','credit.client','credit.user.account');
$this->entity = $invitation->credit;
$this->entity_string = 'credit';
} elseif ($invitation instanceof RecurringInvoiceInvitation) {
// $invitation->load('contact.client.company','recurring_invoice');
$this->entity = $invitation->recurring_invoice;
$this->entity_string = 'recurring_invoice';
}
@ -86,6 +92,8 @@ class CreateEntityPdf implements ShouldQueue
$this->contact = $invitation->contact;
$this->client = $invitation->contact->client;
$this->disk = Ninja::isHosted() ? config('filesystems.default') : $disk;
}
@ -102,7 +110,7 @@ class CreateEntityPdf implements ShouldQueue
App::setLocale($this->contact->preferredLocale());
/* Set customized translations _NOW_ */
$t->replace(Ninja::transformTranslations($this->entity->client->getMergedSettings()));
$t->replace(Ninja::transformTranslations($this->client->getMergedSettings()));
if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') {
return (new Phantom)->generate($this->invitation);
@ -111,22 +119,22 @@ class CreateEntityPdf implements ShouldQueue
$entity_design_id = '';
if ($this->entity instanceof Invoice) {
$path = $this->entity->client->invoice_filepath($this->invitation);
$path = $this->client->invoice_filepath($this->invitation);
$entity_design_id = 'invoice_design_id';
} elseif ($this->entity instanceof Quote) {
$path = $this->entity->client->quote_filepath($this->invitation);
$path = $this->client->quote_filepath($this->invitation);
$entity_design_id = 'quote_design_id';
} elseif ($this->entity instanceof Credit) {
$path = $this->entity->client->credit_filepath($this->invitation);
$path = $this->client->credit_filepath($this->invitation);
$entity_design_id = 'credit_design_id';
} elseif ($this->entity instanceof RecurringInvoice) {
$path = $this->entity->client->recurring_invoice_filepath($this->invitation);
$path = $this->client->recurring_invoice_filepath($this->invitation);
$entity_design_id = 'invoice_design_id';
}
$file_path = $path.$this->entity->numberFormatter().'.pdf';
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id));
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->client->getSetting($entity_design_id));
// if(!$this->company->account->hasFeature(Account::FEATURE_DIFFERENT_DESIGNS))
// $entity_design_id = 2;
@ -152,18 +160,18 @@ class CreateEntityPdf implements ShouldQueue
$state = [
'template' => $template->elements([
'client' => $this->entity->client,
'client' => $this->client,
'entity' => $this->entity,
'pdf_variables' => (array) $this->entity->company->settings->pdf_variables,
'pdf_variables' => (array) $this->company->settings->pdf_variables,
'$product' => $design->design->product,
'variables' => $variables,
]),
'variables' => $variables,
'options' => [
'all_pages_header' => $this->entity->client->getSetting('all_pages_header'),
'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'),
'all_pages_header' => $this->client->getSetting('all_pages_header'),
'all_pages_footer' => $this->client->getSetting('all_pages_footer'),
],
'process_markdown' => $this->entity->client->company->markdown_enabled,
'process_markdown' => $this->client->company->markdown_enabled,
];
$maker = new PdfMakerService($state);

View File

@ -257,6 +257,8 @@ class NinjaMailerJob implements ShouldQueue
if(Ninja::isHosted() && $this->company->account->emailQuotaExceeded())
return true;
if(!str_contains($this->nmo->to_user->email, "@"))
return true;
return false;
}

View File

@ -74,12 +74,15 @@ class EmailPayment implements ShouldQueue
MultiDB::setDb($this->company->db);
$this->payment->load('invoices');
$this->contact->load('client');
$email_builder = (new PaymentEmailEngine($this->payment, $this->contact))->build();
$invitation = null;
if($this->payment->invoices()->exists())
$invitation = $this->payment->invoices()->first()->invitations()->first();
if($this->payment->invoices && $this->payment->invoices->count() >=1)
$invitation = $this->payment->invoices->first()->invitations()->first();
$nmo = new NinjaMailerObject;
$nmo->mailable = new TemplateEmail($email_builder, $this->contact, $invitation);

View File

@ -237,9 +237,12 @@ class Import implements ShouldQueue
//company size check
if ($this->company->invoices()->count() > 500 || $this->company->products()->count() > 500 || $this->company->clients()->count() > 500) {
$this->company->is_large = true;
$this->company->save();
}
$this->company->client_registration_fields = \App\DataMapper\ClientRegistrationFields::generate();
$this->company->save();
$this->setInitialCompanyLedgerBalances();
// $this->fixClientBalances();

View File

@ -38,8 +38,6 @@ class SchedulerCheck implements ShouldQueue
{
set_time_limit(0);
Account::whereNotNull('id')->update(['is_scheduler_running' => true]);
if(config('ninja.app_version') != base_path('VERSION.txt'))
{

View File

@ -47,6 +47,7 @@ class PaymentEmailEngine extends BaseEmailEngine
$this->company = $payment->company;
$this->client = $payment->client;
$this->contact = $contact ?: $this->client->primary_contact()->first();
$this->contact->load('client.company');
$this->settings = $this->client->getMergedSettings();
$this->template_data = $template_data;
$this->helpers = new Helpers();

View File

@ -64,12 +64,12 @@ class SupportMessageSent extends Mailable
$db = str_replace("db-ninja-", "", $company->db);
$is_large = $company->is_large ? "L" : "S";
$platform = array_key_exists('platform', $this->data) ? $this->data['platform'] : "U";
$migrated = strlen($company->company_key) == 32 ? "M" : "T";
$migrated = strlen($company->company_key) == 32 ? "M" : "";
if(Ninja::isHosted())
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated} :: {$plan} :: ".date('M jS, g:ia');
else
$subject = "{$priority}Self Hosted :: {$plan}{$platform} :: ".date('M jS, g:ia');
$subject = "{$priority}Self Hosted :: {$plan} :: {$platform} :: ".date('M jS, g:ia');
return $this->from(config('mail.from.address'), $user->present()->name())
->replyTo($user->email, $user->present()->name())

View File

@ -119,6 +119,10 @@ class Activity extends StaticModel
'hashed_id',
];
protected $with = [
'backup',
];
public function getHashedIdAttribute()
{
return $this->encodePrimaryKey($this->id);

View File

@ -89,7 +89,7 @@ class Client extends BaseModel implements HasLocalePreference
'contacts.company',
// 'currency',
// 'primary_contact',
'country',
// 'country',
// 'contacts',
// 'shipping_country',
// 'company',

View File

@ -103,7 +103,14 @@ class Gateway extends StaticModel
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']],
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]]; //Stripe
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], //Stripe
GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::PRZELEWY24 => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']]];
case 39:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Checkout
break;
@ -137,6 +144,11 @@ class Gateway extends StaticModel
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true] // GoCardless
];
break;
case 58:
return [
GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false] // Razorpay
];
break;
default:
return [];
break;

View File

@ -28,6 +28,10 @@ class GatewayType extends StaticModel
const KBC = 11;
const BANCONTACT = 12;
const IDEAL = 13;
const HOSTED_PAGE = 14; // For gateways that contain multiple methods.
const GIROPAY = 15;
const PRZELEWY24 = 16;
const EPS = 17;
public function gateway()
{
@ -66,6 +70,14 @@ class GatewayType extends StaticModel
return ctrans('texts.bancontact');
case self::IDEAL:
return ctrans('texts.ideal');
case self::HOSTED_PAGE:
return ctrans('texts.aio_checkout');
case self::PRZELEWY24:
return ctrans('texts.przelewy24');
case self::GIROPAY:
return ctrans('texts.giropay');
case self::EPS:
return ctrans('texts.eps');
default:
return 'Undefined.';
break;

View File

@ -46,6 +46,10 @@ class PaymentType extends StaticModel
const KBC = 35;
const BANCONTACT = 36;
const IDEAL = 37;
const HOSTED_PAGE = 38;
const GIROPAY = 39;
const PRZELEWY24 = 40;
const EPS = 41;
public static function parseCardType($cardName)
{

View File

@ -449,6 +449,10 @@ class RecurringInvoice extends BaseModel
public function calculateDueDate($date)
{
//if nothing is set, assume we are using terms.
if(!$this->due_date_days)
return $this->calculateDateFromTerms($date);
switch ($this->due_date_days) {
case 'terms':
return $this->calculateDateFromTerms($date);

View File

@ -64,6 +64,10 @@ class Subscription extends BaseModel
'deleted_at' => 'timestamp',
];
protected $with = [
'company',
];
public function service(): SubscriptionService
{
return new SubscriptionService($this);

View File

@ -74,6 +74,7 @@ class SystemLog extends Model
const TYPE_EWAY = 313;
const TYPE_SQUARE = 320;
const TYPE_GOCARDLESS = 321;
const TYPE_RAZORPAY = 322;
const TYPE_QUOTA_EXCEEDED = 400;
const TYPE_UPSTREAM_FAILURE = 401;

View File

@ -34,7 +34,6 @@ class InvoiceObserver
->where('event_id', Webhook::EVENT_CREATE_INVOICE)
->exists();
if ($subscriptions) {
$invoice->load('client');

View File

@ -30,9 +30,9 @@ class QuoteObserver
->where('event_id', Webhook::EVENT_CREATE_QUOTE)
->exists();
$quote->load('client');
if ($subscriptions) {
$quote->load('client');
WebhookHandler::dispatch(Webhook::EVENT_CREATE_QUOTE, $quote, $quote->company);
}
}
@ -49,10 +49,10 @@ class QuoteObserver
->where('event_id', Webhook::EVENT_UPDATE_QUOTE)
->exists();
$quote->load('client');
if ($subscriptions) {
$quote->load('client');
WebhookHandler::dispatch(Webhook::EVENT_UPDATE_QUOTE, $quote, $quote->company);
}
@ -71,6 +71,7 @@ class QuoteObserver
->exists();
if ($subscriptions) {
$quote->load('client');
WebhookHandler::dispatch(Webhook::EVENT_DELETE_QUOTE, $quote, $quote->company);
}
}

View File

@ -0,0 +1,184 @@
<?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://opensource.org/licenses/AAL
*/
namespace App\PaymentDrivers\Razorpay;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Http\Requests\Request;
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\Common\MethodInterface;
use App\PaymentDrivers\RazorpayPaymentDriver;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Razorpay\Api\Errors\SignatureVerificationError;
class Hosted implements MethodInterface
{
protected RazorpayPaymentDriver $razorpay;
public function __construct(RazorpayPaymentDriver $razorpay)
{
$this->razorpay = $razorpay;
$this->razorpay->init();
}
/**
* Show the authorization page for Razorpay.
*
* @param array $data
* @return View
*/
public function authorizeView(array $data): View
{
return render('gateways.razorpay.hosted.authorize', $data);
}
/**
* Handle the authorization page for Razorpay.
*
* @param Request $request
* @return RedirectResponse
*/
public function authorizeResponse(Request $request): RedirectResponse
{
return redirect()->route('client.payment_methods.index');
}
/**
* Payment view for the Razorpay.
*
* @param array $data
* @return View
*/
public function paymentView(array $data): View
{
$order = $this->razorpay->gateway->order->create([
'currency' => $this->razorpay->client->currency()->code,
'amount' => $this->razorpay->convertToRazorpayAmount((float) $this->razorpay->payment_hash->data->amount_with_fee),
]);
$this->razorpay->payment_hash->withData('order_id', $order->id);
$this->razorpay->payment_hash->withData('order_amount', $order->amount);
$data['gateway'] = $this->razorpay;
$data['options'] = [
'key' => $this->razorpay->company_gateway->getConfigField('apiKey'),
'amount' => $this->razorpay->convertToRazorpayAmount((float) $this->razorpay->payment_hash->data->amount_with_fee),
'currency' => $this->razorpay->client->currency()->code,
'name' => $this->razorpay->company_gateway->company->present()->name(),
'order_id' => $order->id,
];
return render('gateways.razorpay.hosted.pay', $data);
}
/**
* Handle payments page for Razorpay.
*
* @param PaymentResponseRequest $request
* @return void
*/
public function paymentResponse(PaymentResponseRequest $request)
{
$request->validate([
'payment_hash' => ['required'],
'razorpay_payment_id' => ['required'],
'razorpay_signature' => ['required'],
]);
if (! property_exists($this->razorpay->payment_hash->data, 'order_id')) {
throw new PaymentFailed('Missing [order_id] property. Please contact the administrator. Reference: ' . $this->razorpay->payment_hash->hash);
}
try {
$attributes = [
'razorpay_order_id' => $this->razorpay->payment_hash->data->order_id,
'razorpay_payment_id' => $request->razorpay_payment_id,
'razorpay_signature' => $request->razorpay_signature,
];
$this->razorpay->gateway->utility->verifyPaymentSignature($attributes);
return $this->processSuccessfulPayment($request->razorpay_payment_id);
}
catch (SignatureVerificationError $exception) {
return $this->processUnsuccessfulPayment($exception);
}
}
/**
* Handle the successful payment for Razorpay.
*
* @param string $payment_id
* @return RedirectResponse
*/
public function processSuccessfulPayment(string $payment_id): RedirectResponse
{
$data = [
'gateway_type_id' => GatewayType::HOSTED_PAGE,
'amount' => array_sum(array_column($this->razorpay->payment_hash->invoices(), 'amount')) + $this->razorpay->payment_hash->fee_total,
'payment_type' => PaymentType::HOSTED_PAGE,
'transaction_reference' => $payment_id,
];
$payment_record = $this->razorpay->createPayment($data, Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $payment_id, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_RAZORPAY,
$this->razorpay->client,
$this->razorpay->client->company,
);
return redirect()->route('client.payments.show', ['payment' => $this->razorpay->encodePrimaryKey($payment_record->id)]);
}
/**
* Handle unsuccessful payment for Razorpay.
*
* @param Exception $exception
* @throws PaymentFailed
* @return void
*/
public function processUnsuccessfulPayment(\Exception $exception): void
{
PaymentFailureMailer::dispatch(
$this->razorpay->client,
$exception->getMessage(),
$this->razorpay->client->company,
$this->razorpay->payment_hash->data->amount_with_fee
);
SystemLogger::dispatch(
$exception->getMessage(),
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_RAZORPAY,
$this->razorpay->client,
$this->razorpay->client->company,
);
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
}
}

View File

@ -0,0 +1,102 @@
<?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://opensource.org/licenses/AAL
*/
namespace App\PaymentDrivers;
use App\Models\ClientGatewayToken;
use App\Models\GatewayType;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Models\SystemLog;
use App\PaymentDrivers\Razorpay\Hosted;
use App\Utils\Traits\MakesHash;
class RazorpayPaymentDriver extends BaseDriver
{
use MakesHash;
public $refundable = false;
public $token_billing = false;
public $can_authorise_credit_card = false;
public \Razorpay\Api\Api $gateway;
public $payment_method;
public static $methods = [
GatewayType::HOSTED_PAGE => Hosted::class,
];
const SYSTEM_LOG_TYPE = SystemLog::TYPE_RAZORPAY;
public function init(): self
{
$this->gateway = new \Razorpay\Api\Api(
$this->company_gateway->getConfigField('apiKey'),
$this->company_gateway->getConfigField('apiSecret'),
);
return $this;
}
public function gatewayTypes(): array
{
return [
GatewayType::HOSTED_PAGE,
];
}
public function setPaymentMethod($payment_method_id)
{
$class = self::$methods[$payment_method_id];
$this->payment_method = new $class($this);
return $this;
}
public function authorizeView(array $data)
{
return $this->payment_method->authorizeView($data);
}
public function authorizeResponse($request)
{
return $this->payment_method->authorizeResponse($request);
}
public function processPaymentView(array $data)
{
return $this->payment_method->paymentView($data);
}
public function processPaymentResponse($request)
{
return $this->payment_method->paymentResponse($request);
}
public function refund(Payment $payment, $amount, $return_client_response = false) {}
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash) {}
/**
* Convert the amount to the format that Razorpay supports.
*
* @param mixed|float $amount
* @return int
*/
public function convertToRazorpayAmount($amount): int
{
return \number_format((float) $amount * 100, 0, '.', '');
}
}

View File

@ -0,0 +1,145 @@
<?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\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;
class Bancontact
{
/** @var StripePaymentDriver */
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe = $stripe;
}
public function authorizeView($data)
{
return render('gateways.stripe.bancontact.authorize', $data);
}
public function paymentView(array $data)
{
$data['gateway'] = $this->stripe;
$data['return_url'] = $this->buildReturnUrl();
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['bancontact'],
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.bancontact.pay', $data);
}
private function buildReturnUrl(): string
{
return route('client.payments.response', [
'company_gateway_id' => $this->stripe->company_gateway->id,
'payment_hash' => $this->stripe->payment_hash->hash,
'payment_method_id' => GatewayType::BANCONTACT,
]);
}
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
return $this->processSuccessfulPayment($request->payment_intent);
}
return $this->processUnsuccessfulPayment();
}
public function processSuccessfulPayment(string $payment_intent)
{
/* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */
//catch duplicate submissions.
if(Payment::where('transaction_reference', $payment_intent)->exists())
return redirect()->route('client.payments.index');
$this->stripe->init();
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::BANCONTACT,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::BANCONTACT,
];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
}

View File

@ -0,0 +1,145 @@
<?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\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;
class EPS
{
/** @var StripePaymentDriver */
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe = $stripe;
}
public function authorizeView($data)
{
return render('gateways.stripe.eps.authorize', $data);
}
public function paymentView(array $data)
{
$data['gateway'] = $this->stripe;
$data['return_url'] = $this->buildReturnUrl();
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['eps'],
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.eps.pay', $data);
}
private function buildReturnUrl(): string
{
return route('client.payments.response', [
'company_gateway_id' => $this->stripe->company_gateway->id,
'payment_hash' => $this->stripe->payment_hash->hash,
'payment_method_id' => GatewayType::EPS,
]);
}
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
return $this->processSuccessfulPayment($request->payment_intent);
}
return $this->processUnsuccessfulPayment();
}
public function processSuccessfulPayment(string $payment_intent)
{
/* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */
$this->stripe->init();
//catch duplicate submissions.
if(Payment::where('transaction_reference', $payment_intent)->exists())
return redirect()->route('client.payments.index');
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::EPS,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::EPS,
];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
}

View File

@ -0,0 +1,145 @@
<?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\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;
class GIROPAY
{
/** @var StripePaymentDriver */
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe = $stripe;
}
public function authorizeView($data)
{
return render('gateways.stripe.giropay.authorize', $data);
}
public function paymentView(array $data)
{
$data['gateway'] = $this->stripe;
$data['return_url'] = $this->buildReturnUrl();
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['giropay'],
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.giropay.pay', $data);
}
private function buildReturnUrl(): string
{
return route('client.payments.response', [
'company_gateway_id' => $this->stripe->company_gateway->id,
'payment_hash' => $this->stripe->payment_hash->hash,
'payment_method_id' => GatewayType::GIROPAY,
]);
}
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
return $this->processSuccessfulPayment($request->payment_intent);
}
return $this->processUnsuccessfulPayment();
}
public function processSuccessfulPayment(string $payment_intent)
{
/* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */
$this->stripe->init();
//catch duplicate submissions.
if(Payment::where('transaction_reference', $payment_intent)->exists())
return redirect()->route('client.payments.index');
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::GIROPAY,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::GIROPAY,
];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
}

View File

@ -0,0 +1,145 @@
<?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\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;
class PRZELEWY24
{
/** @var StripePaymentDriver */
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe = $stripe;
}
public function authorizeView($data)
{
return render('gateways.stripe.przelewy24.authorize', $data);
}
public function paymentView(array $data)
{
$data['gateway'] = $this->stripe;
$data['return_url'] = $this->buildReturnUrl();
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['p24'],
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.przelewy24.pay', $data);
}
private function buildReturnUrl(): string
{
return route('client.payments.response', [
'company_gateway_id' => $this->stripe->company_gateway->id,
'payment_hash' => $this->stripe->payment_hash->hash,
'payment_method_id' => GatewayType::PRZELEWY24,
]);
}
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
return $this->processSuccessfulPayment($request->payment_intent);
}
return $this->processUnsuccessfulPayment();
}
public function processSuccessfulPayment(string $payment_intent)
{
/* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */
$this->stripe->init();
//catch duplicate submissions.
if(Payment::where('transaction_reference', $payment_intent)->exists())
return redirect()->route('client.payments.index');
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::PRZELEWY24,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::PRZELEWY24,
];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
}

View File

@ -1,5 +1,4 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
@ -12,98 +11,154 @@
namespace App\PaymentDrivers\Stripe;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\PaymentDrivers\StripePaymentDriver;
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;
use App\Exceptions\PaymentFailed;
class SEPA
{
/** @var StripePaymentDriver */
public $stripe_driver;
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe_driver)
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe_driver = $stripe_driver;
$this->stripe = $stripe;
}
public function authorizeView(array $data)
public function authorizeView($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
return render('gateways.stripe.sepa.authorize', $data);
}
public function paymentView(array $data) {
$data['gateway'] = $this->stripe;
$data['payment_method_id'] = GatewayType::SEPA;
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$data['payment_hash'] = $this->stripe->payment_hash->hash;
return render('gateways.stripe.sepa.authorize', array_merge($data));
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['sepa_debit'],
'setup_future_usage' => 'off_session',
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.sepa.pay', $data);
}
public function paymentResponse(PaymentResponseRequest $request)
{
// $this->stripe_driver->init();
$gateway_response = json_decode($request->gateway_response);
// $state = [
// 'server_response' => json_decode($request->gateway_response),
// 'payment_hash' => $request->payment_hash,
// ];
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
// $state['payment_intent'] = \Stripe\PaymentIntent::retrieve($state['server_response']->id, $this->stripe_driver->stripe_connect_auth);
if (property_exists($gateway_response, 'status') && $gateway_response->status == 'processing') {
// $state['customer'] = $state['payment_intent']->customer;
$this->stripe->init();
$this->storePaymentMethod($gateway_response);
// $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);
return $this->processSuccessfulPayment($gateway_response->id);
}
return $this->processUnsuccessfulPayment();
}
/* 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()
public function processSuccessfulPayment(string $payment_intent)
{
$searchResults = \Stripe\Customer::all([
"email" => $this->stripe_driver->client->present()->email(),
"limit" => 1,
"starting_after" => null
], $this->stripe_driver->stripe_connect_auth);
$this->stripe->init();
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::SEPA,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::SEPA,
];
if(count($searchResults) >= 1)
return $searchResults[0];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
return $this->stripe_driver->findOrCreateCustomer();
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
}
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
private function storePaymentMethod($intent)
{
try {
$method = $this->stripe->getStripePaymentMethod($intent->payment_method);
$payment_meta = new \stdClass;
$payment_meta->brand = (string) \sprintf('%s (%s)', $method->sepa_debit->bank_code, ctrans('texts.sepa'));
$payment_meta->last4 = (string) $method->sepa_debit->last4;
$payment_meta->state = 'authorized';
$payment_meta->type = GatewayType::SEPA;
$data = [
'payment_meta' => $payment_meta,
'token' => $intent->payment_method,
'payment_method_id' => GatewayType::SEPA,
];
$this->stripe->storeGatewayToken($data, ['gateway_customer_reference' => $method->customer]);
} catch (\Exception $e) {
return $this->stripe->processInternallyFailedPayment($this->stripe, $e);
}
}
}

View File

@ -0,0 +1,145 @@
<?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\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;
class iDeal
{
/** @var StripePaymentDriver */
public StripePaymentDriver $stripe;
public function __construct(StripePaymentDriver $stripe)
{
$this->stripe = $stripe;
}
public function authorizeView($data)
{
return render('gateways.stripe.ideal.authorize', $data);
}
public function paymentView(array $data)
{
$data['gateway'] = $this->stripe;
$data['return_url'] = $this->buildReturnUrl();
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
$data['client'] = $this->stripe->client;
$data['customer'] = $this->stripe->findOrCreateCustomer()->id;
$data['country'] = $this->stripe->client->country->iso_3166_2;
$intent = \Stripe\PaymentIntent::create([
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['ideal'],
'customer' => $this->stripe->findOrCreateCustomer(),
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
]);
$data['pi_client_secret'] = $intent->client_secret;
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
return render('gateways.stripe.ideal.pay', $data);
}
private function buildReturnUrl(): string
{
return route('client.payments.response', [
'company_gateway_id' => $this->stripe->company_gateway->id,
'payment_hash' => $this->stripe->payment_hash->hash,
'payment_method_id' => GatewayType::IDEAL,
]);
}
public function paymentResponse($request)
{
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
$this->stripe->payment_hash->save();
if ($request->redirect_status == 'succeeded') {
return $this->processSuccessfulPayment($request->payment_intent);
}
return $this->processUnsuccessfulPayment();
}
public function processSuccessfulPayment(string $payment_intent)
{
/* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */
$this->stripe->init();
//catch duplicate submissions.
if(Payment::where('transaction_reference', $payment_intent)->exists())
return redirect()->route('client.payments.index');
$data = [
'payment_method' => $payment_intent,
'payment_type' => PaymentType::IDEAL,
'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
'transaction_reference' => $payment_intent,
'gateway_type_id' => GatewayType::IDEAL,
];
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
SystemLogger::dispatch(
['response' => $this->stripe->payment_hash->data, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
return redirect()->route('client.payments.index');
}
public function processUnsuccessfulPayment()
{
$server_response = $this->stripe->payment_hash->data;
PaymentFailureMailer::dispatch(
$this->stripe->client,
$server_response,
$this->stripe->client->company,
$this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency())
);
$message = [
'server_response' => $server_response,
'data' => $this->stripe->payment_hash->data,
];
SystemLogger::dispatch(
$message,
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_STRIPE,
$this->stripe->client,
$this->stripe->client->company,
);
throw new PaymentFailed('Failed to process the payment.', 500);
}
}

View File

@ -28,6 +28,7 @@ use App\PaymentDrivers\Stripe\Alipay;
use App\PaymentDrivers\Stripe\Charge;
use App\PaymentDrivers\Stripe\CreditCard;
use App\PaymentDrivers\Stripe\SOFORT;
use App\PaymentDrivers\Stripe\SEPA;
use App\PaymentDrivers\Stripe\Utilities;
use App\Utils\Traits\MakesHash;
use Exception;

View File

@ -32,6 +32,12 @@ use App\PaymentDrivers\Stripe\Connect\Verify;
use App\PaymentDrivers\Stripe\CreditCard;
use App\PaymentDrivers\Stripe\ImportCustomers;
use App\PaymentDrivers\Stripe\SOFORT;
use App\PaymentDrivers\Stripe\SEPA;
use App\PaymentDrivers\Stripe\PRZELEWY24;
use App\PaymentDrivers\Stripe\GIROPAY;
use App\PaymentDrivers\Stripe\iDeal;
use App\PaymentDrivers\Stripe\EPS;
use App\PaymentDrivers\Stripe\Bancontact;
use App\PaymentDrivers\Stripe\UpdatePaymentMethods;
use App\PaymentDrivers\Stripe\Utilities;
use App\Utils\Traits\MakesHash;
@ -75,7 +81,12 @@ class StripePaymentDriver extends BaseDriver
GatewayType::ALIPAY => Alipay::class,
GatewayType::SOFORT => SOFORT::class,
GatewayType::APPLE_PAY => ApplePay::class,
GatewayType::SEPA => 1, // TODO
GatewayType::SEPA => SEPA::class,
GatewayType::PRZELEWY24 => PRZELEWY24::class,
GatewayType::GIROPAY => GIROPAY::class,
GatewayType::IDEAL => iDeal::class,
GatewayType::EPS => EPS::class,
GatewayType::BANCONTACT => Bancontact::class,
];
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE;
@ -146,6 +157,49 @@ class StripePaymentDriver extends BaseDriver
$types[] = GatewayType::ALIPAY;
}
if ($this->client
&& $this->client->currency()
&& ($this->client->currency()->code == 'EUR')
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ['AUS', 'DNK', 'DEU', 'ITA', 'LUX', 'NOR', 'SVN', 'GBR', 'EST', 'GRC', 'JPN', 'PRT', 'ESP', 'USA', 'BEL', 'FIN'])) { // TODO: More has to be added https://stripe.com/docs/payments/sepa-debit
$types[] = GatewayType::SEPA;
}
if ($this->client
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ['POL'])){
$types[] = GatewayType::PRZELEWY24;
}
if($this->client
&& $this->client->currency()
&& ($this->client->currency()->code == 'EUR')
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ["DEU"])){
$types[] = GatewayType::GIROPAY;
}
if ($this->client
&& $this->client->currency()
&& ($this->client->currency()->code == 'EUR')
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ["NLD"]))
$types[] = GatewayType::IDEAL;
if ($this->client
&& $this->client->currency()
&& ($this->client->currency()->code == 'EUR')
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ["AUT"]))
$types[] = GatewayType::EPS;
if ($this->client
&& $this->client->currency()
&& ($this->client->currency()->code == 'EUR')
&& isset($this->client->country)
&& in_array($this->client->country->iso_3166_3, ["BEL"]))
$types[] = GatewayType::BANCONTACT;
return $types;
}
@ -164,12 +218,23 @@ class StripePaymentDriver extends BaseDriver
case GatewayType::SEPA:
return 'gateways.stripe.sepa';
break;
case GatewayType::PRZELEWY24:
return 'gateways.stripe.przelewy24';
break;
case GatewayType::CRYPTO:
case GatewayType::ALIPAY:
case GatewayType::APPLE_PAY:
return 'gateways.stripe.other';
break;
case GatewayType::GIROPAY:
return 'gateways.stripe.giropay';
break;
case GatewayType::IDEAL:
return 'gateways.stripe.ideal';
case GatewayType::EPS:
return 'gateways.stripe.eps';
case GatewayType::BANCONTACT:
return 'gateways.stripe.bancontact';
default:
break;
}
@ -629,6 +694,11 @@ class StripePaymentDriver extends BaseDriver
'stripe_user_id' => $this->company_gateway->getConfigField('account_id'),
]);
$config = $this->company_gateway->getConfig();
$config->account_id = "";
$this->company_gateway->setConfig($config);
$this->company_gateway->save();
}
catch(\Exception $e){
throw new StripeConnectFailure('Unable to disconnect Stripe Connect');

View File

@ -70,13 +70,9 @@ class ActivityRepository extends BaseRepository
*/
public function createBackup($entity, $activity)
{
if($entity instanceof User){
}
else if ($entity->company->is_disabled) {
if ($entity instanceof User || $entity->company->is_disabled)
return;
}
$backup = new Backup();
@ -85,6 +81,7 @@ class ActivityRepository extends BaseRepository
|| get_class($entity) == Credit::class
|| get_class($entity) == RecurringInvoice::class
) {
$entity->load('company', 'client');
$contact = $entity->client->primary_contact()->first();
$backup->html_backup = $this->generateHtml($entity);
$backup->amount = $entity->amount;
@ -92,7 +89,6 @@ class ActivityRepository extends BaseRepository
$backup->activity_id = $activity->id;
$backup->json_backup = '';
//$backup->json_backup = $entity->toJson();
$backup->save();
}
@ -121,6 +117,8 @@ class ActivityRepository extends BaseRepository
$entity_design_id = 'credit_design_id';
}
$entity->load('client','client.company');
$entity_design_id = $entity->design_id ? $entity->design_id : $this->decodePrimaryKey($entity->client->getSetting($entity_design_id));
$design = Design::find($entity_design_id);

View File

@ -29,8 +29,9 @@ class BaseRepository
use MakesHash;
use SavesDocuments;
public $import_mode = false;
public bool $import_mode = false;
private bool $new_model = false;
/**
* @param $entity
* @param $type
@ -207,8 +208,8 @@ class BaseRepository
$model->custom_surcharge_tax4 = $client->company->custom_surcharge_taxes4;
if(!$model->id)
$model->save();
else
$this->new_model = true;
$model->saveQuietly();
/* Model now persisted, now lets do some child tasks */
@ -323,6 +324,9 @@ class BaseRepository
//links tasks and expenses back to the invoice.
$model->service()->linkEntities()->save();
if($this->new_model)
event('eloquent.created: App\Models\Invoice', $model);
}
if ($model instanceof Credit) {
@ -332,6 +336,9 @@ class BaseRepository
if (! $model->design_id)
$model->design_id = $this->decodePrimaryKey($client->getSetting('credit_design_id'));
if($this->new_model)
event('eloquent.created: App\Models\Credit', $model);
}
if ($model instanceof Quote) {
@ -341,6 +348,10 @@ class BaseRepository
$model = $model->calc()->getQuote();
if($this->new_model)
event('eloquent.created: App\Models\Quote', $model);
}
if ($model instanceof RecurringInvoice) {
@ -350,6 +361,9 @@ class BaseRepository
$model = $model->calc()->getRecurringInvoice();
if($this->new_model)
event('eloquent.created: App\Models\RecurringInvoice', $model);
}
$model->save();

View File

@ -155,7 +155,7 @@ class CreditService
*/
public function save() : ?Credit
{
$this->credit->save();
$this->credit->saveQuietly();
return $this->credit;
}

View File

@ -46,7 +46,7 @@ class ApplyPaymentAmount extends AbstractService
}
/*Don't double pay*/
if ($this->invoice->statud_id == Invoice::STATUS_PAID) {
if ($this->invoice->status_id == Invoice::STATUS_PAID) {
return $this->invoice;
}

View File

@ -322,6 +322,8 @@ class InvoiceService
public function deletePdf()
{
$this->invoice->load('invitations');
$this->invoice->invitations->each(function ($invitation){
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath($invitation) . $this->invoice->numberFormatter().'.pdf');
@ -452,13 +454,13 @@ class InvoiceService
if (! $this->invoice->design_id)
$this->invoice->design_id = $this->decodePrimaryKey($settings->invoice_design_id);
if (!isset($this->invoice->footer))
if (!isset($this->invoice->footer) || empty($this->invoice->footer))
$this->invoice->footer = $settings->invoice_footer;
if (!isset($this->invoice->terms))
if (!isset($this->invoice->terms) || empty($this->invoice->terms))
$this->invoice->terms = $settings->invoice_terms;
if (!isset($this->invoice->public_notes))
if (!isset($this->invoice->public_notes) || empty($this->invoice->public_notes))
$this->invoice->public_notes = $this->invoice->client->public_notes;
/* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/
@ -473,8 +475,10 @@ class InvoiceService
if ($this->invoice->status_id == Invoice::STATUS_PAID && $this->invoice->client->getSetting('auto_archive_invoice')) {
/* Throws: Payment amount xxx does not match invoice totals. */
$base_repository = new BaseRepository();
$base_repository->archive($this->invoice);
}
return $this;
@ -486,7 +490,7 @@ class InvoiceService
*/
public function save() :?Invoice
{
$this->invoice->save();
$this->invoice->saveQuietly();
return $this->invoice;
}

View File

@ -43,7 +43,7 @@ class MarkPaid extends AbstractService
}
/*Don't double pay*/
if ($this->invoice->statud_id == Invoice::STATUS_PAID) {
if ($this->invoice->status_id == Invoice::STATUS_PAID) {
return $this->invoice;
}
@ -96,7 +96,6 @@ class MarkPaid extends AbstractService
->save();
$this->invoice->service()->workFlow()->save();
// InvoiceWorkflowSettings::dispatchNow($this->invoice);
return $this->invoice;
}

View File

@ -32,6 +32,8 @@ class SendEmail
*/
public function run()
{
$this->payment->load('company', 'client.contacts');
$this->payment->client->contacts->each(function ($contact) {
if ($contact->email) {
EmailPayment::dispatchNow($this->payment, $this->payment->company, $contact);

View File

@ -202,7 +202,7 @@ class QuoteService
*/
public function save() : ?Quote
{
$this->quote->save();
$this->quote->saveQuietly();
return $this->quote;
}

View File

@ -105,7 +105,7 @@ class RecurringService
public function save()
{
$this->recurring_entity->save();
$this->recurring_entity->saveQuietly();
return $this->recurring_entity;
}

View File

@ -165,6 +165,7 @@ class CompanyTransformer extends EntityTransformer
'markdown_enabled' => (bool) $company->markdown_enabled,
'use_comma_as_decimal_place' => (bool) $company->use_comma_as_decimal_place,
'report_include_drafts' => (bool) $company->report_include_drafts,
'client_registration_fields' => (array) $company->client_registration_fields,
];
}

View File

@ -49,6 +49,7 @@ class HtmlEngine
public function __construct($invitation)
{
$this->invitation = $invitation;
// $invitation->load('contact.client.company', 'company');
$this->entity_string = $this->resolveEntityString();
@ -58,7 +59,9 @@ class HtmlEngine
$this->contact = $invitation->contact;
$this->client = $this->entity->client;
$this->client = $invitation->contact->client;
$this->client->load('country','company');
$this->entity->load('client');
$this->settings = $this->client->getMergedSettings();
@ -113,19 +116,19 @@ class HtmlEngine
$data['$total_tax_values'] = ['value' => $this->totalTaxValues(), 'label' => ctrans('texts.taxes')];
$data['$line_tax_labels'] = ['value' => $this->lineTaxLabels(), 'label' => ctrans('texts.taxes')];
$data['$line_tax_values'] = ['value' => $this->lineTaxValues(), 'label' => ctrans('texts.taxes')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.date')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.date')];
$data['$invoice.date'] = &$data['$date'];
$data['$invoiceDate'] = &$data['$date'];
$data['$due_date'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
$data['$due_date'] = ['value' => $this->translateDate($this->entity->due_date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
$data['$dueDate'] = &$data['$due_date'];
$data['$payment_due'] = ['value' => $this->translateDate($this->entity->due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.payment_due')];
$data['$payment_due'] = ['value' => $this->translateDate($this->entity->due_date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.payment_due')];
$data['$invoice.due_date'] = &$data['$due_date'];
$data['$invoice.number'] = ['value' => $this->entity->number ?: '&nbsp;', 'label' => ctrans('texts.invoice_number')];
$data['$invoice.po_number'] = ['value' => $this->entity->po_number ?: '&nbsp;', 'label' => ctrans('texts.po_number')];
$data['$poNumber'] = &$data['$invoice.po_number'];
$data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->entity->client->date_format(), $this->entity->client->locale()), 'label' => ctrans('texts.date')];
$data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.date')];
$data['$invoice.datetime'] = &$data['$entity.datetime'];
$data['$quote.datetime'] = &$data['$entity.datetime'];
$data['$credit.datetime'] = &$data['$entity.datetime'];
@ -145,9 +148,9 @@ class HtmlEngine
$data['$view_button'] = &$data['$view_link'];
$data['$paymentButton'] = &$data['$payment_button'];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_invoice')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.invoice_date')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.invoice_date')];
if($this->entity->project()->exists()) {
if($this->entity->project) {
$data['$project.name'] = ['value' => $this->entity->project->name, 'label' => ctrans('texts.project_name')];
}
}
@ -164,7 +167,7 @@ class HtmlEngine
$data['$view_button'] = &$data['$view_link'];
$data['$approveButton'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.approve')];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
}
if ($this->entity_string == 'credit') {
@ -179,7 +182,7 @@ class HtmlEngine
$data['$viewLink'] = &$data['$view_link'];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
// $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.credit_date')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.credit_date')];
}
$data['$portal_url'] = ['value' => $this->invitation->getPortalLink(), 'label' =>''];
@ -200,17 +203,20 @@ class HtmlEngine
if ($this->entity->partial > 0) {
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.partial_due')];
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
$data['$due_date'] = ['value' => $this->translateDate($this->entity->partial_due_date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
$data['$amount_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
$data['$due_date'] = ['value' => $this->translateDate($this->entity->partial_due_date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.'.$this->entity_string.'_due_date')];
} else {
if($this->entity->status_id == 1){
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->amount, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.balance_due')];
$data['$balance_due_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.balance_due')];
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
}
else{
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.balance_due')];
$data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')];
$data['$amount_raw'] = ['value' => $this->entity->amount, 'label' => ctrans('texts.amount')];
}
}
@ -233,7 +239,7 @@ class HtmlEngine
$data['$credit.number'] = ['value' => $this->entity->number ?: '&nbsp;', 'label' => ctrans('texts.credit_number')];
$data['$credit.total'] = &$data['$credit.total'];
$data['$credit.po_number'] = &$data['$invoice.po_number'];
$data['$credit.date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()), 'label' => ctrans('texts.credit_date')];
$data['$credit.date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.credit_date')];
$data['$balance'] = ['value' => Number::formatMoney($this->entity_calc->getBalance(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.balance')];
$data['$credit.balance'] = &$data['$balance'];
@ -260,13 +266,13 @@ class HtmlEngine
$data['$entity_issued_to'] = ['value' => '', 'label' => ctrans("texts.{$this->entity_string}_issued_to")];
$data['$your_entity'] = ['value' => '', 'label' => ctrans("texts.your_{$this->entity_string}")];
$data['$quote.date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
$data['$quote.date'] = ['value' => $this->translateDate($this->entity->date, $this->client->date_format(), $this->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
$data['$quote.number'] = ['value' => $this->entity->number ?: '&nbsp;', 'label' => ctrans('texts.quote_number')];
$data['$quote.po_number'] = &$data['$invoice.po_number'];
$data['$quote.quote_number'] = &$data['$quote.number'];
$data['$quote_no'] = &$data['$quote.number'];
$data['$quote.quote_no'] = &$data['$quote.number'];
$data['$quote.valid_until'] = ['value' => $this->translateDate($this->entity->due_date, $this->client->date_format(), $this->entity->client->locale()), 'label' => ctrans('texts.valid_until')];
$data['$quote.valid_until'] = ['value' => $this->translateDate($this->entity->due_date, $this->client->date_format(), $this->client->locale()), 'label' => ctrans('texts.valid_until')];
$data['$valid_until'] = &$data['$quote.valid_until'];
$data['$credit_amount'] = ['value' => Number::formatMoney($this->entity_calc->getTotal(), $this->client) ?: '&nbsp;', 'label' => ctrans('texts.credit_amount')];
$data['$credit_balance'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: '&nbsp;', 'label' => ctrans('texts.credit_balance')];
@ -461,6 +467,7 @@ class HtmlEngine
/*Payment Aliases*/
$data['$paymentLink'] = &$data['$payment_link'];
$data['$payment_url'] = &$data['$payment_link'];
$data['$portalButton'] = &$data['$paymentLink'];
$data['$dir'] = ['value' => optional($this->client->language())->locale === 'ar' ? 'rtl' : 'ltr', 'label' => ''];

View File

@ -89,9 +89,9 @@ class SystemHealth
public static function getPdfEngine()
{
if(config('ninja.invoiceninja_hosted_pdf_generation'))
if(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja')
return 'Invoice Ninja Hosted PDF Generator';
elseif(config('ninja.phantomjs_pdf_generation'))
elseif(config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom')
return 'Phantom JS Web Generator';
else
return 'SnapPDF PDF Generator';

View File

@ -713,6 +713,19 @@ trait GeneratesCounter
$replace[] = $client->id_number;
}
$search[] = '{$user_custom1}';
$replace[] = $entity->user->custom_value1;
$search[] = '{$user_custom2}';
$replace[] = $entity->user->custom_value2;
$search[] = '{$user_custom3}';
$replace[] = $entity->user->custom_value3;
$search[] = '{$client_custom4}';
$replace[] = $entity->user->custom_value4;
return str_replace($search, $replace, $pattern);
}
}

View File

@ -72,6 +72,7 @@
"payfast/payfast-php-sdk": "^1.1",
"pragmarx/google2fa": "^8.0",
"predis/predis": "^1.1",
"razorpay/razorpay": "2.*",
"sentry/sentry-laravel": "^2",
"square/square": "13.0.0.20210721",
"stripe/stripe-php": "^7.50",

346
composer.lock generated
View File

@ -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": "96908a391244cbc96eefbb130bd7bed9",
"content-hash": "dc4f3d21b0f54361b6d4b85674fc900e",
"packages": [
{
"name": "apimatic/jsonmapper",
@ -323,16 +323,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.196.1",
"version": "3.198.1",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "2845899d05c66a00d88eabbf7cf5d3dbae2da58a"
"reference": "79bf3298bd2893eb0b4614c2463e9f675d07118b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2845899d05c66a00d88eabbf7cf5d3dbae2da58a",
"reference": "2845899d05c66a00d88eabbf7cf5d3dbae2da58a",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/79bf3298bd2893eb0b4614c2463e9f675d07118b",
"reference": "79bf3298bd2893eb0b4614c2463e9f675d07118b",
"shasum": ""
},
"require": {
@ -408,9 +408,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.196.1"
"source": "https://github.com/aws/aws-sdk-php/tree/3.198.1"
},
"time": "2021-10-01T18:23:06+00:00"
"time": "2021-10-08T18:28:30+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -1049,16 +1049,16 @@
},
{
"name": "composer/composer",
"version": "2.1.8",
"version": "2.1.9",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
"reference": "24d38e9686092de05214cafa187dc282a5d89497"
"reference": "e558c88f28d102d497adec4852802c0dc14c7077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/composer/zipball/24d38e9686092de05214cafa187dc282a5d89497",
"reference": "24d38e9686092de05214cafa187dc282a5d89497",
"url": "https://api.github.com/repos/composer/composer/zipball/e558c88f28d102d497adec4852802c0dc14c7077",
"reference": "e558c88f28d102d497adec4852802c0dc14c7077",
"shasum": ""
},
"require": {
@ -1127,7 +1127,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/composer/issues",
"source": "https://github.com/composer/composer/tree/2.1.8"
"source": "https://github.com/composer/composer/tree/2.1.9"
},
"funding": [
{
@ -1143,7 +1143,7 @@
"type": "tidelift"
}
],
"time": "2021-09-15T11:55:15+00:00"
"time": "2021-10-05T07:47:38+00:00"
},
{
"name": "composer/metadata-minifier",
@ -3045,16 +3045,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.4.1",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
"url": "https://api.github.com/repos/guzzle/promises/zipball/136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"reference": "136a635e2b4a49b9d79e9c8fee267ffb257fdba0",
"shasum": ""
},
"require": {
@ -3066,7 +3066,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
"dev-master": "1.5-dev"
}
},
"autoload": {
@ -3082,10 +3082,25 @@
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle promises library",
@ -3094,22 +3109,36 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/1.4.1"
"source": "https://github.com/guzzle/promises/tree/1.5.0"
},
"time": "2021-03-07T09:25:29+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
"type": "tidelift"
}
],
"time": "2021-10-07T13:05:22+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.8.2",
"version": "1.8.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91"
"reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/1afdd860a2566ed3c2b0b4a3de6e23434a79ec85",
"reference": "1afdd860a2566ed3c2b0b4a3de6e23434a79ec85",
"shasum": ""
},
"require": {
@ -3146,13 +3175,34 @@
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
@ -3169,9 +3219,23 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.8.2"
"source": "https://github.com/guzzle/psr7/tree/1.8.3"
},
"time": "2021-04-26T09:17:50+00:00"
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2021-10-05T13:56:00+00:00"
},
{
"name": "halaxa/json-machine",
@ -3411,16 +3475,16 @@
},
{
"name": "intervention/image",
"version": "2.6.1",
"version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image.git",
"reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45"
"reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Intervention/image/zipball/0925f10b259679b5d8ca58f3a2add9255ffcda45",
"reference": "0925f10b259679b5d8ca58f3a2add9255ffcda45",
"url": "https://api.github.com/repos/Intervention/image/zipball/9a8cc99d30415ec0b3f7649e1647d03a55698545",
"reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545",
"shasum": ""
},
"require": {
@ -3479,7 +3543,7 @@
],
"support": {
"issues": "https://github.com/Intervention/image/issues",
"source": "https://github.com/Intervention/image/tree/2.6.1"
"source": "https://github.com/Intervention/image/tree/2.7.0"
},
"funding": [
{
@ -3491,7 +3555,7 @@
"type": "github"
}
],
"time": "2021-07-22T14:31:53+00:00"
"time": "2021-10-03T14:17:12+00:00"
},
{
"name": "invoiceninja/inspector",
@ -3558,16 +3622,16 @@
},
{
"name": "jean85/pretty-package-versions",
"version": "2.0.4",
"version": "2.0.5",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "694492c653c518456af2805f04eec445b997ed1f"
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/694492c653c518456af2805f04eec445b997ed1f",
"reference": "694492c653c518456af2805f04eec445b997ed1f",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af",
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af",
"shasum": ""
},
"require": {
@ -3611,9 +3675,9 @@
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.4"
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5"
},
"time": "2021-05-26T08:46:42+00:00"
"time": "2021-10-08T21:21:46+00:00"
},
{
"name": "justinrainbow/json-schema",
@ -3737,16 +3801,16 @@
},
{
"name": "laravel/framework",
"version": "v8.62.0",
"version": "v8.63.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be"
"reference": "8f3d280f36a427730c8c8fa34316c79eed38781e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/60a7e00488167ce2babf3a2aeb3677e48aaf39be",
"reference": "60a7e00488167ce2babf3a2aeb3677e48aaf39be",
"url": "https://api.github.com/repos/laravel/framework/zipball/8f3d280f36a427730c8c8fa34316c79eed38781e",
"reference": "8f3d280f36a427730c8c8fa34316c79eed38781e",
"shasum": ""
},
"require": {
@ -3904,20 +3968,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2021-09-28T13:30:25+00:00"
"time": "2021-10-05T14:04:25+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v1.0.2",
"version": "v1.0.3",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "679e24d36ff8b9be0e36f5222244ec8602e18867"
"reference": "6cfc678735f22ccedad761b8cae2bab14c3d8e5b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/679e24d36ff8b9be0e36f5222244ec8602e18867",
"reference": "679e24d36ff8b9be0e36f5222244ec8602e18867",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/6cfc678735f22ccedad761b8cae2bab14c3d8e5b",
"reference": "6cfc678735f22ccedad761b8cae2bab14c3d8e5b",
"shasum": ""
},
"require": {
@ -3963,7 +4027,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2021-09-29T13:25:52+00:00"
"time": "2021-10-07T14:00:57+00:00"
},
{
"name": "laravel/slack-notification-channel",
@ -4416,16 +4480,16 @@
},
{
"name": "league/csv",
"version": "9.7.1",
"version": "9.7.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1"
"reference": "8544655c460fd01eed0ad258e514488d4b388645"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1",
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/8544655c460fd01eed0ad258e514488d4b388645",
"reference": "8544655c460fd01eed0ad258e514488d4b388645",
"shasum": ""
},
"require": {
@ -4436,10 +4500,10 @@
"require-dev": {
"ext-curl": "*",
"ext-dom": "*",
"friendsofphp/php-cs-fixer": "^2.16",
"phpstan/phpstan": "^0.12.0",
"phpstan/phpstan-phpunit": "^0.12.0",
"phpstan/phpstan-strict-rules": "^0.12.0",
"friendsofphp/php-cs-fixer": "^3.0",
"phpstan/phpstan": "^0.12.99",
"phpstan/phpstan-phpunit": "^0.12.22",
"phpstan/phpstan-strict-rules": "^0.12.11",
"phpunit/phpunit": "^9.5"
},
"suggest": {
@ -4496,7 +4560,7 @@
"type": "github"
}
],
"time": "2021-04-17T16:32:08+00:00"
"time": "2021-10-05T19:41:46+00:00"
},
{
"name": "league/flysystem",
@ -7021,16 +7085,16 @@
},
{
"name": "predis/predis",
"version": "v1.1.8",
"version": "v1.1.9",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "cf5c118a077fbab8b9af1482c20952173125c041"
"reference": "c50c3393bb9f47fa012d0cdfb727a266b0818259"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/cf5c118a077fbab8b9af1482c20952173125c041",
"reference": "cf5c118a077fbab8b9af1482c20952173125c041",
"url": "https://api.github.com/repos/predis/predis/zipball/c50c3393bb9f47fa012d0cdfb727a266b0818259",
"reference": "c50c3393bb9f47fa012d0cdfb727a266b0818259",
"shasum": ""
},
"require": {
@ -7075,7 +7139,7 @@
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/predis/predis/tree/v1.1.8"
"source": "https://github.com/predis/predis/tree/v1.1.9"
},
"funding": [
{
@ -7083,7 +7147,7 @@
"type": "github"
}
],
"time": "2021-09-29T17:48:39+00:00"
"time": "2021-10-05T19:02:38+00:00"
},
{
"name": "psr/cache",
@ -7789,6 +7853,68 @@
],
"time": "2021-09-25T23:10:38+00:00"
},
{
"name": "razorpay/razorpay",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/razorpay/razorpay-php.git",
"reference": "3e70e7ccb0bcb77daa8eaa1f80091906e5a3416e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/razorpay/razorpay-php/zipball/3e70e7ccb0bcb77daa8eaa1f80091906e5a3416e",
"reference": "3e70e7ccb0bcb77daa8eaa1f80091906e5a3416e",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=5.3.0",
"rmccue/requests": "v1.8.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0",
"raveren/kint": "1.*"
},
"type": "library",
"autoload": {
"psr-4": {
"Razorpay\\Api\\": "src/",
"Razorpay\\Tests\\": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Abhay Rana",
"email": "nemo@razorpay.com",
"homepage": "https://captnemo.in",
"role": "Developer"
},
{
"name": "Shashank Kumar",
"email": "shashank@razorpay.com",
"role": "Developer"
}
],
"description": "Razorpay PHP Client Library",
"homepage": "https://docs.razorpay.com",
"keywords": [
"api",
"client",
"php",
"razorpay"
],
"support": {
"email": "contact@razorpay.com",
"issues": "https://github.com/Razorpay/razorpay-php/issues",
"source": "https://github.com/Razorpay/razorpay-php"
},
"time": "2021-10-08T05:54:41+00:00"
},
{
"name": "react/promise",
"version": "v2.8.0",
@ -7839,6 +7965,66 @@
},
"time": "2020-05-12T15:16:56+00:00"
},
{
"name": "rmccue/requests",
"version": "v1.8.0",
"source": {
"type": "git",
"url": "https://github.com/WordPress/Requests.git",
"reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WordPress/Requests/zipball/afbe4790e4def03581c4a0963a1e8aa01f6030f1",
"reference": "afbe4790e4def03581c4a0963a1e8aa01f6030f1",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"php-parallel-lint/php-console-highlighter": "^0.5.0",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpcompatibility/php-compatibility": "^9.0",
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5 || ^7.5",
"requests/test-server": "dev-master",
"squizlabs/php_codesniffer": "^3.5",
"wp-coding-standards/wpcs": "^2.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Requests": "library/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Ryan McCue",
"homepage": "http://ryanmccue.info"
}
],
"description": "A HTTP library written in PHP, for human beings.",
"homepage": "http://github.com/WordPress/Requests",
"keywords": [
"curl",
"fsockopen",
"http",
"idna",
"ipv6",
"iri",
"sockets"
],
"support": {
"issues": "https://github.com/WordPress/Requests/issues",
"source": "https://github.com/WordPress/Requests/tree/v1.8.0"
},
"time": "2021-04-27T11:05:25+00:00"
},
{
"name": "sabre/uri",
"version": "2.2.1",
@ -8237,16 +8423,16 @@
},
{
"name": "sentry/sentry-laravel",
"version": "2.8.0",
"version": "2.9.0",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-laravel.git",
"reference": "21dd07bdd2956e182ffde32d22872ce1a4b3eca9"
"reference": "3acb930f1abeb67046097c3912c7b4b9b4303f08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/21dd07bdd2956e182ffde32d22872ce1a4b3eca9",
"reference": "21dd07bdd2956e182ffde32d22872ce1a4b3eca9",
"url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/3acb930f1abeb67046097c3912c7b4b9b4303f08",
"reference": "3acb930f1abeb67046097c3912c7b4b9b4303f08",
"shasum": ""
},
"require": {
@ -8312,7 +8498,7 @@
],
"support": {
"issues": "https://github.com/getsentry/sentry-laravel/issues",
"source": "https://github.com/getsentry/sentry-laravel/tree/2.8.0"
"source": "https://github.com/getsentry/sentry-laravel/tree/2.9.0"
},
"funding": [
{
@ -8324,7 +8510,7 @@
"type": "custom"
}
],
"time": "2021-08-08T09:03:08+00:00"
"time": "2021-10-06T13:08:08+00:00"
},
{
"name": "square/square",
@ -8385,16 +8571,16 @@
},
{
"name": "stripe/stripe-php",
"version": "v7.97.0",
"version": "v7.98.0",
"source": {
"type": "git",
"url": "https://github.com/stripe/stripe-php.git",
"reference": "ae41c309ce113362706f8d5f19cf0cf2c730bc4a"
"reference": "87f27d3da4a72c93da49d81011cb675c2847a7c0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/ae41c309ce113362706f8d5f19cf0cf2c730bc4a",
"reference": "ae41c309ce113362706f8d5f19cf0cf2c730bc4a",
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/87f27d3da4a72c93da49d81011cb675c2847a7c0",
"reference": "87f27d3da4a72c93da49d81011cb675c2847a7c0",
"shasum": ""
},
"require": {
@ -8440,9 +8626,9 @@
],
"support": {
"issues": "https://github.com/stripe/stripe-php/issues",
"source": "https://github.com/stripe/stripe-php/tree/v7.97.0"
"source": "https://github.com/stripe/stripe-php/tree/v7.98.0"
},
"time": "2021-09-16T21:28:33+00:00"
"time": "2021-10-07T22:39:44+00:00"
},
{
"name": "swiftmailer/swiftmailer",
@ -12572,16 +12758,16 @@
},
{
"name": "facade/ignition",
"version": "2.14.0",
"version": "2.14.1",
"source": {
"type": "git",
"url": "https://github.com/facade/ignition.git",
"reference": "c6126e291bd44ad3fe482537a145fc70e3320598"
"reference": "6d89c4c99537f487ad29f646d57ebf107ef714ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/facade/ignition/zipball/c6126e291bd44ad3fe482537a145fc70e3320598",
"reference": "c6126e291bd44ad3fe482537a145fc70e3320598",
"url": "https://api.github.com/repos/facade/ignition/zipball/6d89c4c99537f487ad29f646d57ebf107ef714ed",
"reference": "6d89c4c99537f487ad29f646d57ebf107ef714ed",
"shasum": ""
},
"require": {
@ -12644,7 +12830,7 @@
"issues": "https://github.com/facade/ignition/issues",
"source": "https://github.com/facade/ignition"
},
"time": "2021-10-01T12:58:45+00:00"
"time": "2021-10-08T12:34:52+00:00"
},
{
"name": "facade/ignition-contracts",

View File

@ -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.3.22',
'app_tag' => '5.3.22',
'app_version' => '5.3.23',
'app_tag' => '5.3.23',
'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''),
@ -33,7 +33,8 @@ return [
'enabled_modules' => 32767,
'phantomjs_key' => env('PHANTOMJS_KEY', 'a-demo-key-with-low-quota-per-ip-address'),
'phantomjs_secret' => env('PHANTOMJS_SECRET', false),
'phantomjs_pdf_generation' => env('PHANTOMJS_PDF_GENERATION', true),
'phantomjs_pdf_generation' => env('PHANTOMJS_PDF_GENERATION', false),
'pdf_generator' => env('PDF_GENERATOR', false),
'trusted_proxies' => env('TRUSTED_PROXIES', false),
'is_docker' => env('IS_DOCKER', false),
'local_download' => env('LOCAL_DOWNLOAD', false),
@ -173,6 +174,5 @@ return [
'ninja_default_company_id' => env('NINJA_COMPANY_ID', null),
'ninja_default_company_gateway_id' => env('NINJA_COMPANY_GATEWAY_ID', null),
'ninja_hosted_secret' => env('NINJA_HOSTED_SECRET', null),
'pdf_generator' => env('PDF_GENERATOR', false),
'internal_queue_enabled' => env('INTERNAL_QUEUE_ENABLED', true),
];

View File

@ -0,0 +1,33 @@
<?php
use App\Models\Gateway;
use App\Models\GatewayType;
use Illuminate\Database\Migrations\Migration;
class Razorpay extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$gateway = new Gateway();
$gateway->id = 58;
$gateway->name = 'Razorpay';
$gateway->key = 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9';
$gateway->provider = 'Razorpay';
$gateway->is_offsite = false;
$configuration = new \stdClass;
$configuration->apiKey = '';
$configuration->apiSecret = '';
$gateway->fields = \json_encode($configuration);
$gateway->visible = true;
$gateway->site_url = 'https://razorpay.com';
$gateway->default_gateway_type_id = GatewayType::HOSTED_PAGE;
$gateway->save();
}
}

View File

@ -0,0 +1,24 @@
<?php
use App\Models\GatewayType;
use App\Models\PaymentType;
use Illuminate\Database\Migrations\Migration;
class AddHostedPageToPaymentTypes extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$type = new PaymentType();
$type->id = 38;
$type->name = 'Hosted Page';
$type->gateway_type_id = GatewayType::HOSTED_PAGE;
$type->save();
}
}

View File

@ -81,6 +81,7 @@ class PaymentLibrariesSeeder extends Seeder
['id' => 54, 'name' => 'PAYMILL', 'provider' => 'Paymill', 'key' => 'ca52f618a39367a4c944098ebf977e1c', 'fields' => '{"apiKey":""}'],
['id' => 55, 'name' => 'Custom', 'provider' => 'Custom', 'is_offsite' => true, 'sort_order' => 21, 'key' => '54faab2ab6e3223dbe848b1686490baa', 'fields' => '{"name":"","text":""}'],
['id' => 57, 'name' => 'Square', 'provider' => 'Square', 'is_offsite' => false, 'sort_order' => 21, 'key' => '65faab2ab6e3223dbe848b1686490baz', 'fields' => '{"accessToken":"","applicationId":"","locationId":"","testMode":false}'],
['id' => 58, 'name' => 'Razorpay', 'provider' => 'Razorpay', 'is_offsite' => false, 'sort_order' => 21, 'key' => 'hxd6gwg3ekb9tb3v9lptgx1mqyg69zu9', 'fields' => '{"apiKey":"","apiSecret":""}'],
];
foreach ($gateways as $gateway) {
@ -97,7 +98,7 @@ class PaymentLibrariesSeeder extends Seeder
Gateway::query()->update(['visible' => 0]);
Gateway::whereIn('id', [1,7,11,15,20,39,46,55,50,57,52])->update(['visible' => 1]);
Gateway::whereIn('id', [1,7,11,15,20,39,46,55,50,57,52,58])->update(['visible' => 1]);
if (Ninja::isHosted()) {
Gateway::whereIn('id', [20])->update(['visible' => 0]);

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

View File

@ -3,38 +3,38 @@ const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
"version.json": "9ec5e3813adc4bfd8713556c5059e97d",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
"/": "c89483e4d5b7e4169b05f1bc0cbe5935",
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
"assets/NOTICES": "9eb7e2eb2888ea5bae5f536720db37cd",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/logo_light.png": "e5f46d5a78e226e7a9553d4ca6f69219",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/laser.png": "b4e6e93dd35517ac429301119ff05868",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/discover.png": "6c0a386a00307f87db7bea366cca35f5",
"assets/assets/images/payment_types/mastercard.png": "6f6cdc29ee2e22e06b1ac029cb52ef71",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/payment_types/ach.png": "7433f0aff779dc98a649b7a2daf777cf",
"assets/assets/images/payment_types/carteblanche.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/assets/images/payment_types/visa.png": "3ddc4a4d25c946e8ad7e6998f30fd4e3",
"assets/assets/images/payment_types/maestro.png": "e533b92bfb50339fdbfa79e3dfe81f08",
"assets/assets/images/payment_types/jcb.png": "07e0942d16c5592118b72e74f2f7198c",
"assets/assets/images/payment_types/solo.png": "2030c3ccaccf5d5e87916a62f5b084d6",
"assets/assets/images/payment_types/switch.png": "4fa11c45327f5fdc20205821b2cfd9cc",
"assets/assets/images/payment_types/paypal.png": "8e06c094c1871376dfea1da8088c29d1",
"assets/assets/images/payment_types/unionpay.png": "7002f52004e0ab8cc0b7450b0208ccb2",
"assets/assets/images/payment_types/amex.png": "c49a4247984b3732a4af50a3390aa978",
"assets/assets/images/google_logo.png": "0f118259ce403274f407f5e982e681c3",
"assets/assets/images/payment_types/dinerscard.png": "06d85186ba858c18ab7c9caa42c92024",
"assets/assets/images/logo_dark.png": "a233ed1d4d0f7414bf97a9a10f11fb0a",
"assets/assets/images/icon.png": "090f69e23311a4b6d851b3880ae52541",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
"assets/fonts/MaterialIcons-Regular.otf": "4e6447691c9509f7acdbf8a931a85ca1",
"assets/AssetManifest.json": "38d9aea341601f3a5c6fa7b5a1216ea5",
"version.json": "9ec5e3813adc4bfd8713556c5059e97d",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
"favicon.ico": "51636d3a390451561744c42188ccd628",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "174c02fc4609e8fc4389f5d21f16a296",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
"main.dart.js": "45c1fed311a0bb61b3ec0e178d9bee9e"
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"main.dart.js": "737a840bed376cb6c2a8198aec8d650b",
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
"/": "62039ec03358e95898baf5b41406df65"
};
// The application shell files that are downloaded before a service worker can

View File

@ -0,0 +1,2 @@
/*! For license information please see razorpay-aio.js.LICENSE.txt */
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=27)}({27:function(e,t,n){e.exports=n("tIvh")},tIvh:function(e,t){var n,r=JSON.parse(null===(n=document.querySelector("meta[name=razorpay-options]"))||void 0===n?void 0:n.content);r.handler=function(e){document.getElementById("razorpay_payment_id").value=e.razorpay_payment_id,document.getElementById("razorpay_signature").value=e.razorpay_signature,document.getElementById("server-response").submit()};var o=new Razorpay(r);document.getElementById("pay-now").onclick=function(e){e.target.parentElement.disabled=!0,o.open()}}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1 @@
!function(n){var r={};function o(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=n,o.c=r,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="/",o(o.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){var n;function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var r=null!==(n=null===(r=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===r?void 0:r.content)&&void 0!==n?n:"",i=null!==(n=null===(n=document.querySelector('meta[name="stripe-account-id"]'))||void 0===n?void 0:n.content)&&void 0!==n?n:"";new function t(e,n){var r=this;!function(e){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this),o(this,"setupStripe",function(){return r.stripe=Stripe(r.key),r.stripeConnect&&(r.stripe.stripeAccount=i),r}),o(this,"handle",function(){document.getElementById("pay-now").addEventListener("click",e=>{let t=document.getElementById("errors");if(!document.getElementById("bancontact-name").value)return t.textContent="Enter name",t.hidden=!1,void console.log("name");document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),this.stripe.confirmBancontactPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{billing_details:{name:document.getElementById("bancontact-name").value}},return_url:document.querySelector('meta[name="return-url"]').content})})}),this.key=e,this.errors=document.getElementById("errors"),this.stripeConnect=n}(r,i).setupStripe().handle()}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1 @@
!function(n){var r={};function o(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=n,o.c=r,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="/",o(o.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){var n;function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var r=null!==(n=null===(r=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===r?void 0:r.content)&&void 0!==n?n:"",i=null!==(n=null===(n=document.querySelector('meta[name="stripe-account-id"]'))||void 0===n?void 0:n.content)&&void 0!==n?n:"";new function t(e,n){var r=this;!function(e){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this),o(this,"setupStripe",function(){r.stripe=Stripe(r.key),r.stripeConnect&&(r.stripe.stripeAccount=i);let e=r.stripe.elements();return r.eps=e.create("epsBank",{style:{base:{padding:"10px 12px",color:"#32325d",fontSize:"16px","::placeholder":{color:"#aab7c4"}}}}),r.eps.mount("#eps-bank-element"),r}),o(this,"handle",function(){document.getElementById("pay-now").addEventListener("click",e=>{let t=document.getElementById("errors");if(!document.getElementById("eps-name").value)return t.textContent="Enter name",t.hidden=!1,void console.log("name");document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),this.stripe.confirmEpsPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{eps:r.eps,billing_details:{name:document.getElementById("eps-name").value}},return_url:document.querySelector('meta[name="return-url"]').content})})}),this.key=e,this.errors=document.getElementById("errors"),this.stripeConnect=n}(r,i).setupStripe().handle()}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1 @@
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){var n,r,o,i;function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var c=null!==(n=null===(r=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===r?void 0:r.content)&&void 0!==n?n:"",l=null!==(o=null===(i=document.querySelector('meta[name="stripe-account-id"]'))||void 0===i?void 0:i.content)&&void 0!==o?o:"";new function e(t,n){var r=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),u(this,"setupStripe",function(){return r.stripe=Stripe(r.key),r.stripeConnect&&(r.stripe.stripeAccount=l),r}),u(this,"handle",function(){document.getElementById("pay-now").addEventListener("click",function(e){let t=document.getElementById("errors");if(!document.getElementById("giropay-mandate-acceptance").checked)return t.textContent="Accept Terms",t.hidden=!1,void console.log("Terms");document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),r.stripe.confirmGiropayPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{billing_details:{name:document.getElementById("giropay-name").value}},return_url:document.querySelector('meta[name="return-url"]').content})})}),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}(c,l).setupStripe().handle()}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1 @@
!function(n){var r={};function o(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.m=n,o.c=r,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="/",o(o.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){var n;function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var r=null!==(n=null===(r=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===r?void 0:r.content)&&void 0!==n?n:"",i=null!==(n=null===(n=document.querySelector('meta[name="stripe-account-id"]'))||void 0===n?void 0:n.content)&&void 0!==n?n:"";new function t(e,n){var r=this;!function(e){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this),o(this,"setupStripe",function(){r.stripe=Stripe(r.key),r.stripeConnect&&(r.stripe.stripeAccount=i);let e=r.stripe.elements();return this.ideal=e.create("idealBank",{style:{base:{padding:"10px 12px",color:"#32325d",fontSize:"16px","::placeholder":{color:"#aab7c4"}}}}),this.ideal.mount("#ideal-bank-element"),r}),o(this,"handle",function(){document.getElementById("pay-now").addEventListener("click",e=>{let t=document.getElementById("errors");if(!document.getElementById("ideal-name").value)return t.textContent="Enter name",t.hidden=!1,void console.log("name");document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),this.stripe.confirmIdealPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{ideal:this.ideal,billing_details:{name:document.getElementById("ideal-name").value}},return_url:document.querySelector('meta[name="return-url"]').content})})}),this.key=e,this.errors=document.getElementById("errors"),this.stripeConnect=n}(r,i).setupStripe().handle()}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1 @@
!function(n){var o={};function r(e){if(o[e])return o[e].exports;var t=o[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=n,r.c=o,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/",r(r.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){var n;function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var o=null!==(n=null===(o=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===o?void 0:o.content)&&void 0!==n?n:"",a=null!==(n=null===(n=document.querySelector('meta[name="stripe-account-id"]'))||void 0===n?void 0:n.content)&&void 0!==n?n:"";new function t(e,n){var o=this;!function(e){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this),r(this,"setupStripe",function(){o.stripe=Stripe(o.key),o.stripeConnect&&(o.stripe.stripeAccount=a);let e=o.stripe.elements();return o.p24bank=e.create("p24Bank",{style:{base:{padding:"10px 12px",color:"#32325d",fontSize:"16px","::placeholder":{color:"#aab7c4"}}}}),o.p24bank.mount("#p24-bank-element"),o}),r(this,"handle",function(){document.getElementById("pay-now").addEventListener("click",function(e){let t=document.getElementById("errors");return""===document.getElementById("p24-name").value?(document.getElementById("p24-name").focus(),t.textContent="Name required.",void(t.hidden=!1)):""===document.getElementById("p24-email-address").value?(document.getElementById("p24-email-address").focus(),t.textContent="Email required.",void(t.hidden=!1)):document.getElementById("p24-mandate-acceptance").checked?(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmP24Payment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{p24:o.p24bank,billing_details:{name:document.getElementById("p24-name").value,email:document.getElementById("p24-email-address").value}},payment_method_options:{p24:{tos_shown_and_accepted:document.getElementById("p24-mandate-acceptance").checked}},return_url:document.querySelector('meta[name="return-url"]').content})):(document.getElementById("p24-mandate-acceptance").focus(),t.textContent="Accept Terms.",void(t.hidden=!1))})}),this.key=e,this.errors=document.getElementById("errors"),this.stripeConnect=n}(o,a).setupStripe().handle()}}),a;

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

View File

@ -0,0 +1,2 @@
/*! For license information please see stripe-sepa.js.LICENSE.txt */
!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=28)}({28:function(e,t,n){e.exports=n("guV3")},guV3:function(e,t){var n,o,r,a;function i(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var l=function(){function e(t,n){var o=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),u(this,"setupStripe",(function(){o.stripe=Stripe(o.key),o.stripeConnect&&(o.stripe.stripeAccount=d);var e=o.stripe.elements(),t={style:{base:{color:"#32325d",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',fontSmoothing:"antialiased",fontSize:"16px","::placeholder":{color:"#aab7c4"},":-webkit-autofill":{color:"#32325d"}},invalid:{color:"#fa755a",iconColor:"#fa755a",":-webkit-autofill":{color:"#fa755a"}}},supportedCountries:["SEPA"],placeholderCountry:document.querySelector('meta[name="country"]').content};return o.iban=e.create("iban",t),o.iban.mount("#sepa-iban"),o})),u(this,"handle",(function(){document.getElementById("pay-now").addEventListener("click",(function(e){var t=document.getElementById("errors");return""===document.getElementById("sepa-name").value?(document.getElementById("sepa-name").focus(),t.textContent="Name required.",void(t.hidden=!1)):""===document.getElementById("sepa-email-address").value?(document.getElementById("sepa-email-address").focus(),t.textContent="Email required.",void(t.hidden=!1)):document.getElementById("sepa-mandate-acceptance").checked?(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{sepa_debit:o.iban,billing_details:{name:document.getElementById("sepa-name").value,email:document.getElementById("sepa-email-address").value}}}).then((function(e){return e.error?o.handleFailure(e.error.message):o.handleSuccess(e)}))):(t.textContent="Accept Terms",t.hidden=!1,void console.log("Terms"))}))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}var t,n,o;return t=e,(n=[{key:"handleSuccess",value:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.paymentIntent),document.getElementById("server-response").submit()}},{key:"handleFailure",value:function(e){var t=document.getElementById("errors");t.textContent="",t.textContent=e,t.hidden=!1,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}}])&&i(t.prototype,n),o&&i(t,o),e}(),c=null!==(n=null===(o=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===o?void 0:o.content)&&void 0!==n?n:"",d=null!==(r=null===(a=document.querySelector('meta[name="stripe-account-id"]'))||void 0===a?void 0:a.content)&&void 0!==r?r:"";new l(c,d).setupStripe().handle()}});

View File

@ -0,0 +1,9 @@
/**
* 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://opensource.org/licenses/AAL
*/

229075
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

274646
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

229119
public/main.last.dart.js vendored

File diff suppressed because one or more lines are too long

230276
public/main.next.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

228939
public/main.wasm.dart.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5",
"/css/app.css": "/css/app.css?id=ad5ff55c9ef56ede1726",
"/css/app.css": "/css/app.css?id=f7f7b35aa3f417a3eca3",
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4",
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
@ -15,10 +15,12 @@
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=08ea84e9451abd434cff",
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=73b66e88e2daabcd6549",
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=c2b5f7831e1a46dd5fb2",
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=817ab3b2b94ee37b14eb",
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=070c86b293b532c5a56c",
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=665ddf663500767f1a17",
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=a30464874dee84678344",
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=e7dc964c85085314b12c",
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=231571942310348aa616",
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=f51400e03c5fdb6cdabe",
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=1b8f9325aa6e8595e7fa",

View File

@ -0,0 +1,29 @@
/**
* 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://opensource.org/licenses/AAL
*/
let options = JSON.parse(
document.querySelector('meta[name=razorpay-options]')?.content
);
options.handler = function(response) {
document.getElementById('razorpay_payment_id').value =
response.razorpay_payment_id;
document.getElementById('razorpay_signature').value =
response.razorpay_signature;
document.getElementById('server-response').submit();
};
let razorpay = new Razorpay(options);
document.getElementById('pay-now').onclick = function(event) {
event.target.parentElement.disabled = true;
razorpay.open();
};

View File

@ -0,0 +1,64 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessBANCONTACTPay {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (!document.getElementById('bancontact-name').value) {
errors.textContent = "Enter name";
errors.hidden = false;
console.log("name");
return ;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmBancontactPayment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
billing_details: {
name: document.getElementById("bancontact-name").value,
},
},
return_url: document.querySelector(
'meta[name="return-url"]'
).content,
}
);
});
};
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessBANCONTACTPay(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -0,0 +1,80 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessEPSPay {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
let elements = this.stripe.elements();
var options = {
style: {
base: {
padding: '10px 12px',
color: '#32325d',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
},
},
},
};
this.eps = elements.create('epsBank', options);
this.eps.mount("#eps-bank-element");
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (!document.getElementById('eps-name').value) {
errors.textContent = "Enter name";
errors.hidden = false;
console.log("name");
return ;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmEpsPayment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
eps: this.eps,
billing_details: {
name: document.getElementById("ideal-name").value,
},
},
return_url: document.querySelector(
'meta[name="return-url"]'
).content,
}
);
});
};
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessEPSPay(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -0,0 +1,65 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessGiroPay {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (!document.getElementById('giropay-mandate-acceptance').checked) {
errors.textContent = "Accept Terms";
errors.hidden = false;
console.log("Terms");
return ;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmGiropayPayment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
billing_details: {
name: document.getElementById("giropay-name").value,
},
},
return_url: document.querySelector(
'meta[name="return-url"]'
).content,
}
);
});
};
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessGiroPay(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -0,0 +1,80 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessIDEALPay {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
let elements = this.stripe.elements();
var options = {
style: {
base: {
padding: '10px 12px',
color: '#32325d',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
},
},
},
};
this.ideal = elements.create('idealBank', options);
this.ideal.mount("#ideal-bank-element");
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (!document.getElementById('ideal-name').value) {
errors.textContent = "Enter name";
errors.hidden = false;
console.log("name");
return ;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmIdealPayment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
ideal: this.ideal,
billing_details: {
name: document.getElementById("ideal-name").value,
},
},
return_url: document.querySelector(
'meta[name="return-url"]'
).content,
}
);
});
};
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessIDEALPay(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -0,0 +1,98 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessPRZELEWY24 {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
let elements = this.stripe.elements()
var options = {
// Custom styling can be passed to options when creating an Element
style: {
base: {
padding: '10px 12px',
color: '#32325d',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
},
},
},
};
this.p24bank = elements.create('p24Bank', options)
this.p24bank.mount('#p24-bank-element');
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (document.getElementById('p24-name').value === "") {
document.getElementById('p24-name').focus();
errors.textContent = "Name required.";
errors.hidden = false;
return;
}
if (document.getElementById('p24-email-address').value === "") {
document.getElementById('p24-email-address').focus();
errors.textContent = "Email required.";
errors.hidden = false;
return;
}
if (!document.getElementById('p24-mandate-acceptance').checked) {
document.getElementById('p24-mandate-acceptance').focus();
errors.textContent = "Accept Terms.";
errors.hidden = false;
return;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmP24Payment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
p24: this.p24bank,
billing_details: {
name: document.getElementById('p24-name').value,
email: document.getElementById('p24-email-address').value,
},
},
payment_method_options: {
p24: {
tos_shown_and_accepted: document.getElementById('p24-mandate-acceptance').checked,
},
},
return_url: document.querySelector('meta[name="return-url"]').content,
}
);
});
};
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessPRZELEWY24(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -0,0 +1,139 @@
/**
* 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://opensource.org/licenses/AAL
*/
class ProcessSEPA {
constructor(key, stripeConnect) {
this.key = key;
this.errors = document.getElementById('errors');
this.stripeConnect = stripeConnect;
}
setupStripe = () => {
this.stripe = Stripe(this.key);
if(this.stripeConnect)
this.stripe.stripeAccount = stripeConnect;
const elements = this.stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#aab7c4"
},
":-webkit-autofill": {
color: "#32325d"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a",
":-webkit-autofill": {
color: "#fa755a"
}
}
};
var options = {
style: style,
supportedCountries: ["SEPA"],
// If you know the country of the customer, you can optionally pass it to
// the Element as placeholderCountry. The example IBAN that is being used
// as placeholder reflects the IBAN format of that country.
placeholderCountry: document.querySelector('meta[name="country"]').content
};
this.iban = elements.create("iban", options);
this.iban.mount("#sepa-iban");
return this;
};
handle = () => {
document.getElementById('pay-now').addEventListener('click', (e) => {
let errors = document.getElementById('errors');
if (document.getElementById('sepa-name').value === "") {
document.getElementById('sepa-name').focus();
errors.textContent = "Name required.";
errors.hidden = false;
return;
}
if (document.getElementById('sepa-email-address').value === "") {
document.getElementById('sepa-email-address').focus();
errors.textContent = "Email required.";
errors.hidden = false;
return ;
}
if (!document.getElementById('sepa-mandate-acceptance').checked) {
errors.textContent = "Accept Terms";
errors.hidden = false;
console.log("Terms");
return ;
}
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe.confirmSepaDebitPayment(
document.querySelector('meta[name=pi-client-secret').content,
{
payment_method: {
sepa_debit: this.iban,
billing_details: {
name: document.getElementById("sepa-name").value,
email: document.getElementById("sepa-email-address").value,
},
},
}
).then((result) => {
if (result.error) {
return this.handleFailure(result.error.message);
}
return this.handleSuccess(result);
});
});
};
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;
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
}
}
const publishableKey = document.querySelector(
'meta[name="stripe-publishable-key"]'
)?.content ?? '';
const stripeConnect =
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
new ProcessSEPA(publishableKey, stripeConnect).setupStripe().handle();

View File

@ -4316,7 +4316,15 @@ $LANG = array(
'payment_method_cannot_be_preauthorized' => 'This payment method cannot be preauthorized.',
'kbc_cbc' => 'KBC/CBC',
'bancontact' => 'Bancontact',
'sepa_mandat' => 'By providing your IBAN and confirming this payment, you are authorizing :company and Stripe, our payment service provider, to send instructions to your bank to debit your account and your bank to debit your account in accordance with those instructions. You are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited.',
'ideal' => 'iDEAL',
'bank_account_holder' => 'Bank Account Holder',
'aio_checkout' => 'All-in-one checkout',
'przelewy24' => 'Przelewy24',
'przelewy24_accept' => 'I declare that I have familiarized myself with the regulations and information obligation of the Przelewy24 service.',
'giropay' => 'GiroPay',
'giropay_law' => 'By entering your Customer information (such as name, sort code and account number) you (the Customer) agree that this information is given voluntarily.',
'eps' => 'EPS',
);
return $LANG;

View File

@ -4250,6 +4250,7 @@ $LANG = array(
'contact_details' => 'Contact Details',
'download_backup_subject' => 'Your company backup is ready for download',
'account_passwordless_login' => 'Account passwordless login',
'przelewy24' => 'Przelewy24',
);
return $LANG;

View File

@ -4249,6 +4249,8 @@ Gdy przelewy zostaną zaksięgowane na Twoim koncie, wróć do tej strony i klik
'contact_details' => 'Contact Details',
'download_backup_subject' => 'Your company backup is ready for download',
'account_passwordless_login' => 'Account passwordless login',
'przelewy24' => 'Przelewy24',
'przelewy24_accept' => 'Oświadczam, że zapoznałem się z regulaminem i obowiązkiem informacyjnym serwisu Przelewy24.'
);
return $LANG;

View File

@ -16,6 +16,10 @@
<div>
<img src="{{ asset('images/invoiceninja-black-logo-2.png') }}" class="border-b border-gray-100 h-18 pb-4" alt="Invoice Ninja logo">
</div>
@elseif(isset($company) && !is_null($company))
<div>
<img src="{{ asset($company->present()->logo()) }}" class="h-14 mb-10" alt="{{ $company->present()->name() }} logo">
</div>
@endif
<div class="flex flex-col">
<h1 class="text-center text-3xl">{{ ctrans('texts.password_recovery') }}</h1>

View File

@ -13,11 +13,14 @@
<div class="{{ $account && !$account->isPaid() ? 'col-span-2' : 'col-span-3' }} h-screen flex">
<div class="m-auto w-1/2 md:w-1/3 lg:w-1/4">
@if($account && !$account->isPaid())
<div>
<img src="{{ asset('images/invoiceninja-black-logo-2.png') }}" class="border-b border-gray-100 h-18 pb-4" alt="Invoice Ninja logo">
</div>
@elseif(isset($company) && !is_null($company))
<div>
<img src="{{ asset($company->present()->logo()) }}" class="h-14 mb-10" alt="{{ $company->present()->name() }} logo">
</div>
@endif
<div class="flex flex-col">
<h1 class="text-center text-3xl">{{ ctrans('texts.password_recovery') }}</h1>

View File

@ -14,6 +14,7 @@
@csrf
<div class="grid grid-cols-12 gap-4 mt-10">
@if($company->client_registration_fields)
@foreach($company->client_registration_fields as $field)
@if($field['required'])
<div class="col-span-12 md:col-span-6">
@ -96,6 +97,7 @@
@endif
@endif
@endforeach
@endif
</div>
<div class="flex justify-between items-center mt-8">

View File

@ -0,0 +1,8 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.aio_checkout'), 'card_title' =>
ctrans('texts.aio_checkout')])
@section('gateway_content')
@component('portal.ninja2020.components.general.card-element-single')
{{ __('texts.payment_method_cannot_be_preauthorized') }}
@endcomponent
@endsection

View File

@ -0,0 +1,36 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.aio_checkout'), 'card_title' =>
ctrans('texts.aio_checkout')])
@section('gateway_head')
<meta name="razorpay-options" content="{{ \json_encode($options) }}">
@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="store_card">
<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 }}">
<input type="hidden" name="razorpay_payment_id" id="razorpay_payment_id">
<input type="hidden" name="razorpay_signature" id="razorpay_signature">
</form>
<div class="alert alert-failure mb-4" hidden id="errors"></div>
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
{{ ctrans('texts.aio_checkout') }}
@endcomponent
@include('portal.ninja2020.gateways.includes.payment_details')
@include('portal.ninja2020.gateways.includes.pay_now')
@endsection
@section('gateway_footer')
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script src="{{ asset('js/clients/payments/razorpay-aio.js') }}"></script>
@endsection

View File

@ -0,0 +1,7 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.bank_account'), 'card_title' => ctrans('texts.bank_account')])
@section('gateway_content')
@component('portal.ninja2020.components.general.card-element-single', ['title' => ctrans('texts.bank_account'), 'show_title' => false])
{{ __('texts.sofort_authorize_label') }}
@endcomponent
@endsection

View File

@ -0,0 +1,7 @@
<div id="stripe--payment-container">
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.name')])
<label for="bancontact-name">
<input class="input w-full" id="bancontact-name" type="text" placeholder="{{ ctrans('texts.bank_account_holder') }}">
</label>
@endcomponent
</div>

Some files were not shown because too many files have changed in this diff Show More