mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 12:04:35 -04:00
Return success to webhook URL when the gateway has been deleted/non-resolvable to prevent constant webhook retries
This commit is contained in:
parent
80a5d8a37d
commit
1d811c49b9
@ -13,6 +13,7 @@
|
|||||||
namespace App\Http\Controllers\ClientPortal;
|
namespace App\Http\Controllers\ClientPortal;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\ClientPortal\RecurringInvoices\ShowRecurringInvoiceRequest;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@ -38,4 +39,20 @@ class SubscriptionController extends Controller
|
|||||||
|
|
||||||
return render('subscriptions.index');
|
return render('subscriptions.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the recurring invoice.
|
||||||
|
*
|
||||||
|
* @param ShowRecurringInvoiceRequest $request
|
||||||
|
* @param RecurringInvoice $recurring_invoice
|
||||||
|
* @return Factory|View
|
||||||
|
*/
|
||||||
|
public function show(ShowRecurringInvoiceRequest $request, RecurringInvoice $recurring_invoice)
|
||||||
|
{
|
||||||
|
return $this->render('subscriptions.show', [
|
||||||
|
'invoice' => $recurring_invoice->load('invoices','subscription'),
|
||||||
|
'subscription' => $recurring_invoice->subscription
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ class PaymentWebhookController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(PaymentWebhookRequest $request)
|
public function __invoke(PaymentWebhookRequest $request)
|
||||||
{
|
{
|
||||||
|
//return early if we cannot resolve the company gateway
|
||||||
|
if(!$request->getCompanyGateway())
|
||||||
|
return response()->json([], 200);
|
||||||
|
|
||||||
return $request
|
return $request
|
||||||
->getCompanyGateway()
|
->getCompanyGateway()
|
||||||
->driver()
|
->driver()
|
||||||
|
51
app/Http/Livewire/SubscriptionsTable.php
Normal file
51
app/Http/Livewire/SubscriptionsTable.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Livewire;
|
||||||
|
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Utils\Traits\WithSorting;
|
||||||
|
use Livewire\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
|
class SubscriptionsTable extends Component
|
||||||
|
{
|
||||||
|
use WithPagination;
|
||||||
|
use WithSorting;
|
||||||
|
|
||||||
|
public $per_page = 10;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$query = RecurringInvoice::query()
|
||||||
|
->where('client_id', auth()->guard('contact')->user()->client->id)
|
||||||
|
->where('company_id', $this->company->id)
|
||||||
|
->whereNotNull('subscription_id')
|
||||||
|
->where('is_deleted', false)
|
||||||
|
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||||
|
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||||
|
->withTrashed()
|
||||||
|
->paginate($this->per_page);
|
||||||
|
|
||||||
|
return render('components.livewire.subscriptions-table', [
|
||||||
|
'recurring_invoices' => $query,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -47,7 +47,8 @@ class PaymentWebhookRequest extends Request
|
|||||||
{
|
{
|
||||||
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
||||||
|
|
||||||
return CompanyGateway::withTrashed()->findOrFail($this->decodePrimaryKey($this->company_gateway_id));
|
return CompanyGateway::withTrashed()->find($this->decodePrimaryKey($this->company_gateway_id));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="mb-4 uppercase leading-4 tracking-wide inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-primary text-white"
|
<div class="flex items-center justify-between">
|
||||||
translate="yes">
|
|
||||||
One-time payments
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between mt-4">
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<span class="mr-2 text-sm hidden md:block">{{ ctrans('texts.per_page') }}</span>
|
<span class="mr-2 text-sm hidden md:block">{{ ctrans('texts.per_page') }}</span>
|
||||||
<select wire:model="per_page" class="form-select py-1 text-sm">
|
<select wire:model="per_page" class="form-select py-1 text-sm">
|
||||||
@ -21,110 +16,60 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
||||||
<span role="button" wire:click="sortBy('number')" class="cursor-pointer">
|
<p role="button" wire:click="sortBy('number')" class="cursor-pointer">
|
||||||
{{ ctrans('texts.invoice') }}
|
{{ ctrans('texts.subscription') }}
|
||||||
</span>
|
</p>
|
||||||
</th>
|
</th>
|
||||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
|
||||||
<span role="button" wire:click="sortBy('amount')" class="cursor-pointer">
|
|
||||||
{{ ctrans('texts.total') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
|
||||||
<span role="button" wire:click="sortBy('public_notes')" class="cursor-pointer">
|
|
||||||
{{ ctrans('texts.date') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@forelse($invoices as $invoice)
|
|
||||||
<tr class="bg-white group hover:bg-gray-100">
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
|
||||||
<a href="{{ route('client.invoice.show', $invoice->hashed_id) }}"
|
|
||||||
class="button-link text-primary">
|
|
||||||
{{ $invoice->number }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
|
||||||
{{ App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }}
|
|
||||||
</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
|
||||||
{{ $invoice->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@empty
|
|
||||||
<tr class="bg-white group hover:bg-gray-100">
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500" colspan="100%">
|
|
||||||
{{ ctrans('texts.no_results') }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforelse
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-center md:justify-between mt-6 mb-6">
|
|
||||||
@if($invoices->total() > 0)
|
|
||||||
<span class="text-gray-700 text-sm hidden md:block">
|
|
||||||
{{ ctrans('texts.showing_x_of', ['first' => $invoices->firstItem(), 'last' => $invoices->lastItem(), 'total' => $invoices->total()]) }}
|
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
{{ $invoices->links('portal/ninja2020/vendor/pagination') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class="mb-4 uppercase leading-4 tracking-wide inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-primary text-white mt-4"
|
|
||||||
translate="yes">
|
|
||||||
Subscriptions
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between mt-4">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<span class="mr-2 text-sm hidden md:block">{{ ctrans('texts.per_page') }}</span>
|
|
||||||
<select wire:model="per_page" class="form-select py-1 text-sm">
|
|
||||||
<option>5</option>
|
|
||||||
<option selected>10</option>
|
|
||||||
<option>15</option>
|
|
||||||
<option>20</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
|
|
||||||
<div class="align-middle inline-block min-w-full overflow-hidden rounded">
|
|
||||||
<table class="min-w-full shadow rounded border border-gray-200 mt-4 credits-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
||||||
<span role="button" wire:click="sortBy('number')" class="cursor-pointer">
|
<p role="button" wire:click="sortBy('number')" class="cursor-pointer">
|
||||||
{{ ctrans('texts.invoice') }}
|
{{ ctrans('texts.frequency') }}
|
||||||
</span>
|
</p>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 text-xs font-medium leading-4 tracking-wider text-left text-white uppercase border-b border-gray-200 bg-primary">
|
||||||
|
<p role="button" wire:click="sortBy('number')" class="cursor-pointer">
|
||||||
|
{{ ctrans('texts.invoice') }}
|
||||||
|
</p>
|
||||||
</th>
|
</th>
|
||||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
||||||
<span role="button" wire:click="sortBy('amount')" class="cursor-pointer">
|
<p role="button" wire:click="sortBy('amount')" class="cursor-pointer">
|
||||||
{{ ctrans('texts.total') }}
|
{{ ctrans('texts.amount') }}
|
||||||
</span>
|
</p>
|
||||||
|
</th>
|
||||||
|
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
||||||
|
<p role="button" wire:click="sortBy('date')" class="cursor-pointer">
|
||||||
|
{{ ctrans('texts.date') }}
|
||||||
|
</p>
|
||||||
</th>
|
</th>
|
||||||
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
<th class="px-6 py-3 border-b border-gray-200 bg-primary text-left text-xs leading-4 font-medium text-white uppercase tracking-wider">
|
||||||
<span role="button" wire:click="sortBy('public_notes')" class="cursor-pointer">
|
|
||||||
{{ ctrans('texts.date') }}
|
|
||||||
</span>
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@forelse($invoices as $invoice)
|
@forelse($recurring_invoices as $recurring_invoice)
|
||||||
<tr class="bg-white group hover:bg-gray-100">
|
<tr class="bg-white group hover:bg-gray-100">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
<a href="{{ route('client.invoice.show', $invoice->hashed_id) }}"
|
{{ $recurring_invoice->subscription->name }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
|
{{ \App\Models\RecurringInvoice::frequencyForKey($recurring_invoice->frequency_id) }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
|
<a href="{{ route('client.recurring_invoice.show', $recurring_invoice->hashed_id) }}"
|
||||||
class="button-link text-primary">
|
class="button-link text-primary">
|
||||||
{{ $invoice->number }}
|
{{ $recurring_invoice->number }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
{{ App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }}
|
{{ App\Utils\Number::formatMoney($recurring_invoice->amount, $recurring_invoice->client) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
{{ $invoice->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()) }}
|
{{ $recurring_invoice->translateDate($recurring_invoice->date, $recurring_invoice->client->date_format(), $recurring_invoice->client->locale()) }}
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm leading-5 text-gray-500">
|
||||||
|
<a href="{{ route('client.subscriptions.show', $recurring_invoice->hashed_id) }}"
|
||||||
|
class="button-link text-primary">
|
||||||
|
{{ ctrans('texts.view') }}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
@ -138,13 +83,13 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center md:justify-between mt-6 mb-6">
|
<div class="flex justify-center md:justify-between mt-6 mb-6">
|
||||||
@if($invoices->total() > 0)
|
@if($recurring_invoices->total() > 0)
|
||||||
<span class="text-gray-700 text-sm hidden md:block">
|
<span class="text-gray-700 text-sm hidden md:block">
|
||||||
{{ ctrans('texts.showing_x_of', ['first' => $invoices->firstItem(), 'last' => $invoices->lastItem(), 'total' => $invoices->total()]) }}
|
{{ ctrans('texts.showing_x_of', ['first' => $recurring_invoices->firstItem(), 'last' => $recurring_invoices->lastItem(), 'total' => $recurring_invoices->total()]) }}
|
||||||
</span>
|
</span>
|
||||||
@endif
|
@endif
|
||||||
{{ $invoices->links('portal/ninja2020/vendor/pagination') }}
|
{{ $recurring_invoices->links('portal/ninja2020/vendor/pagination') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@livewire('subscription-recurring-invoices-table', ['company' => $company])
|
@livewire('subscriptions-table', ['company' => $company])
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
120
resources/views/portal/ninja2020/subscriptions/show.blade.php
Normal file
120
resources/views/portal/ninja2020/subscriptions/show.blade.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
@extends('portal.ninja2020.layout.app')
|
||||||
|
@section('meta_title', ctrans('texts.subscription'))
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="container mx-auto">
|
||||||
|
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
|
||||||
|
<div class="px-4 py-5 border-b border-gray-200 sm:px-6">
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
{{ ctrans('texts.subscription') }}
|
||||||
|
</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500" translate>
|
||||||
|
{{ ctrans('texts.details_of_recurring_invoice') }}.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dl>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||||
|
{{ ctrans('texts.start_date') }}
|
||||||
|
</dt>
|
||||||
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
{{ $invoice->translateDate($invoice->start_date, $invoice->client->date_format(), $invoice->client->locale()) }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||||
|
{{ ctrans('texts.next_send_date') }}
|
||||||
|
</dt>
|
||||||
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
{{ $invoice->translateDate(\Carbon\Carbon::parse($invoice->next_send_date)->subSeconds($invoice->client->timezone_offset()), $invoice->client->date_format(), $invoice->client->locale()) }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||||
|
{{ ctrans('texts.frequency') }}
|
||||||
|
</dt>
|
||||||
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
{{ \App\Models\RecurringInvoice::frequencyForKey($invoice->frequency_id) }}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||||
|
{{ ctrans('texts.cycles_remaining') }}
|
||||||
|
</dt>
|
||||||
|
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
{{ $invoice->remaining_cycles == '-1' ? ctrans('texts.endless') : $invoice->remaining_cycles }}
|
||||||
|
@if($invoice->remaining_cycles == '-1') ∞ @endif
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||||
|
{{ ctrans('texts.amount') }}
|
||||||
|
</dt>
|
||||||
|
<div class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
{{ \App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include('portal.ninja2020.components.entity-documents', ['entity' => $invoice])
|
||||||
|
|
||||||
|
@if($invoice->auto_bill === 'optin' || $invoice->auto_bill === 'optout')
|
||||||
|
<div class="bg-white shadow overflow-hidden lg:rounded-lg mt-4">
|
||||||
|
<div class="flex flex-col md:flex-row items-start justify-between px-4 py-5 sm:p-6">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">{{ ctrans('texts.auto_bill') }}</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">{{ ctrans('texts.auto_bill_option')}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex mt-4 space-x-2">
|
||||||
|
@livewire('recurring-invoices.update-auto-billing', ['invoice' => $invoice])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($invoice->subscription && $invoice->subscription?->allow_cancellation)
|
||||||
|
{{-- INV2-591 --}}
|
||||||
|
{{-- @if(false) --}}
|
||||||
|
<div class="bg-white shadow sm:rounded-lg mt-4">
|
||||||
|
<div class="px-4 py-5 sm:p-6">
|
||||||
|
<div class="sm:flex sm:items-start sm:justify-between">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
{{ ctrans('texts.cancellation') }}
|
||||||
|
</h3>
|
||||||
|
<div class="mt-2 max-w-xl text-sm leading-5 text-gray-500">
|
||||||
|
<p translate>
|
||||||
|
{{ ctrans('texts.about_cancellation') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||||
|
<div class="inline-flex rounded-md shadow-sm" x-data="{ open: false }">
|
||||||
|
<button class="button button-danger" translate @click="open = true">{{ ctrans('texts.request_cancellation') }}
|
||||||
|
</button>
|
||||||
|
@include('portal.ninja2020.recurring_invoices.includes.modals.cancellation')
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($invoice->subscription && $invoice->subscription->allow_plan_changes)
|
||||||
|
<div class="bg-white shadow overflow-hidden px-4 py-5 lg:rounded-lg mt-4">
|
||||||
|
<h3 class="text-lg leading-6 font-medium text-gray-900">Switch Plans:</h3>
|
||||||
|
<p class="mt-1 max-w-2xl text-sm leading-5 text-gray-500">Upgrade or downgrade your current plan.</p>
|
||||||
|
|
||||||
|
<div class="flex mt-4 space-x-2">
|
||||||
|
@foreach($invoice->subscription->service()->getPlans() as $subscription)
|
||||||
|
<a href="{{ route('client.subscription.plan_switch', ['recurring_invoice' => $invoice->hashed_id, 'target' => $subscription->hashed_id]) }}" class="border rounded px-5 py-2 hover:border-gray-800 text-sm cursor-pointer">{{ $subscription->name }}</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -98,8 +98,9 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db','check_clie
|
|||||||
Route::resource('documents', App\Http\Controllers\ClientPortal\DocumentController::class)->only(['index', 'show']);
|
Route::resource('documents', App\Http\Controllers\ClientPortal\DocumentController::class)->only(['index', 'show']);
|
||||||
|
|
||||||
Route::get('subscriptions/{recurring_invoice}/plan_switch/{target}', [App\Http\Controllers\ClientPortal\SubscriptionPlanSwitchController::class, 'index'])->name('subscription.plan_switch');
|
Route::get('subscriptions/{recurring_invoice}/plan_switch/{target}', [App\Http\Controllers\ClientPortal\SubscriptionPlanSwitchController::class, 'index'])->name('subscription.plan_switch');
|
||||||
|
|
||||||
Route::resource('subscriptions', SubscriptionController::class)->middleware('portal_enabled')->only(['index']);
|
Route::get('subscriptions/{recurring_invoice}', [SubscriptionController::class, 'show'])->middleware('portal_enabled')->name('subscriptions.show');
|
||||||
|
Route::get('subscriptions', [SubscriptionController::class, 'index'])->middleware('portal_enabled')->name('subscriptions.index');
|
||||||
|
|
||||||
Route::resource('tasks', TaskController::class)->only(['index']);
|
Route::resource('tasks', TaskController::class)->only(['index']);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user