/** * Create a discount for the given user. * * @param Request $request * @param string $userId * @return Response */ public function store(Request $request, $userId) { $user = Spark::user()->where('id', $userId)->firstOrFail(); $this->validate($request, ['type' => 'required|in:amount,percent', 'value' => 'required|integer', 'duration' => 'required|in:once,forever,repeating', 'months' => 'required_if:duration,repeating']); $coupon = StripeCoupon::create(['currency' => 'usd', 'amount_off' => $request->type == 'amount' ? $request->value * 100 : null, 'percent_off' => $request->type == 'percent' ? $request->value : null, 'duration' => $request->duration, 'duration_in_months' => $request->months, 'max_redemptions' => 1], config('services.stripe.secret')); $user->applyCoupon($coupon->id); }
/** * Get the current discount for the given user. * * @param Request $request * @param string $userId * @return Response */ public function current(Request $request, $userId) { $user = Spark::user()->where('id', $userId)->firstOrFail(); if ($coupon = $this->coupons->forBillable($user)) { return response()->json($coupon->toArray()); } }
/** * Bootstrap any application services. * * @return void */ public function boot() { if (method_exists($this, 'customizeSpark')) { $this->customizeSpark(); } if (method_exists($this, 'customizeRegistration')) { $this->customizeRegistration(); } if (method_exists($this, 'customizeRoles')) { $this->customizeRoles(); } if (method_exists($this, 'customizeProfileUpdates')) { $this->customizeProfileUpdates(); } if (method_exists($this, 'customizeSubscriptionPlans')) { $this->customizeSubscriptionPlans(); } if (method_exists($this, 'customizeSettingsTabs')) { $this->customizeSettingsTabs(); } if ($this->twoFactorAuth) { Spark::withTwoFactorAuth(); } Spark::generateInvoicesWith($this->invoiceWith); }
/** * {@inheritdoc} */ public function handle($user, $plan, $fromRegistration, array $data) { $subscription = $user->newSubscription('default', $plan->id); // Here we will check if we need to skip trial or set trial days on the subscription // when creating it on the provider. By default, we will skip the trial when this // interaction is not from egistration since they have already usually trialed. if (!$fromRegistration) { $subscription->skipTrial(); } elseif ($plan->trialDays > 0) { $subscription->trialDays($plan->trialDays); } if (isset($data['coupon'])) { $subscription->withCoupon($data['coupon']); } // Next, we need to check if this application is storing billing addresses and if so // we will update the billing address in the database so that any tax information // on the user will be up to date via the taxPercentage method on the billable. if (Spark::collectsBillingAddress()) { Spark::call(UserRepository::class . '@updateBillingAddress', [$user, $data]); } // If this application collects European VAT, we will store the VAT ID that was sent // with the request. It is used to determine if the VAT should get charged at all // when billing the customer. When it is present, VAT is not typically charged. if (Spark::collectsEuropeanVat()) { Spark::call(UserRepository::class . '@updateVatId', [$user, array_get($data, 'vat_id')]); } // Here we will create the actual subscription on the service and fire off the event // letting other listeners know a user has subscribed, which will allow any hooks // to fire that need to send the subscription data to any external metrics app. $subscription->create($data[$this->token]); event(new UserSubscribed($user = $user->fresh(), $plan, $fromRegistration)); return $user; }
/** * Handle the event. * * @param UserRegistered $event * @return void */ public function handle(UserRegistered $event) { if (!Spark::trialDays()) { return; } $this->notifications->create($event->user, ['icon' => 'fa-clock-o', 'body' => 'Your trial period will expire on ' . $event->user->trial_ends_at->format('F jS') . '.', 'action_text' => 'Subscribe', 'action_url' => '/settings#/subscription']); }
/** * Determine if the authenticated user is a developer. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return \Illuminate\Http\Response */ public function handle($request, $next) { if ($request->user() && Spark::developer($request->user()->email)) { return $next($request); } return $request->ajax() || $request->wantsJson() ? response('Unauthorized.', 401) : redirect()->guest('login'); }
/** * Get the validator for the request. * * @return \Illuminate\Validation\Validator */ public function validator() { $validator = Validator::make($this->all(), ['plan' => 'required|in:' . Spark::activePlanIdList()]); return $validator->after(function ($validator) { $this->validatePlanEligibility($validator); }); }
/** * Verify the incoming request's user belongs to team. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return \Illuminate\Http\Response */ public function handle($request, $next) { if (Spark::usesTeams() && $request->user() && !$request->user()->hasTeams()) { return redirect('missing-team'); } return $next($request); }
/** * {@inheritdoc} */ public function handle($team, $plan, array $data) { $subscription = $team->newSubscription('default', $plan->id); // Here we will fill the trial days for this team subscription. We will also set any // coupon on the subscription so that the team can receive a discount on the team // subscription. Then we will almost be ready to create the final subscription. $subscription->trialDays($plan->trialDays); if (isset($data['coupon'])) { $subscription->withCoupon($data['coupon']); } // Next, we need to check if this application is storing billing addresses and if so // we will update the billing address in the database so that any tax information // on the team will be up to date via the taxPercentage method on the billable. if (Spark::collectsBillingAddress()) { Spark::call(TeamRepository::class . '@updateBillingAddress', [$team, $data]); } // If this application collects European VAT, we will store the VAT ID that was sent // with the request. It is used to determine if the VAT should get charged at all // when billing the customer. When it is present, VAT is not typically charged. if (Spark::collectsEuropeanVat()) { Spark::call(TeamRepository::class . '@updateVatId', [$team, array_get($data, 'vat_id')]); } // Here we will create the actual subscription on the service and fire off the event // letting other listeners know a team has subscribed, which will allow any hooks // to fire that need to send the subscription data to any external metrics app. $subscription->create($data[$this->token]); event(new TeamSubscribed($team = $team->fresh(), $plan)); return $team; }
/** * Handle the event. * * @param TeamCreated $event * @return void */ public function handle(TeamCreated $event) { if (!Spark::teamTrialDays()) { return; } $this->notifications->create($event->team->owner, ['icon' => 'fa-clock-o', 'body' => "The " . $event->team->name . " team's trial period will expire on " . $event->team->trial_ends_at->format('F jS') . '.', 'action_text' => 'Subscribe', 'action_url' => '/settings/teams/' . $event->team->id . '#/subscription']); }
/** * Get the validator for the request. * * @return \Illuminate\Validation\Validator */ public function validator() { $validator = $this->registerValidator(['stripe_token']); if (Spark::collectsBillingAddress() && $this->hasPaidPlan()) { $this->validateBillingAddress($validator); } return $validator; }
/** * Configure the valdiator to validate the token abilities. * * @param \Illuminate\Validation\Validator $validator * @return \Illuminate\Validation\Validator */ protected function validateAbilities($validator) { $abilities = implode(',', array_keys(Spark::tokensCan())); $validator->sometimes('abilities', 'required|array|in:' . $abilities, function () { return count(Spark::tokensCan()) > 0; }); return $validator; }
/** * Send an invoice notification e-mail. * * @param mixed $billable * @param \Laravel\Cashier\Invoice * @return void */ protected function sendInvoiceNotification($billable, $invoice) { $invoiceData = Spark::invoiceDataFor($billable); $data = compact('billable', 'invoice', 'invoiceData'); Mail::send($this->emailView, $data, function ($message) use($billable, $invoice, $invoiceData) { $this->buildInvoiceMessage($message, $billable, $invoice, $invoiceData); }); }
/** * Execute the given interaction. * * This performs the common validate and handle flow of some interactions. * * @param Request $request * @param string $interaction * @param array $parameters * @return void */ public function interaction(Request $request, $interaction, array $parameters) { $validator = Spark::interact($interaction . '@validator', $parameters); if ($validator->fails()) { $this->throwValidationException($request, $validator); } return Spark::interact($interaction, $parameters); }
/** * Subscribe the given user to a subscription plan. * * @param RegisterRequest $request * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return \Illuminate\Contracts\Auth\Authenticatable */ protected function subscribe($request, $user) { if (!$request->hasPaidPlan()) { return $user; } Spark::interact(Subscribe::class, [$user, $request->plan(), true, $request->all()]); return $user; }
/** * Notify the given user about a new invoice. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Laravel\Cashier\Invoice $invoice * @return void */ public function notify(Authenticatable $user, Invoice $invoice) { $invoiceData = array_merge(['vendor' => 'Vendor', 'product' => 'Product', 'vat' => new ViewExpression(nl2br(e($user->extra_billing_info)))], Spark::generateInvoicesWith()); $data = compact('user', 'invoice', 'invoiceData'); Mail::send('spark::emails.billing.invoice', $data, function ($message) use($user, $invoice, $invoiceData) { $message->to($user->email, $user->name)->subject('Your ' . $invoiceData['product'] . ' Invoice')->attachData($invoice->pdf($invoiceData), 'invoice.pdf'); }); }
/** * Get the validator for the request. * * @return \Illuminate\Validation\Validator */ public function validator() { $validator = $this->baseValidator(['stripe_token' => 'required', 'vat_id' => 'max:50|vat_id']); if (Spark::collectsBillingAddress()) { $this->validateBillingAddress($validator); } return $validator; }
/** * Get all of the available roles that may be assigned to team members. * * @return \Illuminate\Http\Response */ public function getTeamRoles() { $roles = []; foreach (Spark::roles() as $key => $value) { $roles[] = ['value' => $key, 'text' => $value]; } return response()->json($roles); }
/** * Get the validator for the request. * * @return \Illuminate\Validation\Validator */ public function validator() { $validator = Validator::make($this->all(), ['stripe_token' => 'required']); if (Spark::collectsBillingAddress()) { $this->validateBillingAddress($validator); } return $validator; }
/** * Customize the tabs on the settings screen. * * @return void */ protected function customizeSettingsTabs() { Spark::settingsTabs()->configure(function ($tabs) { return [$tabs->profile(), $tabs->teams(), $tabs->security(), $tabs->subscription()]; }); Spark::teamSettingsTabs()->configure(function ($tabs) { return [$tabs->owner(), $tabs->membership()]; }); }
/** * {@inheritdoc} */ public function handle($team, $email) { $invitedUser = Spark::user()->where('email', $email)->first(); $this->emailInvitation($invitation = $this->createInvitation($team, $email, $invitedUser)); if ($invitedUser) { event(new UserInvitedToTeam($team, $invitedUser)); } return $invitation; }
/** * Get the tax percentage to apply to the subscription. * * @return int */ public function taxPercentage() { if (!Spark::collectsEuropeanVat()) { return 0; } $vatCalculator = new VatCalculator(); $vatCalculator->setBusinessCountryCode(Spark::homeCountry()); return $vatCalculator->getTaxRateForCountry($this->card_country, !empty($this->vat_id)) * 100; }
/** * Create a new team for the given user and data. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param array $data * @return \Laravel\Spark\Teams\Team */ public function create($user, array $data) { $class = Spark::model('teams', Team::class); $team = new $class(['name' => $data['name']]); $team->owner_id = $user->id; $team->save(); $team = $user->teams()->attach($team, ['role' => 'owner']); return $team; }
/** * Show the settings dashboard. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function show(Request $request) { $data = ['activeTab' => $request->get('tab', Spark::firstSettingsTabKey()), 'invoices' => [], 'user' => $this->users->getCurrentUser()]; if (Auth::user()->stripe_id) { $data['invoices'] = Cache::remember('spark:invoices:' . Auth::id(), 30, function () { return Auth::user()->invoices(); }); } return view('spark::settings.dashboard', $data); }
/** * Call the custom plan eligibility checker callback. * * @param \Illuminate\Validation\Validator $validator * @param \Laravel\Spark\Plan $plan * @return void */ protected function callCustomCallback($validator, $plan) { try { if (!Spark::eligibleForTeamPlan($this->route('team'), $plan)) { $validator->errors()->add('plan', 'This team is not eligible for this plan.'); } } catch (IneligibleForPlan $e) { $validator->errors()->add('plan', $e->getMessage()); } }
/** * {@inheritdoc} */ public function handle(array $data) { if (!Spark::hasSupportAddress()) { throw new RuntimeException("No customer support request recipient is defined."); } Mail::raw($data['message'], function ($m) use($data) { $m->to(Spark::supportAddress())->subject('Support Request: ' . $data['subject']); $m->replyTo($data['from']); }); }
/** * Get the team matching the given ID. * * @param Request $request * @param string $teamId * @return Response */ public function show(Request $request, $teamId) { $team = Spark::interact(TeamRepository::class . '@find', [$teamId]); abort_unless($request->user()->onTeam($team), 404); if ($request->user()->ownsTeam($team)) { $team->load('subscriptions'); $team->shouldHaveOwnerVisibility(); } return $team; }
/** * Attach a user to a given team based on their invitation. * * @param string $invitationId * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ public function attachUserToTeamByInvitation($invitationId, $user) { $userModel = get_class($user); $inviteModel = get_class((new $userModel())->invitations()->getQuery()->getModel()); $invitation = (new $inviteModel())->where('token', $invitationId)->first(); if ($invitation) { $invitation->team->users()->attach([$user->id], ['role' => Spark::defaultRole()]); $user->switchToTeam($invitation->team); $invitation->delete(); } }
/** * Redeem the given coupon code. * * @param Request $request * @return Response */ public function redeem(Request $request) { $this->validate($request, ['coupon' => 'required']); // We will verify that the coupon can actually be redeemed. In some cases even // valid coupons can not get redeemed by an existing user if this coupon is // running as a promotion for brand new registrations to the application. if (!$this->coupons->canBeRedeemed($request->coupon)) { return response()->json(['coupon' => ['This coupon code is invalid.']], 422); } Spark::interact(RedeemCoupon::class, [$request->user(), $request->coupon]); }
/** * Create the subscription on Stripe. * * @param \Illuminate\Http\Request $request * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ protected function createSubscriptionOnStripe(Request $request, $user) { $plan = Spark::plans()->find($request->plan); $subscription = $user->subscription($plan->id); if ($plan->hasTrial()) { $subscription->trialFor(Carbon::now()->addDays($plan->trialDays)); } if ($request->coupon) { $subscription->withCoupon($request->coupon); } $subscription->create($request->stripe_token, ['email' => $user->email]); }