This commit is contained in:
Joey Kimsey
2024-12-11 07:49:48 -05:00
parent 3bc838ce24
commit a1c849a626
21 changed files with 690 additions and 392 deletions

View File

@ -14,7 +14,7 @@ namespace TheTempusProject\Controllers\Api;
use Stripe\StripeClient;
use Stripe\Event;
use TheTempusProject\Models\User;
use TheTempusProject\Controllers\ApiController;
use TheTempusProject\Classes\ApiController;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Canary\Bin\Canary as Debug;
@ -178,7 +178,7 @@ class Stripe extends ApiController {
$response = 'UnexpectedValueException';
} catch(\Exception $e) {
Debug::error( 'Exception' );
Debug::v( $e );
Debug::error( $e );
http_response_code(400);
$responseType = 'error';
$response = 'Exception';

View File

@ -27,6 +27,9 @@ use TheTempusProject\Hermes\Functions\Route as Routes;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Models\Memberships;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Bedrock\Functions\Hash;
use TheTempusProject\Canary\Bin\Canary as Debug;
class Member extends Controller {
public static $customers;
@ -61,10 +64,17 @@ class Member extends Controller {
Session::flash( 'error', 'You do not have any active payment methods. You can subscribe by going <a href="/member/join/1">here</a>' );
return Redirect::to( 'member/manage' );
}
$session = $stripe->billingPortal->sessions->create([
'customer' => $customer,
'return_url' => Routes::getAddress() . 'member/manage',
]);
try {
$session = $stripe->billingPortal->sessions->create([
'customer' => $customer,
'return_url' => Routes::getAddress() . 'member/manage',
]);
} catch (\Stripe\Exception\InvalidRequestException $e) {
Debug::error('Membership -> ManagePayment - Stripe not configured correctly');
Debug::error( $e );
Session::flash( 'error', 'There was an issue redirecting you to Stripe, please try again.' );
return Redirect::to( 'member/manage' );
}
@ -146,16 +156,6 @@ class Member extends Controller {
}
Views::view( 'members.landing1', $product );
}
public function signup( $id = null ) {
self::$title = 'Sign-up for {SIITENAME}!';
$product = self::$products->findById( $id );
if ( empty( $product ) ) {
Session::flash( 'success', 'We aren\'t currently accepting new members, please check back soon!' );
return Redirect::home();
}
Views::view( 'members.landing2', $product );
}
public function getyearly( $id = null ) {
if ( empty( $id ) ) {
@ -236,4 +236,82 @@ class Member extends Controller {
self::$title = '(almost) Members Area';
Views::view( 'members.paymentcomplete' );
}
public function signup( $plan = 'monthly' ) {
$plan = strtolower( $plan );
if ( ! in_array( $plan, ['monthly','yearly'] ) ) {
Session::flash( 'error', 'Unknown plan' );
return Redirect::to( 'home/index' );
}
$product = self::$products->mainProduct();
if ( empty( $product ) ) {
Session::flash( 'error', 'Unknown product' );
return Redirect::to( 'home/index' );
}
$index = 'stripe_price_' . $plan;
$pretty = 'prettyPrice' . ucfirst( $plan );
$stripePrice = $product->$index;
$prettyPrice = $product->$pretty;
self::$title = 'Sign up for {SITENAME} ' . ucfirst( $plan );
Components::set( 'planName', ucfirst( $plan ) );
Components::set( 'prettyPrice', $prettyPrice );
Components::set( 'TERMS', Views::simpleView( 'terms' ) );
if ( App::$isLoggedIn ) {
Session::flash( 'notice', 'You are already logged in, were you looking for information on <a href="#">Upgrading</a>?' );
return Redirect::to( 'home/index' );
}
if ( !Input::exists() ) {
return Views::view( 'members.register' );
}
if ( ! Forms::check( 'register' ) ) {
Issues::add( 'error', [ 'There was an error with your registration.' => Check::userErrors() ] );
return Views::view( 'members.register' );
}
self::$user->create( [
'username' => Input::post( 'username' ),
'password' => Hash::make( Input::post( 'password' ) ),
'email' => Input::post( 'email' ),
'terms' => 1,
] );
if ( !self::$user->logIn( Input::post( 'username' ), Input::post( 'password' ), Input::post( 'remember' ) ) ) {
Session::flash( 'error', 'Thank you for registering! Unfortunately, there was an issue logging you in, please log in and order again.' );
return Redirect::to( 'home/index' );
}
$user = self::$user->authorize( Input::post( 'username' ), Input::post( 'password' ) );
$customer = self::$customers->findOrCreate( $user->ID );
if ( empty( $customer ) ) {
Session::flash( 'error', 'Thank you for registering! Unfortunately, there was an issue communicating with Stripe and we can\'t collect payment right now.' );
return Redirect::to( 'home/index' );
}
$api_key = Config::getValue( 'memberships/stripeSecret' );
$stripe = new \Stripe\StripeClient( $api_key );
$session = $stripe->checkout->sessions->create([
'payment_method_types' => ['card'],
'customer' => $customer,
'line_items' => [[
'price' => $stripePrice,
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => Routes::getAddress() . 'member/paymentcomplete?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => Routes::getAddress() . 'member/paymentcanceled',
]);
header('Location: ' . $session->url);
exit;
}
}

View File

@ -36,9 +36,6 @@ class MembershipProducts extends DatabaseModel {
public function __construct() {
parent::__construct();
if ( ! self::$loaded ) {
$api_key = Config::getValue( 'memberships/stripeSecret' );
if ( $api_key == 'sk_xxxxxxxxxxxxxxx' || empty($api_key) ) {
@ -48,8 +45,6 @@ class MembershipProducts extends DatabaseModel {
}
self::$loaded = true;
}
}
public function create( $name, $description, $monthly_price, $yearly_price ) {
@ -88,12 +83,14 @@ class MembershipProducts extends DatabaseModel {
]);
return $product;
}
public function createStripePrices( $product, $monthly_price, $yearly_price ) {
$out = [];
$out['monthly'] = $this->createStripeMonthlyPrice( $product, $monthly_price );
$out['yearly'] = $this->createStripeYearlyPrice( $product, $yearly_price );
return $out;
}
public function createStripeMonthlyPrice( $product, $monthly_price ) {
if ( empty( self::$stripe ) ) {
return false;
@ -106,6 +103,7 @@ class MembershipProducts extends DatabaseModel {
'lookup_key' => 'membership-monthly',
]);
}
public function createStripeYearlyPrice( $product, $yearly_price ) {
if ( empty( self::$stripe ) ) {
return false;
@ -173,6 +171,7 @@ class MembershipProducts extends DatabaseModel {
);
return $this->createStripeYearlyPrice( $product, $yearly_price );
}
public function updateStripeMonthlyPrice( $product, $monthly_price ) {
$stripe->prices->update(
$monthly->id,
@ -206,10 +205,18 @@ class MembershipProducts extends DatabaseModel {
public function findByPriceID( $d ) {
$data = self::$db->get( $this->tableName, [ 'stripe_price_monthly', '=', $d, 'OR', 'stripe_price_yearly', '=', $d ] );
if ( ! $data->count() ) {
return false;
}
return $data->first();
}
public function mainProduct() {
$data = self::$db->get( $this->tableName, '*' );
if ( ! $data->count() ) {
return false;
}
return $this->filter( $data->first() );
}
}

View File

@ -2,7 +2,7 @@
<div class="row justify-content-center">
<div class="col-md-8">
<legend>Memberships</legend>
<table class="table table-striped text-center">
<table class="table text-center context-main">
<thead>
<tr>
<th style="width: 25%">Name</th>

View File

@ -0,0 +1,69 @@
<form action="" method="post" class="container py-4">
<h2 class="text-center mb-4">Create an Account</h2>
<p class="text-center">After registration is complete, you will be redirected to Stripe to handle payment.</p>
<p class="text-center">
You have selected the <strong>{planName}</strong> plan at <em>{prettyPrice}</em>.
</p>
<fieldset>
<!-- Username -->
<div class="mb-3 row">
<label for="username" class="col-lg-6 col-form-label text-end">Username:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="username" id="username" required>
</div>
</div>
<!-- Email -->
<div class="mb-3 row">
<label for="email" class="col-lg-6 col-form-label text-end">Email:</label>
<div class="col-lg-2">
<input type="email" class="form-control" name="email" id="email" required>
</div>
</div>
<!-- Re-enter Email -->
<div class="mb-3 row">
<label for="email2" class="col-lg-6 col-form-label text-end">Re-Enter Email:</label>
<div class="col-lg-2">
<input type="email" class="form-control" name="email2" id="email2" required>
</div>
</div>
<!-- Password -->
<div class="mb-3 row">
<label for="password" class="col-lg-6 col-form-label text-end">Password:</label>
<div class="col-lg-2">
<input type="password" class="form-control" name="password" id="password" required>
</div>
</div>
<!-- Re-enter Password -->
<div class="mb-3 row">
<label for="password2" class="col-lg-6 col-form-label text-end">Re-Enter Password:</label>
<div class="col-lg-2">
<input type="password" class="form-control" name="password2" id="password2" required>
</div>
</div>
<!-- Terms of Service -->
<div class="mb-3 text-center">
<div class="">
<input type="checkbox" class="form-check-input" name="terms" id="terms" value="1" required>
<label for="terms" class="form-check-label">
I have read and agree to the <a href="/home/terms" class="text-primary">Terms of Service</a>
</label>
</div>
<div class="terms mt-2 mx-auto">
{TERMS}
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Sign up</button>
</div>
</fieldset>
</form>