db->fetch( 'SELECT COALESCE(SUM(rate_basis_points), 0) AS total_rate FROM tax_rates WHERE active = 1' )['total_rate']; $tax = (int) round($subtotal * $taxRate / 10000); return [ 'subtotal_cents' => $subtotal, 'tax_rate_basis_points' => $taxRate, 'tax_cents' => $tax, 'total_cents' => $subtotal + $tax, ]; } public function place(array $cart, array $customer, ?int $userId, string $sourceId): array { if (empty($cart['items'])) { throw new RuntimeException('Your cart is empty.'); } $totals = $this->totals($cart); $orderNumber = 'FBG-' . date('ymd') . '-' . strtoupper(substr(hash('sha256', (string) $cart['token']), 0, 6)); $payment = $this->payments->charge($sourceId, $totals['total_cents'], $orderNumber); $pdo = $this->db->pdo(); $pdo->beginTransaction(); try { $customerId = $this->customers->capture($customer, $userId); $trackingToken = bin2hex(random_bytes(24)); $statement = $pdo->prepare( 'INSERT INTO orders (order_number, user_id, customer_id, cart_id, tracking_token, customer_name, customer_email, customer_phone, order_type, status, payment_status, payment_provider, payment_reference, subtotal_cents, tax_cents, total_cents, special_instructions, pickup_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' ); $statement->execute([ $orderNumber, $userId, $customerId, (int) $cart['id'], $trackingToken, $customer['customer_name'], $customer['customer_email'], $customer['customer_phone'], 'pickup', 'pending', 'paid', $payment['provider'], $payment['reference'], $totals['subtotal_cents'], $totals['tax_cents'], $totals['total_cents'], $customer['special_instructions'], $customer['pickup_time'] ?: null, ]); $orderId = (int) $pdo->lastInsertId(); $itemStatement = $pdo->prepare( 'INSERT INTO order_items (order_id, menu_item_id, item_name, quantity, unit_price_cents, line_total_cents, notes) VALUES (?, ?, ?, ?, ?, ?, ?)' ); foreach ($cart['items'] as $item) { $itemStatement->execute([ $orderId, (int) $item['menu_item_id'], $item['name'], (int) $item['quantity'], (int) $item['unit_price_cents'], (int) $item['quantity'] * (int) $item['unit_price_cents'], $item['notes'], ]); } $pdo->prepare( 'INSERT INTO order_events (order_id, user_id, event_type, details, status, customer_visible) VALUES (?, ?, ?, ?, ?, 1)' )->execute([ $orderId, $userId, 'order_placed', 'Online pickup order paid successfully and is awaiting staff acceptance.', 'pending', ]); $pdo->prepare( "UPDATE carts SET status = 'converted', converted_at = CURRENT_TIMESTAMP WHERE id = ?" )->execute([(int) $cart['id']]); $this->customers->refresh($customerId); $pdo->commit(); } catch (\Throwable $error) { $pdo->rollBack(); throw $error; } return $this->db->fetch('SELECT * FROM orders WHERE id = ?', [$orderId]) ?? []; } }