diff --git a/wordpress-dev/tests/e2e/order-summary.test.ts b/wordpress-dev/tests/e2e/order-summary.test.ts
new file mode 100644
index 00000000..6e51f13f
--- /dev/null
+++ b/wordpress-dev/tests/e2e/order-summary.test.ts
@@ -0,0 +1,148 @@
+/**
+ * @fileoverview E2E Tests for Order Summary page.
+ * This test suite verifies that trainers can view order details for their events.
+ */
+
+import { test, expect } from '@playwright/test';
+import { LoginPage } from './pages/LoginPage';
+import { DashboardPage } from './pages/DashboardPage';
+
+// Test data
+const TEST_USER = {
+ username: process.env.TEST_TRAINER_USERNAME || 'test_trainer',
+ password: process.env.TEST_TRAINER_PASSWORD || 'Test_password123'
+};
+
+test.describe('Order Summary Page @order-summary', () => {
+ test.beforeEach(async ({ page }) => {
+ // Login before each test
+ const loginPage = new LoginPage(page);
+ await loginPage.goto();
+ await loginPage.login(TEST_USER.username, TEST_USER.password);
+
+ // Verify we're logged in by checking if we're on the dashboard
+ const dashboardPage = new DashboardPage(page);
+ await expect(page).toHaveURL(/.*hvac-dashboard.*/);
+ await expect(dashboardPage.welcomeMessage).toBeVisible();
+ });
+
+ test('should navigate from dashboard to event summary to order summary', async ({ page }) => {
+ // Navigate to dashboard
+ await page.goto('/hvac-dashboard/');
+ await expect(page).toHaveURL(/.*hvac-dashboard.*/);
+
+ // Find an event with tickets and navigate to its event summary
+ // This depends on having test events with ticket sales
+ const eventLinks = await page.$$('a[href*="event-summary"]');
+ if (eventLinks.length === 0) {
+ test.skip('No events with ticket sales found');
+ }
+
+ // Click the first event link
+ await eventLinks[0].click();
+ await expect(page).toHaveURL(/.*event-summary.*/);
+ await expect(page.locator('h1')).toContainText('Summary');
+
+ // Look for order links in the transactions table
+ const orderLinks = await page.$$('a[href*="order-summary"]');
+ if (orderLinks.length === 0) {
+ test.skip('No orders found for this event');
+ }
+
+ // Click the first order link
+ await orderLinks[0].click();
+ await expect(page).toHaveURL(/.*order-summary.*/);
+ await expect(page.locator('h1')).toContainText('Order Summary');
+ });
+
+ test('should display correct order information', async ({ page }) => {
+ // Navigate directly to an order summary page
+ // This depends on having an order ID for testing
+ // For this test, we'll need to get an order ID from an event first
+ await page.goto('/hvac-dashboard/');
+
+ // Find an event and navigate to its summary
+ const eventLinks = await page.$$('a[href*="event-summary"]');
+ if (eventLinks.length === 0) {
+ test.skip('No events with ticket sales found');
+ }
+
+ await eventLinks[0].click();
+ await expect(page).toHaveURL(/.*event-summary.*/);
+
+ // Look for order links and get the first order's ID
+ const orderLink = await page.$('a[href*="order-summary"]');
+ if (!orderLink) {
+ test.skip('No orders found for this event');
+ }
+
+ const href = await orderLink.getAttribute('href');
+ const orderId = href.match(/order_id=(\d+)/)[1];
+
+ // Navigate to order summary page directly
+ await page.goto(`/order-summary/?order_id=${orderId}`);
+ await expect(page).toHaveURL(/.*order-summary.*/);
+
+ // Check that order details are displayed correctly
+ await expect(page.locator('h1')).toContainText('Order Summary');
+ await expect(page.locator('.hvac-details-table')).toBeVisible();
+
+ // Check for order number
+ const orderNumberCell = await page.locator('.hvac-details-table tr', { has: page.locator('th', { hasText: 'Order Number' }) }).locator('td');
+ await expect(orderNumberCell).toBeVisible();
+
+ // Check for tickets table
+ await expect(page.locator('.hvac-tickets-table')).toBeVisible();
+ await expect(page.locator('.hvac-tickets-table th', { hasText: 'Attendee' })).toBeVisible();
+ await expect(page.locator('.hvac-tickets-table th', { hasText: 'Email' })).toBeVisible();
+ await expect(page.locator('.hvac-tickets-table th', { hasText: 'Ticket Type' })).toBeVisible();
+ await expect(page.locator('.hvac-tickets-table th', { hasText: 'Event' })).toBeVisible();
+ });
+
+ test('should redirect to login page when not logged in', async ({ page }) => {
+ // Logout first
+ await page.goto('/wp-login.php?action=logout');
+ await page.click('text=log out');
+
+ // Attempt to access order summary page directly
+ await page.goto('/order-summary/?order_id=1');
+
+ // Should redirect to login page
+ await expect(page.locator('text=Authentication Required')).toBeVisible();
+ await expect(page.locator('text=Please log in to view the order summary')).toBeVisible();
+ await expect(page.locator('a', { hasText: 'Log In' })).toBeVisible();
+ });
+
+ test('should provide navigation back to event summary', async ({ page }) => {
+ // Find an event and navigate to its summary
+ await page.goto('/hvac-dashboard/');
+ const eventLinks = await page.$$('a[href*="event-summary"]');
+ if (eventLinks.length === 0) {
+ test.skip('No events with ticket sales found');
+ }
+
+ await eventLinks[0].click();
+ await expect(page).toHaveURL(/.*event-summary.*/);
+
+ // Get the event ID from the URL
+ const url = page.url();
+ const eventId = url.match(/event_id=(\d+)/)[1];
+
+ // Look for order links and navigate to an order
+ const orderLink = await page.$('a[href*="order-summary"]');
+ if (!orderLink) {
+ test.skip('No orders found for this event');
+ }
+
+ await orderLink.click();
+ await expect(page).toHaveURL(/.*order-summary.*/);
+
+ // Check for "Back to Event Summary" link
+ const backLink = page.locator('a', { hasText: 'Back to Event Summary' });
+ await expect(backLink).toBeVisible();
+
+ // Click the link and verify it goes back to the event summary
+ await backLink.click();
+ await expect(page).toHaveURL(new RegExp(`.*event-summary.*event_id=${eventId}`));
+ });
+});
\ No newline at end of file
diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/community/class-order-summary-data.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/community/class-order-summary-data.php
index 9dbe43e6..c8fcebc6 100644
--- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/community/class-order-summary-data.php
+++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/includes/community/class-order-summary-data.php
@@ -23,6 +23,13 @@ class HVAC_Order_Summary_Data {
* @var object|null
*/
private $order_object = null;
+
+ /**
+ * Array of event IDs associated with this order
+ *
+ * @var array
+ */
+ private $event_ids = [];
/**
* Constructor.
@@ -32,6 +39,11 @@ class HVAC_Order_Summary_Data {
public function __construct( $order_id ) {
$this->order_id = absint( $order_id );
$this->order_object = $this->load_order_object( $this->order_id );
+
+ // Load associated events
+ if ($this->is_valid_order()) {
+ $this->event_ids = $this->get_associated_events();
+ }
}
/**
@@ -48,7 +60,13 @@ class HVAC_Order_Summary_Data {
return $order;
}
}
+
// Event Tickets RSVP/Tribe order (fallback)
+ if ( class_exists( 'Tribe__Tickets__RSVP' ) ) {
+ // Implementation depends on how RSVP orders are stored
+ // This is a placeholder for potential RSVP orders
+ }
+
// Add additional logic for other ticket providers if needed
return null;
}
@@ -61,6 +79,66 @@ class HVAC_Order_Summary_Data {
public function is_valid_order() {
return ! is_null( $this->order_object );
}
+
+ /**
+ * Check if the current user has permission to view this order.
+ * Users can only view orders for events they created.
+ *
+ * @return bool
+ */
+ public function user_can_view_order() {
+ // User must be logged in
+ if (!is_user_logged_in()) {
+ return false;
+ }
+
+ // Order must be valid
+ if (!$this->is_valid_order()) {
+ return false;
+ }
+
+ // Admin users can view all orders
+ if (current_user_can('manage_options')) {
+ return true;
+ }
+
+ // Get the current user ID
+ $current_user_id = get_current_user_id();
+
+ // Check if the user is the author of any of the events in this order
+ foreach ($this->event_ids as $event_id) {
+ $event = get_post($event_id);
+ if ($event && $event->post_author == $current_user_id) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get event IDs associated with this order.
+ *
+ * @return array Array of event IDs
+ */
+ public function get_associated_events() {
+ $event_ids = [];
+
+ // Get attendees for this order
+ $attendees = [];
+ if (function_exists('tribe_tickets_get_order_attendees')) {
+ $attendees = tribe_tickets_get_order_attendees($this->order_id);
+ }
+
+ // Extract event IDs from attendees
+ foreach ($attendees as $attendee) {
+ if (isset($attendee['event_id'])) {
+ $event_ids[] = absint($attendee['event_id']);
+ }
+ }
+
+ return array_unique($event_ids);
+ }
/**
* Get basic order details.
@@ -81,6 +159,10 @@ class HVAC_Order_Summary_Data {
'total_price' => null,
'status' => null,
'tickets' => [],
+ 'events' => [],
+ 'billing_address' => null,
+ 'payment_method' => null,
+ 'organization' => null,
];
// WooCommerce order details
@@ -89,9 +171,30 @@ class HVAC_Order_Summary_Data {
$details['purchaser_name'] = $this->order_object->get_billing_first_name() . ' ' . $this->order_object->get_billing_last_name();
$details['purchaser_email']= $this->order_object->get_billing_email();
$details['purchase_date'] = $this->order_object->get_date_created() ? $this->order_object->get_date_created()->date( 'Y-m-d H:i:s' ) : null;
- $details['total_price'] = $this->order_object->get_total();
+ $details['total_price'] = $this->order_object->get_formatted_order_total();
$details['status'] = $this->order_object->get_status();
$details['tickets'] = $this->get_order_tickets();
+ $details['events'] = $this->get_event_details();
+
+ // Get billing address
+ $address_parts = [
+ $this->order_object->get_billing_address_1(),
+ $this->order_object->get_billing_address_2(),
+ $this->order_object->get_billing_city(),
+ $this->order_object->get_billing_state(),
+ $this->order_object->get_billing_postcode(),
+ $this->order_object->get_billing_country()
+ ];
+
+ // Filter out empty address parts and join
+ $address_parts = array_filter($address_parts);
+ $details['billing_address'] = implode(', ', $address_parts);
+
+ // Get payment method
+ $details['payment_method'] = $this->order_object->get_payment_method_title();
+
+ // Get organization (company name)
+ $details['organization'] = $this->order_object->get_billing_company();
}
// Add additional providers here if needed
@@ -108,13 +211,18 @@ class HVAC_Order_Summary_Data {
$tickets = [];
// WooCommerce + Event Tickets Plus
- if ( $this->order_object instanceof WC_Order && function_exists( 'Tribe__Tickets_Plus__Commerce__WooCommerce__Main' ) ) {
+ if ( $this->order_object instanceof WC_Order && function_exists( 'tribe_tickets_get_order_attendees' ) ) {
$order_id = $this->order_id;
- $attendees = function_exists( 'tribe_tickets_get_order_attendees' )
- ? tribe_tickets_get_order_attendees( $order_id )
- : [];
+ $attendees = tribe_tickets_get_order_attendees( $order_id );
foreach ( $attendees as $attendee ) {
+ $event_id = $attendee['event_id'] ?? null;
+ $event_title = '';
+
+ if ($event_id) {
+ $event_title = get_the_title($event_id);
+ }
+
$tickets[] = [
'attendee_id' => $attendee['attendee_id'] ?? null,
'ticket_type' => $attendee['ticket_name'] ?? null,
@@ -123,7 +231,10 @@ class HVAC_Order_Summary_Data {
'attendee_email' => $attendee['holder_email'] ?? null,
'security_code' => $attendee['security_code'] ?? null,
'checked_in' => isset( $attendee['check_in'] ) ? (bool) $attendee['check_in'] : false,
- // Add other fields as needed
+ 'event_id' => $event_id,
+ 'event_title' => $event_title,
+ 'price' => $attendee['price'] ?? $attendee['price_paid'] ?? null,
+ 'additional_fields' => $this->get_attendee_additional_fields($attendee),
];
}
}
@@ -132,4 +243,101 @@ class HVAC_Order_Summary_Data {
return $tickets;
}
+
+ /**
+ * Get details of events associated with this order.
+ *
+ * @return array
+ */
+ public function get_event_details() {
+ $events = [];
+
+ foreach ($this->event_ids as $event_id) {
+ $event = get_post($event_id);
+ if (!$event) {
+ continue;
+ }
+
+ $event_data = [
+ 'id' => $event_id,
+ 'title' => $event->post_title,
+ 'permalink' => get_permalink($event_id),
+ 'start_date' => null,
+ 'end_date' => null,
+ 'venue' => null,
+ ];
+
+ // Add Event Calendar specific data if available
+ if (function_exists('tribe_get_start_date')) {
+ $event_data['start_date'] = tribe_get_start_date($event_id, false);
+ $event_data['end_date'] = tribe_get_end_date($event_id, false);
+
+ if (function_exists('tribe_get_venue')) {
+ $event_data['venue'] = tribe_get_venue($event_id);
+ }
+ }
+
+ $events[] = $event_data;
+ }
+
+ return $events;
+ }
+
+ /**
+ * Get additional fields for an attendee.
+ * These could be custom fields collected during checkout.
+ *
+ * @param array $attendee The attendee data
+ * @return array
+ */
+ private function get_attendee_additional_fields($attendee) {
+ $additional_fields = [];
+
+ // Check for meta data stored with the attendee
+ if (isset($attendee['attendee_meta']) && is_array($attendee['attendee_meta'])) {
+ foreach ($attendee['attendee_meta'] as $key => $value) {
+ // Skip internal or empty fields
+ if (strpos($key, '_') === 0 || empty($value)) {
+ continue;
+ }
+
+ // Format field name for display
+ $field_name = ucwords(str_replace(['_', '-'], ' ', $key));
+
+ $additional_fields[$key] = [
+ 'label' => $field_name,
+ 'value' => $value
+ ];
+ }
+ }
+
+ return $additional_fields;
+ }
+
+ /**
+ * Get order notes.
+ *
+ * @return array
+ */
+ public function get_order_notes() {
+ $notes = [];
+
+ if ($this->order_object instanceof WC_Order && function_exists('wc_get_order_notes')) {
+ $raw_notes = wc_get_order_notes([
+ 'order_id' => $this->order_id,
+ 'type' => 'customer',
+ ]);
+
+ foreach ($raw_notes as $note) {
+ $notes[] = [
+ 'id' => $note->id,
+ 'content' => $note->content,
+ 'date' => $note->date_created->date('Y-m-d H:i:s'),
+ 'author' => $note->added_by,
+ ];
+ }
+ }
+
+ return $notes;
+ }
}
\ No newline at end of file
diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/event-summary/template-event-summary.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/event-summary/template-event-summary.php
index dcce773f..7c06352b 100644
--- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/event-summary/template-event-summary.php
+++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/event-summary/template-event-summary.php
@@ -263,11 +263,27 @@ get_header();
- |
+
+
+
+
+
+
+
+
+ |
|
|
$ |
- |
+
+
+
+
+
+
+
+
+ |
|
diff --git a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/single-hvac-order-summary.php b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/single-hvac-order-summary.php
index dfa68c36..07ce49bf 100644
--- a/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/single-hvac-order-summary.php
+++ b/wordpress-dev/wordpress/wp-content/plugins/hvac-community-events/templates/single-hvac-order-summary.php
@@ -22,93 +22,482 @@ if ( ! class_exists( 'HVAC_Order_Summary_Data' ) ) {
}
}
+// Check if user is logged in
+if ( ! is_user_logged_in() ) {
+ get_header();
+ echo '';
+ echo '
';
+ echo '';
+ echo '
Authentication Required
';
+ echo '
Please log in to view the order summary.
';
+ echo '
Log In
';
+ echo '
';
+ echo ' ';
+ get_footer();
+ exit;
+}
+
+// Get order ID from query var or context
+$order_id = isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : 0;
+
+if ( $order_id <= 0 ) {
+ get_header();
+ echo '';
+ echo '
';
+ echo 'No order specified. Please return to your dashboard.
';
+ echo 'Return to Dashboard
';
+ echo ' ';
+ get_footer();
+ exit;
+}
+
+// Initialize order data handler
+$order_summary = new HVAC_Order_Summary_Data( $order_id );
+
+// Check if order is valid and user has permission to view it
+if ( ! $order_summary->is_valid_order() || ! $order_summary->user_can_view_order() ) {
+ get_header();
+ echo '';
+ echo '
';
+ echo 'Order not found or you do not have permission to view this order.
';
+ echo 'Return to Dashboard
';
+ echo ' ';
+ get_footer();
+ exit;
+}
+
+// Get order data
+$order_details = $order_summary->get_order_details();
+$tickets = $order_details['tickets'];
+$events = $order_details['events'];
+$notes = $order_summary->get_order_notes();
+
get_header();
-
?>
->
+
+
+
+
+
+
+
+
+ Order Overview
+
+
+
+
+
+ | Order Number: |
+ |
+
+
+ | Purchaser: |
+
+
+
+
+
+ |
+
+
+
+ | Organization: |
+ |
+
+
+
+ | Purchase Date: |
+ |
+
+
+ | Status: |
+ |
+
+
+ | Total Price: |
+ |
+
+
+
+ | Payment Method: |
+ |
+
+
+
+
+ | Billing Address: |
+ |
+
+
+
+
+
+
+
+
+
+
+ Events
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tickets & Attendees
+
+
+
+
+
+ | Attendee |
+ Email |
+ Ticket Type |
+ Event |
+ Price |
+ Status |
+
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+ |
+ |
+ |
+
+
+
+
+
+ Additional Information
+
+
+ |
+
+
+
+
+
+
+
No tickets or attendees found for this order.
+
+
+
+
+
+
+
+
+
+
+
-
-
- 0 ) {
- $order_summary = new HVAC_Order_Summary_Data( $order_id );
-
- if ( $order_summary->is_valid_order() ) {
- $order_details = $order_summary->get_order_details();
- $tickets = $order_details['tickets'];
- ?>
-
>
-
-
-
-
-
- Order Details
-
- - Order Number:
- - Purchaser Name:
- - Purchaser Email:
- - Purchase Date:
- - Total Price:
- - Status:
-
-
-
-
- Tickets / Attendees
-
-
-
-
- | Attendee Name |
- Attendee Email |
- Ticket Type |
- Checked In |
- Security Code |
-
-
-
-
-
- |
- |
- |
- |
- |
-
-
-
-
-
- No tickets or attendees found for this order.
-
-
-
-
- Order not found or you do not have permission to view this order.";
- }
- } else {
- echo "
No order specified.
";
- }
- ?>
-
-
-
-
+
\ No newline at end of file