Skip to content

Commit

Permalink
feat: api checkout
Browse files Browse the repository at this point in the history
  • Loading branch information
huydevct committed Jul 12, 2023
1 parent 5599134 commit da4906f
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 13 deletions.
16 changes: 11 additions & 5 deletions app/Http/Controllers/CartController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,23 @@ public function __construct(Cart $cartModel, Product $productModel){

public function addProductToCart(AddToCartRequest $request){
$productId = $request['product_id'];
$userId = auth()->user()->id;
$amount = $request['amount'];
$userId = optional(auth()->user())->id;
if($userId == 0){
return response()->json(['message' => 'Unauthorized'], 403);
}
if ($request['cart_id'] == null){
$product = $this->productModel->getOneProduct($productId);
if ($product == null){
return response()->json(['message'=> 'Product not found'], 400);
}

$result = $this->cartModel->addProductToNewCart($productId, $userId);
if ($product->stock < $amount){
return response()->json(['message'=> 'Product is not enough'], 400);
}

$result = $this->cartModel->addProductToNewCart($productId, $userId, $amount);
if ($result == null){
$this->productModel->decreaseOne($productId);
return response()->json(['message' => 'Add product to cart failed'], 500);
}
}
Expand All @@ -40,9 +47,8 @@ public function addProductToCart(AddToCartRequest $request){
return response()->json(['message'=> 'Product not found'], 400);
}

$result = $this->cartModel->addProductToCart($cartId, $product->id, $userId);
$result = $this->cartModel->addProductToCart($cartId, $product->id, $userId, $amount);
if ($result){
$this->productModel->decreaseOne($productId);
return response()->json(['message' => 'Add product to cart success', 'cart_id' => $result], 201);
}

Expand Down
128 changes: 128 additions & 0 deletions app/Http/Controllers/PaypalController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php

namespace App\Http\Controllers;

use App\Http\Requests\CreatePaymentRequest;
use App\Models\Cart;
use App\Models\Payment;
use App\Models\Product;
use Illuminate\Http\Request;
use Srmklive\PayPal\Services\PayPal as PayPalClient;

class PaypalController extends Controller
{
private $paymentModel;
private $productModel;
private $cartModel;

public function __construct(Payment $paymentModel, Product $productModel, Cart $cartModel)
{
$this->paymentModel = $paymentModel;
$this->productModel = $productModel;
$this->cartModel = $cartModel;
}

public function handlePayment(CreatePaymentRequest $request)
{
$provider = new PayPalClient;
$provider->setApiCredentials(config('paypal'));
$paypalToken = $provider->getAccessToken();

$cartId = $request['cart_id'];
$userId = optional(auth()->user())->id;
if ($userId == null) {
return response()->json(['message' => 'Unauthorized'], 403);
}

$result = $this->paymentModel->pay($cartId, $userId, 'Paypal');
if ($result == null) {
return response()->json(['message' => 'Cart not found'], 404);
}

if ($result == 'Cart was checked out'){
return response()->json(['message' => $result], 400);
}

$response = $provider->createOrder([
"intent" => "CAPTURE",
"application_context" => [
"return_url" => route('success.payment'),
"cancel_url" => route('cancel.payment'),
],
"purchase_units" => [
0 => [
"amount" => [
"currency_code" => "USD",
"value" => sprintf("%.2f", $result['total_price'])
]
]
]
]);

if (isset($response['id']) && $response['id'] != null) {
foreach ($response['links'] as $links) {
if ($links['rel'] == 'approve') {
$res = $this->paymentModel->updateStatusPayment($result['payment_id'], "SUCCESS");
if ($res == 0) {
return response()->json(['message' => 'error update payment success'], 500);
}

$this->cartModel->updateStatusCart($cartId, 'SUCCESS');

foreach ($result['products'][0] as $key => $value) {
$this->productModel->decrease($key, $value);
}

redirect()->away($links['href']);
return response()->json(['result' => $result], 200);
}
}

$res = $this->paymentModel->updateStatusPayment($result['payment_id'], "FAILED");
if ($res == 0) {
return response()->json(['message' => 'error update payment failed'], 500);
}

$this->cartModel->updateStatusCart($cartId, 'FAILED');

return redirect()
->route('cancel.payment')
->with('error', 'Something went wrong.');
} else {
$res = $this->paymentModel->updateStatusPayment($result['payment_id'], "FAILED");
if ($res == 0) {
return response()->json(['message' => 'error update payment failed'], 500);
}

$this->cartModel->updateStatusCart($cartId, 'FAILED');

return redirect()
->route('create.payment')
->with('error', $response['message'] ?? 'Something went wrong.');
}
}

public function paymentCancel()
{
return redirect()
->route('create.payment')
->with('error', $response['message'] ?? 'You have canceled the transaction.');
}

public function paymentSuccess(Request $request)
{
$provider = new PayPalClient;
$provider->setApiCredentials(config('paypal'));
$provider->getAccessToken();
$response = $provider->capturePaymentOrder($request['token']);
if (isset($response['status']) && $response['status'] == 'COMPLETED') {
return redirect()
->route('create.payment')
->with('success', 'Transaction complete.');
} else {
return redirect()
->route('create.payment')
->with('error', $response['message'] ?? 'Something went wrong.');
}
}
}
1 change: 1 addition & 0 deletions app/Http/Requests/AddToCartRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class AddToCartRequest extends FormRequest
public function rules(){
return [
'product_id' => 'required',
'amount' => 'required',
];
}

Expand Down
24 changes: 24 additions & 0 deletions app/Http/Requests/CreatePaymentRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;

class CreatePaymentRequest extends FormRequest
{
public function rules(){
return [
'cart_id' => 'required',
];
}

protected function failedValidation(Validator $validator): void
{
throw new ValidationException($validator, response()->json([
'success' => false,
'message' => $validator->messages()->first(),
]));
}
}
17 changes: 12 additions & 5 deletions app/Models/Cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@

class Cart extends Model
{
public function addProductToCart($cartId, $productId, $userId)
public function addProductToCart($cartId, $productId, $userId, $quantity)
{
$cartFromDB = DB::table('carts')->where('id', $cartId)->where('product_id', $productId)->where('user_id', $userId)->first();
if ($cartFromDB != null) {
DB::table('carts')->where('id', $cartId)->where('product_id', $productId)->where('user_id', $userId)->update(array('quantity' => $cartFromDB->quantity + 1));
DB::table('carts')->where('id', $cartId)->where('product_id', $productId)->where('user_id', $userId)->update(array('quantity' => $cartFromDB->quantity + $quantity));
return $cartId;
}

return DB::table('carts')->insertGetId(
[
'quantity' => 1,
'quantity' => $quantity,
'user_id' => $userId,
'product_id' => $productId,
'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
'status' => 'PENDING',
]
);
}

public function addProductToNewCart($productId, $userId){
public function addProductToNewCart($productId, $userId, $quantity){
return DB::table('carts')->insertGetId(
[
'quantity' => 1,
'quantity' => $quantity,
'user_id' => $userId,
'product_id' => $productId,
'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
'status' => 'PENDING',
]
);
}
Expand Down Expand Up @@ -63,4 +66,8 @@ public function listCartById($cartId)

return $result;
}

public function updateStatusCart($cartId, $status){
return DB::table('carts')->where('id', $cartId)->update([ 'status' => $status]);
}
}
98 changes: 98 additions & 0 deletions app/Models/Payment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class Payment extends Model
{
public function pay($cartId, $userId, $payMethod)
{
DB::beginTransaction();
try {
$timeNow = Carbon::now()->format('Y-m-d H:i:s');
$carts = DB::table('carts')->where('id', $cartId)->where('user_id', $userId)->get();
if (count($carts) == 0) {
return null;
}

$amount = 0;
$productIds = array();
foreach ($carts as $cart){
if ($cart->status == 'SUCCESS'){
continue;
}
$amount += $cart->quantity;
array_push($productIds, $cart->product_id);
}

if ($amount == 0){
return 'Cart was checked out';
}

$products = DB::table('products')->whereIn('id', $productIds)->get();
$totalPrice = 0.00;
$productsResult = [];

foreach ($products as $product){
foreach ($carts as $cart){
if ($product->id == $cart->product_id){
$price = $product->price * $cart->quantity;
$totalPrice += $price;
array_push($productsResult, [
$product->id => $cart->quantity,
]);
}
}
}

$paymentId = DB::table('payments')->insertGetId([
'payment_date' => $timeNow,
'payment_method' => $payMethod,
'amount' => $amount,
'user_id' => $userId,
'created_at' => $timeNow,
]);

$orderId = DB::table('orders')->insertGetId([
'order_date' => $timeNow,
'total_price' => $totalPrice,
'user_id' => $userId,
'payment_id' => $paymentId,
'created_at' => $timeNow,
]);

foreach ($products as $product){
foreach ($carts as $cart){
if ($product->id == $cart->product_id){
$price = $product->price * $cart->quantity;
DB::table('order_item')->insertGetId([
'quantity' => $cart->quantity,
'price' => $price,
'product_id' => $product->id,
'order_id' => $orderId,
'created_at' => $timeNow,
]);
}
}
}

DB::commit();

return [
'payment_id' => $paymentId,
'total_price' => $totalPrice,
'order_id' => $orderId,
'products' => $productsResult,
];
} catch (\Exception $e) {
DB::rollBack();
}
}

public function updateStatusPayment($paymentId, $status){
return DB::table('payments')->where('id', $paymentId)->update([ 'status' => $status]);
}
}
4 changes: 2 additions & 2 deletions app/Models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ public function getOneProduct($productId)
return $product;
}

public function decreaseOne($productId)
public function decrease($productId, $amount)
{
$productFromDB = DB::table('products')->where('id', $productId)->first();
if ($productFromDB == null) {
return "Product not found";
}
return DB::table('products')->where('id', $productId)->update(['stock' => $productFromDB->stock - 1]);
return DB::table('products')->where('id', $productId)->update(['stock' => $productFromDB->stock - $amount]);
}
}
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"laravel/framework": "^10.10",
"laravel/sanctum": "^3.2",
"laravel/tinker": "^2.8",
"srmklive/paypal": "~3.0",
"tymon/jwt-auth": "^2.0"
},
"require-dev": {
Expand Down
Loading

0 comments on commit da4906f

Please sign in to comment.