mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #6961 from turbo124/v5-develop
Restrict API access for free/unpaid accounts
This commit is contained in:
commit
2505b86360
@ -59,7 +59,6 @@ class InvoiceController extends Controller
|
||||
|
||||
$invoice->service()->removeUnpaidGatewayFees()->save();
|
||||
|
||||
|
||||
$invitation = $invoice->invitations()->where('client_contact_id', auth()->user()->id)->first();
|
||||
|
||||
if ($invitation && auth()->guard('contact') && ! request()->has('silent') && ! $invitation->viewed_date) {
|
||||
|
@ -13,12 +13,31 @@
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\RecurringInvoice;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SubscriptionController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
||||
if(Ninja::isHosted()){
|
||||
|
||||
|
||||
$count = RecurringInvoice::query()
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', auth('contact')->user()->client->company_id)
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->whereNotNull('subscription_id')
|
||||
->count();
|
||||
|
||||
if($count == 0)
|
||||
return redirect()->route('client.ninja_contact_login', ['contact_key' => auth('contact')->user()->contact_key, 'company_key' => auth('contact')->user()->company->company_key]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return render('subscriptions.index');
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class ImportController extends Controller {
|
||||
$contents = file_get_contents( $file->getPathname() );
|
||||
|
||||
// Store the csv in cache with an expiry of 10 minutes
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 600 );
|
||||
|
||||
// Parse CSV
|
||||
$csv_array = $this->getCsvData( $contents );
|
||||
@ -111,7 +111,7 @@ class ImportController extends Controller {
|
||||
$contents = file_get_contents( $file->getPathname() );
|
||||
|
||||
// Store the csv in cache with an expiry of 10 minutes
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 3600 );
|
||||
Cache::put( $hash . '-' . $entityType, base64_encode( $contents ), 600 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,9 +522,6 @@ class InvoiceController extends BaseController
|
||||
|
||||
$ids = request()->input('ids');
|
||||
|
||||
nlog($action);
|
||||
nlog($ids);
|
||||
|
||||
$invoices = Invoice::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
|
||||
|
||||
if (! $invoices) {
|
||||
@ -542,7 +539,7 @@ nlog($ids);
|
||||
return response()->json(['message' => ctrans('text.access_denied')]);
|
||||
}
|
||||
});
|
||||
nlog("bulky");
|
||||
|
||||
ZipInvoices::dispatch($invoices, $invoices->first()->company, auth()->user());
|
||||
|
||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||
|
@ -293,7 +293,7 @@ class BillingPortalPurchase extends Component
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ((int)$this->subscription->price == 0)
|
||||
if ((int)$this->price == 0)
|
||||
$this->steps['payment_required'] = false;
|
||||
else
|
||||
$this->steps['fetched_payment_methods'] = true;
|
||||
|
@ -42,7 +42,7 @@ class RecurringInvoicesTable extends Component
|
||||
$query = $query
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_PENDING, RecurringInvoice::STATUS_ACTIVE, RecurringInvoice::STATUS_PAUSED,RecurringInvoice::STATUS_COMPLETED])
|
||||
->whereIn('status_id', [RecurringInvoice::STATUS_ACTIVE])
|
||||
->orderBy('status_id', 'asc')
|
||||
->with('client')
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
|
@ -38,6 +38,7 @@ class SubscriptionRecurringInvoicesTable extends Component
|
||||
->where('client_id', auth('contact')->user()->client->id)
|
||||
->where('company_id', $this->company->id)
|
||||
->whereNotNull('subscription_id')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->orderBy($this->sort_field, $this->sort_asc ? 'asc' : 'desc')
|
||||
->withTrashed()
|
||||
->paginate($this->per_page);
|
||||
|
@ -42,6 +42,16 @@ class TokenAuth
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
if(Ninja::isHosted() && $company_token->is_system == 0 && !$user->account->isPaid()){
|
||||
|
||||
$error = [
|
||||
'message' => 'Feature not available with free / unpaid account.',
|
||||
'errors' => new stdClass,
|
||||
];
|
||||
|
||||
return response()->json($error, 403);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
||||
| Necessary evil here: As we are authenticating on CompanyToken,
|
||||
|
@ -221,6 +221,9 @@ class BaseTransformer
|
||||
{
|
||||
$name = strtolower(trim($name));
|
||||
|
||||
if(strlen($name) == 2)
|
||||
return $this->getCountryIdBy2($name);
|
||||
|
||||
return isset($this->maps['countries'][$name]) ? $this->maps['countries'][$name] : null;
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ class CSVImport implements ShouldQueue {
|
||||
}
|
||||
|
||||
private function getCsvData( $entityType ) {
|
||||
$base64_encoded_csv = Cache::get( $this->hash . '-' . $entityType );
|
||||
$base64_encoded_csv = Cache::pull( $this->hash . '-' . $entityType );
|
||||
if ( empty( $base64_encoded_csv ) ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ class ZipInvoices implements ShouldQueue
|
||||
*/
|
||||
|
||||
public function handle()
|
||||
{nlog("bulky");
|
||||
{
|
||||
# create new zip object
|
||||
$zip = new ZipArchive();
|
||||
|
||||
|
@ -232,6 +232,7 @@ class Import implements ShouldQueue
|
||||
|
||||
$account = $this->company->account;
|
||||
$account->default_company_id = $this->company->id;
|
||||
$account->is_migrated = true;
|
||||
$account->save();
|
||||
|
||||
//company size check
|
||||
|
@ -49,15 +49,19 @@ class SystemLogger implements ShouldQueue
|
||||
|
||||
public function handle() :void
|
||||
{
|
||||
if(!$this->company)
|
||||
if(!$this->company){
|
||||
nlog("SystemLogger:: No company");
|
||||
return;
|
||||
}
|
||||
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$client_id = $this->client ? $this->client->id : null;
|
||||
|
||||
if(!$this->client && !$this->company->owner())
|
||||
if(!$this->client && !$this->company->owner()){
|
||||
nlog("SystemLogger:: could not find client and/or company owner");
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = $this->client ? $this->client->user_id : $this->company->owner()->id;
|
||||
|
||||
@ -71,9 +75,16 @@ class SystemLogger implements ShouldQueue
|
||||
'type_id' => $this->type_id,
|
||||
];
|
||||
|
||||
if(!$this->log)
|
||||
if(!$this->log){
|
||||
nlog("SystemLogger:: no log to store");
|
||||
return;
|
||||
}
|
||||
|
||||
SystemLog::create($sl);
|
||||
}
|
||||
|
||||
public function failed($e)
|
||||
{
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,10 @@ class InvoiceCreatedNotification implements ShouldQueue
|
||||
|
||||
/* The User */
|
||||
$user = $company_user->user;
|
||||
|
||||
if(!$user)
|
||||
continue;
|
||||
|
||||
/* This is only here to handle the alternate message channels - ie Slack */
|
||||
// $notification = new EntitySentNotification($event->invitation, 'invoice');
|
||||
|
||||
@ -71,11 +75,6 @@ class InvoiceCreatedNotification implements ShouldQueue
|
||||
|
||||
}
|
||||
|
||||
/* Override the methods in the Notification Class */
|
||||
// $notification->method = $methods;
|
||||
|
||||
// Notify on the alternate channels
|
||||
// $user->notify($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ class QuoteCreatedNotification implements ShouldQueue
|
||||
/* The User */
|
||||
$user = $company_user->user;
|
||||
|
||||
if(!$user)
|
||||
continue;
|
||||
|
||||
/* This is only here to handle the alternate message channels - ie Slack */
|
||||
// $notification = new EntitySentNotification($event->invitation, 'quote');
|
||||
|
||||
|
@ -3,9 +3,11 @@
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Utils\Ninja;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class MigrationCompleted extends Mailable
|
||||
{
|
||||
@ -33,6 +35,11 @@ class MigrationCompleted extends Mailable
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
|
||||
App::forgetInstance('translator');
|
||||
$t = app('translator');
|
||||
$t->replace(Ninja::transformTranslations($this->company->settings));
|
||||
|
||||
$data['settings'] = $this->company->settings;
|
||||
$data['company'] = $this->company->fresh();
|
||||
$data['whitelabel'] = $this->company->account->isPaid() ? true : false;
|
||||
|
@ -57,7 +57,7 @@ class HandleReversal extends AbstractService
|
||||
$paymentables->each(function ($paymentable) use ($total_paid) {
|
||||
|
||||
//new concept - when reversing, we unwind the payments
|
||||
$payment = Payment::find($paymentable->payment_id);
|
||||
$payment = Payment::withTrashed()->find($paymentable->payment_id);
|
||||
|
||||
$reversable_amount = $paymentable->amount - $paymentable->refunded;
|
||||
$total_paid -= $reversable_amount;
|
||||
|
@ -37,34 +37,37 @@ class MarkSent extends AbstractService
|
||||
return $this->invoice;
|
||||
}
|
||||
|
||||
$adjustment = $this->invoice->amount;
|
||||
|
||||
/*Set status*/
|
||||
$this->invoice
|
||||
->service()
|
||||
->setStatus(Invoice::STATUS_SENT)
|
||||
->updateBalance($adjustment, true)
|
||||
->save();
|
||||
|
||||
$this->invoice
|
||||
/*Adjust client balance*/
|
||||
$this->client
|
||||
->service()
|
||||
->updateBalance($adjustment)
|
||||
->save();
|
||||
|
||||
/*Update ledger*/
|
||||
$this->invoice
|
||||
->ledger()
|
||||
->updateInvoiceBalance($adjustment, "Invoice {$this->invoice->number} marked as sent.");
|
||||
|
||||
/* Perform additional actions on invoice */
|
||||
$this->invoice
|
||||
->service()
|
||||
->applyNumber()
|
||||
->setDueDate()
|
||||
->updateBalance($this->invoice->amount, true)
|
||||
->deletePdf()
|
||||
->setReminder()
|
||||
->save();
|
||||
|
||||
$this->invoice->markInvitationsSent();
|
||||
|
||||
/*Adjust client balance*/
|
||||
$this->client
|
||||
->service()
|
||||
->updateBalance($this->invoice->balance)
|
||||
->save();
|
||||
|
||||
/*Update ledger*/
|
||||
$this->invoice
|
||||
->ledger()
|
||||
->updateInvoiceBalance($this->invoice->balance, "Invoice {$this->invoice->number} marked as sent.");
|
||||
|
||||
event(new InvoiceWasUpdated($this->invoice, $this->invoice->company, Ninja::eventVars(auth()->user() ? auth()->user()->id : null)));
|
||||
|
||||
return $this->invoice->fresh();
|
||||
|
@ -290,6 +290,9 @@ class SubscriptionService
|
||||
|
||||
$days_in_frequency = $this->getDaysInFrequency();
|
||||
|
||||
if($days_of_subscription_used >= $days_in_frequency)
|
||||
return 0;
|
||||
|
||||
$pro_rata_refund = round((($days_in_frequency - $days_of_subscription_used)/$days_in_frequency) * $invoice->amount ,2);
|
||||
|
||||
// nlog("days in frequency = {$days_in_frequency} - days of subscription used {$days_of_subscription_used}");
|
||||
@ -322,7 +325,8 @@ class SubscriptionService
|
||||
|
||||
$days_of_subscription_used = $start_date->diffInDays($current_date);
|
||||
|
||||
$days_in_frequency = $this->getDaysInFrequency();
|
||||
// $days_in_frequency = $this->getDaysInFrequency();
|
||||
$days_in_frequency = $invoice->subscription->service()->getDaysInFrequency();
|
||||
|
||||
$ratio = ($days_in_frequency - $days_of_subscription_used)/$days_in_frequency;
|
||||
|
||||
@ -427,6 +431,8 @@ class SubscriptionService
|
||||
|
||||
nlog("total payable = {$total_payable}");
|
||||
|
||||
$credit = false;
|
||||
|
||||
/* Only generate a credit if the previous invoice was paid in full. */
|
||||
if($last_invoice->balance == 0)
|
||||
$credit = $this->createCredit($last_invoice, $target_subscription, $is_credit);
|
||||
@ -436,7 +442,7 @@ class SubscriptionService
|
||||
$context = [
|
||||
'context' => 'change_plan',
|
||||
'recurring_invoice' => $new_recurring_invoice->hashed_id,
|
||||
'credit' => $credit->hashed_id,
|
||||
'credit' => $credit ? $credit->hashed_id : null,
|
||||
'client' => $new_recurring_invoice->client->hashed_id,
|
||||
'subscription' => $target_subscription->hashed_id,
|
||||
'contact' => auth('contact')->user()->hashed_id,
|
||||
@ -446,7 +452,10 @@ class SubscriptionService
|
||||
|
||||
nlog($response);
|
||||
|
||||
return $this->handleRedirect('/client/credits/'.$credit->hashed_id);
|
||||
if($credit)
|
||||
return $this->handleRedirect('/client/credits/'.$credit->hashed_id);
|
||||
else
|
||||
return $this->handleRedirect('/client/credits');
|
||||
|
||||
}
|
||||
|
||||
@ -545,6 +554,9 @@ class SubscriptionService
|
||||
|
||||
$old_recurring_invoice = RecurringInvoice::find($payment_hash->data->billing_context->recurring_invoice);
|
||||
|
||||
if(!$old_recurring_invoice)
|
||||
return $this->handleRedirect('/client/recurring_invoices/');
|
||||
|
||||
$recurring_invoice = $this->createNewRecurringInvoice($old_recurring_invoice);
|
||||
|
||||
$context = [
|
||||
@ -702,7 +714,7 @@ class SubscriptionService
|
||||
|
||||
$recurring_invoice = RecurringInvoiceFactory::create($this->subscription->company_id, $this->subscription->user_id);
|
||||
$recurring_invoice->client_id = $client_id;
|
||||
$recurring_invoice->line_items = $subscription_repo->generateLineItems($this->subscription, true);
|
||||
$recurring_invoice->line_items = $subscription_repo->generateLineItems($this->subscription, true, false);
|
||||
$recurring_invoice->subscription_id = $this->subscription->id;
|
||||
$recurring_invoice->frequency_id = $this->subscription->frequency_id ?: RecurringInvoice::FREQUENCY_MONTHLY;
|
||||
$recurring_invoice->date = now();
|
||||
|
@ -82,6 +82,7 @@ class AccountTransformer extends EntityTransformer
|
||||
'disable_auto_update' => (bool) config('ninja.disable_auto_update'),
|
||||
'emails_sent' => (int) $account->emailsSent(),
|
||||
'email_quota' => (int) $account->getDailyEmailLimit(),
|
||||
'is_migrated' => (bool) $account->is_migrated,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -113,8 +113,14 @@ class Ninja
|
||||
|
||||
public static function eventVars($user_id = null)
|
||||
{
|
||||
|
||||
if(request()->hasHeader('Cf-Connecting-Ip'))
|
||||
$ip = request()->header('Cf-Connecting-Ip');
|
||||
else
|
||||
$ip = request()->getClientIp();
|
||||
|
||||
return [
|
||||
'ip' => request()->getClientIp(),
|
||||
'ip' => $ip,
|
||||
'token' => request()->header('X-API-TOKEN'),
|
||||
'is_system' => app()->runningInConsole(),
|
||||
'user_id' => $user_id,
|
||||
|
@ -207,7 +207,7 @@ return [
|
||||
['options' => [
|
||||
'replication' => 'sentinel',
|
||||
'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'),
|
||||
'sentinel_timeout' => 1.0,
|
||||
'sentinel_timeout' => 2.0,
|
||||
'parameters' => [
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'database' => env('REDIS_DB', 0),
|
||||
@ -226,7 +226,7 @@ return [
|
||||
['options' => [
|
||||
'replication' => 'sentinel',
|
||||
'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'),
|
||||
'sentinel_timeout' => 1.0,
|
||||
'sentinel_timeout' => 2.0,
|
||||
'parameters' => [
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'database' => env('REDIS_CACHE_DB', 1),
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsMigrateColumnToAccountsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
$table->boolean('is_migrated')->default(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('accounts', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
663
package-lock.json
generated
663
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2
public/js/app.js
vendored
2
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/clients/linkify-urls.js
vendored
2
public/js/clients/linkify-urls.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e,t={8945:(e,t,r)=>{"use strict";const a=r(920),n=r(3523),s=r(2263),o=new Set(n);e.exports=e=>{if((e=Object.assign({name:"div",attributes:{},html:""},e)).html&&e.text)throw new Error("The `html` and `text` options are mutually exclusive");const t=e.text?s.escape(e.text):e.html;let r=`<${e.name}${a(e.attributes)}>`;return o.has(e.name)||(r+=`${t}</${e.name}>`),r}},3523:(e,t,r)=>{"use strict";e.exports=r(8346)},2263:(e,t)=>{"use strict";t.escape=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">"),t.unescape=e=>e.replace(/>/g,">").replace(/</g,"<").replace(/'/g,"'").replace(/"/g,'"').replace(/&/g,"&"),t.escapeTag=function(e){let r=e[0];for(let a=1;a<arguments.length;a++)r=r+t.escape(arguments[a])+e[a];return r},t.unescapeTag=function(e){let r=e[0];for(let a=1;a<arguments.length;a++)r=r+t.unescape(arguments[a])+e[a];return r}},1881:(e,t,r)=>{"use strict";const a=r(8945),n=(e,t)=>a({name:"a",attributes:{href:"",...t.attributes,href:e},text:void 0===t.value?e:void 0,html:void 0===t.value?void 0:"function"==typeof t.value?t.value(e):t.value});e.exports=(e,t)=>{if("string"===(t={attributes:{},type:"string",...t}).type)return((e,t)=>e.replace(/((?<!\+)(?:https?(?::\/\/))(?:www\.)?(?:[a-zA-Z\d-_.]+(?:(?:\.|@)[a-zA-Z\d]{2,})|localhost)(?:(?:[-a-zA-Z\d:%_+.~#*$!?&//=@]*)(?:[,](?![\s]))*)*)/g,(e=>n(e,t))))(e,t);if("dom"===t.type)return((e,t)=>{const r=document.createDocumentFragment();for(const[s,o]of Object.entries(e.split(/((?<!\+)(?:https?(?::\/\/))(?:www\.)?(?:[a-zA-Z\d-_.]+(?:(?:\.|@)[a-zA-Z\d]{2,})|localhost)(?:(?:[-a-zA-Z\d:%_+.~#*$!?&//=@]*)(?:[,](?![\s]))*)*)/g)))s%2?r.append((a=n(o,t),document.createRange().createContextualFragment(a))):o.length>0&&r.append(o);var a;return r})(e,t);throw new Error("The type option must be either `dom` or `string`")}},920:(e,t,r)=>{"use strict";const a=r(2263);e.exports=e=>{const t=[];for(const r of Object.keys(e)){let n=e[r];if(!1===n)continue;Array.isArray(n)&&(n=n.join(" "));let s=a.escape(r);!0!==n&&(s+=`="${a.escape(String(n))}"`),t.push(s)}return t.length>0?" "+t.join(" "):""}},8346:e=>{"use strict";e.exports=JSON.parse('["area","base","br","col","embed","hr","img","input","link","menuitem","meta","param","source","track","wbr"]')}},r={};function a(e){var n=r[e];if(void 0!==n)return n.exports;var s=r[e]={exports:{}};return t[e](s,s.exports,a),s.exports}e=a(1881),document.querySelectorAll("[data-ref=entity-terms]").forEach((function(t){t.innerHTML=e(t.innerText,{attributes:{target:"_blank",class:"text-primary"}})}))})();
|
||||
(()=>{var e,t={2623:(e,t,r)=>{"use strict";e.exports=r(4666)},1886:(e,t)=>{"use strict";const r=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">"),n=e=>e.replace(/>/g,">").replace(/</g,"<").replace(/�?39;/g,"'").replace(/"/g,'"').replace(/&/g,"&");t.T=(e,...t)=>{if("string"==typeof e)return r(e);let n=e[0];for(const[o,a]of t.entries())n=n+r(String(a))+e[o+1];return n}},7636:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>s});var n=r(1886);var o=r(2623);const a=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">");const i=new Set(o);function c({name:e="div",attributes:t={},html:r="",text:o}={}){if(r&&o)throw new Error("The `html` and `text` options are mutually exclusive");const c=o?function(e,...t){if("string"==typeof e)return a(e);let r=e[0];for(const[n,o]of t.entries())r=r+a(String(o))+e[n+1];return r}(o):r;let l=`<${e}${function(e){const t=[];for(let[r,o]of Object.entries(e)){if(!1===o)continue;Array.isArray(o)&&(o=o.join(" "));let e=(0,n.T)(r);!0!==o&&(e+=`="${(0,n.T)(String(o))}"`),t.push(e)}return t.length>0?" "+t.join(" "):""}(t)}>`;return i.has(e)||(l+=`${c}</${e}>`),l}const l=(e,t)=>c({name:"a",attributes:{href:"",...t.attributes,href:e},text:void 0===t.value?e:void 0,html:void 0===t.value?void 0:"function"==typeof t.value?t.value(e):t.value});function s(e,t){if("string"===(t={attributes:{},type:"string",...t}).type)return((e,t)=>e.replace(/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g,(e=>l(e,t))))(e,t);if("dom"===t.type)return((e,t)=>{const r=document.createDocumentFragment();for(const[o,a]of Object.entries(e.split(/((?<!\+)https?:\/\/(?:www\.)?(?:[-\w.]+?[.@][a-zA-Z\d]{2,}|localhost)(?:[-\w.:%+~#*$!?&/=@]*?(?:,(?!\s))*?)*)/g)))o%2?r.append((n=l(a,t),document.createRange().createContextualFragment(n))):a.length>0&&r.append(a);var n;return r})(e,t);throw new TypeError("The type option must be either `dom` or `string`")}},4666:e=>{"use strict";e.exports=JSON.parse('["area","base","br","col","embed","hr","img","input","link","menuitem","meta","param","source","track","wbr"]')}},r={};function n(e){var o=r[e];if(void 0!==o)return o.exports;var a=r[e]={exports:{}};return t[e](a,a.exports,n),a.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},e=n(7636),document.querySelectorAll("[data-ref=entity-terms]").forEach((function(t){t.innerHTML=e(t.innerText,{attributes:{target:"_blank",class:"text-primary"}})}))})();
|
@ -1,2 +1,2 @@
|
||||
/*! For license information please see wepay-bank-account.js.LICENSE.txt */
|
||||
(()=>{function e(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var n=function(){function n(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n)}var t,o,r;return t=n,(o=[{key:"initializeWePay",value:function(){var e,n=null===(e=document.querySelector('meta[name="wepay-environment"]'))||void 0===e?void 0:e.content;return WePay.set_endpoint("staging"===n?"stage":"production"),this}},{key:"showBankPopup",value:function(){var e,n;WePay.bank_account.create({client_id:null===(e=document.querySelector("meta[name=wepay-client-id]"))||void 0===e?void 0:e.content,email:null===(n=document.querySelector("meta[name=contact-email]"))||void 0===n?void 0:n.content},(function(e){e.error?(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1):(document.querySelector('input[name="bank_account_id"]').value=e.bank_account_id,document.getElementById("server_response").submit())}),(function(e){e.error&&(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1)}))}},{key:"handle",value:function(){this.initializeWePay().showBankPopup()}}])&&e(t.prototype,o),r&&e(t,r),n}();document.addEventListener("DOMContentLoaded",(function(){(new n).handle()}))})();
|
||||
(()=>{function e(e,n){for(var t=0;t<n.length;t++){var o=n[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var n=function(){function n(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,n)}var t,o,r;return t=n,(o=[{key:"initializeWePay",value:function(){var e,n=null===(e=document.querySelector('meta[name="wepay-environment"]'))||void 0===e?void 0:e.content;return WePay.set_endpoint("staging"===n?"stage":"production"),this}},{key:"showBankPopup",value:function(){var e,n;WePay.bank_account.create({client_id:null===(e=document.querySelector("meta[name=wepay-client-id]"))||void 0===e?void 0:e.content,email:null===(n=document.querySelector("meta[name=contact-email]"))||void 0===n?void 0:n.content,options:{avoidMicrodeposits:!0}},(function(e){e.error?(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1):(document.querySelector('input[name="bank_account_id"]').value=e.bank_account_id,document.getElementById("server_response").submit())}),(function(e){e.error&&(errors.textContent="",errors.textContent=e.error_description,errors.hidden=!1)}))}},{key:"handle",value:function(){this.initializeWePay().showBankPopup()}}])&&e(t.prototype,o),r&&e(t,r),n}();document.addEventListener("DOMContentLoaded",(function(){(new n).handle()}))})();
|
2
public/js/setup/setup.js
vendored
2
public/js/setup/setup.js
vendored
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=0d1e02ebdcc97462d422",
|
||||
"/js/app.js": "/js/app.js?id=0e3959ab851d3350364d",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=de4468c682d6861847de",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=cfe5de1cf87a0b01568d",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=5e74bc0d346beeb57ee9",
|
||||
@ -11,15 +11,15 @@
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=63f0688329be80ee8693",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=795d2f44cf3d117a554e",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=ea4250be693260798735",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=6b870beeb350d83668c5",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=7e19431f4cb9ad45e177",
|
||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314f",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=73a0d914ad3577f257f4",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12c",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=448d055fa1e8357130e6",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=44c51b4838d1f135bbe3",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=a334dd9257dd510a1feb",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=37950e8a39281d2f596a",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=ba4d5b7175117ababdb2",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=b1704cb9bd7975605310",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=8328c6c32a65cd3e8a3d",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=59d9913b746fe5a540ff",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=c2cf632fb3cc91b4ff7c",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=ff17e039dd15d505448f",
|
||||
|
@ -20,7 +20,10 @@ class WePayBank {
|
||||
showBankPopup() {
|
||||
WePay.bank_account.create({
|
||||
client_id: document.querySelector('meta[name=wepay-client-id]')?.content,
|
||||
email: document.querySelector('meta[name=contact-email]')?.content
|
||||
email: document.querySelector('meta[name=contact-email]')?.content,
|
||||
options: {
|
||||
avoidMicrodeposits:true
|
||||
}
|
||||
}, function (data) {
|
||||
if (data.error) {
|
||||
errors.textContent = '';
|
||||
|
@ -61,7 +61,7 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@elseif($amount < 0)
|
||||
@elseif($amount <= 0)
|
||||
<div class="relative flex justify-center text-sm leading-5">
|
||||
<h1 class="text-2xl font-bold tracking-wide bg-gray-100 px-6 py-0">
|
||||
{{ ctrans('texts.total') }}: {{ \App\Utils\Number::formatMoney($amount, $subscription->company) }}
|
||||
|
@ -2,18 +2,18 @@
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('client', 'Auth\ContactLoginController@showLoginForm')->name('client.catchall')->middleware(['domain_db', 'contact_account','locale']); //catch all
|
||||
Route::get('client', 'Auth\ContactLoginController@showLoginForm')->name('client.catchall')->middleware(['throttle:10,1','domain_db', 'contact_account','locale']); //catch all
|
||||
|
||||
Route::get('client/login', 'Auth\ContactLoginController@showLoginForm')->name('client.login')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::get('client/login', 'Auth\ContactLoginController@showLoginForm')->name('client.login')->middleware(['throttle:10,1','domain_db', 'contact_account','locale']);
|
||||
Route::post('client/login', 'Auth\ContactLoginController@login')->name('client.login.submit');
|
||||
|
||||
Route::get('client/register/{company_key?}', 'Auth\ContactRegisterController@showRegisterForm')->name('client.register')->middleware(['domain_db', 'contact_account', 'contact_register','locale']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['domain_db', 'contact_account', 'contact_register', 'locale']);
|
||||
Route::get('client/register/{company_key?}', 'Auth\ContactRegisterController@showRegisterForm')->name('client.register')->middleware(['throttle:10,1','domain_db', 'contact_account', 'contact_register','locale']);
|
||||
Route::post('client/register/{company_key?}', 'Auth\ContactRegisterController@register')->middleware(['throttle:10,1','domain_db', 'contact_account', 'contact_register', 'locale']);
|
||||
|
||||
Route::get('client/password/reset', 'Auth\ContactForgotPasswordController@showLinkRequestForm')->name('client.password.request')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/email', 'Auth\ContactForgotPasswordController@sendResetLinkEmail')->name('client.password.email')->middleware('locale');
|
||||
Route::get('client/password/reset/{token}', 'Auth\ContactResetPasswordController@showResetForm')->name('client.password.reset')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/reset', 'Auth\ContactResetPasswordController@reset')->name('client.password.update')->middleware(['domain_db', 'contact_account','locale']);
|
||||
Route::get('client/password/reset', 'Auth\ContactForgotPasswordController@showLinkRequestForm')->name('client.password.request')->middleware(['throttle:10,1','domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/email', 'Auth\ContactForgotPasswordController@sendResetLinkEmail')->name('client.password.email')->middleware('throttle:10,1','locale');
|
||||
Route::get('client/password/reset/{token}', 'Auth\ContactResetPasswordController@showResetForm')->name('client.password.reset')->middleware(['throttle:10,1','domain_db', 'contact_account','locale']);
|
||||
Route::post('client/password/reset', 'Auth\ContactResetPasswordController@reset')->name('client.password.update')->middleware(['throttle:10,1','domain_db', 'contact_account','locale']);
|
||||
|
||||
Route::get('view/{entity_type}/{invitation_key}', 'ClientPortal\EntityViewController@index')->name('client.entity_view');
|
||||
Route::get('view/{entity_type}/{invitation_key}/password', 'ClientPortal\EntityViewController@password')->name('client.entity_view.password');
|
||||
@ -21,14 +21,14 @@ Route::post('view/{entity_type}/{invitation_key}/password', 'ClientPortal\Entity
|
||||
|
||||
Route::get('tmp_pdf/{hash}', 'ClientPortal\TempRouteController@index')->name('tmp_pdf');
|
||||
|
||||
Route::get('client/key_login/{contact_key}', 'ClientPortal\ContactHashLoginController@login')->name('client.contact_login')->middleware(['domain_db','contact_key_login']);
|
||||
Route::get('client/magic_link/{magic_link}', 'ClientPortal\ContactHashLoginController@magicLink')->name('client.contact_magic_link')->middleware(['domain_db','contact_key_login']);
|
||||
Route::get('documents/{document_hash}', 'ClientPortal\DocumentController@publicDownload')->name('documents.public_download')->middleware(['document_db']);
|
||||
Route::get('client/key_login/{contact_key}', 'ClientPortal\ContactHashLoginController@login')->name('client.contact_login')->middleware(['throttle:40,1','domain_db','contact_key_login']);
|
||||
Route::get('client/magic_link/{magic_link}', 'ClientPortal\ContactHashLoginController@magicLink')->name('client.contact_magic_link')->middleware(['throttle:40,1','domain_db','contact_key_login']);
|
||||
Route::get('documents/{document_hash}', 'ClientPortal\DocumentController@publicDownload')->name('documents.public_download')->middleware(['throttle:40,1','document_db']);
|
||||
Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name('client.error');
|
||||
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']);
|
||||
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']);
|
||||
Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['throttle:40,1','domain_db','contact_key_login']);
|
||||
Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['throttle:40,1','domain_db']);
|
||||
|
||||
Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence','domain_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
Route::group(['middleware' => ['throttle:60,1','auth:contact', 'locale', 'check_client_existence','domain_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||
|
||||
Route::get('invoices', 'ClientPortal\InvoiceController@index')->name('invoices.index')->middleware('portal_enabled');
|
||||
@ -92,7 +92,7 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence
|
||||
|
||||
Route::get('client/subscriptions/{subscription}/purchase', 'ClientPortal\SubscriptionPurchaseController@index')->name('client.subscription.purchase')->middleware('domain_db');
|
||||
|
||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
Route::group(['middleware' => ['throttle:40,1','invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
/*Invitation catches*/
|
||||
Route::get('recurring_invoice/{invitation_key}', 'ClientPortal\InvitationController@recurringRouter');
|
||||
Route::get('invoice/{invitation_key}', 'ClientPortal\InvitationController@invoiceRouter');
|
||||
@ -108,6 +108,6 @@ Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'clie
|
||||
|
||||
});
|
||||
|
||||
Route::get('phantom/{entity}/{invitation_key}', '\App\Utils\PhantomJS\Phantom@displayInvitation')->middleware(['invite_db', 'phantom_secret'])->name('phantom_view');
|
||||
Route::get('phantom/{entity}/{invitation_key}', '\App\Utils\PhantomJS\Phantom@displayInvitation')->middleware(['throttle:60,1','invite_db', 'phantom_secret'])->name('phantom_view');
|
||||
|
||||
Route::fallback('BaseController@notFoundClient');
|
||||
|
@ -297,6 +297,8 @@ class ClientTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
|
||||
$company_token->save();
|
||||
|
||||
$this->token = $company_token->token;
|
||||
@ -353,6 +355,7 @@ class ClientTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$this->token = $company_token->token;
|
||||
|
@ -160,6 +160,7 @@ class LoginTest extends TestCase
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = \Illuminate\Support\Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$user->companies()->attach($company->id, [
|
||||
|
@ -167,6 +167,7 @@ class UserTest extends TestCase
|
||||
$company_token->account_id = $this->account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = \Illuminate\Support\Str::random(64);
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
/*Manually link this user to the company*/
|
||||
|
@ -128,6 +128,7 @@ class CompanyLedgerTest extends TestCase
|
||||
$company_token->account_id = $this->account->id;
|
||||
$company_token->name = 'test token';
|
||||
$company_token->token = $this->token;
|
||||
$company_token->is_system = true;
|
||||
$company_token->save();
|
||||
|
||||
$this->client = Client::factory()->create([
|
||||
|
Loading…
x
Reference in New Issue
Block a user