/** * Calculate costs from posted values * @param array $posted * @return string cost */ public function calculate_booking_cost($posted) { if (!empty($this->booking_cost)) { return $this->booking_cost; } // Get costs $costs = $this->product->get_costs(); // Get posted data $data = $this->get_posted_data($posted); $validate = $this->is_bookable($data); if (is_wp_error($validate)) { return $validate; } $base_cost = max(0, $this->product->wc_booking_cost); $base_block_cost = max(0, $this->product->wc_booking_base_cost); $total_block_cost = 0; $person_block_costs = 0; // See if we have an auto_assigned_resource_id if (isset($this->auto_assigned_resource_id)) { $data['_resource_id'] = $this->auto_assigned_resource_id; } // Get resource cost if (isset($data['_resource_id'])) { $resource = $this->product->get_resource($data['_resource_id']); $base_block_cost += $resource->get_block_cost(); $base_cost += $resource->get_base_cost(); } // Potentially increase costs if dealing with persons if (!empty($data['_persons'])) { if ($this->product->has_person_types()) { foreach ($data['_persons'] as $person_id => $person_count) { $person_cost = get_post_meta($person_id, 'cost', true); $person_block_cost = get_post_meta($person_id, 'block_cost', true); // Only a single cost - multiplication comes later if wc_booking_person_cost_multiplier is enabled if ($person_count > 0) { if ($person_cost > 0) { $base_cost += $person_cost * $person_count; } if ($person_block_cost > 0) { $person_block_costs += $person_block_cost * $person_count; } } } } } $this->applied_cost_rules = array(); $block_duration = $this->product->get_duration(); $block_unit = $this->product->get_duration_unit(); $blocks_booked = isset($data['_duration']) ? absint($data['_duration']) : $block_duration; $block_timestamp = $data['_start_date']; if ($this->product->is_duration_type('fixed')) { $blocks_booked = ceil($blocks_booked / $block_duration); } // Evaluate costs for each booked block for ($block = 0; $block < $blocks_booked; $block++) { $block_cost = $base_block_cost + $person_block_costs; $block_start_time_offset = $block * $block_duration; $block_end_time_offset = ($block + 1) * $block_duration; $block_start_time = $this->get_formatted_times(strtotime("+{$block_start_time_offset} {$block_unit}", $block_timestamp)); $block_end_time = $this->get_formatted_times(strtotime("+{$block_end_time_offset} {$block_unit}", $block_timestamp)); foreach ($costs as $rule_key => $rule) { $type = $rule[0]; $rules = $rule[1]; if (strrpos($type, 'time') === 0) { if (!in_array($this->product->get_duration_unit(), array('minute', 'hour'))) { continue; } if (!empty($rules['day'])) { if ($rules['day'] != $block_start_time['day_of_week']) { continue; } } $rule_start_time_hi = date("YmdHi", strtotime(str_replace(':', '', $rules['from']), $block_start_time['timestamp'])); $rule_end_time_hi = date("YmdHi", strtotime(str_replace(':', '', $rules['to']), $block_start_time['timestamp'])); $matched = false; // Reverse time rule - The end time is tomorrow e.g. 16:00 today - 12:00 tomorrow if ($rule_end_time_hi <= $rule_start_time_hi) { if ($block_end_time['time'] > $rule_start_time_hi) { $matched = true; } if ($block_start_time['time'] >= $rule_start_time_hi && $block_end_time['time'] >= $rule_end_time_hi) { $matched = true; } if ($block_start_time['time'] <= $rule_start_time_hi && $block_end_time['time'] <= $rule_end_time_hi) { $matched = true; } // Normal rule } else { if ($block_start_time['time'] >= $rule_start_time_hi && $block_end_time['time'] <= $rule_end_time_hi) { $matched = true; } } if ($matched) { $block_cost = $this->apply_cost($block_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_base_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1], $rule_key); } } else { switch ($type) { case 'months': case 'weeks': case 'days': $check_date = $block_start_time['timestamp']; while ($check_date < $block_end_time['timestamp']) { $checking_date = $this->get_formatted_times($check_date); $date_key = $type == 'days' ? 'day_of_week' : substr($type, 0, -1); if (isset($rules[$checking_date[$date_key]])) { $rule = $rules[$checking_date[$date_key]]; $block_cost = $this->apply_cost($block_cost, $rule['block'][0], $rule['block'][1]); $base_cost = $this->apply_base_cost($base_cost, $rule['base'][0], $rule['base'][1], $rule_key); } $check_date = strtotime("+1 {$type}", $check_date); } break; case 'custom': $check_date = $block_start_time['timestamp']; while ($check_date < $block_end_time['timestamp']) { $checking_date = $this->get_formatted_times($check_date); if (isset($rules[$checking_date['year']][$checking_date['month']][$checking_date['day']])) { $rule = $rules[$checking_date['year']][$checking_date['month']][$checking_date['day']]; $block_cost = $this->apply_cost($block_cost, $rule['block'][0], $rule['block'][1]); $base_cost = $this->apply_base_cost($base_cost, $rule['base'][0], $rule['base'][1], $rule_key); } $check_date = strtotime("+1 day", $check_date); } break; case 'persons': if (!empty($data['_persons'])) { if ($rules['from'] <= array_sum($data['_persons']) && $rules['to'] >= array_sum($data['_persons'])) { $block_cost = $this->apply_cost($block_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_base_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1], $rule_key); } } break; case 'blocks': if (!empty($data['_duration'])) { if ($rules['from'] <= $data['_duration'] && $rules['to'] >= $data['_duration']) { $block_cost = $this->apply_cost($block_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_base_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1], $rule_key); } } break; } } } $total_block_cost += $block_cost; } // Person multiplier mutliplies all costs $this->booking_cost = max(0, $total_block_cost + $base_cost); if (!empty($data['_persons'])) { if ('yes' === $this->product->wc_booking_person_cost_multiplier) { $this->booking_cost = $this->booking_cost * array_sum($data['_persons']); } } return apply_filters('booking_form_calculated_booking_cost', $this->booking_cost, $this, $posted); }
/** * Calculate costs from posted values * @param array $posted * @return string cost */ public function calculate_booking_cost($posted) { if (!empty($this->booking_cost)) { return $this->booking_cost; } // Base costs $base_cost = max(0, $this->product->wc_booking_cost); $booking_cost = max(0, $this->product->wc_booking_base_cost); // Get costs $costs = $this->product->get_costs(); // Get posted data $data = $this->get_posted_data($posted); $validate = $this->is_bookable($data); if (is_wp_error($validate)) { return $validate; } // See if we have an auto_assigned_resource_id if (isset($this->auto_assigned_resource_id)) { $data['_resource_id'] = $this->auto_assigned_resource_id; } // Get resource cost if (isset($data['_resource_id'])) { $resource = $this->product->get_resource($data['_resource_id']); $booking_cost += $resource->get_block_cost(); $base_cost += $resource->get_base_cost(); } // Get cost for date foreach ($costs as $rule) { $type = $rule[0]; $rules = $rule[1]; switch ($type) { case 'months': $check_date = $data['_start_date']; while ($check_date < $data['_end_date']) { $month = date('n', $check_date); if (isset($rules[$month])) { $booking_cost = $this->apply_cost($booking_cost, $rules[$month]['block'][0], $rules[$month]['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1]); break 2; } $check_date = strtotime("+1 day", $check_date); } break; case 'weeks': $check_date = $data['_start_date']; while ($check_date < $data['_end_date']) { $year = date('Y', $check_date); $month = date('n', $check_date); $day = date('j', $check_date); $week = absint(date('W', strtotime(implode('-', array($year, $month, $day))))); if (isset($rules[$week])) { $booking_cost = $this->apply_cost($booking_cost, $rules[$month]['block'][0], $rules[$month]['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules[$month]['base'][0], $rules[$month]['base'][1]); break 2; } $check_date = strtotime("+1 day", $check_date); } break; case 'days': $check_date = $data['_start_date']; while ($check_date < $data['_end_date']) { $year = date('Y', $check_date); $month = date('n', $check_date); $day = date('j', $check_date); $day_of_week = absint(date('N', strtotime(implode('-', array($year, $month, $day))))); if (isset($rules[$day_of_week])) { $booking_cost = $this->apply_cost($booking_cost, $rules[$day_of_week]['block'][0], $rules[$day_of_week]['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules[$day_of_week]['base'][0], $rules[$day_of_week]['base'][1]); break 2; } $check_date = strtotime("+1 day", $check_date); } break; case 'custom': $check_date = $data['_start_date']; while ($check_date < $data['_end_date']) { $year = date('Y', $check_date); $month = date('n', $check_date); $day = date('j', $check_date); if (isset($rules[$year][$month][$day])) { $booking_cost = $this->apply_cost($booking_cost, $rules[$year][$month][$day]['block'][0], $rules[$year][$month][$day]['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules[$year][$month][$day]['base'][0], $rules[$year][$month][$day]['base'][1]); break 2; } $check_date = strtotime("+1 day", $check_date); } break; case 'time': if (in_array($this->product->get_duration_unit(), array('minute', 'hour'))) { $booked_from = date("Hi", $data['_start_date']); $booked_to = date("Hi", $data['_end_date']); if ($booked_from >= str_replace(':', '', $rules['from']) && $booked_to <= str_replace(':', '', $rules['to'])) { $booking_cost = $this->apply_cost($booking_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1]); } } break; case 'persons': if (isset($data['_persons']) && $data['_persons']) { if ($rules['from'] <= array_sum($data['_persons']) && $rules['to'] >= array_sum($data['_persons'])) { $booking_cost = $this->apply_cost($booking_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1]); } } break; case 'blocks': if (isset($data['_duration']) && $data['_duration']) { if ($rules['from'] <= $data['_duration'] && $rules['to'] >= $data['_duration']) { $booking_cost = $this->apply_cost($booking_cost, $rules['rule']['block'][0], $rules['rule']['block'][1]); $base_cost = $this->apply_cost($base_cost, $rules['rule']['base'][0], $rules['rule']['base'][1]); } } break; } } if (!empty($data['_persons'])) { // Person multiplier mutliplies all costs if ('yes' === $this->product->wc_booking_person_cost_multiplier) { $booking_cost = $booking_cost * array_sum($data['_persons']); } // Add base costs for person types if there are any set if ($this->product->has_person_types()) { foreach ($data['_persons'] as $person_id => $person_count) { $person_cost = get_post_meta($person_id, 'cost', true); // Only a single cost - multiplication comes later if wc_booking_person_cost_multiplier is enabled if ($person_count > 0 && $person_cost > 0) { $booking_cost += $person_cost * $person_count; } } } } // Duration costs if (isset($data['_duration'])) { $booking_cost = $booking_cost * $data['_duration']; } $this->booking_cost = max(0, $booking_cost + $base_cost); return apply_filters('booking_form_calculated_booking_cost', $this->booking_cost, $this, $posted); }