mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Fixes
This commit is contained in:
parent
c7d7916b04
commit
8e2c07b0df
@ -1 +1 @@
|
||||
5.1.29
|
||||
5.1.32
|
@ -52,8 +52,7 @@ class PostUpdate extends Command
|
||||
|
||||
nlog("finished migrating");
|
||||
|
||||
exec('vendor/bin/composer install --no-dev');
|
||||
exec('vendor/bin/composer dump');
|
||||
exec('vendor/bin/composer install --no-dev -o');
|
||||
|
||||
nlog("finished running composer install ");
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\Cron\BillingSubscriptionCron;
|
||||
use App\Jobs\Cron\SubscriptionCron;
|
||||
use App\Jobs\Cron\RecurringInvoicesCron;
|
||||
use App\Jobs\Ninja\AdjustEmailQuota;
|
||||
use App\Jobs\Ninja\CompanySizeCheck;
|
||||
@ -44,7 +44,7 @@ class Kernel extends ConsoleKernel
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
|
||||
$schedule->job(new VersionCheck)->daily()->withoutOverlapping();
|
||||
$schedule->job(new VersionCheck)->daily();
|
||||
|
||||
$schedule->command('ninja:check-data')->daily()->withoutOverlapping();
|
||||
|
||||
@ -54,7 +54,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->job(new UpdateExchangeRates)->daily()->withoutOverlapping();
|
||||
|
||||
$schedule->job(new BillingSubscriptionCron)->daily()->withoutOverlapping();
|
||||
$schedule->job(new SubscriptionCron)->daily()->withoutOverlapping();
|
||||
|
||||
$schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping();
|
||||
|
||||
|
@ -109,7 +109,7 @@ class CompanySettings extends BaseSettings
|
||||
|
||||
public $shared_invoice_quote_counter = false; //@implemented
|
||||
public $shared_invoice_credit_counter = false; //@implemented
|
||||
public $recurring_number_prefix = 'R'; //@implemented
|
||||
public $recurring_number_prefix = ''; //@implemented
|
||||
public $reset_counter_frequency_id = '0'; //@implemented
|
||||
public $reset_counter_date = ''; //@implemented
|
||||
public $counter_padding = 4; //@implemented
|
||||
@ -574,7 +574,8 @@ class CompanySettings extends BaseSettings
|
||||
public static function notificationDefaults() :stdClass
|
||||
{
|
||||
$notification = new stdClass;
|
||||
$notification->email = ['all_notifications'];
|
||||
$notification->email = [];
|
||||
// $notification->email = ['all_notifications'];
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events\BillingSubscription;
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class BillingSubscriptionWasCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
/**
|
||||
* @var BillingSubscription
|
||||
*/
|
||||
public $billing_subscription;
|
||||
|
||||
/**
|
||||
* @var Company
|
||||
*/
|
||||
public $company;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $event_vars;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(BillingSubscription $billing_subscription, Company $company, array $event_vars)
|
||||
{
|
||||
$this->billing_subscription = $billing_subscription;
|
||||
$this->company = $company;
|
||||
$this->event_vars = $event_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
namespace App\Events\Credit;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\CreditInvitation;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
|
@ -94,7 +94,9 @@ class Handler extends ExceptionHandler
|
||||
}
|
||||
}
|
||||
|
||||
parent::report($exception);
|
||||
if(config('ninja.expanded_logging'))
|
||||
parent::report($exception);
|
||||
|
||||
}
|
||||
|
||||
private function validException($exception)
|
||||
@ -105,7 +107,7 @@ class Handler extends ExceptionHandler
|
||||
if (strpos($exception->getMessage(), 'Permission denied') !== false)
|
||||
return false;
|
||||
|
||||
if (strpos($exception->getMessage(), 'flock()') !== false)
|
||||
if (strpos($exception->getMessage(), 'flock') !== false)
|
||||
return false;
|
||||
|
||||
if (strpos($exception->getMessage(), 'expects parameter 1 to be resource') !== false)
|
||||
@ -114,6 +116,8 @@ class Handler extends ExceptionHandler
|
||||
if (strpos($exception->getMessage(), 'fwrite()') !== false)
|
||||
return false;
|
||||
|
||||
if(strpos($exception->getMessage(), 'LockableFile') !== false)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
|
||||
class BillingSubscriptionFactory
|
||||
{
|
||||
public static function create(int $company_id, int $user_id): BillingSubscription
|
||||
{
|
||||
$billing_subscription = new BillingSubscription();
|
||||
$billing_subscription->company_id = $company_id;
|
||||
$billing_subscription->user_id = $user_id;
|
||||
|
||||
return $billing_subscription;
|
||||
}
|
||||
}
|
@ -35,7 +35,8 @@ class CompanyFactory
|
||||
$company->custom_fields = (object) [];
|
||||
$company->subdomain = '';
|
||||
$company->enabled_modules = config('ninja.enabled_modules'); //32767;//8191; //4095
|
||||
$company->default_password_timeout = 30 * 60000;
|
||||
$company->default_password_timeout = 1800000;
|
||||
|
||||
|
||||
return $company;
|
||||
}
|
||||
|
@ -193,8 +193,7 @@ class LoginController extends BaseController
|
||||
}
|
||||
|
||||
$user->setCompany($user->account->default_company);
|
||||
$timeout = auth()->user()->company()->default_password_timeout;
|
||||
|
||||
$timeout = auth()->user()->company()->default_password_timeout / 60000;
|
||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
||||
|
||||
$cu = CompanyUser::query()
|
||||
@ -312,6 +311,8 @@ class LoginController extends BaseController
|
||||
|
||||
Auth::login($existing_user, true);
|
||||
$existing_user->setCompany($existing_user->account->default_company);
|
||||
$timeout = $existing_user->company()->default_password_timeout / 60000;
|
||||
Cache::put($existing_user->hashed_id.'_logged_in', Str::random(64), $timeout);
|
||||
|
||||
$cu = CompanyUser::query()
|
||||
->where('user_id', auth()->user()->id);
|
||||
@ -322,34 +323,6 @@ class LoginController extends BaseController
|
||||
}
|
||||
|
||||
if ($user) {
|
||||
|
||||
// we are no longer accessing the permissions for gmail - email permissions here
|
||||
|
||||
// $client = new Google_Client();
|
||||
// $client->setClientId(config('ninja.auth.google.client_id'));
|
||||
// $client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||
// $client->setRedirectUri(config('ninja.app_url'));
|
||||
|
||||
// $token = false;
|
||||
|
||||
// try{
|
||||
// $token = $client->authenticate(request()->input('server_auth_code'));
|
||||
// }
|
||||
// catch(\Exception $e) {
|
||||
|
||||
// return response()
|
||||
// ->json(['message' => ctrans('texts.invalid_credentials')], 401)
|
||||
// ->header('X-App-Version', config('ninja.app_version'))
|
||||
// ->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
|
||||
// }
|
||||
|
||||
// $refresh_token = '';
|
||||
|
||||
// if (array_key_exists('refresh_token', $token)) {
|
||||
// $refresh_token = $token['refresh_token'];
|
||||
// }
|
||||
|
||||
|
||||
$name = OAuth::splitName($google->harvestName($user));
|
||||
|
||||
@ -359,8 +332,8 @@ class LoginController extends BaseController
|
||||
'password' => '',
|
||||
'email' => $google->harvestEmail($user),
|
||||
'oauth_user_id' => $google->harvestSubField($user),
|
||||
'oauth_user_token' => $token,
|
||||
'oauth_user_refresh_token' => $refresh_token,
|
||||
// 'oauth_user_token' => $token,
|
||||
// 'oauth_user_refresh_token' => $refresh_token,
|
||||
'oauth_provider_id' => 'google',
|
||||
];
|
||||
|
||||
@ -372,6 +345,8 @@ class LoginController extends BaseController
|
||||
|
||||
auth()->user()->email_verified_at = now();
|
||||
auth()->user()->save();
|
||||
$timeout = auth()->user()->company()->default_password_timeout / 60000;
|
||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
||||
|
||||
$ct = CompanyUser::whereUserId(auth()->user()->id);
|
||||
|
||||
|
@ -92,11 +92,13 @@ class BaseController extends Controller
|
||||
'company.quotes.invitations.company',
|
||||
'company.quotes.documents',
|
||||
'company.tasks.documents',
|
||||
'company.subscriptions',
|
||||
'company.tax_rates',
|
||||
'company.tokens_hashed',
|
||||
'company.vendors.contacts.company',
|
||||
'company.vendors.documents',
|
||||
'company.webhooks',
|
||||
'company.system_logs',
|
||||
];
|
||||
|
||||
private $mini_load = [
|
||||
@ -214,7 +216,7 @@ class BaseController extends Controller
|
||||
|
||||
if(!$user->hasPermission('view_client'))
|
||||
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
|
||||
|
||||
|
||||
},
|
||||
'company.company_gateways' => function ($query) use ($user) {
|
||||
$query->whereNotNull('updated_at');
|
||||
@ -339,7 +341,14 @@ class BaseController extends Controller
|
||||
|
||||
if(!$user->isAdmin())
|
||||
$query->where('activities.user_id', $user->id);
|
||||
|
||||
|
||||
},
|
||||
'company.subscriptions'=> function ($query) use($updated_at, $user) {
|
||||
$query->where('updated_at', '>=', $updated_at);
|
||||
|
||||
if(!$user->isAdmin())
|
||||
$query->where('subscriptions.user_id', $user->id);
|
||||
|
||||
}
|
||||
]
|
||||
);
|
||||
@ -435,7 +444,7 @@ class BaseController extends Controller
|
||||
if ($this->serializer && $this->serializer != EntityTransformer::API_SERIALIZER_JSON) {
|
||||
$this->entity_type = null;
|
||||
}
|
||||
|
||||
|
||||
$resource = new Item($item, $transformer, $this->entity_type);
|
||||
|
||||
if (auth()->user() && request()->include_static) {
|
||||
|
@ -1,410 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Events\BillingSubscription\BillingSubscriptionWasCreated;
|
||||
use App\Factory\BillingSubscriptionFactory;
|
||||
use App\Http\Requests\BillingSubscription\CreateBillingSubscriptionRequest;
|
||||
use App\Http\Requests\BillingSubscription\DestroyBillingSubscriptionRequest;
|
||||
use App\Http\Requests\BillingSubscription\EditBillingSubscriptionRequest;
|
||||
use App\Http\Requests\BillingSubscription\ShowBillingSubscriptionRequest;
|
||||
use App\Http\Requests\BillingSubscription\StoreBillingSubscriptionRequest;
|
||||
use App\Http\Requests\BillingSubscription\UpdateBillingSubscriptionRequest;
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Repositories\BillingSubscriptionRepository;
|
||||
use App\Transformers\BillingSubscriptionTransformer;
|
||||
use App\Utils\Ninja;
|
||||
|
||||
class BillingSubscriptionController extends BaseController
|
||||
{
|
||||
protected $entity_type = BillingSubscription::class;
|
||||
|
||||
protected $entity_transformer = BillingSubscriptionTransformer::class;
|
||||
|
||||
protected $billing_subscription_repo;
|
||||
|
||||
public function __construct(BillingSubscriptionRepository $billing_subscription_repo)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->billing_subscription_repo = $billing_subscription_repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the list of BillingSubscriptions.
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/api/v1/billing_subscriptions",
|
||||
* operationId="getBillingSubscriptions",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Gets a list of billing_subscriptions",
|
||||
* description="Lists billing_subscriptions.",
|
||||
*
|
||||
* @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\Response(
|
||||
* response=200,
|
||||
* description="A list of billing_subscriptions",
|
||||
* @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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 index(): \Illuminate\Http\Response
|
||||
{
|
||||
$billing_subscriptions = BillingSubscription::query()->company();
|
||||
|
||||
return $this->listResponse($billing_subscriptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param CreateBillingSubscriptionRequest $request The request
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/api/v1/billing_subscriptions/create",
|
||||
* operationId="getBillingSubscriptionsCreate",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Gets a new blank billing_subscriptions object",
|
||||
* description="Returns a blank object with default values",
|
||||
* @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\Response(
|
||||
* response=200,
|
||||
* description="A blank billing_subscriptions 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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 create(CreateBillingSubscriptionRequest $request): \Illuminate\Http\Response
|
||||
{
|
||||
$billing_subscription = BillingSubscriptionFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||
|
||||
return $this->itemResponse($billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param StoreBillingSubscriptionRequest $request The request
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
*
|
||||
* @OA\Post(
|
||||
* path="/api/v1/billing_subscriptions",
|
||||
* operationId="storeBillingSubscription",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Adds a billing_subscriptions",
|
||||
* description="Adds an billing_subscriptions to the system",
|
||||
* @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\Response(
|
||||
* response=200,
|
||||
* description="Returns the saved billing_subscriptions 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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 store(StoreBillingSubscriptionRequest $request): \Illuminate\Http\Response
|
||||
{
|
||||
$billing_subscription = $this->billing_subscription_repo->save($request->all(), BillingSubscriptionFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
||||
|
||||
event(new BillingsubscriptionWasCreated($billing_subscription, $billing_subscription->company, Ninja::eventVars()));
|
||||
|
||||
return $this->itemResponse($billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param ShowBillingSubscriptionRequest $request The request
|
||||
* @param Invoice $billing_subscription The invoice
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/api/v1/billing_subscriptions/{id}",
|
||||
* operationId="showBillingSubscription",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Shows an billing_subscriptions",
|
||||
* description="Displays an billing_subscriptions by id",
|
||||
* @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="id",
|
||||
* in="path",
|
||||
* description="The BillingSubscription Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the BillingSubscription 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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 show(ShowBillingSubscriptionRequest $request, BillingSubscription $billing_subscription): \Illuminate\Http\Response
|
||||
{
|
||||
return $this->itemResponse($billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param EditBillingSubscriptionRequest $request The request
|
||||
* @param Invoice $billing_subscription The invoice
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/api/v1/billing_subscriptions/{id}/edit",
|
||||
* operationId="editBillingSubscription",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Shows an billing_subscriptions for editting",
|
||||
* description="Displays an billing_subscriptions by id",
|
||||
* @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="id",
|
||||
* in="path",
|
||||
* description="The BillingSubscription Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the invoice 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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 edit(EditBillingSubscriptionRequest $request, BillingSubscription $billing_subscription): \Illuminate\Http\Response
|
||||
{
|
||||
return $this->itemResponse($billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param UpdateBillingSubscriptionRequest $request The request
|
||||
* @param BillingSubscription $billing_subscription The invoice
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
*
|
||||
* @OA\Put(
|
||||
* path="/api/v1/billing_subscriptions/{id}",
|
||||
* operationId="updateBillingSubscription",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Updates an billing_subscriptions",
|
||||
* description="Handles the updating of an billing_subscriptions by id",
|
||||
* @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="id",
|
||||
* in="path",
|
||||
* description="The BillingSubscription Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns the billing_subscriptions 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/BillingSubscription"),
|
||||
* ),
|
||||
* @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 update(UpdateBillingSubscriptionRequest $request, BillingSubscription $billing_subscription)
|
||||
{
|
||||
if ($request->entityIsDeleted($billing_subscription)) {
|
||||
return $request->disallowUpdate();
|
||||
}
|
||||
|
||||
$billing_subscription = $this->billing_subscription_repo->save($request->all(), $billing_subscription);
|
||||
|
||||
return $this->itemResponse($billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param DestroyBillingSubscriptionRequest $request
|
||||
* @param BillingSubscription $invoice
|
||||
*
|
||||
* @return Response
|
||||
*
|
||||
* @throws \Exception
|
||||
* @OA\Delete(
|
||||
* path="/api/v1/billing_subscriptions/{id}",
|
||||
* operationId="deleteBillingSubscription",
|
||||
* tags={"billing_subscriptions"},
|
||||
* summary="Deletes a billing_subscriptions",
|
||||
* description="Handles the deletion of an billing_subscriptions by id",
|
||||
* @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="id",
|
||||
* in="path",
|
||||
* description="The BillingSubscription Hashed ID",
|
||||
* example="D2J234DFA",
|
||||
* required=true,
|
||||
* @OA\Schema(
|
||||
* type="string",
|
||||
* format="string",
|
||||
* ),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Returns a HTTP status",
|
||||
* @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\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 destroy(DestroyBillingSubscriptionRequest $request, BillingSubscription $billing_subscription): \Illuminate\Http\Response
|
||||
{
|
||||
$this->billing_subscription_repo->delete($billing_subscription);
|
||||
|
||||
return $this->itemResponse($billing_subscription->fresh());
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\ClientPortal;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\BillingSubscription;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class BillingSubscriptionPurchaseController extends Controller
|
||||
{
|
||||
public function index(BillingSubscription $billing_subscription)
|
||||
{
|
||||
return view('billing-portal.purchase', [
|
||||
'billing_subscription' => $billing_subscription,
|
||||
'hash' => Str::uuid()->toString(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -14,9 +14,12 @@ namespace App\Http\Controllers;
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Libraries\OAuth\Providers\Google;
|
||||
use App\Models\CompanyUser;
|
||||
use App\Models\User;
|
||||
use App\Transformers\CompanyUserTransformer;
|
||||
use App\Transformers\UserTransformer;
|
||||
use Google_Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ConnectedAccountController extends BaseController
|
||||
{
|
||||
@ -95,7 +98,51 @@ class ConnectedAccountController extends BaseController
|
||||
$client->setClientId(config('ninja.auth.google.client_id'));
|
||||
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||
$client->setRedirectUri(config('ninja.app_url'));
|
||||
$token = $client->authenticate(request()->input('server_auth_code'));
|
||||
$refresh_token = '';
|
||||
$token = '';
|
||||
|
||||
$connected_account = [
|
||||
'email' => $google->harvestEmail($user),
|
||||
'oauth_user_id' => $google->harvestSubField($user),
|
||||
'oauth_provider_id' => 'google',
|
||||
'email_verified_at' =>now()
|
||||
];
|
||||
|
||||
auth()->user()->update($connected_account);
|
||||
auth()->user()->email_verified_at = now();
|
||||
auth()->user()->save();
|
||||
|
||||
$timeout = auth()->user()->company()->default_password_timeout;
|
||||
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
|
||||
|
||||
return $this->itemResponse(auth()->user());
|
||||
|
||||
}
|
||||
|
||||
return response()
|
||||
->json(['message' => ctrans('texts.invalid_credentials')], 401)
|
||||
->header('X-App-Version', config('ninja.app_version'))
|
||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function handleGmailOauth(Request $request)
|
||||
{
|
||||
|
||||
$user = false;
|
||||
|
||||
$google = new Google();
|
||||
|
||||
$user = $google->getTokenResponse($request->input('id_token'));
|
||||
|
||||
if ($user) {
|
||||
|
||||
$client = new Google_Client();
|
||||
$client->setClientId(config('ninja.auth.google.client_id'));
|
||||
$client->setClientSecret(config('ninja.auth.google.client_secret'));
|
||||
$client->setRedirectUri(config('ninja.app_url'));
|
||||
$token = $client->authenticate($request->input('server_auth_code'));
|
||||
|
||||
$refresh_token = '';
|
||||
|
||||
@ -104,7 +151,6 @@ class ConnectedAccountController extends BaseController
|
||||
}
|
||||
|
||||
$connected_account = [
|
||||
'password' => '',
|
||||
'email' => $google->harvestEmail($user),
|
||||
'oauth_user_id' => $google->harvestSubField($user),
|
||||
'oauth_user_token' => $token,
|
||||
@ -116,17 +162,32 @@ class ConnectedAccountController extends BaseController
|
||||
auth()->user()->update($connected_account);
|
||||
auth()->user()->email_verified_at = now();
|
||||
auth()->user()->save();
|
||||
|
||||
//$ct = CompanyUser::whereUserId(auth()->user()->id);
|
||||
//return $this->listResponse($ct);
|
||||
|
||||
$this->activateGmail(auth()->user());
|
||||
|
||||
return $this->itemResponse(auth()->user());
|
||||
// return $this->listResponse(auth()->user());
|
||||
|
||||
}
|
||||
|
||||
return response()
|
||||
->json(['message' => ctrans('texts.invalid_credentials')], 401)
|
||||
->header('X-App-Version', config('ninja.app_version'))
|
||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||
|
||||
}
|
||||
|
||||
private function activateGmail(User $user)
|
||||
{
|
||||
$company = $user->company();
|
||||
$settings = $company->settings;
|
||||
|
||||
if($settings->email_sending_method == 'default')
|
||||
{
|
||||
$settings->email_sending_method = 'gmail';
|
||||
$settings->gmail_sending_user_id = (string)$user->hashed_id;
|
||||
|
||||
$company->settings = $settings;
|
||||
$company->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ class EmailController extends BaseController
|
||||
|
||||
$entity_obj->service()->markSent()->save();
|
||||
|
||||
EmailEntity::dispatch($invitation, $invitation->company, $template, $data)
|
||||
EmailEntity::dispatch($invitation->fresh(), $invitation->company, $template, $data)
|
||||
->delay(now()->addSeconds(5));
|
||||
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ class InvoiceController extends BaseController
|
||||
}
|
||||
|
||||
if ($invoice->isLocked()) {
|
||||
return response()->json(['message' => ctrans('texts.locked_invoice')]);
|
||||
return response()->json(['message' => ctrans('texts.locked_invoice')], 403);
|
||||
}
|
||||
|
||||
$invoice = $this->invoice_repo->save($request->all(), $invoice);
|
||||
@ -795,6 +795,8 @@ class InvoiceController extends BaseController
|
||||
|
||||
$file_path = $invoice->service()->getInvoicePdf($contact);
|
||||
|
||||
nlog($file_path);
|
||||
|
||||
return response()->download($file_path, basename($file_path));
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* @OA\Schema(
|
||||
* schema="BillingSubscription",
|
||||
* schema="Subscription",
|
||||
* type="object",
|
||||
* @OA\Property(property="id", type="string", example="Opnel5aKBz", description="______"),
|
||||
* @OA\Property(property="user_id", type="string", example="Opnel5aKBz", description="______"),
|
||||
|
@ -532,7 +532,7 @@ class QuoteController extends BaseController
|
||||
return response()->json(['message' => ctrans('texts.sent_message')], 200);
|
||||
}
|
||||
|
||||
if ($action == 'convert') {
|
||||
if ($action == 'convert' || $action == 'convert_to_invoice') {
|
||||
$this->entity_type = Quote::class;
|
||||
$this->entity_transformer = QuoteTransformer::class;
|
||||
|
||||
@ -572,7 +572,6 @@ class QuoteController extends BaseController
|
||||
* description="Performs a custom action on an Quote.
|
||||
|
||||
The current range of actions are as follows
|
||||
- clone_to_Quote
|
||||
- clone_to_quote
|
||||
- history
|
||||
- delivery_note
|
||||
@ -580,6 +579,8 @@ class QuoteController extends BaseController
|
||||
- download
|
||||
- archive
|
||||
- delete
|
||||
- convert
|
||||
- convert_to_invoice
|
||||
- email",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||
@ -640,6 +641,14 @@ class QuoteController extends BaseController
|
||||
private function performAction(Quote $quote, $action, $bulk = false)
|
||||
{
|
||||
switch ($action) {
|
||||
case 'convert':
|
||||
case 'convert_to_invoice':
|
||||
|
||||
$this->entity_type = Invoice::class;
|
||||
$this->entity_transformer = InvoiceTransformer::class;
|
||||
return $this->itemResponse($quote->service()->convertToInvoice());
|
||||
|
||||
break;
|
||||
case 'clone_to_invoice':
|
||||
|
||||
$this->entity_type = Invoice::class;
|
||||
|
@ -66,10 +66,16 @@ class SelfUpdateController extends BaseController
|
||||
$repo = new GitRepository(base_path());
|
||||
|
||||
nlog('Are there changes to pull? '.$repo->hasChanges());
|
||||
$output = '';
|
||||
|
||||
try {
|
||||
$res = $repo->pull();
|
||||
// $res = $repo->pull();
|
||||
|
||||
$output = $repo->execute('pull origin');
|
||||
|
||||
} catch (GitException $e) {
|
||||
|
||||
nlog($output);
|
||||
nlog($e->getMessage());
|
||||
return response()->json(['message'=>$e->getMessage()], 500);
|
||||
}
|
||||
@ -78,7 +84,7 @@ class SelfUpdateController extends BaseController
|
||||
Artisan::call('ninja:post-update');
|
||||
});
|
||||
|
||||
return response()->json(['message' => ''], 200);
|
||||
return response()->json(['message' => $output], 200);
|
||||
}
|
||||
|
||||
public function checkVersion()
|
||||
|
@ -608,11 +608,18 @@ class UserController extends BaseController
|
||||
*/
|
||||
public function detach(DetachCompanyUserRequest $request, User $user)
|
||||
{
|
||||
if($user->isOwner())
|
||||
return response()->json(['message', 'Cannot detach owner.'],400);
|
||||
|
||||
if ($request->entityIsDeleted($user)) {
|
||||
return $request->disallowUpdate();
|
||||
}
|
||||
|
||||
$company_user = CompanyUser::whereUserId($user->id)
|
||||
->whereCompanyId(auth()->user()->companyId())->first();
|
||||
->whereCompanyId(auth()->user()->companyId())
|
||||
->withTrashed()
|
||||
->first();
|
||||
|
||||
if($company_user->is_owner)
|
||||
return response()->json(['message', 'Cannot detach owner.'], 401);
|
||||
|
||||
$token = $company_user->token->where('company_id', $company_user->company_id)->where('user_id', $company_user->user_id)->first();
|
||||
|
||||
|
@ -12,48 +12,148 @@
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\Invoice;
|
||||
use App\Repositories\ClientContactRepository;
|
||||
use App\Repositories\ClientRepository;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Livewire\Component;
|
||||
|
||||
class BillingPortalPurchase extends Component
|
||||
{
|
||||
/**
|
||||
* Random hash generated by backend to handle the tracking of state.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hash;
|
||||
|
||||
public $heading_text = 'Log in';
|
||||
/**
|
||||
* Top level text on the left side of billing page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $heading_text;
|
||||
|
||||
|
||||
/**
|
||||
* E-mail address model for user input.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* Password model for user input.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $password;
|
||||
|
||||
public $billing_subscription;
|
||||
/**
|
||||
* Instance of subscription.
|
||||
*
|
||||
* @var Subscription
|
||||
*/
|
||||
public $subscription;
|
||||
|
||||
/**
|
||||
* Instance of client contact.
|
||||
*
|
||||
* @var null|ClientContact
|
||||
*/
|
||||
public $contact;
|
||||
|
||||
/**
|
||||
* Rules for validating the form.
|
||||
*
|
||||
* @var \string[][]
|
||||
*/
|
||||
protected $rules = [
|
||||
'email' => ['required', 'email'],
|
||||
];
|
||||
|
||||
/**
|
||||
* Id for CompanyGateway record.
|
||||
*
|
||||
* @var string|integer
|
||||
*/
|
||||
public $company_gateway_id;
|
||||
|
||||
/**
|
||||
* Id for GatewayType.
|
||||
*
|
||||
* @var string|integer
|
||||
*/
|
||||
public $payment_method_id;
|
||||
|
||||
/**
|
||||
* List of steps that frontend form follows.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $steps = [
|
||||
'passed_email' => false,
|
||||
'existing_user' => false,
|
||||
'fetched_payment_methods' => false,
|
||||
'fetched_client' => false,
|
||||
'show_start_trial' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* List of payment methods fetched from client.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $methods = [];
|
||||
|
||||
/**
|
||||
* Instance of \App\Models\Invoice
|
||||
*
|
||||
* @var Invoice
|
||||
*/
|
||||
public $invoice;
|
||||
|
||||
/**
|
||||
* Coupon model for user input
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $coupon;
|
||||
|
||||
/**
|
||||
* Quantity for seats
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $quantity = 1;
|
||||
|
||||
/**
|
||||
* First-hit request data (queries, locales...).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $request_data;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $price;
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->price = $this->subscription->service()->price();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle user authentication
|
||||
*
|
||||
* @return $this|bool|void
|
||||
*/
|
||||
public function authenticate()
|
||||
{
|
||||
$this->validate();
|
||||
@ -81,38 +181,79 @@ class BillingPortalPurchase extends Component
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a blank client. Used for new customers purchasing.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Laracasts\Presenter\Exceptions\PresenterException
|
||||
*/
|
||||
protected function createBlankClient()
|
||||
{
|
||||
$company = $this->billing_subscription->company;
|
||||
$user = $this->billing_subscription->user;
|
||||
$company = $this->subscription->company;
|
||||
$user = $this->subscription->user;
|
||||
|
||||
$client_repo = new ClientRepository(new ClientContactRepository());
|
||||
|
||||
$client = $client_repo->save([
|
||||
$data = [
|
||||
'name' => 'Client Name',
|
||||
'contacts' => [
|
||||
['email' => $this->email],
|
||||
]
|
||||
], ClientFactory::create($company->id, $user->id));
|
||||
],
|
||||
'settings' => [],
|
||||
];
|
||||
|
||||
if (array_key_exists('locale', $this->request_data)) {
|
||||
$request = $this->request_data;
|
||||
|
||||
$record = Cache::get('languages')->filter(function ($item) use ($request) {
|
||||
return $item->locale == $request['locale'];
|
||||
})->first();
|
||||
|
||||
if ($record) {
|
||||
$data['settings']['language_id'] = (string)$record->id;
|
||||
}
|
||||
}
|
||||
|
||||
$client = $client_repo->save($data, ClientFactory::create($company->id, $user->id));
|
||||
|
||||
return $client->contacts->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetching payment methods from the client.
|
||||
*
|
||||
* @param ClientContact $contact
|
||||
* @return $this
|
||||
*/
|
||||
protected function getPaymentMethods(ClientContact $contact): self
|
||||
{
|
||||
$this->steps['fetched_payment_methods'] = true;
|
||||
|
||||
$this->methods = $contact->client->service()->getPaymentMethods(1000);
|
||||
|
||||
$this->heading_text = 'Pick a payment method';
|
||||
|
||||
Auth::guard('contact')->login($contact);
|
||||
|
||||
$this->contact = $contact;
|
||||
|
||||
if ($this->subscription->trial_enabled) {
|
||||
$this->heading_text = ctrans('texts.plan_trial');
|
||||
$this->steps['show_start_trial'] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->steps['fetched_payment_methods'] = true;
|
||||
|
||||
$this->methods = $contact->client->service()->getPaymentMethods(1000);
|
||||
|
||||
$this->heading_text = ctrans('texts.payment_methods');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Middle method between selecting payment method &
|
||||
* submitting the from to the backend.
|
||||
*
|
||||
* @param $company_gateway_id
|
||||
* @param $gateway_type_id
|
||||
*/
|
||||
public function handleMethodSelectingEvent($company_gateway_id, $gateway_type_id)
|
||||
{
|
||||
$this->company_gateway_id = $company_gateway_id;
|
||||
@ -121,10 +262,13 @@ class BillingPortalPurchase extends Component
|
||||
$this->handleBeforePaymentEvents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle events before payments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleBeforePaymentEvents()
|
||||
{
|
||||
|
||||
//stubs
|
||||
$data = [
|
||||
'client_id' => $this->contact->client->id,
|
||||
'date' => now()->format('Y-m-d'),
|
||||
@ -133,31 +277,75 @@ class BillingPortalPurchase extends Component
|
||||
'client_contact_id' => $this->contact->hashed_id,
|
||||
]],
|
||||
'user_input_promo_code' => $this->coupon,
|
||||
'quantity' => 1, // Option to increase quantity
|
||||
'coupon' => empty($this->subscription->promo_code) ? '' : $this->coupon,
|
||||
'quantity' => $this->quantity,
|
||||
];
|
||||
|
||||
$this->invoice = $this->billing_subscription
|
||||
$this->invoice = $this->subscription
|
||||
->service()
|
||||
->createInvoice($data)
|
||||
->service()
|
||||
->markSent()
|
||||
->fillDefaults()
|
||||
->save();
|
||||
|
||||
Cache::put($this->hash, [
|
||||
'subscription_id' => $this->subscription->id,
|
||||
'email' => $this->email ?? $this->contact->email,
|
||||
'client_id' => $this->contact->client->id,
|
||||
'invoice_id' => $this->invoice->id],
|
||||
now()->addMinutes(60)
|
||||
'invoice_id' => $this->invoice->id,
|
||||
now()->addMinutes(60)]
|
||||
);
|
||||
|
||||
$this->emit('beforePaymentEventsCompleted');
|
||||
}
|
||||
|
||||
|
||||
//this isn't managed here - this is taken care of in the BS
|
||||
public function applyCouponCode()
|
||||
/**
|
||||
* Proxy method for starting the trial.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
|
||||
*/
|
||||
public function handleTrial()
|
||||
{
|
||||
dd('Applying coupon code: ' . $this->coupon);
|
||||
return $this->subscription->service()->startTrial([
|
||||
'email' => $this->email ?? $this->contact->email,
|
||||
'quantity' => $this->quantity,
|
||||
'contact_id' => $this->contact->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update quantity property.
|
||||
*
|
||||
* @param string $option
|
||||
* @return int
|
||||
*/
|
||||
public function updateQuantity(string $option): int
|
||||
{
|
||||
if ($this->quantity == 1 && $option == 'decrement') {
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
if ($this->quantity >= $this->subscription->max_seats_limit && $option == 'increment') {
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
if ($option == 'increment') {
|
||||
$this->quantity++;
|
||||
return $this->price = (int)$this->price + $this->subscription->product->price;
|
||||
}
|
||||
|
||||
$this->quantity--;
|
||||
$this->price = (int)$this->price - $this->subscription->product->price;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function handleCoupon()
|
||||
{
|
||||
if ($this->coupon == $this->subscription->promo_code) {
|
||||
$this->price = $this->subscription->promo_price;
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\BillingSubscription;
|
||||
|
||||
class CreateBillingSubscriptionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth()->user()->can('create', BillingSubscription::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class DestroyBillingSubscriptionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->user()->can('edit', $this->billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EditBillingSubscriptionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->user()->can('edit', $this->billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ShowBillingSubscriptionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() : bool
|
||||
{
|
||||
return auth()->user()->can('view', $this->billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\BillingSubscription;
|
||||
|
||||
class StoreBillingSubscriptionRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->user()->can('create', BillingSubscription::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'user_id' => ['sometimes'],
|
||||
'product_id' => ['sometimes'],
|
||||
'assigned_user_id' => ['sometimes'],
|
||||
'company_id' => ['sometimes'],
|
||||
'is_recurring' => ['sometimes'],
|
||||
'frequency_id' => ['sometimes'],
|
||||
'auto_bill' => ['sometimes'],
|
||||
'promo_code' => ['sometimes'],
|
||||
'promo_discount' => ['sometimes'],
|
||||
'is_amount_discount' => ['sometimes'],
|
||||
'allow_cancellation' => ['sometimes'],
|
||||
'per_set_enabled' => ['sometimes'],
|
||||
'min_seats_limit' => ['sometimes'],
|
||||
'max_seats_limit' => ['sometimes'],
|
||||
'trial_enabled' => ['sometimes'],
|
||||
'trial_duration' => ['sometimes'],
|
||||
'allow_query_overrides' => ['sometimes'],
|
||||
'allow_plan_changes' => ['sometimes'],
|
||||
'plan_map' => ['sometimes'],
|
||||
'refund_period' => ['sometimes'],
|
||||
'webhook_configuration' => ['sometimes'],
|
||||
];
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Http\Requests\BillingSubscription;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
|
||||
class UpdateBillingSubscriptionRequest extends Request
|
||||
{
|
||||
use ChecksEntityStatus;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return auth()->user()->can('edit', $this->billing_subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -47,6 +47,10 @@ class StoreClientRequest extends Request
|
||||
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
if (isset($this->number)) {
|
||||
$rules['number'] = Rule::unique('clients')->where('company_id', auth()->user()->company()->id);
|
||||
}
|
||||
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
|
@ -67,8 +67,10 @@ class UpdateCreditRequest extends Request
|
||||
|
||||
$input = $this->decodePrimaryKeys($input);
|
||||
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
|
||||
if (isset($input['line_items'])) {
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
}
|
||||
|
||||
$input['id'] = $this->credit->id;
|
||||
|
||||
$this->replace($input);
|
||||
|
@ -45,8 +45,6 @@ class ActionInvoiceRequest extends Request
|
||||
{
|
||||
$input = $this->all();
|
||||
|
||||
$this->invoice = Invoice::find($this->decodePrimary($invoice_id));
|
||||
|
||||
if (!array_key_exists('action', $input)) {
|
||||
$this->error_msg = 'Action is a required field';
|
||||
} elseif (!$this->invoiceDeletable($this->invoice)) {
|
||||
|
@ -66,8 +66,10 @@ class UpdateInvoiceRequest extends Request
|
||||
|
||||
$input['id'] = $this->invoice->id;
|
||||
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
|
||||
if (isset($input['line_items'])) {
|
||||
$input['line_items'] = isset($input['line_items']) ? $this->cleanItems($input['line_items']) : [];
|
||||
}
|
||||
|
||||
if (array_key_exists('documents', $input)) {
|
||||
unset($input['documents']);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use App\Http\ValidationRules\Quote\UniqueQuoteNumberRule;
|
||||
use App\Models\Quote;
|
||||
use App\Utils\Traits\CleanLineItems;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreQuoteRequest extends Request
|
||||
{
|
||||
@ -48,7 +49,9 @@ class StoreQuoteRequest extends Request
|
||||
$rules['documents'] = 'file|mimes:png,ai,svg,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000';
|
||||
}
|
||||
|
||||
$rules['number'] = new UniqueQuoteNumberRule($this->all());
|
||||
$rules['number'] = ['nullable',Rule::unique('quotes')->where('company_id', auth()->user()->company()->id)];
|
||||
|
||||
// $rules['number'] = new UniqueQuoteNumberRule($this->all());
|
||||
$rules['line_items'] = 'array';
|
||||
|
||||
return $rules;
|
||||
|
@ -70,6 +70,10 @@ class Request extends FormRequest
|
||||
|
||||
public function decodePrimaryKeys($input)
|
||||
{
|
||||
if (array_key_exists('group_id', $input) && is_string($input['group_id'])) {
|
||||
$input['group_id'] = $this->decodePrimaryKey($input['group_id']);
|
||||
}
|
||||
|
||||
if (array_key_exists('subscription_id', $input) && is_string($input['subscription_id'])) {
|
||||
$input['subscription_id'] = $this->decodePrimaryKey($input['subscription_id']);
|
||||
}
|
||||
|
@ -13,12 +13,14 @@ namespace App\Http\Requests\User;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\User;
|
||||
use App\Utils\Traits\ChecksEntityStatus;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class DetachCompanyUserRequest extends Request
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
use ChecksEntityStatus;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
|
@ -79,6 +79,7 @@ class PortalComposer
|
||||
$data[] = ['title' => ctrans('texts.credits'), 'url' => 'client.credits.index', 'icon' => 'credit-card'];
|
||||
$data[] = ['title' => ctrans('texts.payment_methods'), 'url' => 'client.payment_methods.index', 'icon' => 'shield'];
|
||||
$data[] = ['title' => ctrans('texts.documents'), 'url' => 'client.documents.index', 'icon' => 'download'];
|
||||
$data[] = ['title' => ctrans('texts.subscriptions'), 'url' => 'client.subscriptions.index', 'icon' => 'calendar'];
|
||||
|
||||
if (auth()->user('contact')->client->getSetting('enable_client_portal_tasks')) {
|
||||
$data[] = ['title' => ctrans('texts.tasks'), 'url' => 'client.dashboard', 'icon' => 'clock'];
|
||||
|
@ -59,6 +59,7 @@ class CreateCompany
|
||||
$company->enabled_modules = config('ninja.enabled_modules');
|
||||
$company->subdomain = isset($this->request['subdomain']) ? $this->request['subdomain'] : '';
|
||||
$company->custom_fields = new \stdClass;
|
||||
$company->default_password_timeout = 1800000;
|
||||
$company->save();
|
||||
|
||||
return $company;
|
||||
|
@ -1,72 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Jobs\Cron;
|
||||
|
||||
use App\Libraries\MultiDB;
|
||||
use App\Models\ClientSubscription;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class BillingSubscriptionCron
|
||||
{
|
||||
use Dispatchable;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle() : void
|
||||
{
|
||||
|
||||
if (! config('ninja.db.multi_db_enabled')) {
|
||||
$this->loopSubscriptions();
|
||||
} else {
|
||||
//multiDB environment, need to
|
||||
foreach (MultiDB::$dbs as $db) {
|
||||
|
||||
MultiDB::setDB($db);
|
||||
$this->loopSubscriptions();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function loopSubscriptions()
|
||||
{
|
||||
$client_subs = ClientSubscription::whereNull('deleted_at')
|
||||
->cursor()
|
||||
->each(function ($cs){
|
||||
$this->processSubscription($cs);
|
||||
});
|
||||
}
|
||||
|
||||
/* Our daily cron should check
|
||||
|
||||
1. Is the subscription still in trial phase?
|
||||
2. Check the recurring invoice and its remaining_cycles to see whether we need to cancel or perform any other function.
|
||||
3. Any notifications that need to fire?
|
||||
*/
|
||||
private function processSubscription($client_subscription)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ class RecurringInvoicesCron
|
||||
|
||||
if (! config('ninja.db.multi_db_enabled')) {
|
||||
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '<=', now())
|
||||
->whereNotNull('next_send_date')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->with('company')
|
||||
@ -62,6 +63,7 @@ class RecurringInvoicesCron
|
||||
MultiDB::setDB($db);
|
||||
|
||||
$recurring_invoices = RecurringInvoice::whereDate('next_send_date', '<=', now())
|
||||
->whereNotNull('next_send_date')
|
||||
->where('status_id', RecurringInvoice::STATUS_ACTIVE)
|
||||
->where('remaining_cycles', '!=', '0')
|
||||
->with('company')
|
||||
|
@ -35,6 +35,8 @@ class SendRecurring implements ShouldQueue
|
||||
|
||||
protected $db;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
@ -63,6 +65,7 @@ class SendRecurring implements ShouldQueue
|
||||
->markSent()
|
||||
->applyNumber()
|
||||
->createInvitations()
|
||||
->fillDefaults()
|
||||
->save();
|
||||
|
||||
nlog("Invoice {$invoice->number} created");
|
||||
@ -74,16 +77,6 @@ class SendRecurring implements ShouldQueue
|
||||
}
|
||||
});
|
||||
|
||||
//Admin notification for recurring invoice sent.
|
||||
if ($invoice->invitations->count() >= 1) {
|
||||
$invoice->entityEmailEvent($invoice->invitations->first(), 'invoice', 'email_template_invoice');
|
||||
}
|
||||
|
||||
if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $this->recurring_invoice->auto_bill_enabled) {
|
||||
nlog("attempting to autobill {$invoice->number}");
|
||||
$invoice->service()->autoBill()->save();
|
||||
}
|
||||
|
||||
nlog("updating recurring invoice dates");
|
||||
/* Set next date here to prevent a recurring loop forming */
|
||||
$this->recurring_invoice->next_send_date = $this->recurring_invoice->nextSendDate()->format('Y-m-d');
|
||||
@ -101,6 +94,17 @@ class SendRecurring implements ShouldQueue
|
||||
|
||||
$this->recurring_invoice->save();
|
||||
|
||||
//Admin notification for recurring invoice sent.
|
||||
if ($invoice->invitations->count() >= 1) {
|
||||
$invoice->entityEmailEvent($invoice->invitations->first(), 'invoice', 'email_template_invoice');
|
||||
}
|
||||
|
||||
if ($invoice->client->getSetting('auto_bill_date') == 'on_send_date' && $this->recurring_invoice->auto_bill_enabled) {
|
||||
nlog("attempting to autobill {$invoice->number}");
|
||||
$invoice->service()->autoBill()->save();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function failed($exception = null)
|
||||
|
@ -424,7 +424,10 @@ class Import implements ShouldQueue
|
||||
unset($modified['password']); //cant import passwords.
|
||||
|
||||
$user = $user_repository->save($modified, $this->fetchUser($resource['email']), true, true);
|
||||
|
||||
$user->email_verified_at = now();
|
||||
$user->confirmation_code = '';
|
||||
$user->save();
|
||||
|
||||
$user_agent = array_key_exists('token_name', $resource) ?: request()->server('HTTP_USER_AGENT');
|
||||
|
||||
CreateCompanyToken::dispatchNow($this->company, $user, $user_agent);
|
||||
|
@ -54,7 +54,7 @@ class CreditEmailedNotification implements ShouldQueue
|
||||
|
||||
// $notification = new EntitySentNotification($event->invitation, 'credit');
|
||||
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'credit', ['all_notifications', 'credit_sent']);
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'credit', ['all_notifications', 'credit_sent', 'credit_sent_all']);
|
||||
|
||||
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
|
||||
unset($methods[$key]);
|
||||
|
@ -60,7 +60,7 @@ class InvoiceEmailedNotification implements ShouldQueue
|
||||
// $notification = new EntitySentNotification($event->invitation, 'invoice');
|
||||
|
||||
/* Returns an array of notification methods */
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent']);
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent', 'invoice_sent_all']);
|
||||
|
||||
/* If one of the methods is email then we fire the EntitySentMailer */
|
||||
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
|
||||
|
@ -56,7 +56,7 @@ class InvoiceFailedEmailNotification
|
||||
|
||||
// $notification = new EntitySentNotification($event->invitation, 'invoice');
|
||||
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent']);
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent', 'invoice_sent_all']);
|
||||
|
||||
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
|
||||
unset($methods[$key]);
|
||||
|
@ -55,7 +55,7 @@ class QuoteEmailedNotification implements ShouldQueue
|
||||
|
||||
// $notification = new EntitySentNotification($event->invitation, 'quote');
|
||||
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'quote', ['all_notifications', 'quote_sent']);
|
||||
$methods = $this->findUserNotificationTypes($event->invitation, $company_user, 'quote', ['all_notifications', 'quote_sent', 'quote_sent_all']);
|
||||
|
||||
if (($key = array_search('mail', $methods)) !== false && $first_notification_sent === true) {
|
||||
unset($methods[$key]);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\Mail\Engine;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Utils\HtmlEngine;
|
||||
use App\Utils\Number;
|
||||
|
||||
|
@ -45,7 +45,7 @@ class SupportMessageSent extends Mailable
|
||||
|
||||
$log_file->seek(PHP_INT_MAX);
|
||||
$last_line = $log_file->key();
|
||||
$lines = new LimitIterator($log_file, $last_line - 10, $last_line);
|
||||
$lines = new LimitIterator($log_file, $last_line - 100, $last_line);
|
||||
|
||||
$log_lines = iterator_to_array($lines);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace App\Mail;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientContact;
|
||||
use App\Models\User;
|
||||
use App\Utils\HtmlEngine;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
@ -52,6 +53,9 @@ class TemplateEmail extends Mailable
|
||||
|
||||
$company = $this->client->company;
|
||||
|
||||
$html_variables = (new HtmlEngine($this->invitation))->makeValues();
|
||||
|
||||
//str_replace(array_keys($html_variables), array_values($html_variables), $settings->email_signature)
|
||||
$this->from(config('mail.from.address'), $this->company->present()->name());
|
||||
|
||||
if (strlen($settings->bcc_email) > 1)
|
||||
@ -71,7 +75,7 @@ class TemplateEmail extends Mailable
|
||||
'view_link' => $this->build_email->getViewLink(),
|
||||
'view_text' => $this->build_email->getViewText(),
|
||||
'title' => '',
|
||||
'signature' => $settings->email_signature,
|
||||
'signature' => str_replace(array_keys($html_variables), array_values($html_variables), $settings->email_signature),
|
||||
'settings' => $settings,
|
||||
'company' => $company,
|
||||
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
|
||||
|
@ -191,7 +191,9 @@ class BaseModel extends Model
|
||||
|
||||
public function numberFormatter()
|
||||
{
|
||||
$formatted_number = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $this->number);
|
||||
$number = strlen($this->number) > 1 ? $this->number : class_basename($this);
|
||||
|
||||
$formatted_number = mb_ereg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $number);
|
||||
// Remove any runs of periods (thanks falstro!)
|
||||
$formatted_number = mb_ereg_replace("([\.]{2,})", '', $formatted_number);
|
||||
|
||||
|
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Services\BillingSubscription\BillingSubscriptionService;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class BillingSubscription extends BaseModel
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'product_id',
|
||||
'company_id',
|
||||
'product_id',
|
||||
'is_recurring',
|
||||
'frequency_id',
|
||||
'auto_bill',
|
||||
'promo_code',
|
||||
'promo_discount',
|
||||
'is_amount_discount',
|
||||
'allow_cancellation',
|
||||
'per_set_enabled',
|
||||
'min_seats_limit',
|
||||
'max_seats_limit',
|
||||
'trial_enabled',
|
||||
'trial_duration',
|
||||
'allow_query_overrides',
|
||||
'allow_plan_changes',
|
||||
'plan_map',
|
||||
'refund_period',
|
||||
'webhook_configuration',
|
||||
'currency_id',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_deleted' => 'boolean',
|
||||
'plan_map' => 'object',
|
||||
'webhook_configuration' => 'object',
|
||||
'updated_at' => 'timestamp',
|
||||
'created_at' => 'timestamp',
|
||||
'deleted_at' => 'timestamp',
|
||||
];
|
||||
|
||||
public function service()
|
||||
{
|
||||
return new BillingSubscriptionService($this);
|
||||
}
|
||||
|
||||
public function company(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Company::class);
|
||||
}
|
||||
|
||||
public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function product(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
@ -159,15 +159,10 @@ class Company extends BaseModel
|
||||
{
|
||||
return $this->hasMany(ExpenseCategory::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function client_subscriptions()
|
||||
|
||||
public function subscriptions()
|
||||
{
|
||||
return $this->hasMany(ClientSubscription::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function billing_subscriptions()
|
||||
{
|
||||
return $this->hasMany(BillingSubscription::class)->withTrashed();
|
||||
return $this->hasMany(Subscription::class)->withTrashed();
|
||||
}
|
||||
|
||||
public function task_statuses()
|
||||
@ -396,7 +391,7 @@ class Company extends BaseModel
|
||||
|
||||
public function system_logs()
|
||||
{
|
||||
return $this->hasMany(SystemLog::class)->orderBy('id', 'DESC')->take(50);
|
||||
return $this->hasMany(SystemLog::class)->orderBy('id', 'DESC')->take(100);
|
||||
}
|
||||
|
||||
public function system_log_relation()
|
||||
|
@ -97,13 +97,13 @@ class CompanyPresenter extends EntityPresenter
|
||||
}
|
||||
}
|
||||
|
||||
public function getSpcQrCode($client_currency, $invoice_number, $balance_due_raw)
|
||||
public function getSpcQrCode($client_currency, $invoice_number, $balance_due_raw, $user_iban)
|
||||
{
|
||||
$settings = $this->entity->settings;
|
||||
|
||||
return
|
||||
|
||||
"SPC\n0200\n1\nCH860021421411198240K\nK\n{$this->name}\n{$settings->address1}\n{$settings->postal_code} {$settings->city}\n\n\nCH\n\n\n\n\n\n\n\n{$balance_due_raw}\n{$client_currency}\n\n\n\n\n\n\n\nNON\n\n{$invoice_number}\nEPD\n";
|
||||
"SPC\n0200\n1\n{$user_iban}\nK\n{$this->name}\n{$settings->address1}\n{$settings->postal_code} {$settings->city}\n\n\nCH\n\n\n\n\n\n\n\n{$balance_due_raw}\n{$client_currency}\n\n\n\n\n\n\n\nNON\n\n{$invoice_number}\nEPD\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
|
||||
class BillingSubscriptionObserver
|
||||
{
|
||||
/**
|
||||
* Handle the billing_subscription "created" event.
|
||||
*
|
||||
* @param BillingSubscription $billing_subscription
|
||||
* @return void
|
||||
*/
|
||||
public function created(BillingSubscription $billing_subscription)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the billing_subscription "updated" event.
|
||||
*
|
||||
* @param BillingSubscription $billing_subscription
|
||||
* @return void
|
||||
*/
|
||||
public function updated(BillingSubscription $billing_subscription)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the billing_subscription "deleted" event.
|
||||
*
|
||||
* @param BillingSubscription $billing_subscription
|
||||
* @return void
|
||||
*/
|
||||
public function deleted(BillingSubscription $billing_subscription)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the billing_subscription "restored" event.
|
||||
*
|
||||
* @param BillingSubscription $billing_subscription
|
||||
* @return void
|
||||
*/
|
||||
public function restored(BillingSubscription $billing_subscription)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the billing_subscription "force deleted" event.
|
||||
*
|
||||
* @param BillingSubscription $billing_subscription
|
||||
* @return void
|
||||
*/
|
||||
public function forceDeleted(BillingSubscription $billing_subscription)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -211,12 +211,20 @@ class AuthorizeCreditCard
|
||||
{
|
||||
$response = $data['response'];
|
||||
|
||||
$code = '';
|
||||
$description = '';
|
||||
|
||||
if($response->getTransactionResponse()->getMessages() !== null){
|
||||
$code = $response->getTransactionResponse()->getMessages()[0]->getCode();
|
||||
$description = $response->getTransactionResponse()->getMessages()[0]->getDescription();
|
||||
}
|
||||
|
||||
return [
|
||||
'transaction_reference' => $response->getTransactionResponse()->getTransId(),
|
||||
'amount' => $vars['amount'],
|
||||
'auth_code' => $response->getTransactionResponse()->getAuthCode(),
|
||||
'code' => $response->getTransactionResponse()->getMessages()[0]->getCode(),
|
||||
'description' => $response->getTransactionResponse()->getMessages()[0]->getDescription(),
|
||||
'code' => $code,
|
||||
'description' => $description,
|
||||
'invoices' => $vars['invoices'],
|
||||
];
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\SystemLog;
|
||||
use App\Services\BillingSubscription\BillingSubscriptionService;
|
||||
use App\Services\Subscription\SubscriptionService;
|
||||
use App\Utils\Ninja;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Utils\Traits\SystemLogTrait;
|
||||
@ -241,7 +241,11 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
|
||||
|
||||
//(new BillingSubscriptionService)->completePurchase($this->payment_hash);
|
||||
if (property_exists($this->payment_hash->data, 'billing_context')) {
|
||||
$billing_subscription = \App\Models\Subscription::find($this->payment_hash->data->billing_context->subscription_id);
|
||||
|
||||
(new SubscriptionService($billing_subscription))->completePurchase($this->payment_hash);
|
||||
}
|
||||
|
||||
return $payment->service()->applyNumber()->save();
|
||||
}
|
||||
|
@ -100,22 +100,19 @@ class StripePaymentDriver extends BaseDriver
|
||||
// GatewayType::APPLE_PAY, // TODO:: Missing implementation
|
||||
];
|
||||
|
||||
if ($this->company_gateway->getSofortEnabled()
|
||||
&& $this->client
|
||||
if ($this->client
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->country->iso_3166_3, ['AUT', 'BEL', 'DEU', 'ITA', 'NLD', 'ESP'])) {
|
||||
$types[] = GatewayType::SOFORT;
|
||||
}
|
||||
|
||||
if ($this->company_gateway->getAchEnabled()
|
||||
&& $this->client
|
||||
if ($this->client
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->country->iso_3166_3, ['USA'])) {
|
||||
$types[] = GatewayType::BANK_TRANSFER;
|
||||
}
|
||||
|
||||
if ($this->company_gateway->getAlipayEnabled()
|
||||
&& $this->client
|
||||
if ($this->client
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->country->iso_3166_3, ['AUS', 'DNK', 'DEU', 'ITA', 'LUX', 'NOR', 'SVN', 'GBR', 'AUT', 'EST', 'GRC', 'JPN', 'MYS', 'PRT', 'ESP', 'USA', 'BEL', 'FIN', 'HKG', 'LVA', 'NLD', 'SGP', 'SWE', 'CAN', 'FRA', 'IRL', 'LTU', 'NZL', 'SVK', 'CHE'])) {
|
||||
$types[] = GatewayType::ALIPAY;
|
||||
@ -178,7 +175,6 @@ class StripePaymentDriver extends BaseDriver
|
||||
$fields[] = ['name' => 'client_address_line_2', 'label' => ctrans('texts.address2'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_city', 'label' => ctrans('texts.city'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_state', 'label' => ctrans('texts.state'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
|
||||
$fields[] = ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'text', 'validation' => 'required'];
|
||||
}
|
||||
|
||||
|
@ -1,31 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
/**
|
||||
* Class BillingSubscriptionPolicy.
|
||||
*/
|
||||
class BillingSubscriptionPolicy extends EntityPolicy
|
||||
{
|
||||
/**
|
||||
* Checks if the user has create permissions.
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user) : bool
|
||||
{
|
||||
return $user->isAdmin() || $user->hasPermission('create_billing_subscription') || $user->hasPermission('create_all');
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientSubscription;
|
||||
use App\Models\Company;
|
||||
@ -28,7 +28,7 @@ use App\Models\Quote;
|
||||
use App\Models\Task;
|
||||
use App\Models\User;
|
||||
use App\Observers\AccountObserver;
|
||||
use App\Observers\BillingSubscriptionObserver;
|
||||
use App\Observers\SubscriptionObserver;
|
||||
use App\Observers\ClientObserver;
|
||||
use App\Observers\ClientSubscriptionObserver;
|
||||
use App\Observers\CompanyGatewayObserver;
|
||||
@ -80,7 +80,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
Schema::defaultStringLength(191);
|
||||
|
||||
Account::observe(AccountObserver::class);
|
||||
BillingSubscription::observe(BillingSubscriptionObserver::class);
|
||||
Subscription::observe(SubscriptionObserver::class);
|
||||
Client::observe(ClientObserver::class);
|
||||
ClientSubscription::observe(ClientSubscriptionObserver::class);
|
||||
Company::observe(CompanyObserver::class);
|
||||
|
@ -12,9 +12,8 @@
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientSubscription;
|
||||
use App\Models\Company;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\CompanyToken;
|
||||
@ -39,7 +38,7 @@ use App\Models\User;
|
||||
use App\Models\Vendor;
|
||||
use App\Models\Webhook;
|
||||
use App\Policies\ActivityPolicy;
|
||||
use App\Policies\BillingSubscriptionPolicy;
|
||||
use App\Policies\SubscriptionPolicy;
|
||||
use App\Policies\ClientPolicy;
|
||||
use App\Policies\ClientSubscriptionPolicy;
|
||||
use App\Policies\CompanyGatewayPolicy;
|
||||
@ -77,9 +76,8 @@ class AuthServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected $policies = [
|
||||
Activity::class => ActivityPolicy::class,
|
||||
BillingSubscription::class => BillingSubscriptionPolicy::class,
|
||||
Subscription::class => SubscriptionPolicy::class,
|
||||
Client::class => ClientPolicy::class,
|
||||
ClientSubscription::class => ClientSubscriptionPolicy::class,
|
||||
Company::class => CompanyPolicy::class,
|
||||
CompanyToken::class => CompanyTokenPolicy::class,
|
||||
CompanyGateway::class => CompanyGatewayPolicy::class,
|
||||
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
|
||||
class BillingSubscriptionRepository extends BaseRepository
|
||||
{
|
||||
public function save($data, BillingSubscription $billing_subscription): ?BillingSubscription
|
||||
{
|
||||
$billing_subscription
|
||||
->fill($data)
|
||||
->save();
|
||||
|
||||
return $billing_subscription;
|
||||
}
|
||||
}
|
@ -182,7 +182,6 @@ class PaymentRepository extends BaseRepository {
|
||||
$company_currency = $client->company->settings->currency_id;
|
||||
|
||||
if ($company_currency != $client_currency) {
|
||||
$currency = $client->currency();
|
||||
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
|
@ -24,18 +24,6 @@ class RecurringInvoiceRepository extends BaseRepository
|
||||
{
|
||||
|
||||
$invoice = $this->alternativeSave($data, $invoice);
|
||||
// $invoice->fill($data);
|
||||
|
||||
// $invoice->save();
|
||||
|
||||
// $invoice_calc = new InvoiceSum($invoice);
|
||||
|
||||
// $invoice->service()
|
||||
// ->applyNumber()
|
||||
// ->createInvitations()
|
||||
// ->save();
|
||||
|
||||
// $invoice = $invoice_calc->build()->getRecurringInvoice();
|
||||
|
||||
return $invoice;
|
||||
}
|
||||
|
@ -148,9 +148,9 @@ class UserRepository extends BaseRepository
|
||||
|
||||
event(new UserWasDeleted($user, auth()->user(), $company, Ninja::eventVars()));
|
||||
|
||||
// $user->is_deleted = true;
|
||||
// $user->save();
|
||||
// $user->delete();
|
||||
$user->is_deleted = true;
|
||||
$user->save();
|
||||
$user->delete();
|
||||
|
||||
|
||||
return $user->fresh();
|
||||
@ -177,7 +177,17 @@ class UserRepository extends BaseRepository
|
||||
return;
|
||||
}
|
||||
|
||||
$user->is_deleted = false;
|
||||
$user->save();
|
||||
$user->restore();
|
||||
// $user->company_user->restore();
|
||||
|
||||
$cu = CompanyUser::withTrashed()
|
||||
->where('user_id', $user->id)
|
||||
->where('company_id', auth()->user()->company()->id)
|
||||
->first();
|
||||
|
||||
$cu->restore();
|
||||
|
||||
event(new UserWasRestored($user, auth()->user(), auth()->user()->company, Ninja::eventVars()));
|
||||
|
||||
|
@ -1,209 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Services\BillingSubscription;
|
||||
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\Factory\InvoiceFactory;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\ClientSubscription;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\Product;
|
||||
use App\Models\SystemLog;
|
||||
use App\Repositories\InvoiceRepository;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
class BillingSubscriptionService
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/** @var BillingSubscription */
|
||||
private $billing_subscription;
|
||||
|
||||
private $client_subscription;
|
||||
|
||||
public function __construct(BillingSubscription $billing_subscription)
|
||||
{
|
||||
$this->billing_subscription = $billing_subscription;
|
||||
}
|
||||
|
||||
public function completePurchase(PaymentHash $payment_hash)
|
||||
{
|
||||
|
||||
if (!property_exists($payment_hash, 'billing_context')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we have some state carried from the billing page
|
||||
// to this, available as $payment_hash->data->billing_context. Make something awesome ⭐
|
||||
|
||||
// create client subscription record
|
||||
//
|
||||
// create recurring invoice if is_recurring
|
||||
//
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function startTrial(array $data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function createInvoice($data): ?\App\Models\Invoice
|
||||
{
|
||||
$invoice_repo = new InvoiceRepository();
|
||||
|
||||
$data['line_items'] = $this->createLineItems($data);
|
||||
|
||||
/*
|
||||
If trial_enabled -> return early
|
||||
|
||||
-- what we need to know that we don't already
|
||||
-- Has a promo code been entered, and does it match
|
||||
-- Is this a recurring subscription
|
||||
--
|
||||
|
||||
1. Is this a recurring product?
|
||||
2. What is the quantity? ie is this a multi seat product ( does this mean we need this value stored in the client sub?)
|
||||
*/
|
||||
|
||||
return $invoice_repo->save($data, InvoiceFactory::create($this->billing_subscription->company_id, $this->billing_subscription->user_id));
|
||||
|
||||
}
|
||||
|
||||
private function createLineItems($data): array
|
||||
{
|
||||
$line_items = [];
|
||||
|
||||
$product = $this->billing_subscription->product;
|
||||
|
||||
$item = new InvoiceItem;
|
||||
$item->quantity = $data['quantity'];
|
||||
$item->product_key = $product->product_key;
|
||||
$item->notes = $product->notes;
|
||||
$item->cost = $product->price;
|
||||
$item->tax_rate1 = $product->tax_rate1 ?: 0;
|
||||
$item->tax_name1 = $product->tax_name1 ?: '';
|
||||
$item->tax_rate2 = $product->tax_rate2 ?: 0;
|
||||
$item->tax_name2 = $product->tax_name2 ?: '';
|
||||
$item->tax_rate3 = $product->tax_rate3 ?: 0;
|
||||
$item->tax_name3 = $product->tax_name3 ?: '';
|
||||
$item->custom_value1 = $product->custom_value1 ?: '';
|
||||
$item->custom_value2 = $product->custom_value2 ?: '';
|
||||
$item->custom_value3 = $product->custom_value3 ?: '';
|
||||
$item->custom_value4 = $product->custom_value4 ?: '';
|
||||
|
||||
//$item->type_id need to switch whether the subscription is a service or product
|
||||
|
||||
$line_items[] = $item;
|
||||
|
||||
|
||||
//do we have a promocode? enter this as a line item.
|
||||
if(strlen($data['coupon']) >=1 && ($data['coupon'] == $this->billing_subscription->promo_code) && $this->billing_subscription->promo_discount > 0)
|
||||
$line_items[] = $this->createPromoLine($data);
|
||||
|
||||
return $line_items;
|
||||
}
|
||||
|
||||
private function createPromoLine($data)
|
||||
{
|
||||
|
||||
$product = $this->billing_subscription->product;
|
||||
|
||||
$discounted_amount = 0;
|
||||
$discount = 0;
|
||||
$amount = $data['quantity'] * $product->cost;
|
||||
|
||||
if ($this->billing_subscription->is_amount_discount == true) {
|
||||
$discount = $this->billing_subscription->promo_discount;
|
||||
}
|
||||
else {
|
||||
$discount = round($amount * ($this->billing_subscription->promo_discount / 100), 2);
|
||||
}
|
||||
|
||||
$discounted_amount = $amount - $discount;
|
||||
|
||||
$item = new InvoiceItem;
|
||||
$item->quantity = 1;
|
||||
$item->product_key = ctrans('texts.promo_code');
|
||||
$item->notes = ctrans('texts.promo_code');
|
||||
$item->cost = $discounted_amount;
|
||||
$item->tax_rate1 = $product->tax_rate1 ?: 0;
|
||||
$item->tax_name1 = $product->tax_name1 ?: '';
|
||||
$item->tax_rate2 = $product->tax_rate2 ?: 0;
|
||||
$item->tax_name2 = $product->tax_name2 ?: '';
|
||||
$item->tax_rate3 = $product->tax_rate3 ?: 0;
|
||||
$item->tax_name3 = $product->tax_name3 ?: '';
|
||||
|
||||
return $item;
|
||||
|
||||
}
|
||||
|
||||
private function convertInvoiceToRecurring()
|
||||
{
|
||||
//The first invoice is a plain invoice - the second is fired on the recurring schedule.
|
||||
}
|
||||
|
||||
public function createClientSubscription($payment_hash, $recurring_invoice_id = null)
|
||||
{
|
||||
//create the client sub record
|
||||
|
||||
//?trial enabled?
|
||||
$cs = new ClientSubscription();
|
||||
$cs->subscription_id = $this->billing_subscription->id;
|
||||
$cs->company_id = $this->billing_subscription->company_id;
|
||||
|
||||
// client_id
|
||||
$cs->save();
|
||||
|
||||
$this->client_subscription = $cs;
|
||||
|
||||
}
|
||||
|
||||
public function triggerWebhook($payment_hash)
|
||||
{
|
||||
//hit the webhook to after a successful onboarding
|
||||
//$client = xxxxxxx
|
||||
//todo webhook
|
||||
|
||||
$body = [
|
||||
'billing_subscription' => $this->billing_subscription,
|
||||
'client_subscription' => $this->client_subscription,
|
||||
// 'client' => $client->toArray(),
|
||||
];
|
||||
|
||||
|
||||
$client = new \GuzzleHttp\Client(['headers' => $this->billing_subscription->webhook_configuration->post_purchase_headers]);
|
||||
|
||||
$response = $client->{$this->billing_subscription->webhook_configuration->post_purchase_rest_method}($this->billing_subscription->post_purchase_url,[
|
||||
RequestOptions::JSON => ['body' => $body]
|
||||
]);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$body,
|
||||
SystemLog::CATEGORY_WEBHOOK,
|
||||
SystemLog::EVENT_WEBHOOK_RESPONSE,
|
||||
SystemLog::TYPE_WEBHOOK_RESPONSE,
|
||||
//$client,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function fireNotifications()
|
||||
{
|
||||
//scan for any notification we are required to send
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -186,7 +186,7 @@ class PaymentMethod
|
||||
foreach ($child_array as $gateway_id => $gateway_type_id) {
|
||||
$gateway = CompanyGateway::find($gateway_id);
|
||||
|
||||
$fee_label = $gateway->calcGatewayFeeLabel($this->amount, $this->client);
|
||||
$fee_label = $gateway->calcGatewayFeeLabel($this->amount, $this->client, $gateway_type_id);
|
||||
|
||||
if(!$gateway_type_id){
|
||||
|
||||
|
@ -14,6 +14,7 @@ namespace App\Services\Invoice;
|
||||
use App\Jobs\Entity\CreateEntityPdf;
|
||||
use App\Jobs\Invoice\InvoiceWorkflowSettings;
|
||||
use App\Jobs\Util\UnlinkFile;
|
||||
use App\Libraries\Currency\Conversion\CurrencyApi;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Expense;
|
||||
use App\Models\Invoice;
|
||||
@ -62,7 +63,25 @@ class InvoiceService
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exchange rate on the invoice if the client currency
|
||||
* is different to the company currency.
|
||||
*/
|
||||
public function setExchangeRate()
|
||||
{
|
||||
|
||||
$client_currency = $this->invoice->client->getSetting('currency_id');
|
||||
$company_currency = $this->invoice->company->settings->currency_id;
|
||||
|
||||
if ($company_currency != $client_currency) {
|
||||
|
||||
$exchange_rate = new CurrencyApi();
|
||||
|
||||
$this->invoice->exchange_rate = $exchange_rate->exchangeRate($client_currency, $company_currency, now());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Applies the recurring invoice number.
|
||||
* @return $this InvoiceService object
|
||||
@ -132,6 +151,8 @@ class InvoiceService
|
||||
{
|
||||
$this->invoice = (new MarkSent($this->invoice->client, $this->invoice))->run();
|
||||
|
||||
$this->setExchangeRate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ class Design extends BaseDesign
|
||||
{
|
||||
$_variables = array_key_exists('variables', $this->context)
|
||||
? $this->context['variables']
|
||||
: ['values' => ['$entity.public_notes' => nl2br($this->entity->public_notes), '$entity.terms' => $this->entity->terms, '$entity_footer' => $this->entity->footer], 'labels' => []];
|
||||
: ['values' => ['$entity.public_notes' => $this->entity->public_notes, '$entity.terms' => $this->entity->terms, '$entity_footer' => $this->entity->footer], 'labels' => []];
|
||||
|
||||
if ($this->type == 'delivery_note') {
|
||||
return [];
|
||||
@ -443,9 +443,9 @@ class Design extends BaseDesign
|
||||
['element' => 'div', 'properties' => ['style' => 'display: flex; flex-direction: column;'], 'elements' => [
|
||||
['element' => 'p', 'content' => strtr($_variables['values']['$entity.public_notes'], $_variables), 'properties' => ['data-ref' => 'total_table-public_notes', 'style' => 'text-align: left;']],
|
||||
['element' => 'p', 'content' => '', 'properties' => ['style' => 'text-align: left; display: flex; flex-direction: column;'], 'elements' => [
|
||||
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left;']],
|
||||
['element' => 'span', 'content' => '$entity.terms_label: ', 'properties' => ['hidden' => $this->entityVariableCheck('$entity.terms'), 'data-ref' => 'total_table-terms-label', 'style' => 'font-weight: bold; text-align: left; margin-top: 1rem;']],
|
||||
['element' => 'span', 'content' => strtr($_variables['values']['$entity.terms'], $_variables), 'properties' => ['data-ref' => 'total_table-terms', 'style' => 'text-align: left;']],
|
||||
['element' => 'span', 'content' => strtr($_variables['values']['$entity_footer'], $_variables), 'properties' => ['data-ref' => 'total_table-footer', 'style' => 'text-align: left;']],
|
||||
['element' => 'span', 'content' => strtr($_variables['values']['$entity_footer'], $_variables), 'properties' => ['data-ref' => 'total_table-footer', 'style' => 'text-align: left; margin-top: 1rem;']],
|
||||
]],
|
||||
['element' => 'img', 'properties' => ['hidden' => $this->client->getSetting('signature_on_pdf'), 'style' => 'max-width: 50%; height: auto;', 'src' => '$contact.signature']],
|
||||
['element' => 'div', 'properties' => ['style' => 'margin-top: 1.5rem; display: flex; align-items: flex-start;'], 'elements' => [
|
||||
|
@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace App\Transformers;
|
||||
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class BillingSubscriptionTransformer extends EntityTransformer
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultIncludes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $availableIncludes = [
|
||||
'product',
|
||||
];
|
||||
|
||||
public function transform(BillingSubscription $billing_subscription): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->encodePrimaryKey($billing_subscription->id),
|
||||
'user_id' => $this->encodePrimaryKey($billing_subscription->user_id),
|
||||
'product_id' => $this->encodePrimaryKey($billing_subscription->product_id),
|
||||
'assigned_user_id' => $this->encodePrimaryKey($billing_subscription->assigned_user_id),
|
||||
'company_id' => $this->encodePrimaryKey($billing_subscription->company_id),
|
||||
'is_recurring' => (bool)$billing_subscription->is_recurring,
|
||||
'frequency_id' => (string)$billing_subscription->frequency_id,
|
||||
'auto_bill' => (string)$billing_subscription->auto_bill,
|
||||
'promo_code' => (string)$billing_subscription->promo_code,
|
||||
'promo_discount' => (float)$billing_subscription->promo_discount,
|
||||
'is_amount_discount' => (bool)$billing_subscription->is_amount_discount,
|
||||
'allow_cancellation' => (bool)$billing_subscription->allow_cancellation,
|
||||
'per_seat_enabled' => (bool)$billing_subscription->per_set_enabled,
|
||||
'min_seats_limit' => (int)$billing_subscription->min_seats_limit,
|
||||
'max_seats_limit' => (int)$billing_subscription->max_seats_limit,
|
||||
'trial_enabled' => (bool)$billing_subscription->trial_enabled,
|
||||
'trial_duration' => (int)$billing_subscription->trial_duration,
|
||||
'allow_query_overrides' => (bool)$billing_subscription->allow_query_overrides,
|
||||
'allow_plan_changes' => (bool)$billing_subscription->allow_plan_changes,
|
||||
'plan_map' => (string)$billing_subscription->plan_map,
|
||||
'refund_period' => (int)$billing_subscription->refund_period,
|
||||
'webhook_configuration' => (string)$billing_subscription->webhook_configuration,
|
||||
'purchase_page' => (string)route('client.subscription.purchase', $billing_subscription->hashed_id),
|
||||
'is_deleted' => (bool)$billing_subscription->is_deleted,
|
||||
'created_at' => (int)$billing_subscription->created_at,
|
||||
'updated_at' => (int)$billing_subscription->updated_at,
|
||||
'archived_at' => (int)$billing_subscription->deleted_at,
|
||||
];
|
||||
}
|
||||
|
||||
public function includeProduct(BillingSubscription $billing_subscription): \League\Fractal\Resource\Item
|
||||
{
|
||||
$transformer = new ProductTransformer($this->serializer);
|
||||
|
||||
return $this->includeItem($billing_subscription->product, $transformer, Product::class);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ namespace App\Transformers;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Activity;
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\Subscription;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientSubscription;
|
||||
use App\Models\Company;
|
||||
@ -92,7 +92,7 @@ class CompanyTransformer extends EntityTransformer
|
||||
'system_logs',
|
||||
'expense_categories',
|
||||
'task_statuses',
|
||||
'client_subscriptions',
|
||||
'subscriptions',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -362,17 +362,10 @@ class CompanyTransformer extends EntityTransformer
|
||||
return $this->includeCollection($company->system_logs, $transformer, SystemLog::class);
|
||||
}
|
||||
|
||||
public function includeClientSubscriptions(Company $company)
|
||||
public function includeSubscriptions(Company $company)
|
||||
{
|
||||
$transformer = new ClientSubscriptionTransformer($this->serializer);
|
||||
$transformer = new SubscriptionTransformer($this->serializer);
|
||||
|
||||
return $this->includeCollection($company->client_subscriptions, $transformer, ClientSubscription::class);
|
||||
}
|
||||
|
||||
public function includeBillingSubscriptions(Company $company)
|
||||
{
|
||||
$transformer = new BillingSubscriptionTransformer($this->serializer);
|
||||
|
||||
return $this->includeCollection($company->billing_subscriptions, $transformer, BillingSubscription::class);
|
||||
return $this->includeCollection($company->subscriptions, $transformer, Subscription::class);
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ class RecurringInvoiceTransformer extends EntityTransformer
|
||||
'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled,
|
||||
'due_date_days' => (string) $invoice->due_date_days ?: '',
|
||||
'paid_to_date' => (float) $invoice->paid_to_date,
|
||||
'subscription_id' => (string)$this->encodePrimaryKey($invoice->subscription_id),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ class UserTransformer extends EntityTransformer
|
||||
'last_confirmed_email_address' => (string) $user->last_confirmed_email_address ?: '',
|
||||
'google_2fa_secret' => (bool) $user->google_2fa_secret,
|
||||
'has_password' => (bool) $user->has_password,
|
||||
'oauth_user_token' => empty($user->oauth_user_token) ? '' : '***',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -160,8 +160,8 @@ class HtmlEngine
|
||||
$data['$invoice.subtotal'] = &$data['$subtotal'];
|
||||
|
||||
if ($this->entity->partial > 0) {
|
||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.partial_due')];
|
||||
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
|
||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
||||
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.balance_due')];
|
||||
} else {
|
||||
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->balance, $this->client) ?: ' ', 'label' => ctrans('texts.balance_due')];
|
||||
$data['$balance_due_raw'] = ['value' => $this->entity->balance, 'label' => ctrans('texts.balance_due')];
|
||||
@ -192,11 +192,12 @@ class HtmlEngine
|
||||
$data['$taxes'] = ['value' => Number::formatMoney($this->entity_calc->getItemTotalTaxes(), $this->client) ?: ' ', 'label' => ctrans('texts.taxes')];
|
||||
$data['$invoice.taxes'] = &$data['$taxes'];
|
||||
|
||||
$data['$user_iban'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'company1', $this->settings->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'company1')];
|
||||
$data['$invoice.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice1', $this->entity->custom_value1, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice1')];
|
||||
$data['$invoice.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice2', $this->entity->custom_value2, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice2')];
|
||||
$data['$invoice.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice3', $this->entity->custom_value3, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice3')];
|
||||
$data['$invoice.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'invoice4', $this->entity->custom_value4, $this->client) ?: ' ', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'invoice4')];
|
||||
$data['$invoice.public_notes'] = ['value' => nl2br($this->entity->public_notes) ?: '', 'label' => ctrans('texts.public_notes')];
|
||||
$data['$invoice.public_notes'] = ['value' => $this->entity->public_notes ?: '', 'label' => ctrans('texts.public_notes')];
|
||||
$data['$entity.public_notes'] = &$data['$invoice.public_notes'];
|
||||
$data['$public_notes'] = &$data['$invoice.public_notes'];
|
||||
|
||||
@ -259,7 +260,7 @@ class HtmlEngine
|
||||
$data['$contact.email'] = ['value' => $this->contact->email, 'label' => ctrans('texts.email')];
|
||||
$data['$contact.phone'] = ['value' => $this->contact->phone, 'label' => ctrans('texts.phone')];
|
||||
|
||||
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : 'no contact name on record', 'label' => ctrans('texts.contact_name')];
|
||||
$data['$contact.name'] = ['value' => isset($this->contact) ? $this->contact->present()->name() : $this->client->present()->name(), 'label' => ctrans('texts.contact_name')];
|
||||
$data['$contact.first_name'] = ['value' => isset($this->contact) ? $this->contact->first_name : '', 'label' => ctrans('texts.first_name')];
|
||||
$data['$contact.last_name'] = ['value' => isset($this->contact) ? $this->contact->last_name : '', 'label' => ctrans('texts.last_name')];
|
||||
|
||||
@ -287,7 +288,7 @@ class HtmlEngine
|
||||
|
||||
$data['$signature'] = ['value' => $this->settings->email_signature ?: ' ', 'label' => ''];
|
||||
|
||||
$data['$spc_qr_code'] = ['value' => $this->company->present()->getSpcQrCode($this->client->currency()->code, $this->entity->number, $this->entity->balance), 'label' => ''];
|
||||
$data['$spc_qr_code'] = ['value' => $this->company->present()->getSpcQrCode($this->client->currency()->code, $this->entity->number, $this->entity->balance, $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'company1', $this->settings->custom_value1, $this->client)), 'label' => ''];
|
||||
|
||||
$logo = $this->company->present()->logo($this->settings);
|
||||
|
||||
|
@ -28,7 +28,7 @@ trait CleanLineItems
|
||||
$cleaned_items = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
$cleaned_items[] = $this->cleanLineItem($item);
|
||||
$cleaned_items[] = $this->cleanLineItem((array)$item);
|
||||
}
|
||||
|
||||
return $cleaned_items;
|
||||
|
@ -34,10 +34,12 @@ trait UserNotifies
|
||||
array_push($required_permissions, 'all_user_notifications');
|
||||
}
|
||||
|
||||
if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect($required_permissions, ['all_user_notifications'])) >= 1 || count(array_intersect($required_permissions, ['all_notifications'])) >= 1) {
|
||||
if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect(['all_user_notifications'], $notifications->email)) >= 1 || count(array_intersect(['all_notifications'],$notifications->email)) >= 1) {
|
||||
array_push($notifiable_methods, 'mail');
|
||||
}
|
||||
|
||||
nlog($notifiable_methods);
|
||||
|
||||
// if(count(array_intersect($required_permissions, $notifications->slack)) >=1)
|
||||
// array_push($notifiable_methods, 'slack');
|
||||
|
||||
|
@ -106,7 +106,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
"vendor/bin/snappdf download"
|
||||
"if [ \"${IS_DOCKER:-false}\" != \"true\" ]; then vendor/bin/snappdf download; fi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"vendor/bin/snappdf download"
|
||||
|
196
composer.lock
generated
196
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "113acad46f6d9eea9f9f5bd4501428d1",
|
||||
"content-hash": "2307a2f3214da0d1cc772cc1a1405682",
|
||||
"packages": [
|
||||
{
|
||||
"name": "authorizenet/authorizenet",
|
||||
@ -55,16 +55,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.173.28",
|
||||
"version": "3.175.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "593baa5930896bb443c437032daf4016e1e3878d"
|
||||
"reference": "fce65d31f033c39cd3615fd2d3e503e212d81a3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/593baa5930896bb443c437032daf4016e1e3878d",
|
||||
"reference": "593baa5930896bb443c437032daf4016e1e3878d",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/fce65d31f033c39cd3615fd2d3e503e212d81a3e",
|
||||
"reference": "fce65d31f033c39cd3615fd2d3e503e212d81a3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -139,9 +139,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.173.28"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.175.1"
|
||||
},
|
||||
"time": "2021-03-12T19:29:55+00:00"
|
||||
"time": "2021-03-22T18:13:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -198,16 +198,16 @@
|
||||
},
|
||||
{
|
||||
"name": "beganovich/snappdf",
|
||||
"version": "v1.5.0",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/beganovich/snappdf.git",
|
||||
"reference": "63ad3f1a0eec7bffc3a3c85f286769fca9a33fd5"
|
||||
"reference": "5c0a7e2e2c33441c0dd9d1fcbfc8de71c3cc920c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/beganovich/snappdf/zipball/63ad3f1a0eec7bffc3a3c85f286769fca9a33fd5",
|
||||
"reference": "63ad3f1a0eec7bffc3a3c85f286769fca9a33fd5",
|
||||
"url": "https://api.github.com/repos/beganovich/snappdf/zipball/5c0a7e2e2c33441c0dd9d1fcbfc8de71c3cc920c",
|
||||
"reference": "5c0a7e2e2c33441c0dd9d1fcbfc8de71c3cc920c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -245,9 +245,9 @@
|
||||
"description": "Convert webpages or HTML into the PDF file using Chromium or Google Chrome.",
|
||||
"support": {
|
||||
"issues": "https://github.com/beganovich/snappdf/issues",
|
||||
"source": "https://github.com/beganovich/snappdf/tree/v1.5.0"
|
||||
"source": "https://github.com/beganovich/snappdf/tree/v1.6.0"
|
||||
},
|
||||
"time": "2021-01-10T17:06:47+00:00"
|
||||
"time": "2021-03-19T21:20:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
@ -2010,16 +2010,16 @@
|
||||
},
|
||||
{
|
||||
"name": "google/apiclient-services",
|
||||
"version": "v0.163.0",
|
||||
"version": "v0.165.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/googleapis/google-api-php-client-services.git",
|
||||
"reference": "8e326f378a1f505064912fddd19fd93bbdcc80fb"
|
||||
"reference": "c8d7ff2c9cb6cad6e88bc5825491c47b8b2e52fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/8e326f378a1f505064912fddd19fd93bbdcc80fb",
|
||||
"reference": "8e326f378a1f505064912fddd19fd93bbdcc80fb",
|
||||
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/c8d7ff2c9cb6cad6e88bc5825491c47b8b2e52fd",
|
||||
"reference": "c8d7ff2c9cb6cad6e88bc5825491c47b8b2e52fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2045,9 +2045,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/googleapis/google-api-php-client-services/issues",
|
||||
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.163.0"
|
||||
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.165.0"
|
||||
},
|
||||
"time": "2021-03-06T12:20:02+00:00"
|
||||
"time": "2021-03-21T11:20:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "google/auth",
|
||||
@ -2331,16 +2331,16 @@
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "1.7.0",
|
||||
"version": "1.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3"
|
||||
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/53330f47520498c0ae1f61f7e2c90f55690c06a3",
|
||||
"reference": "53330f47520498c0ae1f61f7e2c90f55690c06a3",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1",
|
||||
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2400,9 +2400,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/1.7.0"
|
||||
"source": "https://github.com/guzzle/psr7/tree/1.8.1"
|
||||
},
|
||||
"time": "2020-09-30T07:37:11+00:00"
|
||||
"time": "2021-03-21T16:25:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hashids/hashids",
|
||||
@ -2783,16 +2783,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.32.1",
|
||||
"version": "v8.33.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "7c37b64f8153c16b6406f5c28cf37828ebbe8846"
|
||||
"reference": "354c57b8cb457549114074c500944455a288d6cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/7c37b64f8153c16b6406f5c28cf37828ebbe8846",
|
||||
"reference": "7c37b64f8153c16b6406f5c28cf37828ebbe8846",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/354c57b8cb457549114074c500944455a288d6cc",
|
||||
"reference": "354c57b8cb457549114074c500944455a288d6cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2947,7 +2947,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2021-03-09T15:37:45+00:00"
|
||||
"time": "2021-03-16T19:42:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/slack-notification-channel",
|
||||
@ -3845,16 +3845,16 @@
|
||||
},
|
||||
{
|
||||
"name": "livewire/livewire",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/livewire/livewire.git",
|
||||
"reference": "8055af7730938cd607616fde122825ed960a9b71"
|
||||
"reference": "b0cb782674673a67ddfd5910d2fcb5308bb32857"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/livewire/livewire/zipball/8055af7730938cd607616fde122825ed960a9b71",
|
||||
"reference": "8055af7730938cd607616fde122825ed960a9b71",
|
||||
"url": "https://api.github.com/repos/livewire/livewire/zipball/b0cb782674673a67ddfd5910d2fcb5308bb32857",
|
||||
"reference": "b0cb782674673a67ddfd5910d2fcb5308bb32857",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3905,7 +3905,7 @@
|
||||
"description": "A front-end framework for Laravel.",
|
||||
"support": {
|
||||
"issues": "https://github.com/livewire/livewire/issues",
|
||||
"source": "https://github.com/livewire/livewire/tree/v2.4.0"
|
||||
"source": "https://github.com/livewire/livewire/tree/v2.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3913,7 +3913,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-02-23T17:44:50+00:00"
|
||||
"time": "2021-03-22T14:03:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maennchen/zipstream-php",
|
||||
@ -6919,16 +6919,16 @@
|
||||
},
|
||||
{
|
||||
"name": "stripe/stripe-php",
|
||||
"version": "v7.75.0",
|
||||
"version": "v7.76.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/stripe/stripe-php.git",
|
||||
"reference": "d377a667cd789b99ccab768441a5a2160cc4ea80"
|
||||
"reference": "47e66d4186712be33c593fe820dccf270a04d5d6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/d377a667cd789b99ccab768441a5a2160cc4ea80",
|
||||
"reference": "d377a667cd789b99ccab768441a5a2160cc4ea80",
|
||||
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/47e66d4186712be33c593fe820dccf270a04d5d6",
|
||||
"reference": "47e66d4186712be33c593fe820dccf270a04d5d6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -6974,9 +6974,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/stripe/stripe-php/issues",
|
||||
"source": "https://github.com/stripe/stripe-php/tree/v7.75.0"
|
||||
"source": "https://github.com/stripe/stripe-php/tree/v7.76.0"
|
||||
},
|
||||
"time": "2021-02-22T14:31:21+00:00"
|
||||
"time": "2021-03-22T16:50:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
@ -9664,16 +9664,16 @@
|
||||
},
|
||||
{
|
||||
"name": "turbo124/beacon",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/turbo124/beacon.git",
|
||||
"reference": "2f38612c1bb4c292d154c8fba478bdf8c019fcd9"
|
||||
"reference": "d48227fdfafc463cce055f36b149f9cb1d9b8f81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/turbo124/beacon/zipball/2f38612c1bb4c292d154c8fba478bdf8c019fcd9",
|
||||
"reference": "2f38612c1bb4c292d154c8fba478bdf8c019fcd9",
|
||||
"url": "https://api.github.com/repos/turbo124/beacon/zipball/d48227fdfafc463cce055f36b149f9cb1d9b8f81",
|
||||
"reference": "d48227fdfafc463cce055f36b149f9cb1d9b8f81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -9721,9 +9721,9 @@
|
||||
"turbo124"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/turbo124/beacon/tree/1.0.6"
|
||||
"source": "https://github.com/turbo124/beacon/tree/1.0.7"
|
||||
},
|
||||
"time": "2021-03-09T09:25:50+00:00"
|
||||
"time": "2021-03-23T09:54:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
@ -9881,30 +9881,35 @@
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.9.1",
|
||||
"version": "1.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozarts/assert.git",
|
||||
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
|
||||
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
|
||||
"reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
|
||||
"url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25",
|
||||
"reference": "6964c76c7804814a842473e0c8fd15bab0f18e25",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.3 || ^7.0 || ^8.0",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<0.12.20",
|
||||
"vimeo/psalm": "<3.9.1"
|
||||
"vimeo/psalm": "<4.6.1 || 4.6.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.36 || ^7.5.13"
|
||||
"phpunit/phpunit": "^8.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webmozart\\Assert\\": "src/"
|
||||
@ -9928,9 +9933,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/webmozarts/assert/issues",
|
||||
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
|
||||
"source": "https://github.com/webmozarts/assert/tree/1.10.0"
|
||||
},
|
||||
"time": "2020-07-08T17:02:28+00:00"
|
||||
"time": "2021-03-09T10:59:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webpatser/laravel-countries",
|
||||
@ -11079,16 +11084,16 @@
|
||||
},
|
||||
{
|
||||
"name": "filp/whoops",
|
||||
"version": "2.9.2",
|
||||
"version": "2.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/filp/whoops.git",
|
||||
"reference": "df7933820090489623ce0be5e85c7e693638e536"
|
||||
"reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/df7933820090489623ce0be5e85c7e693638e536",
|
||||
"reference": "df7933820090489623ce0be5e85c7e693638e536",
|
||||
"url": "https://api.github.com/repos/filp/whoops/zipball/f6e14679f948d8a5cfb866fa7065a30c66bd64d3",
|
||||
"reference": "f6e14679f948d8a5cfb866fa7065a30c66bd64d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -11138,7 +11143,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/filp/whoops/issues",
|
||||
"source": "https://github.com/filp/whoops/tree/2.9.2"
|
||||
"source": "https://github.com/filp/whoops/tree/2.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -11146,20 +11151,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-24T12:00:00+00:00"
|
||||
"time": "2021-03-19T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v2.18.3",
|
||||
"version": "v2.18.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
|
||||
"reference": "ab99202fccff2a9f97592fbe1b5c76dd06df3513"
|
||||
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ab99202fccff2a9f97592fbe1b5c76dd06df3513",
|
||||
"reference": "ab99202fccff2a9f97592fbe1b5c76dd06df3513",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/06f764e3cb6d60822d8f5135205f9d32b5508a31",
|
||||
"reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -11242,7 +11247,7 @@
|
||||
"description": "A tool to automatically fix PHP code style",
|
||||
"support": {
|
||||
"issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.3"
|
||||
"source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -11250,7 +11255,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-10T19:39:05+00:00"
|
||||
"time": "2021-03-20T14:52:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
@ -12016,16 +12021,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.12.2",
|
||||
"version": "1.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "245710e971a030f42e08f4912863805570f23d39"
|
||||
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39",
|
||||
"reference": "245710e971a030f42e08f4912863805570f23d39",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea",
|
||||
"reference": "be1996ed8adc35c3fd795488a653f4b518be70ea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -12077,9 +12082,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpspec/prophecy/issues",
|
||||
"source": "https://github.com/phpspec/prophecy/tree/1.12.2"
|
||||
"source": "https://github.com/phpspec/prophecy/tree/1.13.0"
|
||||
},
|
||||
"time": "2020-12-19T10:15:11+00:00"
|
||||
"time": "2021-03-17T13:42:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -12401,16 +12406,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.2",
|
||||
"version": "9.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4"
|
||||
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f661659747f2f87f9e72095bb207bceb0f151cb4",
|
||||
"reference": "f661659747f2f87f9e72095bb207bceb0f151cb4",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
|
||||
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -12488,7 +12493,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.2"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -12500,7 +12505,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-02-02T14:45:58+00:00"
|
||||
"time": "2021-03-23T07:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -13468,16 +13473,16 @@
|
||||
},
|
||||
{
|
||||
"name": "swagger-api/swagger-ui",
|
||||
"version": "v3.45.0",
|
||||
"version": "v3.45.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/swagger-api/swagger-ui.git",
|
||||
"reference": "1ba7af074f97c872a64a415e0507c11cf8f3601b"
|
||||
"reference": "72506e581f860244f3c74de5a2fb9809e53d1876"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/1ba7af074f97c872a64a415e0507c11cf8f3601b",
|
||||
"reference": "1ba7af074f97c872a64a415e0507c11cf8f3601b",
|
||||
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/72506e581f860244f3c74de5a2fb9809e53d1876",
|
||||
"reference": "72506e581f860244f3c74de5a2fb9809e53d1876",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -13523,9 +13528,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/swagger-api/swagger-ui/issues",
|
||||
"source": "https://github.com/swagger-api/swagger-ui/tree/v3.45.0"
|
||||
"source": "https://github.com/swagger-api/swagger-ui/tree/v3.45.1"
|
||||
},
|
||||
"time": "2021-03-11T17:20:14+00:00"
|
||||
"time": "2021-03-19T17:14:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
@ -13853,20 +13858,20 @@
|
||||
},
|
||||
{
|
||||
"name": "vimeo/psalm",
|
||||
"version": "4.6.2",
|
||||
"version": "4.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vimeo/psalm.git",
|
||||
"reference": "bca09d74adc704c4eaee36a3c3e9d379e290fc3b"
|
||||
"reference": "97fe86c4e158b5a57c5150aa5055c38b5a809aab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/bca09d74adc704c4eaee36a3c3e9d379e290fc3b",
|
||||
"reference": "bca09d74adc704c4eaee36a3c3e9d379e290fc3b",
|
||||
"url": "https://api.github.com/repos/vimeo/psalm/zipball/97fe86c4e158b5a57c5150aa5055c38b5a809aab",
|
||||
"reference": "97fe86c4e158b5a57c5150aa5055c38b5a809aab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"amphp/amp": "^2.1",
|
||||
"amphp/amp": "^2.4.2",
|
||||
"amphp/byte-stream": "^1.5",
|
||||
"composer/package-versions-deprecated": "^1.8.0",
|
||||
"composer/semver": "^1.4 || ^2.0 || ^3.0",
|
||||
@ -13892,7 +13897,6 @@
|
||||
"psalm/psalm": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/amp": "^2.4.2",
|
||||
"bamarni/composer-bin-plugin": "^1.2",
|
||||
"brianium/paratest": "^4.0||^6.0",
|
||||
"ext-curl": "*",
|
||||
@ -13952,9 +13956,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/vimeo/psalm/issues",
|
||||
"source": "https://github.com/vimeo/psalm/tree/4.6.2"
|
||||
"source": "https://github.com/vimeo/psalm/tree/4.6.4"
|
||||
},
|
||||
"time": "2021-02-26T02:24:18+00:00"
|
||||
"time": "2021-03-16T23:28:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/path-util",
|
||||
@ -14092,7 +14096,7 @@
|
||||
"ext-libxml": "*"
|
||||
},
|
||||
"platform-dev": {
|
||||
"php": "^7.4"
|
||||
"php": "^7.3|^7.4"
|
||||
},
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ return [
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
'mix_url' => env('APP_URL', 'http://localhost'),
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|
@ -13,7 +13,7 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', ''),
|
||||
'app_version' => '5.1.29',
|
||||
'app_version' => '5.1.32',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', false),
|
||||
|
@ -1,38 +0,0 @@
|
||||
<?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 Database\Factories;
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class BillingSubscriptionFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = BillingSubscription::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
@ -37,10 +37,6 @@ class AddUniqueConstraintsOnAllEntities extends Migration
|
||||
$table->unique(['company_id', 'number']);
|
||||
});
|
||||
|
||||
Schema::table('payment_hashes', function (Blueprint $table) {
|
||||
$table->unique(['hash']);
|
||||
});
|
||||
|
||||
Schema::table('recurring_invoices', function (Blueprint $table) {
|
||||
$table->string('number')->change();
|
||||
$table->unique(['company_id', 'number']);
|
||||
|
@ -3968,7 +3968,7 @@ $LANG = array(
|
||||
'list_of_recurring_invoices' => 'List of recurring invoices',
|
||||
'details_of_recurring_invoice' => 'Here are some details about recurring invoice',
|
||||
'cancellation' => 'Cancellation',
|
||||
'about_cancellation' => 'In case you want to stop the recurring invoice,\n please click the request the cancellation.',
|
||||
'about_cancellation' => 'In case you want to stop the recurring invoice, please click the request the cancellation.',
|
||||
'cancellation_warning' => 'Warning! You are requesting a cancellation of this service.\n Your service may be cancelled with no further notification to you.',
|
||||
'cancellation_pending' => 'Cancellation pending, we\'ll be in touch!',
|
||||
'list_of_payments' => 'List of payments',
|
||||
@ -4177,6 +4177,7 @@ $LANG = array(
|
||||
'migration_auth_label' => 'Let\'s continue by authenticating.',
|
||||
'api_secret' => 'API secret',
|
||||
'migration_api_secret_notice' => 'You can find API_SECRET in the .env file or Invoice Ninja v5. If property is missing, leave field blank.',
|
||||
'billing_coupon_notice' => 'Your discount will be applied on the checkout.',
|
||||
'use_last_email' => 'Use last email',
|
||||
'activate_company' => 'Activate Company',
|
||||
'activate_company_help' => 'Enable emails, recurring invoices and notifications',
|
||||
@ -4200,6 +4201,7 @@ $LANG = array(
|
||||
'invoice_task_datelog' => 'Invoice Task Datelog',
|
||||
'invoice_task_datelog_help' => 'Add date details to the invoice line items',
|
||||
'promo_code' => 'Promo code',
|
||||
'recurring_invoice_issued_to' => 'Recurring invoice issued to',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -1,8 +1,8 @@
|
||||
@extends('portal.ninja2020.layout.clean')
|
||||
@section('meta_title', $billing_subscription->product->product_key)
|
||||
@section('meta_title', ctrans('texts.purchase'))
|
||||
|
||||
@section('body')
|
||||
@livewire('billing-portal-purchase', ['billing_subscription' => $billing_subscription, 'contact' => auth('contact')->user(), 'hash' => $hash])
|
||||
@livewire('billing-portal-purchase', ['subscription' => $subscription, 'contact' => auth('contact')->user(), 'hash' => $hash, 'request_data' => $request_data])
|
||||
@stop
|
||||
|
||||
@push('footer')
|
||||
|
@ -1 +1 @@
|
||||
{{ $body }}
|
||||
{!! $body !!}
|
@ -1,18 +1,80 @@
|
||||
<div class="grid grid-cols-12">
|
||||
<div class="col-span-12 lg:col-span-6 bg-gray-50 shadow-lg lg:h-screen flex flex-col items-center">
|
||||
<div class="w-full p-10 lg:w-1/2 lg:mt-48 lg:p-0">
|
||||
<img class="h-8" src="{{ $billing_subscription->company->present()->logo }}"
|
||||
alt="{{ $billing_subscription->company->present()->name }}">
|
||||
<div class="col-span-12 lg:col-span-6 bg-gray-50 flex flex-col items-center">
|
||||
<div class="w-full p-10 lg:w-1/2 lg:mt-24 lg:p-0">
|
||||
<img class="h-8" src="{{ $subscription->company->present()->logo }}"
|
||||
alt="{{ $subscription->company->present()->name }}">
|
||||
|
||||
<h1 id="billing-page-company-logo" class="text-3xl font-bold tracking-wide mt-8">
|
||||
{{ $billing_subscription->product->product_key }}
|
||||
</h1>
|
||||
<div class="mt-6">
|
||||
@if(!empty($subscription->product_ids))
|
||||
<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">
|
||||
One-time purchase
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<p class="my-6">{{ $billing_subscription->product->notes }}</p>
|
||||
@if(!empty($subscription->recurring_product_ids))
|
||||
<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">
|
||||
Subscription
|
||||
</p>
|
||||
@endif
|
||||
|
||||
<span class="text-sm uppercase font-bold">{{ ctrans('texts.total') }}:</span>
|
||||
<h1 id="billing-page-company-logo" class="text-3xl font-bold tracking-wide">
|
||||
{{ $subscription->name }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<h1 class="text-2xl font-bold tracking-wide">{{ App\Utils\Number::formatMoney($billing_subscription->product->price, $billing_subscription->company) }}</h1>
|
||||
@if(!empty($subscription->product_ids))
|
||||
<div class="flex flex-col mt-8">
|
||||
<p
|
||||
class="mb-4 uppercase leading-4 tracking-wide inline-flex items-center rounded-full text-xs font-medium">
|
||||
One-time purchases:
|
||||
</p>
|
||||
|
||||
@foreach($subscription->service()->products() as $product)
|
||||
<div class="flex items-center justify-between mb-4 bg-white rounded px-6 py-4 shadow-sm border">
|
||||
<div class="text-sm">{{ $product->product_key }}</div>
|
||||
<div data-ref="price-and-quantity-container">
|
||||
<span
|
||||
data-ref="price">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}</span>
|
||||
{{-- <span data-ref="quantity" class="text-sm">(1x)</span>--}}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(!empty($subscription->recurring_product_ids))
|
||||
<div class="flex flex-col mt-8">
|
||||
<p
|
||||
class="mb-4 uppercase leading-4 tracking-wide inline-flex items-center rounded-full text-xs font-medium">
|
||||
Recurring purchases:
|
||||
</p>
|
||||
|
||||
@foreach($subscription->service()->recurring_products() as $product)
|
||||
<div class="flex items-center justify-between mb-4 bg-white rounded px-6 py-4 shadow-sm border">
|
||||
<div class="text-sm">{{ $product->product_key }}</div>
|
||||
<div data-ref="price-and-quantity-container">
|
||||
<span
|
||||
data-ref="price">{{ \App\Utils\Number::formatMoney($product->price, $subscription->company) }}</span>
|
||||
{{-- <span data-ref="quantity" class="text-sm">(1x)</span>--}}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="relative mt-8">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300"></div>
|
||||
</div>
|
||||
|
||||
<div class="relative flex justify-center text-sm leading-5">
|
||||
<h1 class="text-2xl font-bold tracking-wide bg-gray-50 px-6 py-0">
|
||||
{{ ctrans('texts.total') }}: {{ $price }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(auth('contact')->user())
|
||||
<a href="{{ route('client.invoices.index') }}" class="block mt-16 inline-flex items-center space-x-2">
|
||||
@ -29,17 +91,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 lg:col-span-6 bg-white lg:shadow-lg lg:h-screen">
|
||||
<div class="col-span-12 lg:col-span-6 bg-white lg:h-screen">
|
||||
<div class="grid grid-cols-12 flex flex-col p-10 lg:mt-48 lg:ml-16">
|
||||
<div class="col-span-12 w-full lg:col-span-6">
|
||||
<h2 class="text-2xl font-bold tracking-wide">{{ $heading_text }}</h2>
|
||||
<h2 class="text-2xl font-bold tracking-wide">{{ $heading_text ?? ctrans('texts.login') }}</h2>
|
||||
@if (session()->has('message'))
|
||||
@component('portal.ninja2020.components.message')
|
||||
{{ session('message') }}
|
||||
@endcomponent
|
||||
@endif
|
||||
|
||||
@if($this->steps['fetched_payment_methods'])
|
||||
@if($steps['fetched_payment_methods'])
|
||||
<div class="flex items-center mt-4 text-sm">
|
||||
<form action="{{ route('client.payments.process', ['hash' => $hash, 'sidebar' => 'hidden']) }}"
|
||||
method="post"
|
||||
@ -67,6 +129,17 @@
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@elseif($steps['show_start_trial'])
|
||||
<form wire:submit.prevent="handleTrial" class="mt-8">
|
||||
@csrf
|
||||
<p class="mb-4">Some text about the trial goes here. Details about the days, etc.</p>
|
||||
|
||||
|
||||
<button class="px-3 py-2 border rounded mr-4 hover:border-blue-600">
|
||||
{{ ctrans('texts.trial_call_to_action') }}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@else
|
||||
<form wire:submit.prevent="authenticate" class="mt-8">
|
||||
@csrf
|
||||
@ -100,27 +173,27 @@
|
||||
</form>
|
||||
@endif
|
||||
|
||||
<div class="relative mt-8">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300"></div>
|
||||
@if(!empty($subscription->promo_code) && !$subscription->trial_enabled)
|
||||
<div class="relative mt-8">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300"></div>
|
||||
</div>
|
||||
|
||||
<div class="relative flex justify-center text-sm leading-5">
|
||||
<span class="px-2 text-gray-700 bg-white">Have a coupon code?</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative flex justify-center text-sm leading-5">
|
||||
<span class="px-2 text-gray-700 bg-white">Have a coupon code?</span>
|
||||
</div>
|
||||
</div>
|
||||
<form wire:submit.prevent="handleCoupon" class="flex items-center mt-4">
|
||||
@csrf
|
||||
|
||||
<form wire:submit.prevent="applyCouponCode" class="mt-4">
|
||||
@csrf
|
||||
|
||||
<div class="flex items-center">
|
||||
<label class="w-full mr-2">
|
||||
<input type="text" wire:model.defer="coupon" class="input w-full m-0" />
|
||||
<input type="text" wire:model.lazy="coupon" class="input w-full m-0"/>
|
||||
</label>
|
||||
|
||||
<button class="button bg-primary m-0 text-white">{{ ctrans('texts.apply') }}</button>
|
||||
</div>
|
||||
</form>
|
||||
<button class="button button-primary bg-primary">Apply</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
@unless(isset($show_card_element) && $show_card_element == false)
|
||||
@component('portal.ninja2020.components.general.card-element-single')
|
||||
<div id="card-element"></div>
|
||||
<div id="card-element" class="border p-4 rounded"></div>
|
||||
@endcomponent
|
||||
@endunless
|
||||
</div>
|
||||
|
@ -62,7 +62,7 @@
|
||||
<div>
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.invoice_number_placeholder', ['invoice' => $invoice->number])}}
|
||||
- {{ ctrans('texts.paid') }}
|
||||
- {{ \App\Models\Invoice::stringStatus($invoice->status_id) }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.pending_approval') }}
|
||||
{{ ctrans('texts.approve') }}
|
||||
</h3>
|
||||
|
||||
<div class="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center">
|
||||
|
@ -57,7 +57,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white shadow sm:rounded-lg mb-4 mt-4" translate>
|
||||
|
||||
<div class="bg-white shadow sm:rounded-lg mb-4 mt-4">
|
||||
<div class="px-4 py-5 sm:p-6">
|
||||
<div class="sm:flex sm:items-start sm:justify-between">
|
||||
<div>
|
||||
@ -72,7 +73,8 @@
|
||||
</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">Request Cancellation</button>
|
||||
<button class="button button-danger" translate @click="open = true">Request Cancellation
|
||||
</button>
|
||||
@include('portal.ninja2020.recurring_invoices.includes.modals.cancellation')
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24,6 +24,7 @@ Route::group(['middleware' => ['api_secret_check', 'email_db']], function () {
|
||||
});
|
||||
|
||||
Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
|
||||
Route::post('check_subdomain', 'SubdomainController@index')->name('check_subdomain');
|
||||
Route::get('ping', 'PingController@index')->name('ping');
|
||||
Route::get('health_check', 'PingController@health')->name('health_check');
|
||||
|
||||
@ -37,6 +38,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk');
|
||||
|
||||
Route::post('connected_account', 'ConnectedAccountController@index');
|
||||
Route::post('connected_account/gmail', 'ConnectedAccountController@handleGmailOauth');
|
||||
|
||||
Route::resource('client_statement', 'ClientStatementController@statement'); // name = (client_statement. index / create / show / update / destroy / edit
|
||||
|
||||
@ -174,7 +176,7 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
// Route::post('hooks', 'SubscriptionController@subscribe')->name('hooks.subscribe');
|
||||
// Route::delete('hooks/{subscription_id}', 'SubscriptionController@unsubscribe')->name('hooks.unsubscribe');
|
||||
|
||||
Route::resource('billing_subscriptions', 'BillingSubscriptionController');
|
||||
Route::resource('subscriptions', 'SubscriptionController');
|
||||
Route::resource('cliente_subscriptions', 'ClientSubscriptionController');
|
||||
});
|
||||
|
||||
|
@ -71,12 +71,14 @@ Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence
|
||||
Route::get('documents/{document}/download', 'ClientPortal\DocumentController@download')->name('documents.download');
|
||||
Route::resource('documents', 'ClientPortal\DocumentController')->only(['index', 'show']);
|
||||
|
||||
Route::resource('subscriptions', 'ClientPortal\SubscriptionController')->only(['index']);
|
||||
|
||||
Route::post('upload', 'ClientPortal\UploadController')->name('upload.store');
|
||||
|
||||
Route::get('logout', 'Auth\ContactLoginController@logout')->name('logout');
|
||||
});
|
||||
|
||||
Route::get('client/subscription/{billing_subscription}/purchase', 'ClientPortal\BillingSubscriptionPurchaseController@index')->name('client.subscription.purchase');
|
||||
Route::get('client/subscription/{subscription}/purchase', 'ClientPortal\SubscriptionPurchaseController@index')->name('client.subscription.purchase');
|
||||
|
||||
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
|
||||
/*Invitation catches*/
|
||||
|
3
tailwind.config.js
vendored
3
tailwind.config.js
vendored
@ -1,6 +1,9 @@
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
|
||||
module.exports = {
|
||||
future: {
|
||||
purgeLayersByDefault: true
|
||||
},
|
||||
purge: [
|
||||
'./resources/views/portal/ninja2020/**/*.blade.php',
|
||||
'./resources/views/email/template/**/*.blade.php',
|
||||
|
@ -1,134 +0,0 @@
|
||||
<?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\Feature;
|
||||
|
||||
use App\Models\BillingSubscription;
|
||||
use App\Models\Product;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Tests\MockAccountData;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @covers App\Http\Controllers\BillingSubscriptionController
|
||||
*/
|
||||
class BillingSubscriptionApiTest extends TestCase
|
||||
{
|
||||
use MakesHash;
|
||||
use DatabaseTransactions;
|
||||
use MockAccountData;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->makeTestData();
|
||||
|
||||
Session::start();
|
||||
|
||||
$this->faker = \Faker\Factory::create();
|
||||
|
||||
Model::reguard();
|
||||
}
|
||||
|
||||
public function testBillingSubscriptionsGet()
|
||||
{
|
||||
$product = Product::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
$billing_subscription = BillingSubscription::factory()->create([
|
||||
'product_id' => $product->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->get('/api/v1/billing_subscriptions/' . $this->encodePrimaryKey($billing_subscription->id));
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testBillingSubscriptionsPost()
|
||||
{
|
||||
$product = Product::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/billing_subscriptions', ['product_id' => $product->id, 'allow_cancellation' => true]);
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testBillingSubscriptionPut()
|
||||
{
|
||||
$product = Product::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
$response1 = $this
|
||||
->withHeaders(['X-API-SECRET' => config('ninja.api_secret'),'X-API-TOKEN' => $this->token])
|
||||
->post('/api/v1/billing_subscriptions', ['product_id' => $product->id])
|
||||
->assertStatus(200)
|
||||
->json();
|
||||
|
||||
$response2 = $this
|
||||
->withHeaders(['X-API-SECRET' => config('ninja.api_secret'),'X-API-TOKEN' => $this->token])
|
||||
->put('/api/v1/billing_subscriptions/' . $response1['data']['id'], ['allow_cancellation' => true])
|
||||
->assertStatus(200)
|
||||
->json();
|
||||
|
||||
$this->assertNotEquals($response1['data']['allow_cancellation'], $response2['data']['allow_cancellation']);
|
||||
}
|
||||
|
||||
/*
|
||||
TypeError : Argument 1 passed to App\Transformers\BillingSubscriptionTransformer::transform() must be an instance of App\Models\BillingSubscription, bool given, called in /var/www/html/vendor/league/fractal/src/Scope.php on line 407
|
||||
/var/www/html/app/Transformers/BillingSubscriptionTransformer.php:35
|
||||
/var/www/html/vendor/league/fractal/src/Scope.php:407
|
||||
/var/www/html/vendor/league/fractal/src/Scope.php:349
|
||||
/var/www/html/vendor/league/fractal/src/Scope.php:235
|
||||
/var/www/html/app/Http/Controllers/BaseController.php:395
|
||||
/var/www/html/app/Http/Controllers/BillingSubscriptionController.php:408
|
||||
*/
|
||||
public function testBillingSubscriptionDeleted()
|
||||
{
|
||||
|
||||
$product = Product::factory()->create([
|
||||
'company_id' => $this->company->id,
|
||||
'user_id' => $this->user->id,
|
||||
]);
|
||||
|
||||
$billing_subscription = BillingSubscription::factory()->create([
|
||||
'product_id' => $product->id,
|
||||
'company_id' => $this->company->id,
|
||||
]);
|
||||
|
||||
$response = $this
|
||||
->withHeaders(['X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token])
|
||||
->delete('/api/v1/billing_subscriptions/' . $this->encodePrimaryKey($billing_subscription->id))
|
||||
->assertStatus(200)
|
||||
->json();
|
||||
|
||||
}
|
||||
}
|
@ -310,6 +310,28 @@ class AuthorizeTest extends TestCase
|
||||
$controller = new CreateTransactionController($request);
|
||||
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
|
||||
|
||||
// nlog($response);
|
||||
nlog($response->getTransactionResponse()->getMessages() !== null);
|
||||
nlog($response->getTransactionResponse()->getMessages());
|
||||
nlog($response->getTransactionResponse()->getMessages()[0]);
|
||||
//nlog($response->getTransactionResponse()->getMessages()[0]->getCode());
|
||||
|
||||
$code = '';
|
||||
$description = '';
|
||||
|
||||
if($response->getTransactionResponse()->getMessages() !== null){
|
||||
$code = $response->getTransactionResponse()->getMessages()[0]->getCode();
|
||||
$description = $response->getTransactionResponse()->getMessages()[0]->getDescription();
|
||||
}
|
||||
|
||||
$log = [
|
||||
'transaction_reference' => $response->getTransactionResponse()->getTransId(),
|
||||
'auth_code' => $response->getTransactionResponse()->getAuthCode(),
|
||||
'code' => $code,
|
||||
'description' => $description,
|
||||
];
|
||||
|
||||
|
||||
if ($response != null) {
|
||||
if ($response->getMessages()->getResultCode() == 'Ok') {
|
||||
$tresponse = $response->getTransactionResponse();
|
||||
|
Loading…
x
Reference in New Issue
Block a user