mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #5417 from turbo124/v5-develop
Subscription bulk action routes
This commit is contained in:
commit
608f81c6eb
@ -14,8 +14,10 @@ namespace App\Console\Commands;
|
|||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\DataMapper\FeesAndLimits;
|
use App\DataMapper\FeesAndLimits;
|
||||||
use App\Events\Invoice\InvoiceWasCreated;
|
use App\Events\Invoice\InvoiceWasCreated;
|
||||||
|
use App\Factory\GroupSettingFactory;
|
||||||
use App\Factory\InvoiceFactory;
|
use App\Factory\InvoiceFactory;
|
||||||
use App\Factory\InvoiceItemFactory;
|
use App\Factory\InvoiceItemFactory;
|
||||||
|
use App\Factory\SubscriptionFactory;
|
||||||
use App\Helpers\Invoice\InvoiceSum;
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
use App\Jobs\Company\CreateCompanyTaskStatuses;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
@ -201,6 +203,54 @@ class CreateSingleAccount extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->createGateways($company, $user);
|
$this->createGateways($company, $user);
|
||||||
|
|
||||||
|
$this->createSubsData($company, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createSubsData($company, $user)
|
||||||
|
{
|
||||||
|
$gs = GroupSettingFactory::create($company->id, $user->id);
|
||||||
|
$gs->name = "plans";
|
||||||
|
$gs->save();
|
||||||
|
|
||||||
|
$p1 = Product::factory()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'product_key' => 'pro_plan',
|
||||||
|
'notes' => 'The Pro Plan',
|
||||||
|
'cost' => 10,
|
||||||
|
'price' => 10,
|
||||||
|
'quantity' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$p2 = Product::factory()->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'product_key' => 'enterprise_plan',
|
||||||
|
'notes' => 'The Pro Plan',
|
||||||
|
'cost' => 10,
|
||||||
|
'price' => 10,
|
||||||
|
'quantity' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$webhook_config = [
|
||||||
|
'post_purchase_url' => 'http://ninja.test:8000/api/admin/plan',
|
||||||
|
'post_purchase_rest_method' => 'POST',
|
||||||
|
];
|
||||||
|
|
||||||
|
$sub = SubscriptionFactory::create($company->id, $user->id);
|
||||||
|
$sub->name = "Pro Plan";
|
||||||
|
$sub->group_id = $gs->id;
|
||||||
|
$sub->recurring_product_ids = "{$p1->hashed_id}";
|
||||||
|
$sub->webhook_configuration = $webhook_config;
|
||||||
|
$sub->save();
|
||||||
|
|
||||||
|
$sub = SubscriptionFactory::create($company->id, $user->id);
|
||||||
|
$sub->name = "Enterprise Plan";
|
||||||
|
$sub->group_id = $gs->id;
|
||||||
|
$sub->recurring_product_ids = "{$p2->hashed_id}";
|
||||||
|
$sub->webhook_configuration = $webhook_config;
|
||||||
|
$sub->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createClient($company, $user)
|
private function createClient($company, $user)
|
||||||
|
@ -11,17 +11,21 @@
|
|||||||
|
|
||||||
namespace App\Factory;
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\GroupSetting;
|
use App\Models\GroupSetting;
|
||||||
|
|
||||||
class GroupSettingFactory
|
class GroupSettingFactory
|
||||||
{
|
{
|
||||||
public static function create(int $company_id, int $user_id) :GroupSetting
|
public static function create(int $company_id, int $user_id) :GroupSetting
|
||||||
{
|
{
|
||||||
|
$settings = new \stdClass;
|
||||||
|
$settings->entity = Client::class;
|
||||||
|
|
||||||
$gs = new GroupSetting;
|
$gs = new GroupSetting;
|
||||||
$gs->name = '';
|
$gs->name = '';
|
||||||
$gs->company_id = $company_id;
|
$gs->company_id = $company_id;
|
||||||
$gs->user_id = $user_id;
|
$gs->user_id = $user_id;
|
||||||
$gs->settings = '{}';
|
$gs->settings = $settings;
|
||||||
|
|
||||||
return $gs;
|
return $gs;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ namespace App\Http\Controllers\ClientPortal;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\ClientPortal\Subscriptions\ShowPlanSwitchRequest;
|
use App\Http\Requests\ClientPortal\Subscriptions\ShowPlanSwitchRequest;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@ -23,15 +24,20 @@ class SubscriptionPlanSwitchController extends Controller
|
|||||||
* Show the page for switching between plans.
|
* Show the page for switching between plans.
|
||||||
*
|
*
|
||||||
* @param ShowPlanSwitchRequest $request
|
* @param ShowPlanSwitchRequest $request
|
||||||
* @param Subscription $subscription
|
* @param RecurringInvoice $recurring_invoice
|
||||||
* @param string $target
|
* @param string $target
|
||||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||||
*/
|
*/
|
||||||
public function index(ShowPlanSwitchRequest $request, Subscription $subscription, Subscription $target)
|
public function index(ShowPlanSwitchRequest $request, RecurringInvoice $recurring_invoice, Subscription $target)
|
||||||
{
|
{
|
||||||
|
//calculate whether a payment is required or whether we pass through a credit for this.
|
||||||
|
|
||||||
|
$amount = $recurring_invoice->subscription->service()->calculateUpgradePrice($recurring_invoice, $target);
|
||||||
|
|
||||||
return render('subscriptions.switch', [
|
return render('subscriptions.switch', [
|
||||||
'subscription' => $subscription,
|
'subscription' => $subscription,
|
||||||
'target' => $target,
|
'target' => $target,
|
||||||
|
'amount' => $amount,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,12 @@ use App\Models\Subscription;
|
|||||||
use App\Repositories\SubscriptionRepository;
|
use App\Repositories\SubscriptionRepository;
|
||||||
use App\Transformers\SubscriptionTransformer;
|
use App\Transformers\SubscriptionTransformer;
|
||||||
use App\Utils\Ninja;
|
use App\Utils\Ninja;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class SubscriptionController extends BaseController
|
class SubscriptionController extends BaseController
|
||||||
{
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
protected $entity_type = Subscription::class;
|
protected $entity_type = Subscription::class;
|
||||||
|
|
||||||
protected $entity_transformer = SubscriptionTransformer::class;
|
protected $entity_transformer = SubscriptionTransformer::class;
|
||||||
@ -407,4 +410,72 @@ class SubscriptionController extends BaseController
|
|||||||
|
|
||||||
return $this->itemResponse($subscription->fresh());
|
return $this->itemResponse($subscription->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bulk actions on the list view.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/subscriptions/bulk",
|
||||||
|
* operationId="bulkSubscriptions",
|
||||||
|
* tags={"subscriptions"},
|
||||||
|
* summary="Performs bulk actions on an array of subscriptions",
|
||||||
|
* description="",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/index"),
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* description="User credentials",
|
||||||
|
* required=true,
|
||||||
|
* @OA\MediaType(
|
||||||
|
* mediaType="application/json",
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(
|
||||||
|
* type="integer",
|
||||||
|
* description="Array of hashed IDs to be bulk 'actioned",
|
||||||
|
* example="[0,1,2,3]",
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The Subscription response",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Subscription"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function bulk()
|
||||||
|
{
|
||||||
|
$action = request()->input('action');
|
||||||
|
|
||||||
|
$ids = request()->input('ids');
|
||||||
|
$subscriptions = Subscription::withTrashed()->find($this->transformKeys($ids));
|
||||||
|
|
||||||
|
$subscriptions->each(function ($subscription, $key) use ($action) {
|
||||||
|
if (auth()->user()->can('edit', $subscription)) {
|
||||||
|
$this->subscription_repo->{$action}($subscription);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->listResponse(Subscription::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,10 @@ class TemplateEmail extends Mailable
|
|||||||
{
|
{
|
||||||
$template_name = 'email.template.'.$this->build_email->getTemplate();
|
$template_name = 'email.template.'.$this->build_email->getTemplate();
|
||||||
|
|
||||||
|
if($this->build_email->getTemplate() == 'custom') {
|
||||||
|
$this->build_email->setBody(str_replace('$body', $this->build_email->getBody(), $this->client->getSetting('email_style_custom')));
|
||||||
|
}
|
||||||
|
|
||||||
$settings = $this->client->getMergedSettings();
|
$settings = $this->client->getMergedSettings();
|
||||||
|
|
||||||
$company = $this->client->company;
|
$company = $this->client->company;
|
||||||
|
@ -297,7 +297,6 @@ class InvoiceService
|
|||||||
|
|
||||||
public function deletePdf()
|
public function deletePdf()
|
||||||
{
|
{
|
||||||
nlog("delete PDF");
|
|
||||||
//UnlinkFile::dispatchNow(config('filesystems.default'), $this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf');
|
//UnlinkFile::dispatchNow(config('filesystems.default'), $this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf');
|
||||||
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf');
|
Storage::disk(config('filesystems.default'))->delete($this->invoice->client->invoice_filepath() . $this->invoice->numberFormatter().'.pdf');
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ use App\Utils\Ninja;
|
|||||||
use App\Utils\Traits\CleanLineItems;
|
use App\Utils\Traits\CleanLineItems;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use App\Utils\Traits\SubscriptionHooker;
|
use App\Utils\Traits\SubscriptionHooker;
|
||||||
|
use Carbon\Carbon;
|
||||||
use GuzzleHttp\RequestOptions;
|
use GuzzleHttp\RequestOptions;
|
||||||
|
|
||||||
class SubscriptionService
|
class SubscriptionService
|
||||||
@ -44,14 +45,15 @@ class SubscriptionService
|
|||||||
/** @var subscription */
|
/** @var subscription */
|
||||||
private $subscription;
|
private $subscription;
|
||||||
|
|
||||||
/** @var client_subscription */
|
|
||||||
// private $client_subscription;
|
|
||||||
|
|
||||||
public function __construct(Subscription $subscription)
|
public function __construct(Subscription $subscription)
|
||||||
{
|
{
|
||||||
$this->subscription = $subscription;
|
$this->subscription = $subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Performs the initial purchase of a
|
||||||
|
one time or recurring product
|
||||||
|
*/
|
||||||
public function completePurchase(PaymentHash $payment_hash)
|
public function completePurchase(PaymentHash $payment_hash)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -181,9 +183,79 @@ class SubscriptionService
|
|||||||
return redirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id);
|
return redirect('/client/recurring_invoices/'.$recurring_invoice->hashed_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function calculateUpgradePrice(RecurringInvoice $recurring_invoice, Subscription $target)
|
||||||
|
{
|
||||||
|
//calculate based on daily prices
|
||||||
|
|
||||||
|
$current_amount = $recurring_invoice->amount;
|
||||||
|
$currency_frequency = $recurring_invoice->frequency_id;
|
||||||
|
|
||||||
|
$outstanding = $recurring_invoice->invoices
|
||||||
|
->where('is_deleted', 0)
|
||||||
|
->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL])
|
||||||
|
->where('balance', '>', 0);
|
||||||
|
|
||||||
|
$outstanding_amounts = $outstanding->sum('balance');
|
||||||
|
$outstanding_invoices = $outstanding->get();
|
||||||
|
|
||||||
|
if ($outstanding->count() == 0){
|
||||||
|
//nothing outstanding
|
||||||
|
return $target->price;
|
||||||
|
}
|
||||||
|
elseif ($outstanding->count() == 1){
|
||||||
|
//user has multiple amounts outstanding
|
||||||
|
return $target->price - $this->calculateProRataRefund($outstanding->first());
|
||||||
|
}
|
||||||
|
elseif ($outstanding->count > 1) {
|
||||||
|
//user is changing plan mid frequency cycle
|
||||||
|
//we cannot handle this if there are more than one invoice outstanding.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calculateProRataRefund($invoice)
|
||||||
|
{
|
||||||
|
//determine the start date
|
||||||
|
|
||||||
|
$start_date = Carbon::parse($invoice->date);
|
||||||
|
|
||||||
|
$current_date = now();
|
||||||
|
|
||||||
|
$days_to_refund = $start_date->diffInDays($current_date);
|
||||||
|
$days_in_frequency = $this->getDaysInFrequency();
|
||||||
|
|
||||||
|
$pro_rata_refund = round(($days_to_refund/$days_in_frequency) * $invoice->amount ,2);
|
||||||
|
|
||||||
|
return $pro_rata_refund;
|
||||||
|
}
|
||||||
|
|
||||||
public function createChangePlanInvoice($data)
|
public function createChangePlanInvoice($data)
|
||||||
{
|
{
|
||||||
|
//Data array structure
|
||||||
|
/**
|
||||||
|
* [
|
||||||
|
* 'subscription' => Subscription::class,
|
||||||
|
* 'target' => Subscription::class
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
//logic
|
||||||
|
|
||||||
|
// Is the user paid up to date? ie are there any outstanding invoices for this subscription
|
||||||
|
|
||||||
|
// User in arrears.
|
||||||
|
|
||||||
|
|
||||||
|
// User paid up to date (in credit!)
|
||||||
|
|
||||||
|
//generate credit amount.
|
||||||
|
//
|
||||||
|
//generate new billable amount
|
||||||
|
//
|
||||||
|
|
||||||
|
//if billable amount is LESS than 0 -> generate a credit and pass through.
|
||||||
|
//
|
||||||
|
//if billable amoun is GREATER than 0 -> gener
|
||||||
return Invoice::where('status_id', Invoice::STATUS_SENT)->first();
|
return Invoice::where('status_id', Invoice::STATUS_SENT)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +280,7 @@ class SubscriptionService
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function convertInvoiceToRecurring($client_id)
|
private function convertInvoiceToRecurring($client_id) :RecurringInvoice
|
||||||
{
|
{
|
||||||
|
|
||||||
$subscription_repo = new SubscriptionRepository();
|
$subscription_repo = new SubscriptionRepository();
|
||||||
@ -334,4 +406,38 @@ class SubscriptionService
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDaysInFrequency()
|
||||||
|
{
|
||||||
|
|
||||||
|
switch ($this->subscription->frequency_id) {
|
||||||
|
case self::FREQUENCY_DAILY:
|
||||||
|
return 1;
|
||||||
|
case self::FREQUENCY_WEEKLY:
|
||||||
|
return 7;
|
||||||
|
case self::FREQUENCY_TWO_WEEKS:
|
||||||
|
return 14;
|
||||||
|
case self::FREQUENCY_FOUR_WEEKS:
|
||||||
|
return now()->diffInDays(now()->addWeeks(4));
|
||||||
|
case self::FREQUENCY_MONTHLY:
|
||||||
|
return now()->diffInDays(now()->addMonthNoOverflow());
|
||||||
|
case self::FREQUENCY_TWO_MONTHS:
|
||||||
|
return now()->diffInDays(now()->addMonthNoOverflow(2));
|
||||||
|
case self::FREQUENCY_THREE_MONTHS:
|
||||||
|
return now()->diffInDays(now()->addMonthNoOverflow(3));
|
||||||
|
case self::FREQUENCY_FOUR_MONTHS:
|
||||||
|
return now()->diffInDays(now()->addMonthNoOverflow(4));
|
||||||
|
case self::FREQUENCY_SIX_MONTHS:
|
||||||
|
return now()->diffInDays(now()->addMonthNoOverflow(6));
|
||||||
|
case self::FREQUENCY_ANNUALLY:
|
||||||
|
return now()->diffInDays(now()->addYear());
|
||||||
|
case self::FREQUENCY_TWO_YEARS:
|
||||||
|
return now()->diffInDays(now()->addYears(2));
|
||||||
|
case self::FREQUENCY_THREE_YEARS:
|
||||||
|
return now()->diffInDays(now()->addYears(3));
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,16 @@
|
|||||||
{!! $body !!}
|
{!! $body !!}
|
||||||
|
@isset($whitelabel)
|
||||||
|
@if(!$whitelabel)
|
||||||
|
<table cellpadding="0" cellspacing="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p>
|
||||||
|
<a href="https://invoiceninja.com" target="_blank">
|
||||||
|
{{ __('texts.ninja_email_footer', ['site' => 'Invoice Ninja']) }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
@endif
|
||||||
|
@endif
|
@ -92,7 +92,7 @@
|
|||||||
|
|
||||||
<div class="flex mt-4">
|
<div class="flex mt-4">
|
||||||
@foreach($invoice->subscription->service()->getPlans() as $subscription)
|
@foreach($invoice->subscription->service()->getPlans() as $subscription)
|
||||||
<a href="{{ route('client.subscription.plan_switch', ['subscription' => $invoice->subscription->hashed_id, 'target' => $subscription->hashed_id]) }}" class="border rounded px-5 py-2 hover:border-gray-800 text-sm cursor-pointer">{{ $subscription->name }}</a>
|
<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
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -177,6 +177,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
|||||||
// Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
|
// Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
|
||||||
|
|
||||||
Route::resource('subscriptions', 'SubscriptionController');
|
Route::resource('subscriptions', 'SubscriptionController');
|
||||||
|
Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk');
|
||||||
|
|
||||||
Route::resource('cliente_subscriptions', 'ClientSubscriptionController');
|
Route::resource('cliente_subscriptions', 'ClientSubscriptionController');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence
|
|||||||
Route::get('documents/{document}/download', 'ClientPortal\DocumentController@download')->name('documents.download');
|
Route::get('documents/{document}/download', 'ClientPortal\DocumentController@download')->name('documents.download');
|
||||||
Route::resource('documents', 'ClientPortal\DocumentController')->only(['index', 'show']);
|
Route::resource('documents', 'ClientPortal\DocumentController')->only(['index', 'show']);
|
||||||
|
|
||||||
Route::get('subscriptions/{subscription}/plan_switch/{target}', 'ClientPortal\SubscriptionPlanSwitchController@index')->name('subscription.plan_switch');
|
Route::get('subscriptions/{recurring_invoice}/plan_switch/{target}', 'ClientPortal\SubscriptionPlanSwitchController@index')->name('subscription.plan_switch');
|
||||||
|
|
||||||
Route::resource('subscriptions', 'ClientPortal\SubscriptionController')->only(['index']);
|
Route::resource('subscriptions', 'ClientPortal\SubscriptionController')->only(['index']);
|
||||||
|
|
||||||
|
56
tests/Unit/DatesTest.php
Normal file
56
tests/Unit/DatesTest.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?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 Tests\Unit;
|
||||||
|
|
||||||
|
use App\Helpers\Invoice\InvoiceSum;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
class DatesTest extends TestCase
|
||||||
|
{
|
||||||
|
use MockAccountData;
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function setUp() :void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
// $this->makeTestData();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDaysDiff()
|
||||||
|
{
|
||||||
|
$string_date = '2021-06-01';
|
||||||
|
|
||||||
|
$start_date = Carbon::parse($string_date);
|
||||||
|
$current_date = Carbon::parse('2021-06-20');
|
||||||
|
|
||||||
|
$diff_in_days = $start_date->diffInDays($current_date);
|
||||||
|
|
||||||
|
$this->assertEquals(19, $diff_in_days);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDiffInDaysRange()
|
||||||
|
{
|
||||||
|
$now = Carbon::parse('2020-01-01');
|
||||||
|
|
||||||
|
$x = now()->diffInDays(now()->addDays(7));
|
||||||
|
|
||||||
|
$this->assertEquals(7, $x);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user