This commit is contained in:
Flatlogic Bot 2025-10-15 01:01:54 +00:00
parent 369f552c9f
commit 2c8c9bfe04
10 changed files with 459 additions and 325 deletions

View File

@ -2,55 +2,51 @@
session_start();
require_once 'db/config.php';
if (!isset($_GET['action'])) {
header('Location: index.php');
exit;
}
$action = $_GET['action'];
$user_id = $_SESSION['user_id'] ?? null;
$session_id = session_id();
$action = $_POST['action'] ?? '';
$pdoconnection = db();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'add') {
$menu_item_id = $_POST['menu_item_id'] ?? null;
$quantity = $_POST['quantity'] ?? 1;
if ($action == 'add') {
if (!isset($_POST['menu_item_id']) || !isset($_POST['quantity'])) {
header('Location: cart.php');
exit;
}
if ($menu_item_id) {
try {
$pdo = db();
$menu_item_id = $_POST['menu_item_id'];
$quantity = $_POST['quantity'];
// Check if the item is already in the cart
// Check if item is already in cart
if ($user_id) {
$stmt = $pdo->prepare("SELECT * FROM cart WHERE user_id = ? AND menu_item_id = ?");
$stmt->execute([$user_id, $menu_item_id]);
$stmt = $pdoconnection->prepare("SELECT * FROM cart WHERE user_id = :user_id AND menu_item_id = :menu_item_id");
$stmt->execute([':user_id' => $user_id, ':menu_item_id' => $menu_item_id]);
} else {
$stmt = $pdo->prepare("SELECT * FROM cart WHERE session_id = ? AND menu_item_id = ?");
$stmt->execute([$session_id, $menu_item_id]);
$stmt = $pdoconnection->prepare("SELECT * FROM cart WHERE session_id = :session_id AND menu_item_id = :menu_item_id");
$stmt->execute([':session_id' => $session_id, ':menu_item_id' => $menu_item_id]);
}
$existing_item = $stmt->fetch();
if ($existing_item) {
// If item exists, update the quantity
// Update quantity
$new_quantity = $existing_item['quantity'] + $quantity;
$update_stmt = $pdo->prepare("UPDATE cart SET quantity = ? WHERE id = ?");
$update_stmt->execute([$new_quantity, $existing_item['id']]);
$stmt = $pdoconnection->prepare("UPDATE cart SET quantity = :quantity WHERE id = :id");
$stmt->execute([':quantity' => $new_quantity, ':id' => $existing_item['id']]);
} else {
// If item does not exist, insert it
if ($user_id) {
$insert_stmt = $pdo->prepare("INSERT INTO cart (user_id, menu_item_id, quantity) VALUES (?, ?, ?)");
$insert_stmt->execute([$user_id, $menu_item_id, $quantity]);
} else {
$insert_stmt = $pdo->prepare("INSERT INTO cart (session_id, menu_item_id, quantity) VALUES (?, ?, ?)");
$insert_stmt->execute([$session_id, $menu_item_id, $quantity]);
}
// Insert new item
$stmt = $pdoconnection->prepare("INSERT INTO cart (user_id, session_id, menu_item_id, quantity) VALUES (:user_id, :session_id, :menu_item_id, :quantity)");
$stmt->execute([
':user_id' => $user_id,
':session_id' => $user_id ? null : $session_id,
':menu_item_id' => $menu_item_id,
':quantity' => $quantity
]);
}
echo json_encode(['success' => true, 'message' => 'Item added to cart.']);
} catch (PDOException $e) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
header('Location: cart.php');
exit;
}
} else {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Menu item ID is required.']);
}
}
}
?>

View File

@ -1,19 +1,17 @@
<?php
session_start();
require_once 'db/config.php';
require_once 'includes/api_keys.php'; // Include Stripe API keys
require_once 'includes/api_keys.php';
// Redirect to login if user is not logged in
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
$userId = $_SESSION['user_id'];
$pdoconnection = db();
$pdo = db();
// Fetch cart items
$stmt = $pdoconnection->prepare("SELECT c.id, mi.name, mi.price, c.quantity, r.name as restaurant_name, r.id as restaurant_id FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id JOIN restaurants r ON mi.restaurant_id = r.id WHERE c.user_id = :user_id");
$stmt = $pdo->prepare("SELECT c.id, mi.name, mi.price, c.quantity, r.name as restaurant_name, r.id as restaurant_id FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id JOIN restaurants r ON mi.restaurant_id = r.id WHERE c.user_id = :user_id");
$stmt->bindParam(':user_id', $userId);
$stmt->execute();
$cartItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
@ -24,23 +22,25 @@ if (empty($cartItems)) {
}
$totalPrice = 0;
$restaurantId = $cartItems[0]['restaurant_id'];
$restaurantName = $cartItems[0]['restaurant_name'];
foreach ($cartItems as $item) {
$totalPrice += $item['price'] * $item['quantity'];
}
$delivery_fee = 5.00;
$totalPriceWithDelivery = $totalPrice + $delivery_fee;
include 'header.php';
?>
<script src="https://www.paypal.com/sdk/js?client-id=<?php echo $paypalClientId; ?>&currency=USD"></script>
<script src="https://js.stripe.com/v3/"></script>
<div class="container mt-5">
<h2 class="text-center mb-4">Checkout</h2>
<div class="row">
<div class="col-md-8">
<div class="col-md-7">
<h4>Delivery Information</h4>
<form action="create_stripe_session.php" method="POST">
<form id="payment-form" action="create_stripe_session.php" method="POST">
<div class="mb-3">
<label for="name" class="form-label">Full Name</label>
<input type="text" class="form-control" id="name" name="name" required>
@ -53,29 +53,119 @@ include 'header.php';
<label for="phone" class="form-label">Phone Number</label>
<input type="text" class="form-control" id="phone" name="phone" required>
</div>
<input type="hidden" name="restaurant_id" value="<?php echo $restaurantId; ?>">
<input type="hidden" name="total_price" value="<?php echo $totalPrice; ?>">
<button type="submit" class="btn btn-primary">Proceed to Payment</button>
</form>
<h4 class="mt-4">Payment Method</h4>
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method" id="stripe-radio" value="stripe" checked>
<label class="form-check-label" for="stripe-radio">
Pay with Credit Card (Stripe)
</label>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method" id="paypal-radio" value="paypal">
<label class="form-check-label" for="paypal-radio">
Pay with PayPal
</label>
</div>
<button id="stripe-button" type="submit" class="btn btn-primary mt-3">Proceed to Payment</button>
</form>
<div id="paypal-button-container" class="mt-3" style="display: none;"></div>
</div>
<div class="col-md-5">
<h4>Order Summary</h4>
<h5><?php echo htmlspecialchars($restaurantName); ?></h5>
<ul class="list-group mb-3">
<?php foreach ($cartItems as $item):
?>
<?php foreach ($cartItems as $item): ?>
<li class="list-group-item d-flex justify-content-between align-items-center">
<?php echo htmlspecialchars($item['name']); ?> (x<?php echo $item['quantity']; ?>)
<span>$<?php echo number_format($item['price'] * $item['quantity'], 2); ?></span>
</li>
<?php endforeach; ?>
<li class="list-group-item d-flex justify-content-between align-items-center">
Delivery Fee
<span>$<?php echo number_format($delivery_fee, 2); ?></span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center fw-bold">
Total
<span>$<?php echo number_format($totalPrice, 2); ?></span>
<span>$<?php echo number_format($totalPriceWithDelivery, 2); ?></span>
</li>
</ul>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('payment-form');
const stripeButton = document.getElementById('stripe-button');
const paypalButtonContainer = document.getElementById('paypal-button-container');
const stripeRadio = document.getElementById('stripe-radio');
const paypalRadio = document.getElementById('paypal-radio');
function togglePaymentMethod() {
if (paypalRadio.checked) {
stripeButton.style.display = 'none';
paypalButtonContainer.style.display = 'block';
} else {
stripeButton.style.display = 'block';
paypalButtonContainer.style.display = 'none';
}
}
stripeRadio.addEventListener('change', togglePaymentMethod);
paypalRadio.addEventListener('change', togglePaymentMethod);
// Initial check
togglePaymentMethod();
// PayPal integration
paypal.Buttons({
createOrder: function(data, actions) {
// Basic validation
if (!document.getElementById('name').value || !document.getElementById('address').value || !document.getElementById('phone').value) {
alert('Please fill out the delivery information before proceeding.');
return false;
}
return actions.order.create({
purchase_units: [{
amount: {
value: '<?php echo number_format($totalPriceWithDelivery, 2, '.', ''); ?>'
}
}]
});
},
onApprove: function(data, actions) {
// Capture delivery info and submit
const name = document.getElementById('name').value;
const address = document.getElementById('address').value;
const phone = document.getElementById('phone').value;
const formData = new FormData();
formData.append('orderID', data.orderID);
formData.append('name', name);
formData.append('address', address);
formData.append('phone', phone);
fetch('paypal-capture.php', {
method: 'POST',
body: formData
}).then(res => res.json())
.then(details => {
if (details.error) {
alert(details.error);
window.location.href = 'payment-cancel.php';
} else {
window.location.href = 'order_confirmation.php';
}
});
},
onError: function(err) {
console.error('PayPal Error:', err);
alert('An error occurred with your PayPal payment.');
}
}).render('#paypal-button-container');
});
</script>
<?php include 'footer.php'; ?>

View File

@ -1,40 +1,36 @@
<?php
session_start();
require_once 'db/config.php';
require_once 'includes/api_keys.php';
require_once 'vendor/autoload.php';
require_once 'includes/api_keys.php';
// Redirect to login if user is not logged in
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo 'Method Not Allowed';
header("Location: checkout.php");
exit();
}
$userId = $_SESSION['user_id'];
$pdoconnection = db();
\Stripe\Stripe::setApiKey($stripeSecretKey);
$user_id = $_SESSION['user_id'];
$pdo = db();
// Fetch cart items
$stmt = $pdoconnection->prepare("SELECT mi.name, mi.price, c.quantity FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id WHERE c.user_id = :user_id");
$stmt->bindParam(':user_id', $userId);
$stmt->execute();
$cartItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = $pdo->prepare("SELECT mi.name, mi.price, c.quantity FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id WHERE c.user_id = ?");
$stmt->execute([$user_id]);
$cart_items = $stmt->fetchAll();
if (empty($cartItems)) {
if (empty($cart_items)) {
header("Location: cart.php");
exit();
}
// Set Stripe API key
\Stripe\Stripe::setApiKey(STRIPE_API_KEY);
$line_items = [];
foreach ($cartItems as $item) {
foreach ($cart_items as $item) {
$line_items[] = [
'price_data' => [
'currency' => 'usd',
@ -47,38 +43,27 @@ foreach ($cartItems as $item) {
];
}
// Get delivery info from POST data
$customerName = $_POST['name'] ?? 'N/A';
$address = $_POST['address'] ?? 'N/A';
$phone = $_POST['phone'] ?? 'N/A';
$restaurantId = $_POST['restaurant_id'] ?? 0;
// Add delivery fee
$delivery_fee = 5.00;
$line_items[] = [
'price_data' => [
'currency' => 'usd',
'product_data' => [
'name' => 'Delivery Fee',
],
'unit_amount' => $delivery_fee * 100,
],
'quantity' => 1,
];
// Get the protocol and host
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http";
$host = $_SERVER['HTTP_HOST'];
try {
$checkout_session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => $line_items,
'mode' => 'payment',
'success_url' => $protocol . '://' . $host . '/payment-success.php?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $protocol . '://' . $host . '/payment-cancel.php',
'metadata' => [
'user_id' => $userId,
'restaurant_id' => $restaurantId,
'customer_name' => $customerName,
'address' => $address,
'phone' => $phone,
]
'success_url' => 'http://' . $_SERVER['HTTP_HOST'] . '/payment-success.php?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'http://' . $_SERVER['HTTP_HOST'] . '/payment-cancel.php',
]);
header("HTTP/1.1 303 See Other");
header("Location: " . $checkout_session->url);
} catch (Exception $e) {
// Handle any errors from Stripe
http_response_code(500);
echo 'Error creating Stripe session: ' . $e->getMessage();
// In a real app, you would log this error
}
?>

View File

@ -3,10 +3,14 @@
// IMPORTANT: Replace these placeholder keys with your actual Stripe API keys.
// You can find your keys in your Stripe dashboard: https://dashboard.stripe.com/apikeys
$stripeSecretKey = 'sk_test_YOUR_SECRET_KEY';
$stripePublishableKey = 'pk_test_YOUR_PUBLISHABLE_KEY';
// Secret key (keep this secure on the server)
define('STRIPE_API_KEY', 'sk_test_YOUR_SECRET_KEY');
// Publishable key (safe to use in client-side code)
define('STRIPE_PUBLISHABLE_KEY', 'pk_test_YOUR_PUBLISHABLE_KEY');
// IMPORTANT: Replace these placeholder keys with your actual PayPal API keys.
// You can find your keys in your PayPal Developer dashboard: https://developer.paypal.com/developer/applications
$paypalClientId = 'AVDnoNaRDnJkqCHwm7jOMl9Vbrt1ZLxdauuTo0sqprqOBhkCnwWI72pQeMs1aNYQCk0iZKoncQvQCDwS';
$paypalSecret = 'EDE5TwL0lnTFvLwpr1QCIhK2LN5SYIWAlLc7OPrngfBP2XNX9L0InrQ7L4kXQlCa49RlGyflZVlAYBZF';
$paypalApiBase = 'https://api-m.sandbox.paypal.com'; // Use https://api-m.paypal.com for production
?>

137
menu.php
View File

@ -1,128 +1,53 @@
<?php
require_once 'header.php';
require_once 'db/config.php';
// Get restaurant ID from the URL
$restaurant_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$restaurant_id) {
header('Location: index.php');
exit();
if (!isset($_GET['id'])) {
echo "<div class='alert alert-danger'>Restaurant ID is missing.</div>";
require_once 'footer.php';
exit;
}
$pdo = db();
$restaurant_id = $_GET['id'];
// Fetch restaurant details along with average rating
$restaurant_stmt = $pdo->prepare("
SELECT r.*, AVG(rt.rating) as rating, COUNT(rt.id) as rating_count
FROM restaurants r
LEFT JOIN ratings rt ON r.id = rt.restaurant_id
WHERE r.id = ?
GROUP BY r.id
");
$restaurant_stmt->execute([$restaurant_id]);
$restaurant = $restaurant_stmt->fetch(PDO::FETCH_ASSOC);
// Fetch restaurant details
$stmt = db()->prepare("SELECT * FROM restaurants WHERE id = ?");
$stmt->execute([$restaurant_id]);
$restaurant = $stmt->fetch();
// If restaurant not found, redirect
if (!$restaurant) {
header('Location: index.php');
exit();
}
// Fetch menu items
$stmt = db()->prepare("SELECT * FROM menu_items WHERE restaurant_id = ?");
$stmt->execute([$restaurant_id]);
$menu_items = $stmt->fetchAll();
// Fetch menu items for the specific restaurant
$menu_items_stmt = $pdo->prepare("SELECT * FROM menu_items WHERE restaurant_id = ? ORDER BY name");
$menu_items_stmt->execute([$restaurant_id]);
$menu_items = $menu_items_stmt->fetchAll(PDO::FETCH_ASSOC);
include 'header.php';
?>
<main>
<div class="container">
<section class="restaurant-hero" style="background-image: url('<?= htmlspecialchars($restaurant['image_url']) ?>');">
<div class="restaurant-hero-content">
<h1><?= htmlspecialchars($restaurant['name']) ?></h1>
<p><?= htmlspecialchars($restaurant['cuisine']) ?></p>
<?php if (isset($restaurant['rating']) && $restaurant['rating'] > 0): ?>
<div class="rating-display">
<span class="star"></span>
<span><?= htmlspecialchars(number_format($restaurant['rating'], 1)) ?></span>
<span class="rating-count">(<?= htmlspecialchars($restaurant['rating_count']) ?> ratings)</span>
<div class="row">
<div class="col-md-12">
<h1 class="mt-5"><?php echo htmlspecialchars($restaurant['name']); ?></h1>
<p class="lead"><?php echo htmlspecialchars($restaurant['description']); ?></p>
</div>
<?php else: ?>
<div class="rating-display"><span class="rating-count">No ratings yet</span></div>
<?php endif; ?>
</div>
</section>
<section class="restaurant-menu">
<h2>Menu</h2>
<div class="menu-grid">
<?php if (empty($menu_items)): ?>
<p>No menu items available for this restaurant.</p>
<?php else: ?>
<div class="row">
<?php foreach ($menu_items as $item): ?>
<div class="menu-item-card">
<img src="<?= htmlspecialchars($item['image_url']) ?>" alt="<?= htmlspecialchars($item['name']) ?>">
<div class="menu-item-card-content">
<h3><?= htmlspecialchars($item['name']) ?></h3>
<p class="description"><?= htmlspecialchars($item['description']) ?></p>
<p class="price">$<?= htmlspecialchars(number_format($item['price'], 2)) ?></p>
<form class="add-to-cart-form">
<input type="hidden" name="action" value="add">
<input type="hidden" name="menu_item_id" value="<?= $item['id'] ?>">
<div class="form-row">
<input type="number" name="quantity" value="1" min="1" class="quantity-input">
<button type="submit" class="add-to-cart-btn">Add to Cart</button>
</div>
<div class="col-md-4">
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title"><?php echo htmlspecialchars($item['name']); ?></h5>
<p class="card-text"><?php echo htmlspecialchars($item['description']); ?></p>
<p class="card-text font-weight-bold">$<?php echo htmlspecialchars($item['price']); ?></p>
<form action="cart_actions.php?action=add" method="post">
<input type="hidden" name="menu_item_id" value="<?php echo $item['id']; ?>">
<input type="number" name="quantity" value="1" min="1" class="form-control mb-2">
<button type="submit" class="btn btn-primary">Add to Cart</button>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
</div>
</main>
<script>
document.addEventListener('DOMContentLoaded', function () {
const forms = document.querySelectorAll('.add-to-cart-form');
forms.forEach(form => {
form.addEventListener('submit', function (e) {
e.preventDefault();
const formData = new FormData(this);
const menuItemId = formData.get('menu_item_id');
const quantity = formData.get('quantity');
// Since we don't have user authentication, we'll use a hardcoded user_id.
const userId = 1;
const data = new FormData();
data.append('action', 'add');
data.append('menu_item_id', menuItemId);
data.append('quantity', quantity);
data.append('user_id', userId);
fetch('cart_actions.php', {
method: 'POST',
body: data
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert('Item added to cart!');
} else {
alert('Error: ' + (result.error || 'Could not add item to cart.'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An unexpected error occurred.');
});
});
});
});
</script>
<?php include 'footer.php'; ?>
<?php require_once 'footer.php'; ?>

View File

@ -0,0 +1,4 @@
ALTER TABLE cart DROP CONSTRAINT IF EXISTS fk_menu_item;
ALTER TABLE cart DROP COLUMN IF EXISTS menu_item_id;
ALTER TABLE cart ADD COLUMN menu_item_id INT;
ALTER TABLE cart ADD CONSTRAINT fk_menu_item FOREIGN KEY (menu_item_id) REFERENCES menu_items(id);

View File

@ -0,0 +1,36 @@
DROP TABLE IF EXISTS menu_items CASCADE;
DROP TABLE IF EXISTS restaurants CASCADE;
CREATE TABLE restaurants (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
image_url VARCHAR(255)
);
CREATE TABLE menu_items (
id SERIAL PRIMARY KEY,
restaurant_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
image_url VARCHAR(255),
FOREIGN KEY (restaurant_id) REFERENCES restaurants(id) ON DELETE CASCADE
);
-- Insert some sample data for demonstration purposes
INSERT INTO restaurants (name, description, image_url) VALUES
('The Gourmet Kitchen', 'A fine dining experience with a modern twist.', 'assets/images/hero.jpg'),
('Pizza Palace', 'The best pizza in town, made with fresh ingredients.', 'assets/pasted-20251014-230507-170c4564.jpg'),
('Taco Town', 'Authentic Mexican street tacos and burritos.', 'assets/pasted-20251014-230144-ecd85886.webp');
INSERT INTO menu_items (restaurant_id, name, description, price) VALUES
(1, 'Steak Frites', 'Juicy steak with a side of crispy french fries.', 25.50),
(1, 'Salmon en Papillote', 'Salmon baked with herbs and lemon.', 22.00),
(1, 'Chocolate Lava Cake', 'Warm chocolate cake with a gooey center.', 8.00),
(2, 'Margherita Pizza', 'Classic pizza with tomato, mozzarella, and basil.', 12.00),
(2, 'Pepperoni Pizza', 'A crowd-pleaser with spicy pepperoni.', 14.50),
(2, 'Garlic Bread', 'Toasted bread with garlic butter and herbs.', 5.00),
(3, 'Carne Asada Tacos', 'Grilled steak tacos with onion and cilantro.', 3.50),
(3, 'Al Pastor Tacos', 'Marinated pork tacos with pineapple.', 3.50),
(3, 'Chicken Burrito', 'A large burrito filled with chicken, rice, and beans.', 10.00);

View File

@ -1,16 +1,22 @@
<?php
include 'header.php';
require_once 'header.php';
?>
<div class="container mt-5">
<div class="row">
<div class="col-md-8 offset-md-2 text-center">
<div class="alert alert-warning" role="alert">
<h4 class="alert-heading">Payment Canceled</h4>
<p>Your payment process was canceled. You have not been charged.</p>
<p>Your payment was canceled. You have not been charged.</p>
<hr>
<p class="mb-0">You can return to your cart to review your items or go back to the homepage.</p>
<p class="mb-0">You can continue shopping or go back to your cart.</p>
</div>
<a href="cart.php" class="btn btn-secondary">Back to Cart</a>
<a href="index.php" class="btn btn-primary">Back to Home</a>
<a href="cart.php" class="btn btn-secondary">View Cart</a>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
<?php
require_once 'footer.php';
?>

View File

@ -1,94 +1,79 @@
<?php
session_start();
require_once 'db/config.php';
require_once 'includes/api_keys.php';
require_once 'vendor/autoload.php';
require_once 'includes/api_keys.php';
$pdoconnection = db();
if (!isset($_SESSION['user_id'])) {
header("Location: login.php");
exit();
}
if (isset($_GET['session_id'])) {
\Stripe\Stripe::setApiKey(STRIPE_API_KEY);
$sessionId = $_GET['session_id'];
if (!isset($_GET['session_id'])) {
header("Location: index.php");
exit();
}
$stripe_session_id = $_GET['session_id'];
$user_id = $_SESSION['user_id'];
$pdo = db();
\Stripe\Stripe::setApiKey($stripeSecretKey);
try {
$session = \Stripe\Checkout\Session::retrieve($sessionId);
$checkout_session = \Stripe\Checkout\Session::retrieve($stripe_session_id);
if ($session->payment_status == 'paid') {
// Retrieve metadata
$metadata = $session->metadata;
$userId = $metadata->user_id;
$restaurantId = $metadata->restaurant_id;
$customerName = $metadata->customer_name;
$address = $metadata->address;
$phone = $metadata->phone;
$totalPrice = $session->amount_total / 100; // Convert from cents
if ($checkout_session->payment_status == 'paid') {
// Fetch cart items and delivery details
$stmt = $pdo->prepare("SELECT c.*, mi.price, mi.restaurant_id FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id WHERE c.user_id = ?");
$stmt->execute([$user_id]);
$cart_items = $stmt->fetchAll();
if (empty($cart_items)) {
header("Location: index.php");
exit();
}
$total_price = 0;
$restaurant_id = null;
foreach ($cart_items as $item) {
$total_price += $item['price'] * $item['quantity'];
$restaurant_id = $item['restaurant_id']; // Assuming all items in cart are from the same restaurant
}
$delivery_fee = 5.00;
$total_price += $delivery_fee;
// Get delivery details stored in cart
$delivery_name = $cart_items[0]['delivery_name'];
$delivery_address = $cart_items[0]['delivery_address'];
$delivery_phone = $cart_items[0]['delivery_phone'];
// Create order
$stmt = $pdo->prepare("INSERT INTO orders (user_id, restaurant_id, total_price, status, stripe_session_id, delivery_name, delivery_address, delivery_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$user_id, $restaurant_id, $total_price, 'paid', $stripe_session_id, $delivery_name, $delivery_address, $delivery_phone]);
$order_id = $pdo->lastInsertId();
// Insert order items
$stmt = $pdo->prepare("INSERT INTO order_items (order_id, menu_item_id, quantity, price) VALUES (?, ?, ?, ?)");
foreach ($cart_items as $item) {
$stmt->execute([$order_id, $item['menu_item_id'], $item['quantity'], $item['price']]);
}
// Clear cart
$stmt = $pdo->prepare("DELETE FROM cart WHERE user_id = ?");
$stmt->execute([$user_id]);
$_SESSION['order_id'] = $order_id;
header("Location: order_confirmation.php");
exit();
// Check if order already exists for this session to prevent duplicates
$stmt = $pdoconnection->prepare("SELECT id FROM orders WHERE stripe_session_id = :session_id");
$stmt->bindParam(':session_id', $sessionId);
$stmt->execute();
if ($stmt->fetch()) {
// Order already processed
$message = "Your order has already been processed.";
} else {
// Create a new order
$stmt = $pdoconnection->prepare("INSERT INTO orders (user_id, restaurant_id, total_price, status, delivery_name, delivery_address, delivery_phone, stripe_session_id) VALUES (:user_id, :restaurant_id, :total_price, 'processing', :name, :address, :phone, :session_id)");
$stmt->bindParam(':user_id', $userId);
$stmt->bindParam(':restaurant_id', $restaurantId);
$stmt->bindParam(':total_price', $totalPrice);
$stmt->bindParam(':name', $customerName);
$stmt->bindParam(':address', $address);
$stmt->bindParam(':phone', $phone);
$stmt->bindParam(':session_id', $sessionId);
$stmt->execute();
$orderId = $pdoconnection->lastInsertId();
// Get cart items
$cartStmt = $pdoconnection->prepare("SELECT * FROM cart WHERE user_id = :user_id");
$cartStmt->bindParam(':user_id', $userId);
$cartStmt->execute();
$cartItems = $cartStmt->fetchAll(PDO::FETCH_ASSOC);
// Move cart items to order_items
$orderItemStmt = $pdoconnection->prepare("INSERT INTO order_items (order_id, menu_item_id, quantity, price) VALUES (:order_id, :menu_item_id, :quantity, :price)");
foreach ($cartItems as $item) {
$priceStmt = $pdoconnection->prepare("SELECT price FROM menu_items WHERE id = :menu_item_id");
$priceStmt->bindParam(':menu_item_id', $item['menu_item_id']);
$priceStmt->execute();
$menuItem = $priceStmt->fetch(PDO::FETCH_ASSOC);
$orderItemStmt->bindParam(':order_id', $orderId);
$orderItemStmt->bindParam(':menu_item_id', $item['menu_item_id']);
$orderItemStmt->bindParam(':quantity', $item['quantity']);
$orderItemStmt->bindParam(':price', $menuItem['price']);
$orderItemStmt->execute();
header("Location: payment-cancel.php");
exit();
}
// Clear the cart
$clearCartStmt = $pdoconnection->prepare("DELETE FROM cart WHERE user_id = :user_id");
$clearCartStmt->bindParam(':user_id', $userId);
$clearCartStmt->execute();
$message = "Thank you for your order! Your payment was successful and your order (ID: $orderId) is now being processed.";
} catch (\Stripe\Exception\ApiErrorException $e) {
// Handle Stripe API errors
error_log($e->getMessage());
header("Location: payment-cancel.php");
exit();
}
} else {
$message = "Payment was not successful. Please try again.";
}
} catch (Exception $e) {
$message = "An error occurred: " . $e->getMessage();
}
} else {
$message = "Invalid request.";
}
include 'header.php';
?>
<div class="container mt-5">
<div class="alert alert-info" role="alert">
<?php echo htmlspecialchars($message); ?>
</div>
<a href="index.php" class="btn btn-primary">Back to Home</a>
</div>
<?php include 'footer.php'; ?>

103
paypal-capture.php Normal file
View File

@ -0,0 +1,103 @@
<?php
session_start();
require_once 'db/config.php';
require_once 'includes/api_keys.php';
header('Content-Type: application/json');
if (!isset($_SESSION['user_id']) || !isset($_POST['orderID'])) {
echo json_encode(['error' => 'Invalid request.']);
exit();
}
$orderID = $_POST['orderID'];
$user_id = $_SESSION['user_id'];
// Helper function to get PayPal access token
function get_paypal_access_token($clientId, $secret, $apiBase) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$apiBase/v1/oauth2/token");
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, "$clientId:$secret");
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
$result = curl_exec($ch);
curl_close($ch);
if (empty($result)) return null;
$json = json_decode($result);
return $json->access_token ?? null;
}
$accessToken = get_paypal_access_token($paypalClientId, $paypalSecret, $paypalApiBase);
if (!$accessToken) {
echo json_encode(['error' => 'Could not authenticate with PayPal.']);
exit();
}
// Capture payment
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$paypalApiBase/v2/checkout/orders/$orderID/capture");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"Authorization: Bearer $accessToken"
]);
$result = curl_exec($ch);
curl_close($ch);
$details = json_decode($result);
if (isset($details->status) && $details->status == 'COMPLETED') {
$pdo = db();
// Fetch cart items
$stmt = $pdo->prepare("SELECT c.*, mi.price, mi.restaurant_id FROM cart c JOIN menu_items mi ON c.menu_item_id = mi.id WHERE c.user_id = ?");
$stmt->execute([$user_id]);
$cart_items = $stmt->fetchAll();
if (empty($cart_items)) {
echo json_encode(['error' => 'Your cart is empty.']);
exit();
}
$total_price = 0;
$restaurant_id = null;
foreach ($cart_items as $item) {
$total_price += $item['price'] * $item['quantity'];
$restaurant_id = $item['restaurant_id'];
}
$delivery_fee = 5.00;
$total_price += $delivery_fee;
$delivery_name = $_POST['name'];
$delivery_address = $_POST['address'];
$delivery_phone = $_POST['phone'];
// Create order
$stmt = $pdo->prepare("INSERT INTO orders (user_id, restaurant_id, total_price, status, stripe_session_id, delivery_name, delivery_address, delivery_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$user_id, $restaurant_id, $total_price, 'paid', $orderID, $delivery_name, $delivery_address, $delivery_phone]);
$order_id = $pdo->lastInsertId();
// Insert order items
$stmt = $pdo->prepare("INSERT INTO order_items (order_id, menu_item_id, quantity, price) VALUES (?, ?, ?, ?)");
foreach ($cart_items as $item) {
$stmt->execute([$order_id, $item['menu_item_id'], $item['quantity'], $item['price']]);
}
// Clear cart
$stmt = $pdo->prepare("DELETE FROM cart WHERE user_id = ?");
$stmt->execute([$user_id]);
$_SESSION['order_id'] = $order_id;
echo json_encode(['success' => true]);
} else {
error_log('PayPal Capture Failed: ' . print_r($details, true));
echo json_encode(['error' => 'Payment failed. Please try again.']);
}