mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #6626 from turbo124/v5-develop
Approve Quote Webhook
This commit is contained in:
commit
cad16eb629
24
app/Exceptions/SystemError.php
Normal file
24
app/Exceptions/SystemError.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class SystemError extends Exception
|
||||||
|
{
|
||||||
|
public function report()
|
||||||
|
{
|
||||||
|
// ..
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
return view('errors.guest', [
|
||||||
|
'message' => $this->getMessage(),
|
||||||
|
'code' => $this->getCode(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,7 @@ class NinjaPlanController extends Controller
|
|||||||
|
|
||||||
$account = $company->account;
|
$account = $company->account;
|
||||||
|
|
||||||
if (Ninja::isHosted() && MultiDB::findAndSetDbByContactKey($contact_key) && $client_contact = ClientContact::where('contact_key', $contact_key)->first())
|
if (MultiDB::findAndSetDbByContactKey($contact_key) && $client_contact = ClientContact::where('contact_key', $contact_key)->first())
|
||||||
{
|
{
|
||||||
|
|
||||||
nlog("Ninja Plan Controller - Found and set Client Contact");
|
nlog("Ninja Plan Controller - Found and set Client Contact");
|
||||||
|
@ -15,6 +15,7 @@ use App\DataMapper\Analytics\AccountDeleted;
|
|||||||
use App\DataMapper\CompanySettings;
|
use App\DataMapper\CompanySettings;
|
||||||
use App\DataMapper\DefaultSettings;
|
use App\DataMapper\DefaultSettings;
|
||||||
use App\Http\Requests\Company\CreateCompanyRequest;
|
use App\Http\Requests\Company\CreateCompanyRequest;
|
||||||
|
use App\Http\Requests\Company\DefaultCompanyRequest;
|
||||||
use App\Http\Requests\Company\DestroyCompanyRequest;
|
use App\Http\Requests\Company\DestroyCompanyRequest;
|
||||||
use App\Http\Requests\Company\EditCompanyRequest;
|
use App\Http\Requests\Company\EditCompanyRequest;
|
||||||
use App\Http\Requests\Company\ShowCompanyRequest;
|
use App\Http\Requests\Company\ShowCompanyRequest;
|
||||||
@ -598,8 +599,66 @@ class CompanyController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// public function default(DefaultCompanyRequest $request, Company $company)
|
/**
|
||||||
// {
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
// }
|
* @param UploadCompanyRequest $request
|
||||||
|
* @param Company $client
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/companies/{company}/default",
|
||||||
|
* operationId="setDefaultCompany",
|
||||||
|
* tags={"companies"},
|
||||||
|
* summary="Sets the company as the default company.",
|
||||||
|
* description="Sets the company as the default company.",
|
||||||
|
* @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/include"),
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="company",
|
||||||
|
* in="path",
|
||||||
|
* description="The Company Hashed ID",
|
||||||
|
* example="D2J234DFA",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* ),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="Returns the company object",
|
||||||
|
* @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/Company"),
|
||||||
|
* ),
|
||||||
|
* @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 default(DefaultCompanyRequest $request, Company $company)
|
||||||
|
{
|
||||||
|
|
||||||
|
$account = $company->account;
|
||||||
|
$account->default_company_id = $company->id;
|
||||||
|
$account->save();
|
||||||
|
|
||||||
|
return $this->itemResponse($company->fresh());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\DataMapper\FeesAndLimits;
|
use App\DataMapper\FeesAndLimits;
|
||||||
|
use App\Exceptions\SystemError;
|
||||||
use App\Factory\CompanyGatewayFactory;
|
use App\Factory\CompanyGatewayFactory;
|
||||||
use App\Http\Requests\StripeConnect\InitializeStripeConnectRequest;
|
use App\Http\Requests\StripeConnect\InitializeStripeConnectRequest;
|
||||||
use App\Libraries\MultiDB;
|
use App\Libraries\MultiDB;
|
||||||
@ -20,6 +21,7 @@ use App\Models\Company;
|
|||||||
use App\Models\CompanyGateway;
|
use App\Models\CompanyGateway;
|
||||||
use App\Models\GatewayType;
|
use App\Models\GatewayType;
|
||||||
use App\PaymentDrivers\Stripe\Connect\Account;
|
use App\PaymentDrivers\Stripe\Connect\Account;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Stripe\Exception\ApiErrorException;
|
use Stripe\Exception\ApiErrorException;
|
||||||
|
|
||||||
@ -78,7 +80,7 @@ class StripeConnectController extends BaseController
|
|||||||
{
|
{
|
||||||
|
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
|
throw new SystemError($e->getMessage(), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']);
|
MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']);
|
||||||
|
36
app/Http/Requests/Company/DefaultCompanyRequest.php
Normal file
36
app/Http/Requests/Company/DefaultCompanyRequest.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?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\Http\Requests\Company;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class DefaultCompanyRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin()
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -233,7 +233,7 @@ class Import implements ShouldQueue
|
|||||||
$account->save();
|
$account->save();
|
||||||
|
|
||||||
//company size check
|
//company size check
|
||||||
if ($this->company->invoices()->count() > 1000 || $this->company->products()->count() > 1000 || $this->company->clients()->count() > 1000) {
|
if ($this->company->invoices()->count() > 500 || $this->company->products()->count() > 500 || $this->company->clients()->count() > 500) {
|
||||||
$this->company->is_large = true;
|
$this->company->is_large = true;
|
||||||
$this->company->save();
|
$this->company->save();
|
||||||
}
|
}
|
||||||
@ -261,9 +261,6 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
/*After a migration first some basic jobs to ensure the system is up to date*/
|
/*After a migration first some basic jobs to ensure the system is up to date*/
|
||||||
VersionCheck::dispatch();
|
VersionCheck::dispatch();
|
||||||
|
|
||||||
// CreateCompanyPaymentTerms::dispatchNow($sp035a66, $spaa9f78);
|
|
||||||
// CreateCompanyTaskStatuses::dispatchNow($this->company, $this->user);
|
|
||||||
|
|
||||||
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
info('Completed🚀🚀🚀🚀🚀 at '.now());
|
||||||
|
|
||||||
|
47
app/Listeners/Quote/QuoteApprovedWebhook.php
Normal file
47
app/Listeners/Quote/QuoteApprovedWebhook.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Quote Ninja (https://quoteninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/quoteninja/quoteninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Quote Ninja LLC (https://quoteninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Listeners\Quote;
|
||||||
|
|
||||||
|
use App\Jobs\Util\WebhookHandler;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
|
||||||
|
class QuoteApprovedWebhook implements ShouldQueue
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param object $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle($event)
|
||||||
|
{
|
||||||
|
MultiDB::setDb($event->company->db);
|
||||||
|
|
||||||
|
$quote = $event->quote;
|
||||||
|
|
||||||
|
$subscriptions = Webhook::where('company_id', $quote->company_id)
|
||||||
|
->where('event_id', Webhook::EVENT_APPROVE_QUOTE)
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if ($subscriptions) {
|
||||||
|
WebhookHandler::dispatch(Webhook::EVENT_APPROVE_QUOTE, $quote, $quote->company);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -123,7 +123,7 @@ class TemplateEmail extends Mailable
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->invitation->invoice && $settings->ubl_email_attachment && $this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){
|
if($this->invitation && $this->invitation->invoice && $settings->ubl_email_attachment && $this->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){
|
||||||
|
|
||||||
$ubl_string = CreateUbl::dispatchNow($this->invitation->invoice);
|
$ubl_string = CreateUbl::dispatchNow($this->invitation->invoice);
|
||||||
|
|
||||||
|
@ -161,6 +161,7 @@ use App\Listeners\Payment\PaymentEmailedActivity;
|
|||||||
use App\Listeners\Payment\PaymentNotification;
|
use App\Listeners\Payment\PaymentNotification;
|
||||||
use App\Listeners\Payment\PaymentRestoredActivity;
|
use App\Listeners\Payment\PaymentRestoredActivity;
|
||||||
use App\Listeners\Quote\QuoteApprovedActivity;
|
use App\Listeners\Quote\QuoteApprovedActivity;
|
||||||
|
use App\Listeners\Quote\QuoteApprovedWebhook;
|
||||||
use App\Listeners\Quote\QuoteArchivedActivity;
|
use App\Listeners\Quote\QuoteArchivedActivity;
|
||||||
use App\Listeners\Quote\QuoteCreatedNotification;
|
use App\Listeners\Quote\QuoteCreatedNotification;
|
||||||
use App\Listeners\Quote\QuoteDeletedActivity;
|
use App\Listeners\Quote\QuoteDeletedActivity;
|
||||||
@ -385,6 +386,7 @@ class EventServiceProvider extends ServiceProvider
|
|||||||
QuoteWasApproved::class => [
|
QuoteWasApproved::class => [
|
||||||
ReachWorkflowSettings::class,
|
ReachWorkflowSettings::class,
|
||||||
QuoteApprovedActivity::class,
|
QuoteApprovedActivity::class,
|
||||||
|
QuoteApprovedWebhook::class,
|
||||||
],
|
],
|
||||||
QuoteWasCreated::class => [
|
QuoteWasCreated::class => [
|
||||||
CreatedQuoteActivity::class,
|
CreatedQuoteActivity::class,
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"coconutcraig/laravel-postmark": "^2.10",
|
"coconutcraig/laravel-postmark": "^2.10",
|
||||||
"codedge/laravel-selfupdater": "^3.2",
|
"codedge/laravel-selfupdater": "^3.2",
|
||||||
"composer/composer": "^2",
|
"composer/composer": "^2",
|
||||||
"doctrine/dbal": "^2.10",
|
"doctrine/dbal": "^3.0",
|
||||||
"eway/eway-rapid-php": "^1.3",
|
"eway/eway-rapid-php": "^1.3",
|
||||||
"fakerphp/faker": "^1.14",
|
"fakerphp/faker": "^1.14",
|
||||||
"fideloper/proxy": "^4.2",
|
"fideloper/proxy": "^4.2",
|
||||||
|
722
composer.lock
generated
722
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@ input:checked ~ .dot {
|
|||||||
background-color: #48bb78;
|
background-color: #48bb78;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container flex flex-wrap pt-4 pb-10 m-auto mt-6 md:mt-15 lg:px-12 xl:px-16" x-data="{show: true}">
|
<div id="datadiv" class="container flex flex-wrap pt-2 pb-10 m-auto mt-2 md:mt-5 lg:px-16 xl:px-16" x-data="{show: true}">
|
||||||
<div class="w-full px-0 lg:px-4">
|
<div class="w-full px-0 lg:px-4">
|
||||||
<h2 class="px-12 text-base font-bold text-center md:text-2xl text-blue-700">
|
<h2 class="px-12 text-base font-bold text-center md:text-2xl text-blue-700">
|
||||||
Choose your plan
|
Choose your plan
|
||||||
@ -61,14 +61,28 @@ input:checked ~ .dot {
|
|||||||
<p class="text-xs text-center uppercase text-white">
|
<p class="text-xs text-center uppercase text-white">
|
||||||
monthly
|
monthly
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Unlimited clients, invoices, quotes, recurring invoices</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">10 professional invoice & quote template designs</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Remove "Created by Invoice Ninja" from invoices</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Enable emails to be sent via Gmail</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Integrate with Zapier, Integromat or API</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">+ Much more!</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700">
|
<div class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700">
|
||||||
<p class="text-xl text-white">
|
<p class="text-xl text-white">
|
||||||
Sign up!
|
Single User
|
||||||
</p>
|
</p>
|
||||||
<a type="button" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500" href="https://invoiceninja.invoicing.co/client/subscriptions/WJxbojagwO/purchase">
|
<button id="handleProMonthlyClick" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500">
|
||||||
Purchase
|
Purchase
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -78,33 +92,46 @@ input:checked ~ .dot {
|
|||||||
<label class="flex flex-col rounded-lg shadow-lg relative cursor-pointer hover:shadow-2xl">
|
<label class="flex flex-col rounded-lg shadow-lg relative cursor-pointer hover:shadow-2xl">
|
||||||
<div class="w-full px-4 py-8 rounded-t-lg bg-blue-500">
|
<div class="w-full px-4 py-8 rounded-t-lg bg-blue-500">
|
||||||
<h3 class="mx-auto text-base font-semibold text-center underline text-white group-hover:text-white">
|
<h3 class="mx-auto text-base font-semibold text-center underline text-white group-hover:text-white">
|
||||||
Enterprise (1-2 Users)
|
Enterprise Plan
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-5xl font-bold text-center text-white">
|
<p class="text-5xl font-bold text-center text-white" id="m_plan_price">
|
||||||
$14
|
$14
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-center uppercase text-white">
|
<p class="text-xs text-center uppercase text-white">
|
||||||
monthly
|
monthly
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Multiple users and advanced permissions per user</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Attach documents to emails & client side portal!</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Branded client portal: "https://billing.yourcompany.com"</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Custom background for invoices & quotes</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Integrate with Zapier, Integromat or API</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">+ Much more!</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700">
|
<div class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700">
|
||||||
<p class="text-xl text-white">
|
<p class="text-xl text-white">
|
||||||
Sign up!
|
<select id="users_monthly" class="bg-white text-black appearance-none border-none inline-block py-0 pl-3 pr-2 rounded leading-tight w-full">
|
||||||
|
<option value="7LDdwRb1YK" selected>1-2 Users</option>
|
||||||
|
<option value="MVyb8mdvAZ">3-5 Users</option>
|
||||||
|
<option value="WpmbkR5azJ">6-10 Users</option>
|
||||||
|
<option value="k8mepY2aMy">11-20 Users</option>
|
||||||
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<a type="button" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500" href="https://invoiceninja.invoicing.co/client/subscriptions/7LDdwRb1YK/purchase">
|
<button id="handleMonthlyClick" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500">
|
||||||
Purchase
|
Purchase
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Annual Plans -->
|
<!-- Annual Plans -->
|
||||||
<div class="flex flex-wrap items-center justify-center py-4 pt-0" x-show=" !show ">
|
<div class="flex flex-wrap items-center justify-center py-4 pt-0" x-show=" !show ">
|
||||||
<div class="w-full p-4 md:w-1/2 lg:w-1/2">
|
<div class="w-full p-4 md:w-1/2 lg:w-1/2">
|
||||||
@ -119,6 +146,19 @@ input:checked ~ .dot {
|
|||||||
<p class="text-xs text-center uppercase text-white">
|
<p class="text-xs text-center uppercase text-white">
|
||||||
yearly
|
yearly
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Unlimited clients, invoices, quotes, recurring invoices</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">10 professional invoice & quote template designs</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Remove "Created by Invoice Ninja" from invoices</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Enable emails to be sent via Gmail</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Integrate with Zapier, Integromat or API</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">+ Much more!</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700"
|
class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700"
|
||||||
@ -126,9 +166,9 @@ input:checked ~ .dot {
|
|||||||
<p class="text-xl text-white">
|
<p class="text-xl text-white">
|
||||||
Buy 10 months get 2 free!
|
Buy 10 months get 2 free!
|
||||||
</p>
|
</p>
|
||||||
<a type="button" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500" href="https://invoiceninja.invoicing.co/client/subscriptions/q9wdL9wejP/purchase">
|
<button id="handleProYearlyClick" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500">
|
||||||
Purchase
|
Purchase
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -137,24 +177,42 @@ input:checked ~ .dot {
|
|||||||
<label class="flex flex-col rounded-lg shadow-lg relative cursor-pointer hover:shadow-2xl">
|
<label class="flex flex-col rounded-lg shadow-lg relative cursor-pointer hover:shadow-2xl">
|
||||||
<div class="w-full px-4 py-8 rounded-t-lg bg-blue-500">
|
<div class="w-full px-4 py-8 rounded-t-lg bg-blue-500">
|
||||||
<h3 class="mx-auto text-base font-semibold text-center underline text-white group-hover:text-white">
|
<h3 class="mx-auto text-base font-semibold text-center underline text-white group-hover:text-white">
|
||||||
Enterprise (1-2 Users)
|
Enterprise Plan
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-5xl font-bold text-center text-white">
|
<p class="text-5xl font-bold text-center text-white" id="y_plan_price">
|
||||||
$140
|
$140
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-center uppercase text-white">
|
<p class="text-xs text-center uppercase text-white">
|
||||||
yearly
|
yearly
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Multiple users and advanced permissions per user</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Attach documents to emails & client side portal!</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Branded client portal: "https://billing.yourcompany.com"</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Custom background for invoices & quotes</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">Integrate with Zapier, Integromat or API</div>
|
||||||
|
<hr>
|
||||||
|
<div class="py-2 text-sm my-3 text-white">+ Much more!</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700"
|
class="flex flex-col items-center justify-center w-full h-full py-6 rounded-b-lg bg-blue-700"
|
||||||
>
|
>
|
||||||
<p class="text-xl text-white">
|
<p class="text-xl text-white">
|
||||||
Buy 10 months get 2 free!
|
<select id="users_yearly" class="bg-white text-black appearance-none border-none inline-block py-0 pl-3 pr-2 rounded leading-tight w-full">
|
||||||
|
<option value="LYqaQWldnj" selected>1-2 Users</option>
|
||||||
|
<option value="kQBeX6mbyK">3-5 Users</option>
|
||||||
|
<option value="GELe32Qd69">6-10 Users</option>
|
||||||
|
<option value="MVyb86oevA">11-20 Users</option>
|
||||||
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<a type="button" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500" href="https://invoiceninja.invoicing.co/client/subscriptions/LYqaQWldnj/purchase">
|
<button id="handleYearlyClick" class="w-5/6 py-2 mt-2 font-semibold text-center uppercase bg-white border border-transparent rounded text-blue-500" >
|
||||||
Purchase
|
Purchase
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -167,5 +225,68 @@ input:checked ~ .dot {
|
|||||||
|
|
||||||
@push('footer')
|
@push('footer')
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var users_yearly = 'LYqaQWldnj';
|
||||||
|
var users_monthly = '7LDdwRb1YK';
|
||||||
|
|
||||||
|
document.getElementById('users_yearly').options[0].selected = true;
|
||||||
|
document.getElementById('users_monthly').options[0].selected = true;
|
||||||
|
|
||||||
|
document.getElementById("toggleB").addEventListener('change', function() {
|
||||||
|
|
||||||
|
document.getElementById('users_yearly').options[0].selected = true;
|
||||||
|
document.getElementById('users_monthly').options[0].selected = true;
|
||||||
|
document.getElementById('y_plan_price').innerHTML = price_map.get('LYqaQWldnj');
|
||||||
|
document.getElementById('m_plan_price').innerHTML = price_map.get('7LDdwRb1YK');
|
||||||
|
|
||||||
|
users_yearly = 'LYqaQWldnj';
|
||||||
|
users_monthly = '7LDdwRb1YK';
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('users_yearly').addEventListener('change', function() {
|
||||||
|
users_yearly = this.value;
|
||||||
|
document.getElementById('y_plan_price').innerHTML = price_map.get(this.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('users_monthly').addEventListener('change', function() {
|
||||||
|
users_monthly = this.value;
|
||||||
|
document.getElementById('m_plan_price').innerHTML = price_map.get(this.value);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('handleYearlyClick').addEventListener('click', function() {
|
||||||
|
document.getElementById("toggleB").checked = false;
|
||||||
|
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/' + users_yearly + '/purchase';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('handleMonthlyClick').addEventListener('click', function() {
|
||||||
|
document.getElementById("toggleB").checked = false;
|
||||||
|
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/' + users_monthly + '/purchase';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('handleProMonthlyClick').addEventListener('click', function() {
|
||||||
|
document.getElementById("toggleB").checked = false;
|
||||||
|
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/WJxbojagwO/purchase';
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('handleProYearlyClick').addEventListener('click', function() {
|
||||||
|
document.getElementById("toggleB").checked = false;
|
||||||
|
location.href = 'https://invoiceninja.invoicing.co/client/subscriptions/q9wdL9wejP/purchase';
|
||||||
|
});
|
||||||
|
const price_map = new Map();
|
||||||
|
//monthly
|
||||||
|
price_map.set('7LDdwRb1YK', '$14');
|
||||||
|
price_map.set('MVyb8mdvAZ', '$26');
|
||||||
|
price_map.set('WpmbkR5azJ', '$36');
|
||||||
|
price_map.set('k8mepY2aMy', '$44');
|
||||||
|
//yearly
|
||||||
|
price_map.set('LYqaQWldnj', '$140');
|
||||||
|
price_map.set('kQBeX6mbyK', '$260');
|
||||||
|
price_map.set('GELe32Qd69', '$360');
|
||||||
|
price_map.set('MVyb86oevA', '$440');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
@endpush
|
@endpush
|
||||||
|
@ -51,6 +51,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
|||||||
Route::resource('companies', 'CompanyController'); // name = (companies. index / create / show / update / destroy / edit
|
Route::resource('companies', 'CompanyController'); // name = (companies. index / create / show / update / destroy / edit
|
||||||
|
|
||||||
Route::put('companies/{company}/upload', 'CompanyController@upload');
|
Route::put('companies/{company}/upload', 'CompanyController@upload');
|
||||||
|
Route::post('companies/{company}/default', 'CompanyController@default');
|
||||||
|
|
||||||
Route::get('company_ledger', 'CompanyLedgerController@index')->name('company_ledger.index');
|
Route::get('company_ledger', 'CompanyLedgerController@index')->name('company_ledger.index');
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'clie
|
|||||||
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_invitation_key');
|
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_invitation_key');
|
||||||
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_invitation_key');
|
||||||
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
|
||||||
Route::get('{entity}/{client_hash}/{invitation_key}', 'ClientPortal\InvitationController@routerForIframe')->name('invoice.client_hash_and_invitation_key'); //should never need this
|
// Route::get('{entity}/{client_hash}/{invitation_key}', 'ClientPortal\InvitationController@routerForIframe')->name('invoice.client_hash_and_invitation_key'); //should never need this
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user