/** * Adjusts global stock levels for any of the products that were just purchased. * * Expects to fire during the 'event_tickets_edd_tickets_purchased_inventory_recorded' action. * * @param array $quantities */ public function adjust_stock_levels(array $quantities) { foreach ($quantities as $ticket_id => $amount_purchased) { $ticket_id = absint($ticket_id); $event = tribe_events_get_ticket_event($ticket_id); $global_stock = new Tribe__Tickets__Global_Stock($event->ID); // We're only interested if the ticket utilizes global stock if (!$global_stock->is_enabled()) { continue; } // Try to load the actual ticket object $tickets = $this->get_event_tickets($event->ID); // Move on if we couldn't obtain the ticket object if (empty($tickets[$ticket_id])) { continue; } switch ($tickets[$ticket_id]->global_stock_mode()) { // Reduce the cap in line with the number of capped tickets that were purchased, if any case Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE: $original_level = $tickets[$ticket_id]->global_stock_cap(); update_post_meta($ticket_id, '_global_stock_cap', $original_level - $amount_purchased); // Fall-through is deliberate - capped sales still draw from the global inventory pool // Fall-through is deliberate - capped sales still draw from the global inventory pool case Tribe__Tickets__Global_Stock::GLOBAL_STOCK_MODE: $original_level = $global_stock->get_stock_level(); $global_stock->set_stock_level($original_level - $amount_purchased); break; } } }
/** * Gets the "tickets sold" message for a given ticket * * @param Tribe__Tickets__Ticket_Object $ticket Ticket to analyze * * @return string */ function tribe_tickets_get_ticket_stock_message(Tribe__Tickets__Ticket_Object $ticket) { $stock = $ticket->stock(); $sold = $ticket->qty_sold(); $cancelled = $ticket->qty_cancelled(); $pending = $ticket->qty_pending(); $event = Tribe__Tickets__Tickets::find_matching_event($ticket); $global_stock = new Tribe__Tickets__Global_Stock($event->ID); $is_global = Tribe__Tickets__Global_Stock::GLOBAL_STOCK_MODE === $ticket->global_stock_mode(); $is_capped = Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE === $ticket->global_stock_mode(); $stock_cap = $ticket->global_stock_cap(); // If ticket sales are capped, do not suggest that more than the cap amount are available if ($is_capped && $stock > $stock_cap) { $stock = $stock_cap; } // If it is a global-stock ticket but the global stock level has not yet been set for the event // then return something better than just '0' as the available stock if ($is_global && 0 === $stock && !$global_stock->is_enabled()) { $stock = '<i>' . __('global inventory', 'event-tickets') . '</i>'; } // There may not be a fixed inventory - in which case just report the number actually sold so far if (empty($stock) && $stock !== 0) { $message = sprintf(esc_html__('Sold %d', 'event-tickets'), esc_html($sold)); } else { $cancelled_count = empty($cancelled) ? '' : esc_html(sprintf(_x(' cancelled: %1$d', 'ticket stock message (cancelled stock)', 'event-tickets'), (int) $cancelled)); $pending_count = $pending < 1 ? '' : esc_html(sprintf(__(' pending: %1$d', 'ticket stock message (pending stock)', 'event-tickets'), (int) $pending)); $message = sprintf(esc_html__('Sold %1$d (units remaining: %2$s%3$s%4$s)', 'event-tickets'), esc_html($sold), $stock, $cancelled_count, $pending_count); } return $message; }
/** * When WooCommerce reduces stock levels during order processing we need to look * for global stock tickets and ensure we "equalize" the total stock levels/sales * caps as appropriate. * * @param WC_Order $order */ public function stock_equalize(WC_Order $order) { $woo_tickets = Tribe__Tickets_Plus__Commerce__WooCommerce__Main::get_instance(); $total_ordered = array(); $capped_tickets = array(); // Get the total quantity of global stock ordered per event foreach ($order->get_items() as $item) { $product = $order->get_product_from_item($item); $event = $woo_tickets->get_event_for_ticket($product->id); $global_stock = new Tribe__Tickets__Global_Stock($event->ID); // Skip non-tickets or tickets that do not utilize global stock if (!$event || !$global_stock->is_enabled() || !$product->managing_stock()) { continue; } $ticket = $woo_tickets->get_ticket($event->ID, $product->id); switch ($ticket->global_stock_mode()) { case Tribe__Tickets__Global_Stock::CAPPED_STOCK_MODE: $capped_tickets[$product->id] = (int) $item['qty']; // Deliberate fallthrough - $total_ordered should accumulate capped *and* global quantities // Deliberate fallthrough - $total_ordered should accumulate capped *and* global quantities case Tribe__Tickets__Global_Stock::GLOBAL_STOCK_MODE: $total_ordered[$event->ID] += (int) $item['qty']; } } // For each ticket product that utilizes global stock, adjust the product inventory foreach ($total_ordered as $event_id => $quantity_ordered) { $global_stock = new Tribe__Tickets__Global_Stock($event_id); $level = $global_stock->get_stock_level(); $new_level = $level - $quantity_ordered; $global_stock->set_stock_level($new_level); $this->stock_update_global_tickets($event_id, $new_level); } // Now adjust sale caps foreach ($capped_tickets as $ticket_id => $reduce_by) { $event = $woo_tickets->get_event_for_ticket($ticket_id); $ticket = $woo_tickets->get_ticket($event->ID, $ticket_id); $current = $ticket->global_stock_cap(); $new_cap = $current - $reduce_by; $ticket->global_stock_cap($new_cap); update_post_meta($ticket_id, '_global_stock_cap', $new_cap); } }
/** * Determine if the event is set to use global stock for its tickets. * * @param int $event_id * * @return bool */ public function uses_global_stock($event_id) { // In some cases (version mismatch with Event Tickets) the Global Stock class may not be available if (!class_exists('Tribe__Tickets__Global_Stock')) { return false; } $global_stock = new Tribe__Tickets__Global_Stock($event_id); return $global_stock->is_enabled(); }