@@ -13,6 +13,16 @@ use App\Models\Transaction; | |||
class BillingController extends Controller | |||
{ | |||
protected $stripe; | |||
protected $user; | |||
public function __construct() { | |||
$this->stripe = new \Stripe\StripeClient(env('STRIPE_SECRET')); | |||
Stripe::setApiKey(env('STRIPE_SECRET')); | |||
$this->user = Auth::user(); | |||
} | |||
//Expects an array 'packs' representing the amount of each multiple of credits. | |||
//This controller should have a way of figuring out how much of each pack | |||
//was bought later. | |||
@@ -20,6 +30,7 @@ class BillingController extends Controller | |||
public function secret(Request $request) { | |||
Stripe::setApiKey(env('STRIPE_SECRET')); | |||
$user = Auth::user(); | |||
$amount = $request->packs[ 'credits10' ]*1099 + | |||
$request->packs[ 'credits50' ]*5499 + $request->packs[ 'credits100' ]*10999 | |||
+ $request->packs[ 'credits1000' ]*101000; | |||
@@ -34,7 +45,7 @@ class BillingController extends Controller | |||
$request->packs['credits100']*10 + | |||
$request->packs['credits1000']*150; | |||
$transaction->user_id = Auth::user()->id; | |||
$transaction->user_id = $user->id; | |||
$transaction->charge = $amount; | |||
$transaction->status = 'processing'; | |||
$transaction->completed = false; | |||
@@ -43,13 +54,18 @@ class BillingController extends Controller | |||
$intent = PaymentIntent::create([ | |||
'amount' => $amount, | |||
'currency' => 'usd', | |||
'customer' => Auth::user()->customer_id, | |||
'customer' => $user->customer_id, | |||
'description' => "You have received $total_credits credits.", | |||
'receipt_email' => Auth::user()->email, | |||
'metadata' => ['transaction_id' => $transaction->id] | |||
]); | |||
$transaction->intent_id = $intent->id; | |||
//Save the card as a default if none is set and it was selected | |||
if ($user->payment_method == null && $request->card) { | |||
$this->changeDefaultCard($request->card); | |||
} | |||
$transaction->save(); | |||
return $intent->client_secret; | |||
} | |||
@@ -71,7 +87,6 @@ class BillingController extends Controller | |||
$user = $transaction->user; | |||
if ($event->type == 'charge.succeeded') { | |||
Log::debug($charge->metadata['transaction_id']); | |||
$user->credits = $user->credits + $transaction->credits + $transaction->credits_extra; | |||
$transaction->status = 'completed'; | |||
$transaction->completed = true; | |||
@@ -83,4 +98,28 @@ class BillingController extends Controller | |||
$transaction->save(); | |||
} | |||
} | |||
public function changeDefaultCard(String $card) { | |||
$user = Auth::user(); | |||
$user->payment_method = $card; | |||
$user->save(); | |||
$cards = $this->getCards(); | |||
Log::debug($this->user->customer_id); | |||
return PaymentMethod::all([ | |||
'customer' => Auth::user()->customer_id, | |||
'type' => 'card' | |||
]); | |||
} | |||
public function deleteCard(Request $request) { | |||
$this->stripe->paymentMethods->detach($request->card); | |||
$user = Auth::user(); | |||
if ($request->card == $user->payment_method) { | |||
$user->payment_method = null; | |||
$user->save(); | |||
} | |||
return ($this->getCards()); | |||
} | |||
} |
@@ -21,7 +21,7 @@ class CreateUsersTable extends Migration | |||
$table->timestamp('email_verified_at')->nullable(); | |||
$table->string('password'); | |||
$table->enum('role', ['client', 'guest', 'admin']); | |||
$table->string('payment_method'); | |||
$table->string('payment_method')->default(''); | |||
$table->boolean('active')->default(true); | |||
$table->unsignedBigInteger('credits')->default(0); | |||
$table->rememberToken(); | |||
@@ -28,7 +28,7 @@ | |||
<div :class="{right: !selectSaved}" class="menu-slider"><div></div></div> | |||
</div> | |||
<saved-cards v-model:picked-card="picked" :cards="cards" | |||
<saved-cards :preferred="preferred" v-model:picked-card="picked" :cards="cards" | |||
:token="token" v-if="selectSaved"></saved-cards> | |||
<payment-card @set-card="(c) => {card = c}" @card-valid="(val) => {cardValid = val}" | |||
@@ -148,7 +148,7 @@ export default { | |||
}, | |||
computed: {total, ready}, | |||
methods: {getSecret, pay, getCards}, | |||
props: ['token'], | |||
props: ['preferred', 'token'], | |||
emits: ['purchaseComplete'], | |||
created() { | |||
this.getCards() | |||
@@ -6,7 +6,7 @@ | |||
<div v-for="(card, index) in cards" :key="card.id" class="saved-card"> | |||
<span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}} | |||
(••••{{card.card.last4}})</span> | |||
<span><input :checked="index === 0" :value="card.id" name="selected-card" type="radio" | |||
<span><input :checked="card.id == preferred" :value="card.id" name="selected-card" type="radio" | |||
@change="change(card.id)"></span> | |||
<span><img @click="remove(card.id)" src="../../images/close-icon-black.svg"/></span> | |||
</div> | |||
@@ -35,22 +35,22 @@ function change(card) { | |||
body: JSON.stringify({'card': card}) | |||
}).then((response) => { | |||
if (response.ok) { | |||
console.log('ok') | |||
response.json().then((data) => { | |||
this.cards = data | |||
this.cards = data.data | |||
}) | |||
} else { | |||
console.log('bad') | |||
document.getElementById("billing-error").textContent = | |||
`${response.status}: ${response.statusText}` | |||
} | |||
response.json().then(data => { | |||
console.log(data)} | |||
) | |||
}) | |||
} | |||
function remove(card) { | |||
if (card.length == 1) { | |||
return | |||
} | |||
fetch('/panel/delete-card', { | |||
method: 'POST', | |||
headers: {'Content-Type': 'application/json', | |||
@@ -59,18 +59,13 @@ function remove(card) { | |||
body: JSON.stringify({'card': card}) | |||
}).then((response) => { | |||
if (response.ok) { | |||
console.log('ok') | |||
response.json().then((data) => { | |||
this.cards = data | |||
this.cards = data.data | |||
}) | |||
} else { | |||
console.log('bad') | |||
document.getElementById("billing-error").textContent = | |||
`${response.status}: ${response.statusText}` | |||
} | |||
response.json().then(data => { | |||
console.log(data)} | |||
) | |||
}) | |||
} | |||
@@ -82,6 +77,6 @@ export default { | |||
created() { | |||
this.get() | |||
}, | |||
props: ['token',], | |||
props: ['token', 'preferred'], | |||
} | |||
</script> |
@@ -28,7 +28,7 @@ | |||
</div> | |||
<PastOrders :orders="orders" v-else-if="active === '#orders'" id="main"> | |||
</PastOrders> | |||
<NewOrder :token="token" :active="active" :credits="user.credits" v-else-if="active === | |||
<NewOrder :preferred="user.payment_method" :token="token" :active="active" :credits="user.credits" v-else-if="active === | |||
'#new-order' || active === '#credits'" id="main" @update-user='getUser' @update-orders='getOrders'> | |||
</NewOrder> | |||
<div id="main" v-else-if="active === '#exit'"> | |||
@@ -3,7 +3,7 @@ | |||
<div v-for="(card, index) in cards" :key="card.id" class="saved-card"> | |||
<span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}} | |||
(••••{{card.card.last4}})</span> | |||
<input :checked="index === 0" :value="card.id" name="selected-card" type="radio" | |||
<input :checked="index === 0 || card.id == preferred" :value="card.id" name="selected-card" type="radio" | |||
@change="$emit('update:pickedCard', card.id)"> | |||
</div> | |||
</div> | |||
@@ -22,7 +22,7 @@ | |||
unmounted() { | |||
this.$emit('update:pickedCard', null) | |||
}, | |||
props: ['token', 'cards'], | |||
props: ['token', 'cards', 'preferred'], | |||
emits: ['update:pickedCard'] | |||
} | |||
</script> |
@@ -81,7 +81,7 @@ | |||
</template> | |||
<credits @purchase-complete="$emit('updateUser')" :token="token" v-if="page == 'credits'"></credits> | |||
<credits @purchase-complete="$emit('updateUser')" :preferred="preferred" :token="token" v-if="page == 'credits'"></credits> | |||
</div> | |||
</template> | |||
@@ -163,7 +163,7 @@ export default { | |||
paying: false, url: '', completed: false} | |||
}, | |||
components: {ServicePane, Loading, Credits}, | |||
props: ['token', 'credits', 'active'], | |||
props: ['token', 'credits', 'active', 'preferred'], | |||
created() { | |||
fetch("/panel/services", { | |||
method: 'GET', | |||
@@ -3,7 +3,7 @@ | |||
<h3>Settings</h3> | |||
<section class="billing-pane"> | |||
<h4>Billing</h4> | |||
<edit-cards :token="token"></edit-cards> | |||
<edit-cards :preferred="user.payment_method" :token="token"></edit-cards> | |||
</section> | |||
<section class="change-name-pane"> | |||
<h4>Name</h4> | |||
@@ -63,6 +63,13 @@ Route::get('/panel/user', function (Request $request) { | |||
return $request->user(); | |||
})->middleware([ 'auth', 'verified' ]); | |||
Route::post('/panel/change-card', function (Request $request) { | |||
return App::make(BillingController::class)->changeDefaultCard($request->card); | |||
})->middleware([ 'auth', 'verified' ]); | |||
Route::post('/panel/delete-card', [BillingController::class, | |||
'deleteCard'])->middleware([ 'auth', 'verified' ]); | |||
Route::get('/panel/orders', [UserController::class, | |||
'getOrders'])->middleware([ 'auth', 'verified' ]); | |||