PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.7
VikBooking Hotel Booking Engine & PMS v1.8.7
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / helpers / src / mail / parser.php

parser.php in VikBooking Hotel Booking Engine & PMS 1.8.7, at admin/helpers/src/mail/parser.php

264 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Parses the email content for special elements.
16 *
17 * @since 1.5.5
18 */
19 final class VBOMailParser
20 {
21 /**
22 * @var string the default mail wrapper regex pattern (HTML tag in visual editor)
23 */
24 private static $wrapper_pattern = "/<hr class=\"vbo-editor-hl-mailwrapper\"\s*\/?>/";
25
26 /**
27 * Applies a common method for replacing the special tags within a content.
28 * This will NOT include the conditional text rule tags.
29 *
30 * @param string $content The content to parse.
31 * @param array $booking Booking record.
32 * @param array $booking_rooms List of rooms booked.
33 * @param array $customer Optional customer record.
34 *
35 * @return string
36 *
37 * @since 1.17.6 (J) - 1.7.6 (WP)
38 */
39 public static function replaceSpecialTags(string $content, array $booking, array $booking_rooms, array $customer = [])
40 {
41 if (!$booking || empty($booking['id'])) {
42 return $content;
43 }
44
45 if (!$booking_rooms) {
46 $booking_rooms = VikBooking::loadOrdersRoomsData($booking['id']);
47 }
48
49 if (!$customer) {
50 $customer = VikBooking::getCPinInstance()->getCustomerFromBooking($booking['id']);
51 }
52
53 // build and set customer name
54 $booking['customer_name'] = implode(' ', array_filter([($customer['first_name'] ?? ''), ($customer['last_name'] ?? '')]));
55
56 $vbo_df = VikBooking::getDateFormat();
57 $datesep = VikBooking::getDateSeparator();
58 $df = $vbo_df == "%d/%m/%Y" ? 'd/m/Y' : ($vbo_df == "%m/%d/%Y" ? 'm/d/Y' : 'Y-m-d');
59
60 $content = str_replace('{customer_name}', $booking['customer_name'], $content);
61 $content = str_replace('{booking_id}', $booking['id'], $content);
62 $content = str_replace('{checkin_date}', date(str_replace("/", $datesep, $df), $booking['checkin']), $content);
63 $content = str_replace('{checkout_date}', date(str_replace("/", $datesep, $df), $booking['checkout']), $content);
64 $content = str_replace('{num_nights}', $booking['days'], $content);
65
66 $rooms_booked = [];
67 $tot_adults = 0;
68 $tot_children = 0;
69 $tot_guests = 0;
70 foreach ($booking_rooms as $broom) {
71 if (isset($rooms_booked[$broom['room_name']])) {
72 $rooms_booked[$broom['room_name']] += 1;
73 } else {
74 $rooms_booked[$broom['room_name']] = 1;
75 }
76 $tot_adults += (int) $broom['adults'];
77 $tot_children += (int) $broom['children'];
78 $tot_guests += ((int) $broom['adults'] + (int) $broom['children']);
79 }
80 $content = str_replace('{tot_adults}', $tot_adults, $content);
81 $content = str_replace('{tot_children}', $tot_children, $content);
82 $content = str_replace('{tot_guests}', $tot_guests, $content);
83
84 $rooms_booked_quant = [];
85 foreach ($rooms_booked as $rname => $quant) {
86 $rooms_booked_quant[] = ($quant > 1 ? $quant.' ' : '').$rname;
87 }
88 $content = str_replace('{rooms_booked}', implode(', ', $rooms_booked_quant), $content);
89
90 $content = str_replace('{currency}', VikBooking::getCurrencySymb(), $content);
91 if (isset($booking['total'])) {
92 $content = str_replace('{total}', VikBooking::numberFormat($booking['total']), $content);
93 }
94 if (isset($booking['totpaid'])) {
95 $content = str_replace('{total_paid}', VikBooking::numberFormat($booking['totpaid']), $content);
96 }
97 if (isset($booking['total']) && isset($booking['totpaid'])) {
98 // calculate the outstanding balance
99 $remaining_bal = $booking['total'] - $booking['totpaid'];
100 $damage_deposit_payment = VBORoomHelper::getInstance()->getDamageDepositSplitPayment($booking, $booking_rooms);
101 $prev_dd_payments = [];
102 if ($damage_deposit_payment['damagedep_gross'] ?? 0) {
103 $prev_dd_payments = VikBooking::getBookingHistoryInstance($booking['id'])
104 ->getEventsWithData('PN', function($data) {
105 return (is_object($data) && !empty($data->damage_deposit));
106 });
107 if (!$prev_dd_payments) {
108 // check also the first payment event in case of OTA bookings
109 $prev_dd_payments = VikBooking::getBookingHistoryInstance($booking['id'])
110 ->getEventsWithData('P0', function($data) {
111 return (is_object($data) && !empty($data->damage_deposit));
112 });
113 }
114 }
115 if ($prev_dd_payments && !empty($booking['tot_damage_dep'])) {
116 $remaining_bal -= $booking['tot_damage_dep'];
117 }
118 $content = str_replace('{remaining_balance}', VikBooking::numberFormat($remaining_bal), $content);
119 }
120
121 if ($customer['pin'] ?? '') {
122 $content = str_replace('{customer_pin}', $customer['pin'], $content);
123 }
124
125 $use_sid = empty($booking['sid']) && !empty($booking['idorderota']) ? $booking['idorderota'] : $booking['sid'];
126 $bestitemid = VikBooking::findProperItemIdType(['booking'], (!empty($booking['lang']) ? $booking['lang'] : null));
127 $lang_suffix = $bestitemid && !empty($booking['lang']) ? '&lang=' . $booking['lang'] : '';
128 $book_link = VikBooking::externalroute("index.php?option=com_vikbooking&view=booking&sid=" . $use_sid . "&ts=" . $booking['ts'] . $lang_suffix, false, (!empty($bestitemid) ? $bestitemid : null));
129
130 // access the model for shortening URLs
131 $model = VBOModelShortenurl::getInstance($onlyRouted = true)->setBooking($booking);
132
133 $content = str_replace('{booking_link}', $model->getShortUrl($book_link), $content);
134
135 // rooms distinctive features parsing
136 preg_match_all('/\{roomfeature ([a-zA-Z0-9 ]+)\}/U', $content, $matches);
137 if (isset($matches[1]) && $matches[1]) {
138 foreach ($matches[1] as $reqf) {
139 $rooms_features = [];
140 foreach ($booking_rooms as $broom) {
141 $distinctive_features = [];
142 $rparams = !empty($broom['params']) && is_string($broom['params']) ? ((array) json_decode($broom['params'], true)) : [];
143 if (($rparams['features'] ?? []) && ($broom['roomindex'] ?? '') && ($rparams['features'][$broom['roomindex']] ?? [])) {
144 $distinctive_features = $rparams['features'][$broom['roomindex']];
145 }
146 if (!$distinctive_features) {
147 continue;
148 }
149 $feature_found = false;
150 foreach ($distinctive_features as $dfk => $dfv) {
151 if (stripos($dfk, $reqf) !== false) {
152 $feature_found = $dfk;
153 if (strlen(trim($dfk)) == strlen(trim($reqf))) {
154 break;
155 }
156 }
157 }
158 if ($feature_found !== false && strlen((string) $distinctive_features[$feature_found])) {
159 $rooms_features[] = $distinctive_features[$feature_found];
160 }
161 }
162 if ($rooms_features) {
163 $rpval = implode(', ', $rooms_features);
164 } else {
165 $rpval = '';
166 }
167 $content = str_replace("{roomfeature " . $reqf . "}", $rpval, $content);
168 }
169 }
170
171 /**
172 * Parse all Door Access Control tags.
173 *
174 * @since 1.18.4 (J) - 1.8.4 (WP)
175 */
176 VBOFactory::getDoorAccessControl()
177 ->parseTokens((new VBOBookingRegistry($booking, $booking_rooms)), $content);
178
179 return $content;
180 }
181
182 /**
183 * Checks for any content wrapper HTML tags applied through
184 * the Visual Editor during the composing of an email message.
185 *
186 * @param string $content the full email content.
187 *
188 * @return string
189 */
190 public static function checkWrapperSymbols($content)
191 {
192 $chunks = preg_split(static::$wrapper_pattern, (string)$content);
193
194 if (count($chunks) < 2) {
195 // no content wrapper used in email message
196 return $content;
197 }
198
199 $layout_opening = self::getWrapperLayout(true);
200 $layout_closing = self::getWrapperLayout(false);
201
202 $final_content = '';
203 foreach ($chunks as $piece => $part) {
204 $is_even = ($piece === 0 || (($piece % 2) === 0));
205 if (strlen(trim($part)) && !$is_even) {
206 $final_content .= $layout_opening . $part . $layout_closing;
207 } else {
208 $final_content .= $part;
209 }
210 }
211
212 return $final_content;
213 }
214
215 /**
216 * Returns the current mail wrapper layout HTML code.
217 *
218 * @param bool $opening whether to get the opening or closing HTML.
219 *
220 * @return string
221 */
222 public static function getWrapperLayout($opening = true)
223 {
224 // configuration field name
225 $opt_name = 'mail_wrapper_layout_' . ($opening ? 'opening' : 'closing');
226
227 // access the configuration object
228 $config = VBOFactory::getConfig();
229
230 // get the current configuration value
231 $layout = $config->get($opt_name);
232
233 if (!$layout) {
234 // set and get default layout
235 $layout = self::getWrapperDefaultLayout($opening);
236 $config->set($opt_name, $layout);
237 }
238
239 return $layout;
240 }
241
242 /**
243 * Returns the default mail wrapper layout HTML code.
244 *
245 * @param bool $opening whether to get the opening or closing HTML.
246 *
247 * @return string
248 */
249 private static function getWrapperDefaultLayout($opening = true)
250 {
251 $layout_opening = "\n";
252 $layout_opening .= "<div style=\"background: #fdfdfd;padding: 30px 0;\">";
253 $layout_opening .= "\n\t";
254 $layout_opening .= "<div style=\"max-width: 600px;margin: 0 auto;background: #fff;padding: 30px;border: 1px solid #eee;border-radius: 6px\">";
255 $layout_opening .= "\n";
256
257 $layout_closing = "\n";
258 $layout_closing .= "\t</div>\n";
259 $layout_closing .= "</div>\n";
260
261 return $opening ? $layout_opening : $layout_closing;
262 }
263 }
264