@@ -28,602 +28,602 @@ |
||
| 28 | 28 | class EEM_Line_Item extends EEM_Base |
| 29 | 29 | { |
| 30 | 30 | |
| 31 | - /** |
|
| 32 | - * Tax sub-total is just the total of all the taxes, which should be children |
|
| 33 | - * of this line item. There should only ever be one tax sub-total, and it should |
|
| 34 | - * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
| 35 | - */ |
|
| 36 | - const type_tax_sub_total = 'tax-sub-total'; |
|
| 37 | - |
|
| 38 | - /** |
|
| 39 | - * Tax line items indicate a tax applied to all the taxable line items. |
|
| 40 | - * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
| 41 | - * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
| 42 | - */ |
|
| 43 | - const type_tax = 'tax'; |
|
| 44 | - |
|
| 45 | - /** |
|
| 46 | - * Indicating individual items purchased, or discounts or surcharges. |
|
| 47 | - * The sum of all the regular line items plus the tax items should equal the grand total. |
|
| 48 | - * Possible children are sub-line-items and cancellations. |
|
| 49 | - * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
| 50 | - * LIN_totals. Its LIN_percent = 0. |
|
| 51 | - * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
| 52 | - * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
| 53 | - */ |
|
| 54 | - const type_line_item = 'line-item'; |
|
| 55 | - |
|
| 56 | - /** |
|
| 57 | - * Line item indicating all the factors that make a single line item. |
|
| 58 | - * Sub-line items should have NO children line items. |
|
| 59 | - * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
| 60 | - * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
| 61 | - * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
| 62 | - * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
| 63 | - * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
| 64 | - */ |
|
| 65 | - const type_sub_line_item = 'sub-item'; |
|
| 66 | - |
|
| 67 | - /** |
|
| 68 | - * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
| 69 | - * Direct children should be event subtotals. |
|
| 70 | - * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
| 71 | - */ |
|
| 72 | - const type_sub_total = 'sub-total'; |
|
| 73 | - |
|
| 74 | - /** |
|
| 75 | - * Line item for the grand total of an order. |
|
| 76 | - * Its direct children should be tax subtotals and (pre-tax) subtotals, |
|
| 77 | - * and possibly a regular line item indicating a transaction-wide discount/surcharge. |
|
| 78 | - * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount. |
|
| 79 | - */ |
|
| 80 | - const type_total = 'total'; |
|
| 81 | - |
|
| 82 | - /** |
|
| 83 | - * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
| 84 | - * should be created, indicating the quantity that were cancelled |
|
| 85 | - * (because a line item could have a quantity of 1, and its cancellation item |
|
| 86 | - * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
| 87 | - * cancelled, and only one remains). |
|
| 88 | - * When items are refunded, a cancellation line item should be made, which points |
|
| 89 | - * to teh payment model object which actually refunded the payment. |
|
| 90 | - * Cancellations should NOT have any children line items; the should NOT affect |
|
| 91 | - * any calculations, and are only meant as a record that cancellations have occurred. |
|
| 92 | - * Their LIN_percent should be 0. |
|
| 93 | - */ |
|
| 94 | - const type_cancellation = 'cancellation'; |
|
| 95 | - |
|
| 96 | - // various line item object types |
|
| 97 | - const OBJ_TYPE_EVENT = 'Event'; |
|
| 98 | - |
|
| 99 | - const OBJ_TYPE_PRICE = 'Price'; |
|
| 100 | - |
|
| 101 | - const OBJ_TYPE_PROMOTION = 'Promotion'; |
|
| 102 | - |
|
| 103 | - const OBJ_TYPE_TICKET = 'Ticket'; |
|
| 104 | - |
|
| 105 | - const OBJ_TYPE_TRANSACTION = 'Transaction'; |
|
| 106 | - |
|
| 107 | - /** |
|
| 108 | - * @var EEM_Line_Item $_instance |
|
| 109 | - */ |
|
| 110 | - protected static $_instance; |
|
| 111 | - |
|
| 112 | - |
|
| 113 | - /** |
|
| 114 | - * private constructor to prevent direct creation |
|
| 115 | - * |
|
| 116 | - * @Constructor |
|
| 117 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
| 118 | - * (and any incoming timezone data that gets saved). |
|
| 119 | - * Note this just sends the timezone info to the date time model field objects. |
|
| 120 | - * Default is NULL |
|
| 121 | - * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
| 122 | - * @throws EE_Error |
|
| 123 | - * @throws InvalidArgumentException |
|
| 124 | - */ |
|
| 125 | - protected function __construct($timezone) |
|
| 126 | - { |
|
| 127 | - $this->singular_item = esc_html__('Line Item', 'event_espresso'); |
|
| 128 | - $this->plural_item = esc_html__('Line Items', 'event_espresso'); |
|
| 129 | - |
|
| 130 | - $this->_tables = array( |
|
| 131 | - 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'), |
|
| 132 | - ); |
|
| 133 | - $line_items_can_be_for = apply_filters( |
|
| 134 | - 'FHEE__EEM_Line_Item__line_items_can_be_for', |
|
| 135 | - array('Ticket', 'Price', 'Event') |
|
| 136 | - ); |
|
| 137 | - $this->_fields = array( |
|
| 138 | - 'Line_Item' => array( |
|
| 139 | - 'LIN_ID' => new EE_Primary_Key_Int_Field( |
|
| 140 | - 'LIN_ID', |
|
| 141 | - esc_html__('ID', 'event_espresso') |
|
| 142 | - ), |
|
| 143 | - 'LIN_code' => new EE_Slug_Field( |
|
| 144 | - 'LIN_code', |
|
| 145 | - esc_html__('Code for index into Cart', 'event_espresso'), |
|
| 146 | - true |
|
| 147 | - ), |
|
| 148 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 149 | - 'TXN_ID', |
|
| 150 | - esc_html__('Transaction ID', 'event_espresso'), |
|
| 151 | - true, |
|
| 152 | - null, |
|
| 153 | - 'Transaction' |
|
| 154 | - ), |
|
| 155 | - 'LIN_name' => new EE_Full_HTML_Field( |
|
| 156 | - 'LIN_name', |
|
| 157 | - esc_html__('Line Item Name', 'event_espresso'), |
|
| 158 | - false, |
|
| 159 | - '' |
|
| 160 | - ), |
|
| 161 | - 'LIN_desc' => new EE_Full_HTML_Field( |
|
| 162 | - 'LIN_desc', |
|
| 163 | - esc_html__('Line Item Description', 'event_espresso'), |
|
| 164 | - true |
|
| 165 | - ), |
|
| 166 | - 'LIN_unit_price' => new EE_Money_Field( |
|
| 167 | - 'LIN_unit_price', |
|
| 168 | - esc_html__('Unit Price', 'event_espresso'), |
|
| 169 | - false, |
|
| 170 | - 0 |
|
| 171 | - ), |
|
| 172 | - 'LIN_percent' => new EE_Float_Field( |
|
| 173 | - 'LIN_percent', |
|
| 174 | - esc_html__('Percent', 'event_espresso'), |
|
| 175 | - false, |
|
| 176 | - 0 |
|
| 177 | - ), |
|
| 178 | - 'LIN_is_taxable' => new EE_Boolean_Field( |
|
| 179 | - 'LIN_is_taxable', |
|
| 180 | - esc_html__('Taxable', 'event_espresso'), |
|
| 181 | - false, |
|
| 182 | - false |
|
| 183 | - ), |
|
| 184 | - 'LIN_order' => new EE_Integer_Field( |
|
| 185 | - 'LIN_order', |
|
| 186 | - esc_html__('Order of Application towards total of parent', 'event_espresso'), |
|
| 187 | - false, |
|
| 188 | - 1 |
|
| 189 | - ), |
|
| 190 | - 'LIN_total' => new EE_Money_Field( |
|
| 191 | - 'LIN_total', |
|
| 192 | - esc_html__('Total (unit price x quantity)', 'event_espresso'), |
|
| 193 | - false, |
|
| 194 | - 0 |
|
| 195 | - ), |
|
| 196 | - 'LIN_quantity' => new EE_Integer_Field( |
|
| 197 | - 'LIN_quantity', |
|
| 198 | - esc_html__('Quantity', 'event_espresso'), |
|
| 199 | - true, |
|
| 200 | - 1 |
|
| 201 | - ), |
|
| 202 | - 'LIN_parent' => new EE_Integer_Field( |
|
| 203 | - 'LIN_parent', |
|
| 204 | - esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'), |
|
| 205 | - true, |
|
| 206 | - null |
|
| 207 | - ), |
|
| 208 | - 'LIN_type' => new EE_Enum_Text_Field( |
|
| 209 | - 'LIN_type', |
|
| 210 | - esc_html__('Type', 'event_espresso'), |
|
| 211 | - false, |
|
| 212 | - 'line-item', |
|
| 213 | - array( |
|
| 214 | - self::type_line_item => esc_html__('Line Item', 'event_espresso'), |
|
| 215 | - self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'), |
|
| 216 | - self::type_sub_total => esc_html__('Subtotal', 'event_espresso'), |
|
| 217 | - self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'), |
|
| 218 | - self::type_tax => esc_html__('Tax', 'event_espresso'), |
|
| 219 | - self::type_total => esc_html__('Total', 'event_espresso'), |
|
| 220 | - self::type_cancellation => esc_html__('Cancellation', 'event_espresso'), |
|
| 221 | - ) |
|
| 222 | - ), |
|
| 223 | - 'OBJ_ID' => new EE_Foreign_Key_Int_Field( |
|
| 224 | - 'OBJ_ID', |
|
| 225 | - esc_html__('ID of Item purchased.', 'event_espresso'), |
|
| 226 | - true, |
|
| 227 | - null, |
|
| 228 | - $line_items_can_be_for |
|
| 229 | - ), |
|
| 230 | - 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
| 231 | - 'OBJ_type', |
|
| 232 | - esc_html__('Model Name this Line Item is for', 'event_espresso'), |
|
| 233 | - true, |
|
| 234 | - null, |
|
| 235 | - $line_items_can_be_for |
|
| 236 | - ), |
|
| 237 | - 'LIN_timestamp' => new EE_Datetime_Field( |
|
| 238 | - 'LIN_timestamp', |
|
| 239 | - esc_html__('When the line item was created', 'event_espresso'), |
|
| 240 | - false, |
|
| 241 | - EE_Datetime_Field::now, |
|
| 242 | - $timezone |
|
| 243 | - ), |
|
| 244 | - ), |
|
| 245 | - ); |
|
| 246 | - $this->_model_relations = array( |
|
| 247 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 248 | - 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
| 249 | - 'Price' => new EE_Belongs_To_Any_Relation(), |
|
| 250 | - 'Event' => new EE_Belongs_To_Any_Relation(), |
|
| 251 | - ); |
|
| 252 | - $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
| 253 | - $this->_caps_slug = 'transactions'; |
|
| 254 | - parent::__construct($timezone); |
|
| 255 | - } |
|
| 256 | - |
|
| 257 | - |
|
| 258 | - /** |
|
| 259 | - * Gets all the line items for this transaction of the given type |
|
| 260 | - * |
|
| 261 | - * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
| 262 | - * @param EE_Transaction|int $transaction |
|
| 263 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 264 | - * @throws EE_Error |
|
| 265 | - * @throws InvalidArgumentException |
|
| 266 | - * @throws InvalidDataTypeException |
|
| 267 | - * @throws InvalidInterfaceException |
|
| 268 | - */ |
|
| 269 | - public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
| 270 | - { |
|
| 271 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
| 272 | - return $this->get_all(array( |
|
| 273 | - array( |
|
| 274 | - 'LIN_type' => $line_item_type, |
|
| 275 | - 'TXN_ID' => $transaction, |
|
| 276 | - ), |
|
| 277 | - )); |
|
| 278 | - } |
|
| 279 | - |
|
| 280 | - |
|
| 281 | - /** |
|
| 282 | - * Gets all line items unrelated to tickets that are normal line items |
|
| 283 | - * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
| 284 | - * |
|
| 285 | - * @param EE_Transaction|int $transaction |
|
| 286 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 287 | - * @throws EE_Error |
|
| 288 | - * @throws InvalidArgumentException |
|
| 289 | - * @throws InvalidDataTypeException |
|
| 290 | - * @throws InvalidInterfaceException |
|
| 291 | - */ |
|
| 292 | - public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
| 293 | - { |
|
| 294 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
| 295 | - return $this->get_all(array( |
|
| 296 | - array( |
|
| 297 | - 'LIN_type' => self::type_line_item, |
|
| 298 | - 'TXN_ID' => $transaction, |
|
| 299 | - 'OR' => array( |
|
| 300 | - 'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET), |
|
| 301 | - 'OBJ_type*null' => array('IS_NULL'), |
|
| 302 | - ), |
|
| 303 | - ), |
|
| 304 | - )); |
|
| 305 | - } |
|
| 306 | - |
|
| 307 | - |
|
| 308 | - /** |
|
| 309 | - * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
| 310 | - * This needs to be very efficient |
|
| 311 | - * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when |
|
| 312 | - * deleting and joining tables like this. |
|
| 313 | - * |
|
| 314 | - * @return int count of how many deleted |
|
| 315 | - * @throws EE_Error |
|
| 316 | - * @throws InvalidArgumentException |
|
| 317 | - * @throws InvalidDataTypeException |
|
| 318 | - * @throws InvalidInterfaceException |
|
| 319 | - */ |
|
| 320 | - public function delete_line_items_with_no_transaction() |
|
| 321 | - { |
|
| 322 | - /** @type WPDB $wpdb */ |
|
| 323 | - global $wpdb; |
|
| 324 | - $time_to_leave_alone = apply_filters( |
|
| 325 | - 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
| 326 | - WEEK_IN_SECONDS |
|
| 327 | - ); |
|
| 328 | - $query = $wpdb->prepare( |
|
| 329 | - 'DELETE li |
|
| 31 | + /** |
|
| 32 | + * Tax sub-total is just the total of all the taxes, which should be children |
|
| 33 | + * of this line item. There should only ever be one tax sub-total, and it should |
|
| 34 | + * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
| 35 | + */ |
|
| 36 | + const type_tax_sub_total = 'tax-sub-total'; |
|
| 37 | + |
|
| 38 | + /** |
|
| 39 | + * Tax line items indicate a tax applied to all the taxable line items. |
|
| 40 | + * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
| 41 | + * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
| 42 | + */ |
|
| 43 | + const type_tax = 'tax'; |
|
| 44 | + |
|
| 45 | + /** |
|
| 46 | + * Indicating individual items purchased, or discounts or surcharges. |
|
| 47 | + * The sum of all the regular line items plus the tax items should equal the grand total. |
|
| 48 | + * Possible children are sub-line-items and cancellations. |
|
| 49 | + * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
| 50 | + * LIN_totals. Its LIN_percent = 0. |
|
| 51 | + * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
| 52 | + * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
| 53 | + */ |
|
| 54 | + const type_line_item = 'line-item'; |
|
| 55 | + |
|
| 56 | + /** |
|
| 57 | + * Line item indicating all the factors that make a single line item. |
|
| 58 | + * Sub-line items should have NO children line items. |
|
| 59 | + * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
| 60 | + * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
| 61 | + * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
| 62 | + * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
| 63 | + * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
| 64 | + */ |
|
| 65 | + const type_sub_line_item = 'sub-item'; |
|
| 66 | + |
|
| 67 | + /** |
|
| 68 | + * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
| 69 | + * Direct children should be event subtotals. |
|
| 70 | + * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
| 71 | + */ |
|
| 72 | + const type_sub_total = 'sub-total'; |
|
| 73 | + |
|
| 74 | + /** |
|
| 75 | + * Line item for the grand total of an order. |
|
| 76 | + * Its direct children should be tax subtotals and (pre-tax) subtotals, |
|
| 77 | + * and possibly a regular line item indicating a transaction-wide discount/surcharge. |
|
| 78 | + * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount. |
|
| 79 | + */ |
|
| 80 | + const type_total = 'total'; |
|
| 81 | + |
|
| 82 | + /** |
|
| 83 | + * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
| 84 | + * should be created, indicating the quantity that were cancelled |
|
| 85 | + * (because a line item could have a quantity of 1, and its cancellation item |
|
| 86 | + * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
| 87 | + * cancelled, and only one remains). |
|
| 88 | + * When items are refunded, a cancellation line item should be made, which points |
|
| 89 | + * to teh payment model object which actually refunded the payment. |
|
| 90 | + * Cancellations should NOT have any children line items; the should NOT affect |
|
| 91 | + * any calculations, and are only meant as a record that cancellations have occurred. |
|
| 92 | + * Their LIN_percent should be 0. |
|
| 93 | + */ |
|
| 94 | + const type_cancellation = 'cancellation'; |
|
| 95 | + |
|
| 96 | + // various line item object types |
|
| 97 | + const OBJ_TYPE_EVENT = 'Event'; |
|
| 98 | + |
|
| 99 | + const OBJ_TYPE_PRICE = 'Price'; |
|
| 100 | + |
|
| 101 | + const OBJ_TYPE_PROMOTION = 'Promotion'; |
|
| 102 | + |
|
| 103 | + const OBJ_TYPE_TICKET = 'Ticket'; |
|
| 104 | + |
|
| 105 | + const OBJ_TYPE_TRANSACTION = 'Transaction'; |
|
| 106 | + |
|
| 107 | + /** |
|
| 108 | + * @var EEM_Line_Item $_instance |
|
| 109 | + */ |
|
| 110 | + protected static $_instance; |
|
| 111 | + |
|
| 112 | + |
|
| 113 | + /** |
|
| 114 | + * private constructor to prevent direct creation |
|
| 115 | + * |
|
| 116 | + * @Constructor |
|
| 117 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
| 118 | + * (and any incoming timezone data that gets saved). |
|
| 119 | + * Note this just sends the timezone info to the date time model field objects. |
|
| 120 | + * Default is NULL |
|
| 121 | + * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
| 122 | + * @throws EE_Error |
|
| 123 | + * @throws InvalidArgumentException |
|
| 124 | + */ |
|
| 125 | + protected function __construct($timezone) |
|
| 126 | + { |
|
| 127 | + $this->singular_item = esc_html__('Line Item', 'event_espresso'); |
|
| 128 | + $this->plural_item = esc_html__('Line Items', 'event_espresso'); |
|
| 129 | + |
|
| 130 | + $this->_tables = array( |
|
| 131 | + 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'), |
|
| 132 | + ); |
|
| 133 | + $line_items_can_be_for = apply_filters( |
|
| 134 | + 'FHEE__EEM_Line_Item__line_items_can_be_for', |
|
| 135 | + array('Ticket', 'Price', 'Event') |
|
| 136 | + ); |
|
| 137 | + $this->_fields = array( |
|
| 138 | + 'Line_Item' => array( |
|
| 139 | + 'LIN_ID' => new EE_Primary_Key_Int_Field( |
|
| 140 | + 'LIN_ID', |
|
| 141 | + esc_html__('ID', 'event_espresso') |
|
| 142 | + ), |
|
| 143 | + 'LIN_code' => new EE_Slug_Field( |
|
| 144 | + 'LIN_code', |
|
| 145 | + esc_html__('Code for index into Cart', 'event_espresso'), |
|
| 146 | + true |
|
| 147 | + ), |
|
| 148 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 149 | + 'TXN_ID', |
|
| 150 | + esc_html__('Transaction ID', 'event_espresso'), |
|
| 151 | + true, |
|
| 152 | + null, |
|
| 153 | + 'Transaction' |
|
| 154 | + ), |
|
| 155 | + 'LIN_name' => new EE_Full_HTML_Field( |
|
| 156 | + 'LIN_name', |
|
| 157 | + esc_html__('Line Item Name', 'event_espresso'), |
|
| 158 | + false, |
|
| 159 | + '' |
|
| 160 | + ), |
|
| 161 | + 'LIN_desc' => new EE_Full_HTML_Field( |
|
| 162 | + 'LIN_desc', |
|
| 163 | + esc_html__('Line Item Description', 'event_espresso'), |
|
| 164 | + true |
|
| 165 | + ), |
|
| 166 | + 'LIN_unit_price' => new EE_Money_Field( |
|
| 167 | + 'LIN_unit_price', |
|
| 168 | + esc_html__('Unit Price', 'event_espresso'), |
|
| 169 | + false, |
|
| 170 | + 0 |
|
| 171 | + ), |
|
| 172 | + 'LIN_percent' => new EE_Float_Field( |
|
| 173 | + 'LIN_percent', |
|
| 174 | + esc_html__('Percent', 'event_espresso'), |
|
| 175 | + false, |
|
| 176 | + 0 |
|
| 177 | + ), |
|
| 178 | + 'LIN_is_taxable' => new EE_Boolean_Field( |
|
| 179 | + 'LIN_is_taxable', |
|
| 180 | + esc_html__('Taxable', 'event_espresso'), |
|
| 181 | + false, |
|
| 182 | + false |
|
| 183 | + ), |
|
| 184 | + 'LIN_order' => new EE_Integer_Field( |
|
| 185 | + 'LIN_order', |
|
| 186 | + esc_html__('Order of Application towards total of parent', 'event_espresso'), |
|
| 187 | + false, |
|
| 188 | + 1 |
|
| 189 | + ), |
|
| 190 | + 'LIN_total' => new EE_Money_Field( |
|
| 191 | + 'LIN_total', |
|
| 192 | + esc_html__('Total (unit price x quantity)', 'event_espresso'), |
|
| 193 | + false, |
|
| 194 | + 0 |
|
| 195 | + ), |
|
| 196 | + 'LIN_quantity' => new EE_Integer_Field( |
|
| 197 | + 'LIN_quantity', |
|
| 198 | + esc_html__('Quantity', 'event_espresso'), |
|
| 199 | + true, |
|
| 200 | + 1 |
|
| 201 | + ), |
|
| 202 | + 'LIN_parent' => new EE_Integer_Field( |
|
| 203 | + 'LIN_parent', |
|
| 204 | + esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'), |
|
| 205 | + true, |
|
| 206 | + null |
|
| 207 | + ), |
|
| 208 | + 'LIN_type' => new EE_Enum_Text_Field( |
|
| 209 | + 'LIN_type', |
|
| 210 | + esc_html__('Type', 'event_espresso'), |
|
| 211 | + false, |
|
| 212 | + 'line-item', |
|
| 213 | + array( |
|
| 214 | + self::type_line_item => esc_html__('Line Item', 'event_espresso'), |
|
| 215 | + self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'), |
|
| 216 | + self::type_sub_total => esc_html__('Subtotal', 'event_espresso'), |
|
| 217 | + self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'), |
|
| 218 | + self::type_tax => esc_html__('Tax', 'event_espresso'), |
|
| 219 | + self::type_total => esc_html__('Total', 'event_espresso'), |
|
| 220 | + self::type_cancellation => esc_html__('Cancellation', 'event_espresso'), |
|
| 221 | + ) |
|
| 222 | + ), |
|
| 223 | + 'OBJ_ID' => new EE_Foreign_Key_Int_Field( |
|
| 224 | + 'OBJ_ID', |
|
| 225 | + esc_html__('ID of Item purchased.', 'event_espresso'), |
|
| 226 | + true, |
|
| 227 | + null, |
|
| 228 | + $line_items_can_be_for |
|
| 229 | + ), |
|
| 230 | + 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
| 231 | + 'OBJ_type', |
|
| 232 | + esc_html__('Model Name this Line Item is for', 'event_espresso'), |
|
| 233 | + true, |
|
| 234 | + null, |
|
| 235 | + $line_items_can_be_for |
|
| 236 | + ), |
|
| 237 | + 'LIN_timestamp' => new EE_Datetime_Field( |
|
| 238 | + 'LIN_timestamp', |
|
| 239 | + esc_html__('When the line item was created', 'event_espresso'), |
|
| 240 | + false, |
|
| 241 | + EE_Datetime_Field::now, |
|
| 242 | + $timezone |
|
| 243 | + ), |
|
| 244 | + ), |
|
| 245 | + ); |
|
| 246 | + $this->_model_relations = array( |
|
| 247 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 248 | + 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
| 249 | + 'Price' => new EE_Belongs_To_Any_Relation(), |
|
| 250 | + 'Event' => new EE_Belongs_To_Any_Relation(), |
|
| 251 | + ); |
|
| 252 | + $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
| 253 | + $this->_caps_slug = 'transactions'; |
|
| 254 | + parent::__construct($timezone); |
|
| 255 | + } |
|
| 256 | + |
|
| 257 | + |
|
| 258 | + /** |
|
| 259 | + * Gets all the line items for this transaction of the given type |
|
| 260 | + * |
|
| 261 | + * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
| 262 | + * @param EE_Transaction|int $transaction |
|
| 263 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 264 | + * @throws EE_Error |
|
| 265 | + * @throws InvalidArgumentException |
|
| 266 | + * @throws InvalidDataTypeException |
|
| 267 | + * @throws InvalidInterfaceException |
|
| 268 | + */ |
|
| 269 | + public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
| 270 | + { |
|
| 271 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
| 272 | + return $this->get_all(array( |
|
| 273 | + array( |
|
| 274 | + 'LIN_type' => $line_item_type, |
|
| 275 | + 'TXN_ID' => $transaction, |
|
| 276 | + ), |
|
| 277 | + )); |
|
| 278 | + } |
|
| 279 | + |
|
| 280 | + |
|
| 281 | + /** |
|
| 282 | + * Gets all line items unrelated to tickets that are normal line items |
|
| 283 | + * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
| 284 | + * |
|
| 285 | + * @param EE_Transaction|int $transaction |
|
| 286 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 287 | + * @throws EE_Error |
|
| 288 | + * @throws InvalidArgumentException |
|
| 289 | + * @throws InvalidDataTypeException |
|
| 290 | + * @throws InvalidInterfaceException |
|
| 291 | + */ |
|
| 292 | + public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
| 293 | + { |
|
| 294 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
| 295 | + return $this->get_all(array( |
|
| 296 | + array( |
|
| 297 | + 'LIN_type' => self::type_line_item, |
|
| 298 | + 'TXN_ID' => $transaction, |
|
| 299 | + 'OR' => array( |
|
| 300 | + 'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET), |
|
| 301 | + 'OBJ_type*null' => array('IS_NULL'), |
|
| 302 | + ), |
|
| 303 | + ), |
|
| 304 | + )); |
|
| 305 | + } |
|
| 306 | + |
|
| 307 | + |
|
| 308 | + /** |
|
| 309 | + * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
| 310 | + * This needs to be very efficient |
|
| 311 | + * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when |
|
| 312 | + * deleting and joining tables like this. |
|
| 313 | + * |
|
| 314 | + * @return int count of how many deleted |
|
| 315 | + * @throws EE_Error |
|
| 316 | + * @throws InvalidArgumentException |
|
| 317 | + * @throws InvalidDataTypeException |
|
| 318 | + * @throws InvalidInterfaceException |
|
| 319 | + */ |
|
| 320 | + public function delete_line_items_with_no_transaction() |
|
| 321 | + { |
|
| 322 | + /** @type WPDB $wpdb */ |
|
| 323 | + global $wpdb; |
|
| 324 | + $time_to_leave_alone = apply_filters( |
|
| 325 | + 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
| 326 | + WEEK_IN_SECONDS |
|
| 327 | + ); |
|
| 328 | + $query = $wpdb->prepare( |
|
| 329 | + 'DELETE li |
|
| 330 | 330 | FROM ' . $this->table() . ' li |
| 331 | 331 | LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID |
| 332 | 332 | WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', |
| 333 | - // use GMT time because that's what TXN_timestamps are in |
|
| 334 | - date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
| 335 | - ); |
|
| 336 | - return $wpdb->query($query); |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - |
|
| 340 | - /** |
|
| 341 | - * get_line_item_for_transaction_object |
|
| 342 | - * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
| 343 | - * |
|
| 344 | - * @param int $TXN_ID |
|
| 345 | - * @param EE_Base_Class $object |
|
| 346 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 347 | - * @throws EE_Error |
|
| 348 | - * @throws InvalidArgumentException |
|
| 349 | - * @throws InvalidDataTypeException |
|
| 350 | - * @throws InvalidInterfaceException |
|
| 351 | - * @throws ReflectionException |
|
| 352 | - */ |
|
| 353 | - public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
| 354 | - { |
|
| 355 | - return $this->get_all(array( |
|
| 356 | - array( |
|
| 357 | - 'TXN_ID' => $TXN_ID, |
|
| 358 | - 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
| 359 | - 'OBJ_ID' => $object->ID(), |
|
| 360 | - ), |
|
| 361 | - )); |
|
| 362 | - } |
|
| 363 | - |
|
| 364 | - |
|
| 365 | - /** |
|
| 366 | - * get_object_line_items_for_transaction |
|
| 367 | - * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
| 368 | - * |
|
| 369 | - * @param int $TXN_ID |
|
| 370 | - * @param string $OBJ_type |
|
| 371 | - * @param array $OBJ_IDs |
|
| 372 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 373 | - * @throws EE_Error |
|
| 374 | - */ |
|
| 375 | - public function get_object_line_items_for_transaction( |
|
| 376 | - $TXN_ID, |
|
| 377 | - $OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT, |
|
| 378 | - $OBJ_IDs = array() |
|
| 379 | - ) { |
|
| 380 | - $query_params = array( |
|
| 381 | - 'OBJ_type' => $OBJ_type, |
|
| 382 | - // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
| 383 | - 'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs, |
|
| 384 | - ); |
|
| 385 | - if ($TXN_ID) { |
|
| 386 | - $query_params['TXN_ID'] = $TXN_ID; |
|
| 387 | - } |
|
| 388 | - return $this->get_all(array($query_params)); |
|
| 389 | - } |
|
| 390 | - |
|
| 391 | - |
|
| 392 | - /** |
|
| 393 | - * get_all_ticket_line_items_for_transaction |
|
| 394 | - * |
|
| 395 | - * @param EE_Transaction $transaction |
|
| 396 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 397 | - * @throws EE_Error |
|
| 398 | - * @throws InvalidArgumentException |
|
| 399 | - * @throws InvalidDataTypeException |
|
| 400 | - * @throws InvalidInterfaceException |
|
| 401 | - * @throws ReflectionException |
|
| 402 | - */ |
|
| 403 | - public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
| 404 | - { |
|
| 405 | - return $this->get_all(array( |
|
| 406 | - array( |
|
| 407 | - 'TXN_ID' => $transaction->ID(), |
|
| 408 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 409 | - ), |
|
| 410 | - )); |
|
| 411 | - } |
|
| 412 | - |
|
| 413 | - |
|
| 414 | - /** |
|
| 415 | - * get_ticket_line_item_for_transaction |
|
| 416 | - * |
|
| 417 | - * @param int $TXN_ID |
|
| 418 | - * @param int $TKT_ID |
|
| 419 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 420 | - * @throws EE_Error |
|
| 421 | - * @throws InvalidArgumentException |
|
| 422 | - * @throws InvalidDataTypeException |
|
| 423 | - * @throws InvalidInterfaceException |
|
| 424 | - */ |
|
| 425 | - public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
| 426 | - { |
|
| 427 | - return $this->get_one(array( |
|
| 428 | - array( |
|
| 429 | - 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
| 430 | - 'OBJ_ID' => $TKT_ID, |
|
| 431 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 432 | - ), |
|
| 433 | - )); |
|
| 434 | - } |
|
| 435 | - |
|
| 436 | - |
|
| 437 | - /** |
|
| 438 | - * get_existing_promotion_line_item |
|
| 439 | - * searches the cart for existing line items for the specified promotion |
|
| 440 | - * |
|
| 441 | - * @since 1.0.0 |
|
| 442 | - * @param EE_Line_Item $parent_line_item |
|
| 443 | - * @param EE_Promotion $promotion |
|
| 444 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 445 | - * @throws EE_Error |
|
| 446 | - * @throws InvalidArgumentException |
|
| 447 | - * @throws InvalidDataTypeException |
|
| 448 | - * @throws InvalidInterfaceException |
|
| 449 | - * @throws ReflectionException |
|
| 450 | - */ |
|
| 451 | - public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
| 452 | - { |
|
| 453 | - return $this->get_one(array( |
|
| 454 | - array( |
|
| 455 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
| 456 | - 'LIN_parent' => $parent_line_item->ID(), |
|
| 457 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
| 458 | - 'OBJ_ID' => $promotion->ID(), |
|
| 459 | - ), |
|
| 460 | - )); |
|
| 461 | - } |
|
| 462 | - |
|
| 463 | - |
|
| 464 | - /** |
|
| 465 | - * get_all_promotion_line_items |
|
| 466 | - * searches the cart for any and all existing promotion line items |
|
| 467 | - * |
|
| 468 | - * @since 1.0.0 |
|
| 469 | - * @param EE_Line_Item $parent_line_item |
|
| 470 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 471 | - * @throws EE_Error |
|
| 472 | - * @throws InvalidArgumentException |
|
| 473 | - * @throws InvalidDataTypeException |
|
| 474 | - * @throws InvalidInterfaceException |
|
| 475 | - * @throws ReflectionException |
|
| 476 | - */ |
|
| 477 | - public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
| 478 | - { |
|
| 479 | - return $this->get_all(array( |
|
| 480 | - array( |
|
| 481 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
| 482 | - 'LIN_parent' => $parent_line_item->ID(), |
|
| 483 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
| 484 | - ), |
|
| 485 | - )); |
|
| 486 | - } |
|
| 487 | - |
|
| 488 | - |
|
| 489 | - /** |
|
| 490 | - * Gets the registration's corresponding line item. |
|
| 491 | - * Note: basically does NOT support having multiple line items for a single ticket, |
|
| 492 | - * which would happen if some of the registrations had a price modifier while others didn't. |
|
| 493 | - * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
| 494 | - * |
|
| 495 | - * @param EE_Registration $registration |
|
| 496 | - * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL |
|
| 497 | - * @throws EE_Error |
|
| 498 | - */ |
|
| 499 | - public function get_line_item_for_registration(EE_Registration $registration) |
|
| 500 | - { |
|
| 501 | - return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
| 502 | - } |
|
| 503 | - |
|
| 504 | - |
|
| 505 | - /** |
|
| 506 | - * Gets the query params used to retrieve a specific line item for the given registration |
|
| 507 | - * |
|
| 508 | - * @param EE_Registration $registration |
|
| 509 | - * @param array $original_query_params any extra query params you'd like to be merged with |
|
| 510 | - * @return array @see |
|
| 511 | - * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 512 | - * @throws EE_Error |
|
| 513 | - */ |
|
| 514 | - public function line_item_for_registration_query_params( |
|
| 515 | - EE_Registration $registration, |
|
| 516 | - $original_query_params = array() |
|
| 517 | - ) { |
|
| 518 | - return array_replace_recursive($original_query_params, array( |
|
| 519 | - array( |
|
| 520 | - 'OBJ_ID' => $registration->ticket_ID(), |
|
| 521 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 522 | - 'TXN_ID' => $registration->transaction_ID(), |
|
| 523 | - ), |
|
| 524 | - )); |
|
| 525 | - } |
|
| 526 | - |
|
| 527 | - |
|
| 528 | - /** |
|
| 529 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 530 | - * @throws InvalidInterfaceException |
|
| 531 | - * @throws InvalidDataTypeException |
|
| 532 | - * @throws EE_Error |
|
| 533 | - * @throws InvalidArgumentException |
|
| 534 | - */ |
|
| 535 | - public function get_total_line_items_with_no_transaction() |
|
| 536 | - { |
|
| 537 | - return $this->get_total_line_items_for_carts(); |
|
| 538 | - } |
|
| 539 | - |
|
| 540 | - |
|
| 541 | - /** |
|
| 542 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 543 | - * @throws InvalidInterfaceException |
|
| 544 | - * @throws InvalidDataTypeException |
|
| 545 | - * @throws EE_Error |
|
| 546 | - * @throws InvalidArgumentException |
|
| 547 | - */ |
|
| 548 | - public function get_total_line_items_for_active_carts() |
|
| 549 | - { |
|
| 550 | - return $this->get_total_line_items_for_carts(false); |
|
| 551 | - } |
|
| 552 | - |
|
| 553 | - |
|
| 554 | - /** |
|
| 555 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 556 | - * @throws InvalidInterfaceException |
|
| 557 | - * @throws InvalidDataTypeException |
|
| 558 | - * @throws EE_Error |
|
| 559 | - * @throws InvalidArgumentException |
|
| 560 | - */ |
|
| 561 | - public function get_total_line_items_for_expired_carts() |
|
| 562 | - { |
|
| 563 | - return $this->get_total_line_items_for_carts(true); |
|
| 564 | - } |
|
| 565 | - |
|
| 566 | - |
|
| 567 | - /** |
|
| 568 | - * Returns an array of grand total line items where the TXN_ID is 0. |
|
| 569 | - * If $expired is set to true, then only line items for expired sessions will be returned. |
|
| 570 | - * If $expired is set to false, then only line items for active sessions will be returned. |
|
| 571 | - * |
|
| 572 | - * @param null $expired |
|
| 573 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 574 | - * @throws EE_Error |
|
| 575 | - * @throws InvalidArgumentException |
|
| 576 | - * @throws InvalidDataTypeException |
|
| 577 | - * @throws InvalidInterfaceException |
|
| 578 | - */ |
|
| 579 | - private function get_total_line_items_for_carts($expired = null) |
|
| 580 | - { |
|
| 581 | - $where_params = array( |
|
| 582 | - 'TXN_ID' => 0, |
|
| 583 | - 'LIN_type' => 'total', |
|
| 584 | - ); |
|
| 585 | - if ($expired !== null) { |
|
| 586 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 587 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 588 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 589 | - ); |
|
| 590 | - $where_params['LIN_timestamp'] = array( |
|
| 591 | - $expired ? '<=' : '>', |
|
| 592 | - $session_lifespan->expiration(), |
|
| 593 | - ); |
|
| 594 | - } |
|
| 595 | - return $this->get_all(array($where_params)); |
|
| 596 | - } |
|
| 597 | - |
|
| 598 | - |
|
| 599 | - /** |
|
| 600 | - * Returns an array of ticket total line items where the TXN_ID is 0 |
|
| 601 | - * AND the timestamp is older than the session lifespan. |
|
| 602 | - * |
|
| 603 | - * @param int $timestamp |
|
| 604 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 605 | - * @throws EE_Error |
|
| 606 | - * @throws InvalidArgumentException |
|
| 607 | - * @throws InvalidDataTypeException |
|
| 608 | - * @throws InvalidInterfaceException |
|
| 609 | - */ |
|
| 610 | - public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
| 611 | - { |
|
| 612 | - if (! absint($timestamp)) { |
|
| 613 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 614 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 615 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 616 | - ); |
|
| 617 | - $timestamp = $session_lifespan->expiration(); |
|
| 618 | - } |
|
| 619 | - return $this->get_all( |
|
| 620 | - array( |
|
| 621 | - array( |
|
| 622 | - 'TXN_ID' => 0, |
|
| 623 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 624 | - 'LIN_timestamp' => array('<=', $timestamp), |
|
| 625 | - ), |
|
| 626 | - ) |
|
| 627 | - ); |
|
| 628 | - } |
|
| 333 | + // use GMT time because that's what TXN_timestamps are in |
|
| 334 | + date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
| 335 | + ); |
|
| 336 | + return $wpdb->query($query); |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * get_line_item_for_transaction_object |
|
| 342 | + * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
| 343 | + * |
|
| 344 | + * @param int $TXN_ID |
|
| 345 | + * @param EE_Base_Class $object |
|
| 346 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 347 | + * @throws EE_Error |
|
| 348 | + * @throws InvalidArgumentException |
|
| 349 | + * @throws InvalidDataTypeException |
|
| 350 | + * @throws InvalidInterfaceException |
|
| 351 | + * @throws ReflectionException |
|
| 352 | + */ |
|
| 353 | + public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
| 354 | + { |
|
| 355 | + return $this->get_all(array( |
|
| 356 | + array( |
|
| 357 | + 'TXN_ID' => $TXN_ID, |
|
| 358 | + 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
| 359 | + 'OBJ_ID' => $object->ID(), |
|
| 360 | + ), |
|
| 361 | + )); |
|
| 362 | + } |
|
| 363 | + |
|
| 364 | + |
|
| 365 | + /** |
|
| 366 | + * get_object_line_items_for_transaction |
|
| 367 | + * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
| 368 | + * |
|
| 369 | + * @param int $TXN_ID |
|
| 370 | + * @param string $OBJ_type |
|
| 371 | + * @param array $OBJ_IDs |
|
| 372 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 373 | + * @throws EE_Error |
|
| 374 | + */ |
|
| 375 | + public function get_object_line_items_for_transaction( |
|
| 376 | + $TXN_ID, |
|
| 377 | + $OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT, |
|
| 378 | + $OBJ_IDs = array() |
|
| 379 | + ) { |
|
| 380 | + $query_params = array( |
|
| 381 | + 'OBJ_type' => $OBJ_type, |
|
| 382 | + // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
| 383 | + 'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs, |
|
| 384 | + ); |
|
| 385 | + if ($TXN_ID) { |
|
| 386 | + $query_params['TXN_ID'] = $TXN_ID; |
|
| 387 | + } |
|
| 388 | + return $this->get_all(array($query_params)); |
|
| 389 | + } |
|
| 390 | + |
|
| 391 | + |
|
| 392 | + /** |
|
| 393 | + * get_all_ticket_line_items_for_transaction |
|
| 394 | + * |
|
| 395 | + * @param EE_Transaction $transaction |
|
| 396 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 397 | + * @throws EE_Error |
|
| 398 | + * @throws InvalidArgumentException |
|
| 399 | + * @throws InvalidDataTypeException |
|
| 400 | + * @throws InvalidInterfaceException |
|
| 401 | + * @throws ReflectionException |
|
| 402 | + */ |
|
| 403 | + public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
| 404 | + { |
|
| 405 | + return $this->get_all(array( |
|
| 406 | + array( |
|
| 407 | + 'TXN_ID' => $transaction->ID(), |
|
| 408 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 409 | + ), |
|
| 410 | + )); |
|
| 411 | + } |
|
| 412 | + |
|
| 413 | + |
|
| 414 | + /** |
|
| 415 | + * get_ticket_line_item_for_transaction |
|
| 416 | + * |
|
| 417 | + * @param int $TXN_ID |
|
| 418 | + * @param int $TKT_ID |
|
| 419 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 420 | + * @throws EE_Error |
|
| 421 | + * @throws InvalidArgumentException |
|
| 422 | + * @throws InvalidDataTypeException |
|
| 423 | + * @throws InvalidInterfaceException |
|
| 424 | + */ |
|
| 425 | + public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
| 426 | + { |
|
| 427 | + return $this->get_one(array( |
|
| 428 | + array( |
|
| 429 | + 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
| 430 | + 'OBJ_ID' => $TKT_ID, |
|
| 431 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 432 | + ), |
|
| 433 | + )); |
|
| 434 | + } |
|
| 435 | + |
|
| 436 | + |
|
| 437 | + /** |
|
| 438 | + * get_existing_promotion_line_item |
|
| 439 | + * searches the cart for existing line items for the specified promotion |
|
| 440 | + * |
|
| 441 | + * @since 1.0.0 |
|
| 442 | + * @param EE_Line_Item $parent_line_item |
|
| 443 | + * @param EE_Promotion $promotion |
|
| 444 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
| 445 | + * @throws EE_Error |
|
| 446 | + * @throws InvalidArgumentException |
|
| 447 | + * @throws InvalidDataTypeException |
|
| 448 | + * @throws InvalidInterfaceException |
|
| 449 | + * @throws ReflectionException |
|
| 450 | + */ |
|
| 451 | + public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
| 452 | + { |
|
| 453 | + return $this->get_one(array( |
|
| 454 | + array( |
|
| 455 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
| 456 | + 'LIN_parent' => $parent_line_item->ID(), |
|
| 457 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
| 458 | + 'OBJ_ID' => $promotion->ID(), |
|
| 459 | + ), |
|
| 460 | + )); |
|
| 461 | + } |
|
| 462 | + |
|
| 463 | + |
|
| 464 | + /** |
|
| 465 | + * get_all_promotion_line_items |
|
| 466 | + * searches the cart for any and all existing promotion line items |
|
| 467 | + * |
|
| 468 | + * @since 1.0.0 |
|
| 469 | + * @param EE_Line_Item $parent_line_item |
|
| 470 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 471 | + * @throws EE_Error |
|
| 472 | + * @throws InvalidArgumentException |
|
| 473 | + * @throws InvalidDataTypeException |
|
| 474 | + * @throws InvalidInterfaceException |
|
| 475 | + * @throws ReflectionException |
|
| 476 | + */ |
|
| 477 | + public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
| 478 | + { |
|
| 479 | + return $this->get_all(array( |
|
| 480 | + array( |
|
| 481 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
| 482 | + 'LIN_parent' => $parent_line_item->ID(), |
|
| 483 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
| 484 | + ), |
|
| 485 | + )); |
|
| 486 | + } |
|
| 487 | + |
|
| 488 | + |
|
| 489 | + /** |
|
| 490 | + * Gets the registration's corresponding line item. |
|
| 491 | + * Note: basically does NOT support having multiple line items for a single ticket, |
|
| 492 | + * which would happen if some of the registrations had a price modifier while others didn't. |
|
| 493 | + * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
| 494 | + * |
|
| 495 | + * @param EE_Registration $registration |
|
| 496 | + * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL |
|
| 497 | + * @throws EE_Error |
|
| 498 | + */ |
|
| 499 | + public function get_line_item_for_registration(EE_Registration $registration) |
|
| 500 | + { |
|
| 501 | + return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
| 502 | + } |
|
| 503 | + |
|
| 504 | + |
|
| 505 | + /** |
|
| 506 | + * Gets the query params used to retrieve a specific line item for the given registration |
|
| 507 | + * |
|
| 508 | + * @param EE_Registration $registration |
|
| 509 | + * @param array $original_query_params any extra query params you'd like to be merged with |
|
| 510 | + * @return array @see |
|
| 511 | + * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
| 512 | + * @throws EE_Error |
|
| 513 | + */ |
|
| 514 | + public function line_item_for_registration_query_params( |
|
| 515 | + EE_Registration $registration, |
|
| 516 | + $original_query_params = array() |
|
| 517 | + ) { |
|
| 518 | + return array_replace_recursive($original_query_params, array( |
|
| 519 | + array( |
|
| 520 | + 'OBJ_ID' => $registration->ticket_ID(), |
|
| 521 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 522 | + 'TXN_ID' => $registration->transaction_ID(), |
|
| 523 | + ), |
|
| 524 | + )); |
|
| 525 | + } |
|
| 526 | + |
|
| 527 | + |
|
| 528 | + /** |
|
| 529 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 530 | + * @throws InvalidInterfaceException |
|
| 531 | + * @throws InvalidDataTypeException |
|
| 532 | + * @throws EE_Error |
|
| 533 | + * @throws InvalidArgumentException |
|
| 534 | + */ |
|
| 535 | + public function get_total_line_items_with_no_transaction() |
|
| 536 | + { |
|
| 537 | + return $this->get_total_line_items_for_carts(); |
|
| 538 | + } |
|
| 539 | + |
|
| 540 | + |
|
| 541 | + /** |
|
| 542 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 543 | + * @throws InvalidInterfaceException |
|
| 544 | + * @throws InvalidDataTypeException |
|
| 545 | + * @throws EE_Error |
|
| 546 | + * @throws InvalidArgumentException |
|
| 547 | + */ |
|
| 548 | + public function get_total_line_items_for_active_carts() |
|
| 549 | + { |
|
| 550 | + return $this->get_total_line_items_for_carts(false); |
|
| 551 | + } |
|
| 552 | + |
|
| 553 | + |
|
| 554 | + /** |
|
| 555 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 556 | + * @throws InvalidInterfaceException |
|
| 557 | + * @throws InvalidDataTypeException |
|
| 558 | + * @throws EE_Error |
|
| 559 | + * @throws InvalidArgumentException |
|
| 560 | + */ |
|
| 561 | + public function get_total_line_items_for_expired_carts() |
|
| 562 | + { |
|
| 563 | + return $this->get_total_line_items_for_carts(true); |
|
| 564 | + } |
|
| 565 | + |
|
| 566 | + |
|
| 567 | + /** |
|
| 568 | + * Returns an array of grand total line items where the TXN_ID is 0. |
|
| 569 | + * If $expired is set to true, then only line items for expired sessions will be returned. |
|
| 570 | + * If $expired is set to false, then only line items for active sessions will be returned. |
|
| 571 | + * |
|
| 572 | + * @param null $expired |
|
| 573 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 574 | + * @throws EE_Error |
|
| 575 | + * @throws InvalidArgumentException |
|
| 576 | + * @throws InvalidDataTypeException |
|
| 577 | + * @throws InvalidInterfaceException |
|
| 578 | + */ |
|
| 579 | + private function get_total_line_items_for_carts($expired = null) |
|
| 580 | + { |
|
| 581 | + $where_params = array( |
|
| 582 | + 'TXN_ID' => 0, |
|
| 583 | + 'LIN_type' => 'total', |
|
| 584 | + ); |
|
| 585 | + if ($expired !== null) { |
|
| 586 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 587 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 588 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 589 | + ); |
|
| 590 | + $where_params['LIN_timestamp'] = array( |
|
| 591 | + $expired ? '<=' : '>', |
|
| 592 | + $session_lifespan->expiration(), |
|
| 593 | + ); |
|
| 594 | + } |
|
| 595 | + return $this->get_all(array($where_params)); |
|
| 596 | + } |
|
| 597 | + |
|
| 598 | + |
|
| 599 | + /** |
|
| 600 | + * Returns an array of ticket total line items where the TXN_ID is 0 |
|
| 601 | + * AND the timestamp is older than the session lifespan. |
|
| 602 | + * |
|
| 603 | + * @param int $timestamp |
|
| 604 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
| 605 | + * @throws EE_Error |
|
| 606 | + * @throws InvalidArgumentException |
|
| 607 | + * @throws InvalidDataTypeException |
|
| 608 | + * @throws InvalidInterfaceException |
|
| 609 | + */ |
|
| 610 | + public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
| 611 | + { |
|
| 612 | + if (! absint($timestamp)) { |
|
| 613 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 614 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 615 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 616 | + ); |
|
| 617 | + $timestamp = $session_lifespan->expiration(); |
|
| 618 | + } |
|
| 619 | + return $this->get_all( |
|
| 620 | + array( |
|
| 621 | + array( |
|
| 622 | + 'TXN_ID' => 0, |
|
| 623 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
| 624 | + 'LIN_timestamp' => array('<=', $timestamp), |
|
| 625 | + ), |
|
| 626 | + ) |
|
| 627 | + ); |
|
| 628 | + } |
|
| 629 | 629 | } |
@@ -13,816 +13,816 @@ discard block |
||
| 13 | 13 | class EEM_Registration extends EEM_Soft_Delete_Base |
| 14 | 14 | { |
| 15 | 15 | |
| 16 | - /** |
|
| 17 | - * @var EEM_Registration $_instance |
|
| 18 | - */ |
|
| 19 | - protected static $_instance; |
|
| 20 | - |
|
| 21 | - /** |
|
| 22 | - * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values |
|
| 23 | - * are status codes (eg, approved, cancelled, etc) |
|
| 24 | - * |
|
| 25 | - * @var array |
|
| 26 | - */ |
|
| 27 | - private static $_reg_status; |
|
| 28 | - |
|
| 29 | - /** |
|
| 30 | - * The value of REG_count for a primary registrant |
|
| 31 | - */ |
|
| 32 | - const PRIMARY_REGISTRANT_COUNT = 1; |
|
| 33 | - |
|
| 34 | - /** |
|
| 35 | - * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration. |
|
| 36 | - * Initial status for registrations when they are first created |
|
| 37 | - * Payments are NOT allowed. |
|
| 38 | - * Automatically toggled to whatever the default Event registration status is upon completion of the attendee |
|
| 39 | - * information reg step NO space reserved. Registration is NOT active |
|
| 40 | - */ |
|
| 41 | - const status_id_incomplete = 'RIC'; |
|
| 42 | - |
|
| 43 | - /** |
|
| 44 | - * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration. |
|
| 45 | - * Payments are NOT allowed. |
|
| 46 | - * Event Admin must manually toggle STS_ID for it to change |
|
| 47 | - * No space reserved. |
|
| 48 | - * Registration is active |
|
| 49 | - */ |
|
| 50 | - const status_id_not_approved = 'RNA'; |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT . |
|
| 54 | - * Payments are allowed. |
|
| 55 | - * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
| 56 | - * No space reserved. |
|
| 57 | - * Registration is active |
|
| 58 | - */ |
|
| 59 | - const status_id_pending_payment = 'RPP'; |
|
| 60 | - |
|
| 61 | - /** |
|
| 62 | - * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST . |
|
| 63 | - * Payments are allowed. |
|
| 64 | - * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
| 65 | - * No space reserved. |
|
| 66 | - * Registration is active |
|
| 67 | - */ |
|
| 68 | - const status_id_wait_list = 'RWL'; |
|
| 69 | - |
|
| 70 | - /** |
|
| 71 | - * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration. |
|
| 72 | - * the TXN may or may not be completed ( paid in full ) |
|
| 73 | - * Payments are allowed. |
|
| 74 | - * A space IS reserved. |
|
| 75 | - * Registration is active |
|
| 76 | - */ |
|
| 77 | - const status_id_approved = 'RAP'; |
|
| 78 | - |
|
| 79 | - /** |
|
| 80 | - * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee. |
|
| 81 | - * Payments are NOT allowed. |
|
| 82 | - * NO space reserved. |
|
| 83 | - * Registration is NOT active |
|
| 84 | - */ |
|
| 85 | - const status_id_cancelled = 'RCN'; |
|
| 86 | - |
|
| 87 | - /** |
|
| 88 | - * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin |
|
| 89 | - * Payments are NOT allowed. |
|
| 90 | - * No space reserved. |
|
| 91 | - * Registration is NOT active |
|
| 92 | - */ |
|
| 93 | - const status_id_declined = 'RDC'; |
|
| 94 | - |
|
| 95 | - /** |
|
| 96 | - * @var TableAnalysis $table_analysis |
|
| 97 | - */ |
|
| 98 | - protected $_table_analysis; |
|
| 99 | - |
|
| 100 | - |
|
| 101 | - /** |
|
| 102 | - * private constructor to prevent direct creation |
|
| 103 | - * |
|
| 104 | - * @Constructor |
|
| 105 | - * @access protected |
|
| 106 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
| 107 | - * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
| 108 | - * date time model field objects. Default is NULL (and will be assumed using the set |
|
| 109 | - * timezone in the 'timezone_string' wp option) |
|
| 110 | - * @throws EE_Error |
|
| 111 | - */ |
|
| 112 | - protected function __construct($timezone = null) |
|
| 113 | - { |
|
| 114 | - $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true); |
|
| 115 | - $this->singular_item = esc_html__('Registration', 'event_espresso'); |
|
| 116 | - $this->plural_item = esc_html__('Registrations', 'event_espresso'); |
|
| 117 | - $this->_tables = array( |
|
| 118 | - 'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'), |
|
| 119 | - ); |
|
| 120 | - $this->_fields = array( |
|
| 121 | - 'Registration' => array( |
|
| 122 | - 'REG_ID' => new EE_Primary_Key_Int_Field( |
|
| 123 | - 'REG_ID', |
|
| 124 | - esc_html__('Registration ID', 'event_espresso') |
|
| 125 | - ), |
|
| 126 | - 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 127 | - 'EVT_ID', |
|
| 128 | - esc_html__('Event ID', 'event_espresso'), |
|
| 129 | - false, |
|
| 130 | - 0, |
|
| 131 | - 'Event' |
|
| 132 | - ), |
|
| 133 | - 'ATT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 134 | - 'ATT_ID', |
|
| 135 | - esc_html__('Attendee ID', 'event_espresso'), |
|
| 136 | - false, |
|
| 137 | - 0, |
|
| 138 | - 'Attendee' |
|
| 139 | - ), |
|
| 140 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 141 | - 'TXN_ID', |
|
| 142 | - esc_html__('Transaction ID', 'event_espresso'), |
|
| 143 | - false, |
|
| 144 | - 0, |
|
| 145 | - 'Transaction' |
|
| 146 | - ), |
|
| 147 | - 'TKT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 148 | - 'TKT_ID', |
|
| 149 | - esc_html__('Ticket ID', 'event_espresso'), |
|
| 150 | - false, |
|
| 151 | - 0, |
|
| 152 | - 'Ticket' |
|
| 153 | - ), |
|
| 154 | - 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 155 | - 'STS_ID', |
|
| 156 | - esc_html__('Status ID', 'event_espresso'), |
|
| 157 | - false, |
|
| 158 | - EEM_Registration::status_id_incomplete, |
|
| 159 | - 'Status' |
|
| 160 | - ), |
|
| 161 | - 'REG_date' => new EE_Datetime_Field( |
|
| 162 | - 'REG_date', |
|
| 163 | - esc_html__('Time registration occurred', 'event_espresso'), |
|
| 164 | - false, |
|
| 165 | - EE_Datetime_Field::now, |
|
| 166 | - $timezone |
|
| 167 | - ), |
|
| 168 | - 'REG_final_price' => new EE_Money_Field( |
|
| 169 | - 'REG_final_price', |
|
| 170 | - esc_html__('Registration\'s share of the transaction total', 'event_espresso'), |
|
| 171 | - false, |
|
| 172 | - 0 |
|
| 173 | - ), |
|
| 174 | - 'REG_paid' => new EE_Money_Field( |
|
| 175 | - 'REG_paid', |
|
| 176 | - esc_html__('Amount paid to date towards registration', 'event_espresso'), |
|
| 177 | - false, |
|
| 178 | - 0 |
|
| 179 | - ), |
|
| 180 | - 'REG_session' => new EE_Plain_Text_Field( |
|
| 181 | - 'REG_session', |
|
| 182 | - esc_html__('Session ID of registration', 'event_espresso'), |
|
| 183 | - false, |
|
| 184 | - '' |
|
| 185 | - ), |
|
| 186 | - 'REG_code' => new EE_Plain_Text_Field( |
|
| 187 | - 'REG_code', |
|
| 188 | - esc_html__('Unique Code for this registration', 'event_espresso'), |
|
| 189 | - false, |
|
| 190 | - '' |
|
| 191 | - ), |
|
| 192 | - 'REG_url_link' => new EE_Plain_Text_Field( |
|
| 193 | - 'REG_url_link', |
|
| 194 | - esc_html__('String to be used in URL for identifying registration', 'event_espresso'), |
|
| 195 | - false, |
|
| 196 | - '' |
|
| 197 | - ), |
|
| 198 | - 'REG_count' => new EE_Integer_Field( |
|
| 199 | - 'REG_count', |
|
| 200 | - esc_html__('Count of this registration in the group registration ', 'event_espresso'), |
|
| 201 | - true, |
|
| 202 | - 1 |
|
| 203 | - ), |
|
| 204 | - 'REG_group_size' => new EE_Integer_Field( |
|
| 205 | - 'REG_group_size', |
|
| 206 | - esc_html__('Number of registrations on this group', 'event_espresso'), |
|
| 207 | - false, |
|
| 208 | - 1 |
|
| 209 | - ), |
|
| 210 | - 'REG_att_is_going' => new EE_Boolean_Field( |
|
| 211 | - 'REG_att_is_going', |
|
| 212 | - esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'), |
|
| 213 | - false, |
|
| 214 | - false |
|
| 215 | - ), |
|
| 216 | - 'REG_deleted' => new EE_Trashed_Flag_Field( |
|
| 217 | - 'REG_deleted', |
|
| 218 | - esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'), |
|
| 219 | - false, |
|
| 220 | - false |
|
| 221 | - ), |
|
| 222 | - ), |
|
| 223 | - ); |
|
| 224 | - $this->_model_relations = array( |
|
| 225 | - 'Event' => new EE_Belongs_To_Relation(), |
|
| 226 | - 'Attendee' => new EE_Belongs_To_Relation(), |
|
| 227 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 228 | - 'Ticket' => new EE_Belongs_To_Relation(), |
|
| 229 | - 'Status' => new EE_Belongs_To_Relation(), |
|
| 230 | - 'Answer' => new EE_Has_Many_Relation(), |
|
| 231 | - 'Checkin' => new EE_Has_Many_Relation(), |
|
| 232 | - 'Registration_Payment' => new EE_Has_Many_Relation(), |
|
| 233 | - 'Payment' => new EE_HABTM_Relation('Registration_Payment'), |
|
| 234 | - 'Message' => new EE_Has_Many_Any_Relation(false) |
|
| 235 | - // allow deletes even if there are messages in the queue related |
|
| 236 | - ); |
|
| 237 | - $this->_model_chain_to_wp_user = 'Event'; |
|
| 238 | - parent::__construct($timezone); |
|
| 239 | - } |
|
| 240 | - |
|
| 241 | - |
|
| 242 | - /** |
|
| 243 | - * a list of ALL valid registration statuses currently in use within the system |
|
| 244 | - * generated by combining the filterable active and inactive reg status arrays |
|
| 245 | - * |
|
| 246 | - * @return array |
|
| 247 | - */ |
|
| 248 | - public static function reg_statuses() |
|
| 249 | - { |
|
| 250 | - return array_unique( |
|
| 251 | - array_merge( |
|
| 252 | - EEM_Registration::active_reg_statuses(), |
|
| 253 | - EEM_Registration::inactive_reg_statuses() |
|
| 254 | - ) |
|
| 255 | - ); |
|
| 256 | - } |
|
| 257 | - |
|
| 258 | - |
|
| 259 | - /** |
|
| 260 | - * reg_statuses_that_allow_payment |
|
| 261 | - * a filterable list of registration statuses that allow a registrant to make a payment |
|
| 262 | - * |
|
| 263 | - * @access public |
|
| 264 | - * @return array |
|
| 265 | - */ |
|
| 266 | - public static function reg_statuses_that_allow_payment() |
|
| 267 | - { |
|
| 268 | - return apply_filters( |
|
| 269 | - 'FHEE__EEM_Registration__reg_statuses_that_allow_payment', |
|
| 270 | - array( |
|
| 271 | - EEM_Registration::status_id_approved, |
|
| 272 | - EEM_Registration::status_id_pending_payment, |
|
| 273 | - ) |
|
| 274 | - ); |
|
| 275 | - } |
|
| 276 | - |
|
| 277 | - |
|
| 278 | - /** |
|
| 279 | - * active_reg_statuses |
|
| 280 | - * a filterable list of registration statuses that are considered active |
|
| 281 | - * |
|
| 282 | - * @access public |
|
| 283 | - * @return array |
|
| 284 | - */ |
|
| 285 | - public static function active_reg_statuses() |
|
| 286 | - { |
|
| 287 | - return apply_filters( |
|
| 288 | - 'FHEE__EEM_Registration__active_reg_statuses', |
|
| 289 | - array( |
|
| 290 | - EEM_Registration::status_id_approved, |
|
| 291 | - EEM_Registration::status_id_pending_payment, |
|
| 292 | - EEM_Registration::status_id_wait_list, |
|
| 293 | - EEM_Registration::status_id_not_approved, |
|
| 294 | - ) |
|
| 295 | - ); |
|
| 296 | - } |
|
| 297 | - |
|
| 298 | - |
|
| 299 | - /** |
|
| 300 | - * inactive_reg_statuses |
|
| 301 | - * a filterable list of registration statuses that are not considered active |
|
| 302 | - * |
|
| 303 | - * @access public |
|
| 304 | - * @return array |
|
| 305 | - */ |
|
| 306 | - public static function inactive_reg_statuses() |
|
| 307 | - { |
|
| 308 | - return apply_filters( |
|
| 309 | - 'FHEE__EEM_Registration__inactive_reg_statuses', |
|
| 310 | - array( |
|
| 311 | - EEM_Registration::status_id_incomplete, |
|
| 312 | - EEM_Registration::status_id_cancelled, |
|
| 313 | - EEM_Registration::status_id_declined, |
|
| 314 | - ) |
|
| 315 | - ); |
|
| 316 | - } |
|
| 317 | - |
|
| 318 | - |
|
| 319 | - /** |
|
| 320 | - * closed_reg_statuses |
|
| 321 | - * a filterable list of registration statuses that are considered "closed" |
|
| 322 | - * meaning they should not be considered in any calculations involving monies owing |
|
| 323 | - * |
|
| 324 | - * @access public |
|
| 325 | - * @return array |
|
| 326 | - */ |
|
| 327 | - public static function closed_reg_statuses() |
|
| 328 | - { |
|
| 329 | - return apply_filters( |
|
| 330 | - 'FHEE__EEM_Registration__closed_reg_statuses', |
|
| 331 | - array( |
|
| 332 | - EEM_Registration::status_id_cancelled, |
|
| 333 | - EEM_Registration::status_id_declined, |
|
| 334 | - EEM_Registration::status_id_wait_list, |
|
| 335 | - ) |
|
| 336 | - ); |
|
| 337 | - } |
|
| 338 | - |
|
| 339 | - |
|
| 340 | - /** |
|
| 341 | - * get list of registration statuses |
|
| 342 | - * |
|
| 343 | - * @access public |
|
| 344 | - * @param array $exclude The status ids to exclude from the returned results |
|
| 345 | - * @param bool $translated If true will return the values as singular localized strings |
|
| 346 | - * @return array |
|
| 347 | - * @throws EE_Error |
|
| 348 | - */ |
|
| 349 | - public static function reg_status_array($exclude = array(), $translated = false) |
|
| 350 | - { |
|
| 351 | - EEM_Registration::instance()->_get_registration_status_array($exclude); |
|
| 352 | - return $translated |
|
| 353 | - ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence') |
|
| 354 | - : self::$_reg_status; |
|
| 355 | - } |
|
| 356 | - |
|
| 357 | - |
|
| 358 | - /** |
|
| 359 | - * get list of registration statuses |
|
| 360 | - * |
|
| 361 | - * @access private |
|
| 362 | - * @param array $exclude |
|
| 363 | - * @return void |
|
| 364 | - * @throws EE_Error |
|
| 365 | - */ |
|
| 366 | - private function _get_registration_status_array($exclude = array()) |
|
| 367 | - { |
|
| 368 | - // in the very rare circumstance that we are deleting a model's table's data |
|
| 369 | - // and the table hasn't actually been created, this could have an error |
|
| 370 | - /** @type WPDB $wpdb */ |
|
| 371 | - global $wpdb; |
|
| 372 | - if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) { |
|
| 373 | - $results = $wpdb->get_results( |
|
| 374 | - "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'" |
|
| 375 | - ); |
|
| 376 | - self::$_reg_status = array(); |
|
| 377 | - foreach ($results as $status) { |
|
| 378 | - if (!in_array($status->STS_ID, $exclude, true)) { |
|
| 379 | - self::$_reg_status[ $status->STS_ID ] = $status->STS_code; |
|
| 380 | - } |
|
| 381 | - } |
|
| 382 | - } |
|
| 383 | - } |
|
| 384 | - |
|
| 385 | - |
|
| 386 | - /** |
|
| 387 | - * Gets the injected table analyzer, or throws an exception |
|
| 388 | - * |
|
| 389 | - * @return TableAnalysis |
|
| 390 | - * @throws EE_Error |
|
| 391 | - */ |
|
| 392 | - protected function _get_table_analysis() |
|
| 393 | - { |
|
| 394 | - if ($this->_table_analysis instanceof TableAnalysis) { |
|
| 395 | - return $this->_table_analysis; |
|
| 396 | - } |
|
| 397 | - throw new EE_Error( |
|
| 398 | - sprintf( |
|
| 399 | - esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'), |
|
| 400 | - get_class($this) |
|
| 401 | - ) |
|
| 402 | - ); |
|
| 403 | - } |
|
| 404 | - |
|
| 405 | - |
|
| 406 | - /** |
|
| 407 | - * This returns a wpdb->results array of all registration date month and years matching the incoming query params |
|
| 408 | - * and grouped by month and year. |
|
| 409 | - * |
|
| 410 | - * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
| 411 | - * @return array |
|
| 412 | - * @throws EE_Error |
|
| 413 | - */ |
|
| 414 | - public function get_reg_months_and_years($where_params) |
|
| 415 | - { |
|
| 416 | - $query_params[0] = $where_params; |
|
| 417 | - $query_params['group_by'] = array('reg_year', 'reg_month'); |
|
| 418 | - $query_params['order_by'] = array('REG_date' => 'DESC'); |
|
| 419 | - $columns_to_select = array( |
|
| 420 | - 'reg_year' => array('YEAR(REG_date)', '%s'), |
|
| 421 | - 'reg_month' => array('MONTHNAME(REG_date)', '%s'), |
|
| 422 | - ); |
|
| 423 | - return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
| 424 | - } |
|
| 425 | - |
|
| 426 | - |
|
| 427 | - /** |
|
| 428 | - * retrieve ALL registrations for a particular Attendee from db |
|
| 429 | - * |
|
| 430 | - * @param int $ATT_ID |
|
| 431 | - * @return EE_Base_Class[]|EE_Registration[]|null |
|
| 432 | - * @throws EE_Error |
|
| 433 | - */ |
|
| 434 | - public function get_all_registrations_for_attendee($ATT_ID = 0) |
|
| 435 | - { |
|
| 436 | - if (!$ATT_ID) { |
|
| 437 | - return null; |
|
| 438 | - } |
|
| 439 | - return $this->get_all(array(array('ATT_ID' => $ATT_ID))); |
|
| 440 | - } |
|
| 441 | - |
|
| 442 | - |
|
| 443 | - /** |
|
| 444 | - * Gets a registration given their REG_url_link. Yes, this should usually |
|
| 445 | - * be passed via a GET parameter. |
|
| 446 | - * |
|
| 447 | - * @param string $REG_url_link |
|
| 448 | - * @return EE_Base_Class|EE_Registration|null |
|
| 449 | - * @throws EE_Error |
|
| 450 | - */ |
|
| 451 | - public function get_registration_for_reg_url_link($REG_url_link) |
|
| 452 | - { |
|
| 453 | - if (!$REG_url_link) { |
|
| 454 | - return null; |
|
| 455 | - } |
|
| 456 | - return $this->get_one(array(array('REG_url_link' => $REG_url_link))); |
|
| 457 | - } |
|
| 458 | - |
|
| 459 | - |
|
| 460 | - /** |
|
| 461 | - * retrieve registration for a specific transaction attendee from db |
|
| 462 | - * |
|
| 463 | - * @access public |
|
| 464 | - * @param int $TXN_ID |
|
| 465 | - * @param int $ATT_ID |
|
| 466 | - * @param int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the |
|
| 467 | - * attendee number is required |
|
| 468 | - * @return mixed array on success, FALSE on fail |
|
| 469 | - * @throws EE_Error |
|
| 470 | - */ |
|
| 471 | - public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0) |
|
| 472 | - { |
|
| 473 | - return $this->get_one(array( |
|
| 474 | - array( |
|
| 475 | - 'TXN_ID' => $TXN_ID, |
|
| 476 | - 'ATT_ID' => $ATT_ID, |
|
| 477 | - ), |
|
| 478 | - 'limit' => array(min($att_nmbr - 1, 0), 1), |
|
| 479 | - )); |
|
| 480 | - } |
|
| 481 | - |
|
| 482 | - |
|
| 483 | - /** |
|
| 484 | - * get the number of registrations per day for the Registration Admin page Reports Tab. |
|
| 485 | - * (doesn't utilize models because it's a fairly specialized query) |
|
| 486 | - * |
|
| 487 | - * @access public |
|
| 488 | - * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
| 489 | - * @return stdClass[] with properties regDate and total |
|
| 490 | - * @throws EE_Error |
|
| 491 | - */ |
|
| 492 | - public function get_registrations_per_day_report($period = '-1 month') |
|
| 493 | - { |
|
| 494 | - $sql_date = $this->convert_datetime_for_query( |
|
| 495 | - 'REG_date', |
|
| 496 | - date('Y-m-d H:i:s', strtotime($period)), |
|
| 497 | - 'Y-m-d H:i:s', |
|
| 498 | - 'UTC' |
|
| 499 | - ); |
|
| 500 | - $where = array( |
|
| 501 | - 'REG_date' => array('>=', $sql_date), |
|
| 502 | - 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
| 503 | - ); |
|
| 504 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) { |
|
| 505 | - $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
| 506 | - } |
|
| 507 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date'); |
|
| 508 | - $results = $this->_get_all_wpdb_results( |
|
| 509 | - array( |
|
| 510 | - $where, |
|
| 511 | - 'group_by' => 'regDate', |
|
| 512 | - 'order_by' => array('REG_date' => 'ASC'), |
|
| 513 | - ), |
|
| 514 | - OBJECT, |
|
| 515 | - array( |
|
| 516 | - 'regDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
| 517 | - 'total' => array('count(REG_ID)', '%d'), |
|
| 518 | - ) |
|
| 519 | - ); |
|
| 520 | - return $results; |
|
| 521 | - } |
|
| 522 | - |
|
| 523 | - |
|
| 524 | - /** |
|
| 525 | - * Get the number of registrations per day including the count of registrations for each Registration Status. |
|
| 526 | - * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
| 527 | - * |
|
| 528 | - * @param string $period |
|
| 529 | - * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID |
|
| 530 | - * @throws EE_Error |
|
| 531 | - * (i.e. RAP) |
|
| 532 | - */ |
|
| 533 | - public function get_registrations_per_day_and_per_status_report($period = '-1 month') |
|
| 534 | - { |
|
| 535 | - global $wpdb; |
|
| 536 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 537 | - $event_table = $wpdb->posts; |
|
| 538 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 539 | - // prepare the query interval for displaying offset |
|
| 540 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date'); |
|
| 541 | - // inner date query |
|
| 542 | - $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} "; |
|
| 543 | - $inner_where = ' WHERE'; |
|
| 544 | - // exclude events not authored by user if permissions in effect |
|
| 545 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 546 | - $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
| 547 | - $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
| 548 | - } |
|
| 549 | - $inner_where .= " REG_date >= '{$sql_date}'"; |
|
| 550 | - $inner_date_query .= $inner_where; |
|
| 551 | - // start main query |
|
| 552 | - $select = "SELECT DATE({$query_interval}) as Registration_REG_date, "; |
|
| 553 | - $join = ''; |
|
| 554 | - $join_parts = array(); |
|
| 555 | - $select_parts = array(); |
|
| 556 | - // loop through registration stati to do parts for each status. |
|
| 557 | - foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
| 558 | - if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
| 559 | - continue; |
|
| 560 | - } |
|
| 561 | - $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
| 562 | - $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'"; |
|
| 563 | - } |
|
| 564 | - // setup the selects |
|
| 565 | - $select .= implode(', ', $select_parts); |
|
| 566 | - $select .= " FROM ($inner_date_query) AS dates LEFT JOIN "; |
|
| 567 | - // setup the joins |
|
| 568 | - $join .= implode(' LEFT JOIN ', $join_parts); |
|
| 569 | - // now let's put it all together |
|
| 570 | - $query = $select . $join . ' GROUP BY Registration_REG_date'; |
|
| 571 | - // and execute it |
|
| 572 | - return $wpdb->get_results($query, ARRAY_A); |
|
| 573 | - } |
|
| 574 | - |
|
| 575 | - |
|
| 576 | - /** |
|
| 577 | - * get the number of registrations per event for the Registration Admin page Reports Tab |
|
| 578 | - * |
|
| 579 | - * @access public |
|
| 580 | - * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
| 581 | - * @return stdClass[] each with properties event_name, reg_limit, and total |
|
| 582 | - * @throws EE_Error |
|
| 583 | - */ |
|
| 584 | - public function get_registrations_per_event_report($period = '-1 month') |
|
| 585 | - { |
|
| 586 | - $date_sql = $this->convert_datetime_for_query( |
|
| 587 | - 'REG_date', |
|
| 588 | - date('Y-m-d H:i:s', strtotime($period)), |
|
| 589 | - 'Y-m-d H:i:s', |
|
| 590 | - 'UTC' |
|
| 591 | - ); |
|
| 592 | - $where = array( |
|
| 593 | - 'REG_date' => array('>=', $date_sql), |
|
| 594 | - 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
| 595 | - ); |
|
| 596 | - if (!EE_Registry::instance()->CAP->current_user_can( |
|
| 597 | - 'ee_read_others_registrations', |
|
| 598 | - 'reg_per_event_report' |
|
| 599 | - ) |
|
| 600 | - ) { |
|
| 601 | - $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
| 602 | - } |
|
| 603 | - $results = $this->_get_all_wpdb_results( |
|
| 604 | - array( |
|
| 605 | - $where, |
|
| 606 | - 'group_by' => 'Event.EVT_name', |
|
| 607 | - 'order_by' => 'Event.EVT_name', |
|
| 608 | - 'limit' => array(0, 24), |
|
| 609 | - ), |
|
| 610 | - OBJECT, |
|
| 611 | - array( |
|
| 612 | - 'event_name' => array('Event_CPT.post_title', '%s'), |
|
| 613 | - 'total' => array('COUNT(REG_ID)', '%s'), |
|
| 614 | - ) |
|
| 615 | - ); |
|
| 616 | - return $results; |
|
| 617 | - } |
|
| 618 | - |
|
| 619 | - |
|
| 620 | - /** |
|
| 621 | - * Get the number of registrations per event grouped by registration status. |
|
| 622 | - * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
| 623 | - * |
|
| 624 | - * @param string $period |
|
| 625 | - * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID |
|
| 626 | - * @throws EE_Error |
|
| 627 | - * (i.e. RAP) |
|
| 628 | - */ |
|
| 629 | - public function get_registrations_per_event_and_per_status_report($period = '-1 month') |
|
| 630 | - { |
|
| 631 | - global $wpdb; |
|
| 632 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 633 | - $event_table = $wpdb->posts; |
|
| 634 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 635 | - // inner date query |
|
| 636 | - $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table "; |
|
| 637 | - $inner_where = ' WHERE'; |
|
| 638 | - // exclude events not authored by user if permissions in effect |
|
| 639 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 640 | - $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
| 641 | - $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
| 642 | - } |
|
| 643 | - $inner_where .= " REG_date >= '{$sql_date}'"; |
|
| 644 | - $inner_date_query .= $inner_where; |
|
| 645 | - // build main query |
|
| 646 | - $select = 'SELECT Event.post_title as Registration_Event, '; |
|
| 647 | - $join = ''; |
|
| 648 | - $join_parts = array(); |
|
| 649 | - $select_parts = array(); |
|
| 650 | - // loop through registration stati to do parts for each status. |
|
| 651 | - foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
| 652 | - if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
| 653 | - continue; |
|
| 654 | - } |
|
| 655 | - $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
| 656 | - $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date"; |
|
| 657 | - } |
|
| 658 | - // setup the selects |
|
| 659 | - $select .= implode(', ', $select_parts); |
|
| 660 | - $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN "; |
|
| 661 | - // setup remaining joins |
|
| 662 | - $join .= implode(' LEFT JOIN ', $join_parts); |
|
| 663 | - // now put it all together |
|
| 664 | - $query = $select . $join . ' GROUP BY Registration_Event'; |
|
| 665 | - // and execute |
|
| 666 | - return $wpdb->get_results($query, ARRAY_A); |
|
| 667 | - } |
|
| 668 | - |
|
| 669 | - |
|
| 670 | - /** |
|
| 671 | - * Returns the EE_Registration of the primary attendee on the transaction id provided |
|
| 672 | - * |
|
| 673 | - * @param int $TXN_ID |
|
| 674 | - * @return EE_Base_Class|EE_Registration|null |
|
| 675 | - * @throws EE_Error |
|
| 676 | - */ |
|
| 677 | - public function get_primary_registration_for_transaction_ID($TXN_ID = 0) |
|
| 678 | - { |
|
| 679 | - if (!$TXN_ID) { |
|
| 680 | - return null; |
|
| 681 | - } |
|
| 682 | - return $this->get_one(array( |
|
| 683 | - array( |
|
| 684 | - 'TXN_ID' => $TXN_ID, |
|
| 685 | - 'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT, |
|
| 686 | - ), |
|
| 687 | - )); |
|
| 688 | - } |
|
| 689 | - |
|
| 690 | - |
|
| 691 | - /** |
|
| 692 | - * get_event_registration_count |
|
| 693 | - * |
|
| 694 | - * @access public |
|
| 695 | - * @param int $EVT_ID |
|
| 696 | - * @param boolean $for_incomplete_payments |
|
| 697 | - * @return int |
|
| 698 | - * @throws EE_Error |
|
| 699 | - */ |
|
| 700 | - public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false) |
|
| 701 | - { |
|
| 702 | - // we only count approved registrations towards registration limits |
|
| 703 | - $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved)); |
|
| 704 | - if ($for_incomplete_payments) { |
|
| 705 | - $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code); |
|
| 706 | - } |
|
| 707 | - return $this->count($query_params); |
|
| 708 | - } |
|
| 709 | - |
|
| 710 | - |
|
| 711 | - /** |
|
| 712 | - * Deletes all registrations with no transactions. Note that this needs to be very efficient |
|
| 713 | - * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete |
|
| 714 | - * when joining tables like this. |
|
| 715 | - * |
|
| 716 | - * @global WPDB $wpdb |
|
| 717 | - * @return int number deleted |
|
| 718 | - * @throws EE_Error |
|
| 719 | - */ |
|
| 720 | - public function delete_registrations_with_no_transaction() |
|
| 721 | - { |
|
| 722 | - /** @type WPDB $wpdb */ |
|
| 723 | - global $wpdb; |
|
| 724 | - return $wpdb->query( |
|
| 725 | - 'DELETE r FROM ' |
|
| 726 | - . $this->table() |
|
| 727 | - . ' r LEFT JOIN ' |
|
| 728 | - . EEM_Transaction::instance()->table() |
|
| 729 | - . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL' |
|
| 730 | - ); |
|
| 731 | - } |
|
| 732 | - |
|
| 733 | - |
|
| 734 | - /** |
|
| 735 | - * Count registrations checked into (or out of) a datetime |
|
| 736 | - * |
|
| 737 | - * @param int $DTT_ID datetime ID |
|
| 738 | - * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
| 739 | - * @return int |
|
| 740 | - * @throws EE_Error |
|
| 741 | - */ |
|
| 742 | - public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true) |
|
| 743 | - { |
|
| 744 | - global $wpdb; |
|
| 745 | - // subquery to get latest checkin |
|
| 746 | - $query = $wpdb->prepare( |
|
| 747 | - 'SELECT ' |
|
| 748 | - . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
| 749 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
| 750 | - . '( SELECT ' |
|
| 751 | - . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
| 752 | - . 'REG_ID AS REG_ID ' |
|
| 753 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' ' |
|
| 754 | - . 'WHERE DTT_ID=%d ' |
|
| 755 | - . 'GROUP BY REG_ID' |
|
| 756 | - . ') AS most_recent_checkin_per_reg ' |
|
| 757 | - . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
| 758 | - . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
| 759 | - . 'WHERE ' |
|
| 760 | - . 'checkins.CHK_in=%d', |
|
| 761 | - $DTT_ID, |
|
| 762 | - $checked_in |
|
| 763 | - ); |
|
| 764 | - return (int) $wpdb->get_var($query); |
|
| 765 | - } |
|
| 766 | - |
|
| 767 | - |
|
| 768 | - /** |
|
| 769 | - * Count registrations checked into (or out of) an event. |
|
| 770 | - * |
|
| 771 | - * @param int $EVT_ID event ID |
|
| 772 | - * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
| 773 | - * @return int |
|
| 774 | - * @throws EE_Error |
|
| 775 | - */ |
|
| 776 | - public function count_registrations_checked_into_event($EVT_ID, $checked_in = true) |
|
| 777 | - { |
|
| 778 | - global $wpdb; |
|
| 779 | - // subquery to get latest checkin |
|
| 780 | - $query = $wpdb->prepare( |
|
| 781 | - 'SELECT ' |
|
| 782 | - . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
| 783 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
| 784 | - . '( SELECT ' |
|
| 785 | - . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
| 786 | - . 'REG_ID AS REG_ID ' |
|
| 787 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c ' |
|
| 788 | - . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d ' |
|
| 789 | - . 'ON c.DTT_ID=d.DTT_ID ' |
|
| 790 | - . 'WHERE d.EVT_ID=%d ' |
|
| 791 | - . 'GROUP BY REG_ID' |
|
| 792 | - . ') AS most_recent_checkin_per_reg ' |
|
| 793 | - . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
| 794 | - . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
| 795 | - . 'WHERE ' |
|
| 796 | - . 'checkins.CHK_in=%d', |
|
| 797 | - $EVT_ID, |
|
| 798 | - $checked_in |
|
| 799 | - ); |
|
| 800 | - return (int) $wpdb->get_var($query); |
|
| 801 | - } |
|
| 802 | - |
|
| 803 | - |
|
| 804 | - /** |
|
| 805 | - * The purpose of this method is to retrieve an array of |
|
| 806 | - * EE_Registration objects that represent the latest registration |
|
| 807 | - * for each ATT_ID given in the function argument. |
|
| 808 | - * |
|
| 809 | - * @param array $attendee_ids |
|
| 810 | - * @return EE_Base_Class[]|EE_Registration[] |
|
| 811 | - * @throws EE_Error |
|
| 812 | - */ |
|
| 813 | - public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array()) |
|
| 814 | - { |
|
| 815 | - // first do a native wp_query to get the latest REG_ID's matching these attendees. |
|
| 816 | - global $wpdb; |
|
| 817 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 818 | - $attendee_table = $wpdb->posts; |
|
| 819 | - $attendee_ids = is_array($attendee_ids) |
|
| 820 | - ? array_map('absint', $attendee_ids) |
|
| 821 | - : array((int) $attendee_ids); |
|
| 822 | - $ATT_IDs = implode(',', $attendee_ids); |
|
| 823 | - // first we do a query to get the registration ids |
|
| 824 | - // (because a group by before order by causes the order by to be ignored.) |
|
| 825 | - $registration_id_query = " |
|
| 16 | + /** |
|
| 17 | + * @var EEM_Registration $_instance |
|
| 18 | + */ |
|
| 19 | + protected static $_instance; |
|
| 20 | + |
|
| 21 | + /** |
|
| 22 | + * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values |
|
| 23 | + * are status codes (eg, approved, cancelled, etc) |
|
| 24 | + * |
|
| 25 | + * @var array |
|
| 26 | + */ |
|
| 27 | + private static $_reg_status; |
|
| 28 | + |
|
| 29 | + /** |
|
| 30 | + * The value of REG_count for a primary registrant |
|
| 31 | + */ |
|
| 32 | + const PRIMARY_REGISTRANT_COUNT = 1; |
|
| 33 | + |
|
| 34 | + /** |
|
| 35 | + * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration. |
|
| 36 | + * Initial status for registrations when they are first created |
|
| 37 | + * Payments are NOT allowed. |
|
| 38 | + * Automatically toggled to whatever the default Event registration status is upon completion of the attendee |
|
| 39 | + * information reg step NO space reserved. Registration is NOT active |
|
| 40 | + */ |
|
| 41 | + const status_id_incomplete = 'RIC'; |
|
| 42 | + |
|
| 43 | + /** |
|
| 44 | + * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration. |
|
| 45 | + * Payments are NOT allowed. |
|
| 46 | + * Event Admin must manually toggle STS_ID for it to change |
|
| 47 | + * No space reserved. |
|
| 48 | + * Registration is active |
|
| 49 | + */ |
|
| 50 | + const status_id_not_approved = 'RNA'; |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT . |
|
| 54 | + * Payments are allowed. |
|
| 55 | + * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
| 56 | + * No space reserved. |
|
| 57 | + * Registration is active |
|
| 58 | + */ |
|
| 59 | + const status_id_pending_payment = 'RPP'; |
|
| 60 | + |
|
| 61 | + /** |
|
| 62 | + * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST . |
|
| 63 | + * Payments are allowed. |
|
| 64 | + * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
| 65 | + * No space reserved. |
|
| 66 | + * Registration is active |
|
| 67 | + */ |
|
| 68 | + const status_id_wait_list = 'RWL'; |
|
| 69 | + |
|
| 70 | + /** |
|
| 71 | + * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration. |
|
| 72 | + * the TXN may or may not be completed ( paid in full ) |
|
| 73 | + * Payments are allowed. |
|
| 74 | + * A space IS reserved. |
|
| 75 | + * Registration is active |
|
| 76 | + */ |
|
| 77 | + const status_id_approved = 'RAP'; |
|
| 78 | + |
|
| 79 | + /** |
|
| 80 | + * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee. |
|
| 81 | + * Payments are NOT allowed. |
|
| 82 | + * NO space reserved. |
|
| 83 | + * Registration is NOT active |
|
| 84 | + */ |
|
| 85 | + const status_id_cancelled = 'RCN'; |
|
| 86 | + |
|
| 87 | + /** |
|
| 88 | + * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin |
|
| 89 | + * Payments are NOT allowed. |
|
| 90 | + * No space reserved. |
|
| 91 | + * Registration is NOT active |
|
| 92 | + */ |
|
| 93 | + const status_id_declined = 'RDC'; |
|
| 94 | + |
|
| 95 | + /** |
|
| 96 | + * @var TableAnalysis $table_analysis |
|
| 97 | + */ |
|
| 98 | + protected $_table_analysis; |
|
| 99 | + |
|
| 100 | + |
|
| 101 | + /** |
|
| 102 | + * private constructor to prevent direct creation |
|
| 103 | + * |
|
| 104 | + * @Constructor |
|
| 105 | + * @access protected |
|
| 106 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
| 107 | + * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
| 108 | + * date time model field objects. Default is NULL (and will be assumed using the set |
|
| 109 | + * timezone in the 'timezone_string' wp option) |
|
| 110 | + * @throws EE_Error |
|
| 111 | + */ |
|
| 112 | + protected function __construct($timezone = null) |
|
| 113 | + { |
|
| 114 | + $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true); |
|
| 115 | + $this->singular_item = esc_html__('Registration', 'event_espresso'); |
|
| 116 | + $this->plural_item = esc_html__('Registrations', 'event_espresso'); |
|
| 117 | + $this->_tables = array( |
|
| 118 | + 'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'), |
|
| 119 | + ); |
|
| 120 | + $this->_fields = array( |
|
| 121 | + 'Registration' => array( |
|
| 122 | + 'REG_ID' => new EE_Primary_Key_Int_Field( |
|
| 123 | + 'REG_ID', |
|
| 124 | + esc_html__('Registration ID', 'event_espresso') |
|
| 125 | + ), |
|
| 126 | + 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 127 | + 'EVT_ID', |
|
| 128 | + esc_html__('Event ID', 'event_espresso'), |
|
| 129 | + false, |
|
| 130 | + 0, |
|
| 131 | + 'Event' |
|
| 132 | + ), |
|
| 133 | + 'ATT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 134 | + 'ATT_ID', |
|
| 135 | + esc_html__('Attendee ID', 'event_espresso'), |
|
| 136 | + false, |
|
| 137 | + 0, |
|
| 138 | + 'Attendee' |
|
| 139 | + ), |
|
| 140 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 141 | + 'TXN_ID', |
|
| 142 | + esc_html__('Transaction ID', 'event_espresso'), |
|
| 143 | + false, |
|
| 144 | + 0, |
|
| 145 | + 'Transaction' |
|
| 146 | + ), |
|
| 147 | + 'TKT_ID' => new EE_Foreign_Key_Int_Field( |
|
| 148 | + 'TKT_ID', |
|
| 149 | + esc_html__('Ticket ID', 'event_espresso'), |
|
| 150 | + false, |
|
| 151 | + 0, |
|
| 152 | + 'Ticket' |
|
| 153 | + ), |
|
| 154 | + 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 155 | + 'STS_ID', |
|
| 156 | + esc_html__('Status ID', 'event_espresso'), |
|
| 157 | + false, |
|
| 158 | + EEM_Registration::status_id_incomplete, |
|
| 159 | + 'Status' |
|
| 160 | + ), |
|
| 161 | + 'REG_date' => new EE_Datetime_Field( |
|
| 162 | + 'REG_date', |
|
| 163 | + esc_html__('Time registration occurred', 'event_espresso'), |
|
| 164 | + false, |
|
| 165 | + EE_Datetime_Field::now, |
|
| 166 | + $timezone |
|
| 167 | + ), |
|
| 168 | + 'REG_final_price' => new EE_Money_Field( |
|
| 169 | + 'REG_final_price', |
|
| 170 | + esc_html__('Registration\'s share of the transaction total', 'event_espresso'), |
|
| 171 | + false, |
|
| 172 | + 0 |
|
| 173 | + ), |
|
| 174 | + 'REG_paid' => new EE_Money_Field( |
|
| 175 | + 'REG_paid', |
|
| 176 | + esc_html__('Amount paid to date towards registration', 'event_espresso'), |
|
| 177 | + false, |
|
| 178 | + 0 |
|
| 179 | + ), |
|
| 180 | + 'REG_session' => new EE_Plain_Text_Field( |
|
| 181 | + 'REG_session', |
|
| 182 | + esc_html__('Session ID of registration', 'event_espresso'), |
|
| 183 | + false, |
|
| 184 | + '' |
|
| 185 | + ), |
|
| 186 | + 'REG_code' => new EE_Plain_Text_Field( |
|
| 187 | + 'REG_code', |
|
| 188 | + esc_html__('Unique Code for this registration', 'event_espresso'), |
|
| 189 | + false, |
|
| 190 | + '' |
|
| 191 | + ), |
|
| 192 | + 'REG_url_link' => new EE_Plain_Text_Field( |
|
| 193 | + 'REG_url_link', |
|
| 194 | + esc_html__('String to be used in URL for identifying registration', 'event_espresso'), |
|
| 195 | + false, |
|
| 196 | + '' |
|
| 197 | + ), |
|
| 198 | + 'REG_count' => new EE_Integer_Field( |
|
| 199 | + 'REG_count', |
|
| 200 | + esc_html__('Count of this registration in the group registration ', 'event_espresso'), |
|
| 201 | + true, |
|
| 202 | + 1 |
|
| 203 | + ), |
|
| 204 | + 'REG_group_size' => new EE_Integer_Field( |
|
| 205 | + 'REG_group_size', |
|
| 206 | + esc_html__('Number of registrations on this group', 'event_espresso'), |
|
| 207 | + false, |
|
| 208 | + 1 |
|
| 209 | + ), |
|
| 210 | + 'REG_att_is_going' => new EE_Boolean_Field( |
|
| 211 | + 'REG_att_is_going', |
|
| 212 | + esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'), |
|
| 213 | + false, |
|
| 214 | + false |
|
| 215 | + ), |
|
| 216 | + 'REG_deleted' => new EE_Trashed_Flag_Field( |
|
| 217 | + 'REG_deleted', |
|
| 218 | + esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'), |
|
| 219 | + false, |
|
| 220 | + false |
|
| 221 | + ), |
|
| 222 | + ), |
|
| 223 | + ); |
|
| 224 | + $this->_model_relations = array( |
|
| 225 | + 'Event' => new EE_Belongs_To_Relation(), |
|
| 226 | + 'Attendee' => new EE_Belongs_To_Relation(), |
|
| 227 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 228 | + 'Ticket' => new EE_Belongs_To_Relation(), |
|
| 229 | + 'Status' => new EE_Belongs_To_Relation(), |
|
| 230 | + 'Answer' => new EE_Has_Many_Relation(), |
|
| 231 | + 'Checkin' => new EE_Has_Many_Relation(), |
|
| 232 | + 'Registration_Payment' => new EE_Has_Many_Relation(), |
|
| 233 | + 'Payment' => new EE_HABTM_Relation('Registration_Payment'), |
|
| 234 | + 'Message' => new EE_Has_Many_Any_Relation(false) |
|
| 235 | + // allow deletes even if there are messages in the queue related |
|
| 236 | + ); |
|
| 237 | + $this->_model_chain_to_wp_user = 'Event'; |
|
| 238 | + parent::__construct($timezone); |
|
| 239 | + } |
|
| 240 | + |
|
| 241 | + |
|
| 242 | + /** |
|
| 243 | + * a list of ALL valid registration statuses currently in use within the system |
|
| 244 | + * generated by combining the filterable active and inactive reg status arrays |
|
| 245 | + * |
|
| 246 | + * @return array |
|
| 247 | + */ |
|
| 248 | + public static function reg_statuses() |
|
| 249 | + { |
|
| 250 | + return array_unique( |
|
| 251 | + array_merge( |
|
| 252 | + EEM_Registration::active_reg_statuses(), |
|
| 253 | + EEM_Registration::inactive_reg_statuses() |
|
| 254 | + ) |
|
| 255 | + ); |
|
| 256 | + } |
|
| 257 | + |
|
| 258 | + |
|
| 259 | + /** |
|
| 260 | + * reg_statuses_that_allow_payment |
|
| 261 | + * a filterable list of registration statuses that allow a registrant to make a payment |
|
| 262 | + * |
|
| 263 | + * @access public |
|
| 264 | + * @return array |
|
| 265 | + */ |
|
| 266 | + public static function reg_statuses_that_allow_payment() |
|
| 267 | + { |
|
| 268 | + return apply_filters( |
|
| 269 | + 'FHEE__EEM_Registration__reg_statuses_that_allow_payment', |
|
| 270 | + array( |
|
| 271 | + EEM_Registration::status_id_approved, |
|
| 272 | + EEM_Registration::status_id_pending_payment, |
|
| 273 | + ) |
|
| 274 | + ); |
|
| 275 | + } |
|
| 276 | + |
|
| 277 | + |
|
| 278 | + /** |
|
| 279 | + * active_reg_statuses |
|
| 280 | + * a filterable list of registration statuses that are considered active |
|
| 281 | + * |
|
| 282 | + * @access public |
|
| 283 | + * @return array |
|
| 284 | + */ |
|
| 285 | + public static function active_reg_statuses() |
|
| 286 | + { |
|
| 287 | + return apply_filters( |
|
| 288 | + 'FHEE__EEM_Registration__active_reg_statuses', |
|
| 289 | + array( |
|
| 290 | + EEM_Registration::status_id_approved, |
|
| 291 | + EEM_Registration::status_id_pending_payment, |
|
| 292 | + EEM_Registration::status_id_wait_list, |
|
| 293 | + EEM_Registration::status_id_not_approved, |
|
| 294 | + ) |
|
| 295 | + ); |
|
| 296 | + } |
|
| 297 | + |
|
| 298 | + |
|
| 299 | + /** |
|
| 300 | + * inactive_reg_statuses |
|
| 301 | + * a filterable list of registration statuses that are not considered active |
|
| 302 | + * |
|
| 303 | + * @access public |
|
| 304 | + * @return array |
|
| 305 | + */ |
|
| 306 | + public static function inactive_reg_statuses() |
|
| 307 | + { |
|
| 308 | + return apply_filters( |
|
| 309 | + 'FHEE__EEM_Registration__inactive_reg_statuses', |
|
| 310 | + array( |
|
| 311 | + EEM_Registration::status_id_incomplete, |
|
| 312 | + EEM_Registration::status_id_cancelled, |
|
| 313 | + EEM_Registration::status_id_declined, |
|
| 314 | + ) |
|
| 315 | + ); |
|
| 316 | + } |
|
| 317 | + |
|
| 318 | + |
|
| 319 | + /** |
|
| 320 | + * closed_reg_statuses |
|
| 321 | + * a filterable list of registration statuses that are considered "closed" |
|
| 322 | + * meaning they should not be considered in any calculations involving monies owing |
|
| 323 | + * |
|
| 324 | + * @access public |
|
| 325 | + * @return array |
|
| 326 | + */ |
|
| 327 | + public static function closed_reg_statuses() |
|
| 328 | + { |
|
| 329 | + return apply_filters( |
|
| 330 | + 'FHEE__EEM_Registration__closed_reg_statuses', |
|
| 331 | + array( |
|
| 332 | + EEM_Registration::status_id_cancelled, |
|
| 333 | + EEM_Registration::status_id_declined, |
|
| 334 | + EEM_Registration::status_id_wait_list, |
|
| 335 | + ) |
|
| 336 | + ); |
|
| 337 | + } |
|
| 338 | + |
|
| 339 | + |
|
| 340 | + /** |
|
| 341 | + * get list of registration statuses |
|
| 342 | + * |
|
| 343 | + * @access public |
|
| 344 | + * @param array $exclude The status ids to exclude from the returned results |
|
| 345 | + * @param bool $translated If true will return the values as singular localized strings |
|
| 346 | + * @return array |
|
| 347 | + * @throws EE_Error |
|
| 348 | + */ |
|
| 349 | + public static function reg_status_array($exclude = array(), $translated = false) |
|
| 350 | + { |
|
| 351 | + EEM_Registration::instance()->_get_registration_status_array($exclude); |
|
| 352 | + return $translated |
|
| 353 | + ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence') |
|
| 354 | + : self::$_reg_status; |
|
| 355 | + } |
|
| 356 | + |
|
| 357 | + |
|
| 358 | + /** |
|
| 359 | + * get list of registration statuses |
|
| 360 | + * |
|
| 361 | + * @access private |
|
| 362 | + * @param array $exclude |
|
| 363 | + * @return void |
|
| 364 | + * @throws EE_Error |
|
| 365 | + */ |
|
| 366 | + private function _get_registration_status_array($exclude = array()) |
|
| 367 | + { |
|
| 368 | + // in the very rare circumstance that we are deleting a model's table's data |
|
| 369 | + // and the table hasn't actually been created, this could have an error |
|
| 370 | + /** @type WPDB $wpdb */ |
|
| 371 | + global $wpdb; |
|
| 372 | + if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) { |
|
| 373 | + $results = $wpdb->get_results( |
|
| 374 | + "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'" |
|
| 375 | + ); |
|
| 376 | + self::$_reg_status = array(); |
|
| 377 | + foreach ($results as $status) { |
|
| 378 | + if (!in_array($status->STS_ID, $exclude, true)) { |
|
| 379 | + self::$_reg_status[ $status->STS_ID ] = $status->STS_code; |
|
| 380 | + } |
|
| 381 | + } |
|
| 382 | + } |
|
| 383 | + } |
|
| 384 | + |
|
| 385 | + |
|
| 386 | + /** |
|
| 387 | + * Gets the injected table analyzer, or throws an exception |
|
| 388 | + * |
|
| 389 | + * @return TableAnalysis |
|
| 390 | + * @throws EE_Error |
|
| 391 | + */ |
|
| 392 | + protected function _get_table_analysis() |
|
| 393 | + { |
|
| 394 | + if ($this->_table_analysis instanceof TableAnalysis) { |
|
| 395 | + return $this->_table_analysis; |
|
| 396 | + } |
|
| 397 | + throw new EE_Error( |
|
| 398 | + sprintf( |
|
| 399 | + esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'), |
|
| 400 | + get_class($this) |
|
| 401 | + ) |
|
| 402 | + ); |
|
| 403 | + } |
|
| 404 | + |
|
| 405 | + |
|
| 406 | + /** |
|
| 407 | + * This returns a wpdb->results array of all registration date month and years matching the incoming query params |
|
| 408 | + * and grouped by month and year. |
|
| 409 | + * |
|
| 410 | + * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
| 411 | + * @return array |
|
| 412 | + * @throws EE_Error |
|
| 413 | + */ |
|
| 414 | + public function get_reg_months_and_years($where_params) |
|
| 415 | + { |
|
| 416 | + $query_params[0] = $where_params; |
|
| 417 | + $query_params['group_by'] = array('reg_year', 'reg_month'); |
|
| 418 | + $query_params['order_by'] = array('REG_date' => 'DESC'); |
|
| 419 | + $columns_to_select = array( |
|
| 420 | + 'reg_year' => array('YEAR(REG_date)', '%s'), |
|
| 421 | + 'reg_month' => array('MONTHNAME(REG_date)', '%s'), |
|
| 422 | + ); |
|
| 423 | + return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
| 424 | + } |
|
| 425 | + |
|
| 426 | + |
|
| 427 | + /** |
|
| 428 | + * retrieve ALL registrations for a particular Attendee from db |
|
| 429 | + * |
|
| 430 | + * @param int $ATT_ID |
|
| 431 | + * @return EE_Base_Class[]|EE_Registration[]|null |
|
| 432 | + * @throws EE_Error |
|
| 433 | + */ |
|
| 434 | + public function get_all_registrations_for_attendee($ATT_ID = 0) |
|
| 435 | + { |
|
| 436 | + if (!$ATT_ID) { |
|
| 437 | + return null; |
|
| 438 | + } |
|
| 439 | + return $this->get_all(array(array('ATT_ID' => $ATT_ID))); |
|
| 440 | + } |
|
| 441 | + |
|
| 442 | + |
|
| 443 | + /** |
|
| 444 | + * Gets a registration given their REG_url_link. Yes, this should usually |
|
| 445 | + * be passed via a GET parameter. |
|
| 446 | + * |
|
| 447 | + * @param string $REG_url_link |
|
| 448 | + * @return EE_Base_Class|EE_Registration|null |
|
| 449 | + * @throws EE_Error |
|
| 450 | + */ |
|
| 451 | + public function get_registration_for_reg_url_link($REG_url_link) |
|
| 452 | + { |
|
| 453 | + if (!$REG_url_link) { |
|
| 454 | + return null; |
|
| 455 | + } |
|
| 456 | + return $this->get_one(array(array('REG_url_link' => $REG_url_link))); |
|
| 457 | + } |
|
| 458 | + |
|
| 459 | + |
|
| 460 | + /** |
|
| 461 | + * retrieve registration for a specific transaction attendee from db |
|
| 462 | + * |
|
| 463 | + * @access public |
|
| 464 | + * @param int $TXN_ID |
|
| 465 | + * @param int $ATT_ID |
|
| 466 | + * @param int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the |
|
| 467 | + * attendee number is required |
|
| 468 | + * @return mixed array on success, FALSE on fail |
|
| 469 | + * @throws EE_Error |
|
| 470 | + */ |
|
| 471 | + public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0) |
|
| 472 | + { |
|
| 473 | + return $this->get_one(array( |
|
| 474 | + array( |
|
| 475 | + 'TXN_ID' => $TXN_ID, |
|
| 476 | + 'ATT_ID' => $ATT_ID, |
|
| 477 | + ), |
|
| 478 | + 'limit' => array(min($att_nmbr - 1, 0), 1), |
|
| 479 | + )); |
|
| 480 | + } |
|
| 481 | + |
|
| 482 | + |
|
| 483 | + /** |
|
| 484 | + * get the number of registrations per day for the Registration Admin page Reports Tab. |
|
| 485 | + * (doesn't utilize models because it's a fairly specialized query) |
|
| 486 | + * |
|
| 487 | + * @access public |
|
| 488 | + * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
| 489 | + * @return stdClass[] with properties regDate and total |
|
| 490 | + * @throws EE_Error |
|
| 491 | + */ |
|
| 492 | + public function get_registrations_per_day_report($period = '-1 month') |
|
| 493 | + { |
|
| 494 | + $sql_date = $this->convert_datetime_for_query( |
|
| 495 | + 'REG_date', |
|
| 496 | + date('Y-m-d H:i:s', strtotime($period)), |
|
| 497 | + 'Y-m-d H:i:s', |
|
| 498 | + 'UTC' |
|
| 499 | + ); |
|
| 500 | + $where = array( |
|
| 501 | + 'REG_date' => array('>=', $sql_date), |
|
| 502 | + 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
| 503 | + ); |
|
| 504 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) { |
|
| 505 | + $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
| 506 | + } |
|
| 507 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date'); |
|
| 508 | + $results = $this->_get_all_wpdb_results( |
|
| 509 | + array( |
|
| 510 | + $where, |
|
| 511 | + 'group_by' => 'regDate', |
|
| 512 | + 'order_by' => array('REG_date' => 'ASC'), |
|
| 513 | + ), |
|
| 514 | + OBJECT, |
|
| 515 | + array( |
|
| 516 | + 'regDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
| 517 | + 'total' => array('count(REG_ID)', '%d'), |
|
| 518 | + ) |
|
| 519 | + ); |
|
| 520 | + return $results; |
|
| 521 | + } |
|
| 522 | + |
|
| 523 | + |
|
| 524 | + /** |
|
| 525 | + * Get the number of registrations per day including the count of registrations for each Registration Status. |
|
| 526 | + * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
| 527 | + * |
|
| 528 | + * @param string $period |
|
| 529 | + * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID |
|
| 530 | + * @throws EE_Error |
|
| 531 | + * (i.e. RAP) |
|
| 532 | + */ |
|
| 533 | + public function get_registrations_per_day_and_per_status_report($period = '-1 month') |
|
| 534 | + { |
|
| 535 | + global $wpdb; |
|
| 536 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 537 | + $event_table = $wpdb->posts; |
|
| 538 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 539 | + // prepare the query interval for displaying offset |
|
| 540 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date'); |
|
| 541 | + // inner date query |
|
| 542 | + $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} "; |
|
| 543 | + $inner_where = ' WHERE'; |
|
| 544 | + // exclude events not authored by user if permissions in effect |
|
| 545 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 546 | + $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
| 547 | + $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
| 548 | + } |
|
| 549 | + $inner_where .= " REG_date >= '{$sql_date}'"; |
|
| 550 | + $inner_date_query .= $inner_where; |
|
| 551 | + // start main query |
|
| 552 | + $select = "SELECT DATE({$query_interval}) as Registration_REG_date, "; |
|
| 553 | + $join = ''; |
|
| 554 | + $join_parts = array(); |
|
| 555 | + $select_parts = array(); |
|
| 556 | + // loop through registration stati to do parts for each status. |
|
| 557 | + foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
| 558 | + if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
| 559 | + continue; |
|
| 560 | + } |
|
| 561 | + $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
| 562 | + $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'"; |
|
| 563 | + } |
|
| 564 | + // setup the selects |
|
| 565 | + $select .= implode(', ', $select_parts); |
|
| 566 | + $select .= " FROM ($inner_date_query) AS dates LEFT JOIN "; |
|
| 567 | + // setup the joins |
|
| 568 | + $join .= implode(' LEFT JOIN ', $join_parts); |
|
| 569 | + // now let's put it all together |
|
| 570 | + $query = $select . $join . ' GROUP BY Registration_REG_date'; |
|
| 571 | + // and execute it |
|
| 572 | + return $wpdb->get_results($query, ARRAY_A); |
|
| 573 | + } |
|
| 574 | + |
|
| 575 | + |
|
| 576 | + /** |
|
| 577 | + * get the number of registrations per event for the Registration Admin page Reports Tab |
|
| 578 | + * |
|
| 579 | + * @access public |
|
| 580 | + * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
| 581 | + * @return stdClass[] each with properties event_name, reg_limit, and total |
|
| 582 | + * @throws EE_Error |
|
| 583 | + */ |
|
| 584 | + public function get_registrations_per_event_report($period = '-1 month') |
|
| 585 | + { |
|
| 586 | + $date_sql = $this->convert_datetime_for_query( |
|
| 587 | + 'REG_date', |
|
| 588 | + date('Y-m-d H:i:s', strtotime($period)), |
|
| 589 | + 'Y-m-d H:i:s', |
|
| 590 | + 'UTC' |
|
| 591 | + ); |
|
| 592 | + $where = array( |
|
| 593 | + 'REG_date' => array('>=', $date_sql), |
|
| 594 | + 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
| 595 | + ); |
|
| 596 | + if (!EE_Registry::instance()->CAP->current_user_can( |
|
| 597 | + 'ee_read_others_registrations', |
|
| 598 | + 'reg_per_event_report' |
|
| 599 | + ) |
|
| 600 | + ) { |
|
| 601 | + $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
| 602 | + } |
|
| 603 | + $results = $this->_get_all_wpdb_results( |
|
| 604 | + array( |
|
| 605 | + $where, |
|
| 606 | + 'group_by' => 'Event.EVT_name', |
|
| 607 | + 'order_by' => 'Event.EVT_name', |
|
| 608 | + 'limit' => array(0, 24), |
|
| 609 | + ), |
|
| 610 | + OBJECT, |
|
| 611 | + array( |
|
| 612 | + 'event_name' => array('Event_CPT.post_title', '%s'), |
|
| 613 | + 'total' => array('COUNT(REG_ID)', '%s'), |
|
| 614 | + ) |
|
| 615 | + ); |
|
| 616 | + return $results; |
|
| 617 | + } |
|
| 618 | + |
|
| 619 | + |
|
| 620 | + /** |
|
| 621 | + * Get the number of registrations per event grouped by registration status. |
|
| 622 | + * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
| 623 | + * |
|
| 624 | + * @param string $period |
|
| 625 | + * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID |
|
| 626 | + * @throws EE_Error |
|
| 627 | + * (i.e. RAP) |
|
| 628 | + */ |
|
| 629 | + public function get_registrations_per_event_and_per_status_report($period = '-1 month') |
|
| 630 | + { |
|
| 631 | + global $wpdb; |
|
| 632 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 633 | + $event_table = $wpdb->posts; |
|
| 634 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 635 | + // inner date query |
|
| 636 | + $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table "; |
|
| 637 | + $inner_where = ' WHERE'; |
|
| 638 | + // exclude events not authored by user if permissions in effect |
|
| 639 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 640 | + $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
| 641 | + $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
| 642 | + } |
|
| 643 | + $inner_where .= " REG_date >= '{$sql_date}'"; |
|
| 644 | + $inner_date_query .= $inner_where; |
|
| 645 | + // build main query |
|
| 646 | + $select = 'SELECT Event.post_title as Registration_Event, '; |
|
| 647 | + $join = ''; |
|
| 648 | + $join_parts = array(); |
|
| 649 | + $select_parts = array(); |
|
| 650 | + // loop through registration stati to do parts for each status. |
|
| 651 | + foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
| 652 | + if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
| 653 | + continue; |
|
| 654 | + } |
|
| 655 | + $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
| 656 | + $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date"; |
|
| 657 | + } |
|
| 658 | + // setup the selects |
|
| 659 | + $select .= implode(', ', $select_parts); |
|
| 660 | + $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN "; |
|
| 661 | + // setup remaining joins |
|
| 662 | + $join .= implode(' LEFT JOIN ', $join_parts); |
|
| 663 | + // now put it all together |
|
| 664 | + $query = $select . $join . ' GROUP BY Registration_Event'; |
|
| 665 | + // and execute |
|
| 666 | + return $wpdb->get_results($query, ARRAY_A); |
|
| 667 | + } |
|
| 668 | + |
|
| 669 | + |
|
| 670 | + /** |
|
| 671 | + * Returns the EE_Registration of the primary attendee on the transaction id provided |
|
| 672 | + * |
|
| 673 | + * @param int $TXN_ID |
|
| 674 | + * @return EE_Base_Class|EE_Registration|null |
|
| 675 | + * @throws EE_Error |
|
| 676 | + */ |
|
| 677 | + public function get_primary_registration_for_transaction_ID($TXN_ID = 0) |
|
| 678 | + { |
|
| 679 | + if (!$TXN_ID) { |
|
| 680 | + return null; |
|
| 681 | + } |
|
| 682 | + return $this->get_one(array( |
|
| 683 | + array( |
|
| 684 | + 'TXN_ID' => $TXN_ID, |
|
| 685 | + 'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT, |
|
| 686 | + ), |
|
| 687 | + )); |
|
| 688 | + } |
|
| 689 | + |
|
| 690 | + |
|
| 691 | + /** |
|
| 692 | + * get_event_registration_count |
|
| 693 | + * |
|
| 694 | + * @access public |
|
| 695 | + * @param int $EVT_ID |
|
| 696 | + * @param boolean $for_incomplete_payments |
|
| 697 | + * @return int |
|
| 698 | + * @throws EE_Error |
|
| 699 | + */ |
|
| 700 | + public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false) |
|
| 701 | + { |
|
| 702 | + // we only count approved registrations towards registration limits |
|
| 703 | + $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved)); |
|
| 704 | + if ($for_incomplete_payments) { |
|
| 705 | + $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code); |
|
| 706 | + } |
|
| 707 | + return $this->count($query_params); |
|
| 708 | + } |
|
| 709 | + |
|
| 710 | + |
|
| 711 | + /** |
|
| 712 | + * Deletes all registrations with no transactions. Note that this needs to be very efficient |
|
| 713 | + * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete |
|
| 714 | + * when joining tables like this. |
|
| 715 | + * |
|
| 716 | + * @global WPDB $wpdb |
|
| 717 | + * @return int number deleted |
|
| 718 | + * @throws EE_Error |
|
| 719 | + */ |
|
| 720 | + public function delete_registrations_with_no_transaction() |
|
| 721 | + { |
|
| 722 | + /** @type WPDB $wpdb */ |
|
| 723 | + global $wpdb; |
|
| 724 | + return $wpdb->query( |
|
| 725 | + 'DELETE r FROM ' |
|
| 726 | + . $this->table() |
|
| 727 | + . ' r LEFT JOIN ' |
|
| 728 | + . EEM_Transaction::instance()->table() |
|
| 729 | + . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL' |
|
| 730 | + ); |
|
| 731 | + } |
|
| 732 | + |
|
| 733 | + |
|
| 734 | + /** |
|
| 735 | + * Count registrations checked into (or out of) a datetime |
|
| 736 | + * |
|
| 737 | + * @param int $DTT_ID datetime ID |
|
| 738 | + * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
| 739 | + * @return int |
|
| 740 | + * @throws EE_Error |
|
| 741 | + */ |
|
| 742 | + public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true) |
|
| 743 | + { |
|
| 744 | + global $wpdb; |
|
| 745 | + // subquery to get latest checkin |
|
| 746 | + $query = $wpdb->prepare( |
|
| 747 | + 'SELECT ' |
|
| 748 | + . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
| 749 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
| 750 | + . '( SELECT ' |
|
| 751 | + . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
| 752 | + . 'REG_ID AS REG_ID ' |
|
| 753 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' ' |
|
| 754 | + . 'WHERE DTT_ID=%d ' |
|
| 755 | + . 'GROUP BY REG_ID' |
|
| 756 | + . ') AS most_recent_checkin_per_reg ' |
|
| 757 | + . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
| 758 | + . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
| 759 | + . 'WHERE ' |
|
| 760 | + . 'checkins.CHK_in=%d', |
|
| 761 | + $DTT_ID, |
|
| 762 | + $checked_in |
|
| 763 | + ); |
|
| 764 | + return (int) $wpdb->get_var($query); |
|
| 765 | + } |
|
| 766 | + |
|
| 767 | + |
|
| 768 | + /** |
|
| 769 | + * Count registrations checked into (or out of) an event. |
|
| 770 | + * |
|
| 771 | + * @param int $EVT_ID event ID |
|
| 772 | + * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
| 773 | + * @return int |
|
| 774 | + * @throws EE_Error |
|
| 775 | + */ |
|
| 776 | + public function count_registrations_checked_into_event($EVT_ID, $checked_in = true) |
|
| 777 | + { |
|
| 778 | + global $wpdb; |
|
| 779 | + // subquery to get latest checkin |
|
| 780 | + $query = $wpdb->prepare( |
|
| 781 | + 'SELECT ' |
|
| 782 | + . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
| 783 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
| 784 | + . '( SELECT ' |
|
| 785 | + . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
| 786 | + . 'REG_ID AS REG_ID ' |
|
| 787 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c ' |
|
| 788 | + . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d ' |
|
| 789 | + . 'ON c.DTT_ID=d.DTT_ID ' |
|
| 790 | + . 'WHERE d.EVT_ID=%d ' |
|
| 791 | + . 'GROUP BY REG_ID' |
|
| 792 | + . ') AS most_recent_checkin_per_reg ' |
|
| 793 | + . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
| 794 | + . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
| 795 | + . 'WHERE ' |
|
| 796 | + . 'checkins.CHK_in=%d', |
|
| 797 | + $EVT_ID, |
|
| 798 | + $checked_in |
|
| 799 | + ); |
|
| 800 | + return (int) $wpdb->get_var($query); |
|
| 801 | + } |
|
| 802 | + |
|
| 803 | + |
|
| 804 | + /** |
|
| 805 | + * The purpose of this method is to retrieve an array of |
|
| 806 | + * EE_Registration objects that represent the latest registration |
|
| 807 | + * for each ATT_ID given in the function argument. |
|
| 808 | + * |
|
| 809 | + * @param array $attendee_ids |
|
| 810 | + * @return EE_Base_Class[]|EE_Registration[] |
|
| 811 | + * @throws EE_Error |
|
| 812 | + */ |
|
| 813 | + public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array()) |
|
| 814 | + { |
|
| 815 | + // first do a native wp_query to get the latest REG_ID's matching these attendees. |
|
| 816 | + global $wpdb; |
|
| 817 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 818 | + $attendee_table = $wpdb->posts; |
|
| 819 | + $attendee_ids = is_array($attendee_ids) |
|
| 820 | + ? array_map('absint', $attendee_ids) |
|
| 821 | + : array((int) $attendee_ids); |
|
| 822 | + $ATT_IDs = implode(',', $attendee_ids); |
|
| 823 | + // first we do a query to get the registration ids |
|
| 824 | + // (because a group by before order by causes the order by to be ignored.) |
|
| 825 | + $registration_id_query = " |
|
| 826 | 826 | SELECT registrations.registration_ids as registration_id |
| 827 | 827 | FROM ( |
| 828 | 828 | SELECT |
@@ -836,61 +836,61 @@ discard block |
||
| 836 | 836 | ) AS registrations |
| 837 | 837 | GROUP BY registrations.attendee_ids |
| 838 | 838 | "; |
| 839 | - $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A); |
|
| 840 | - if (empty($registration_ids)) { |
|
| 841 | - return array(); |
|
| 842 | - } |
|
| 843 | - $ids_for_model_query = array(); |
|
| 844 | - // let's flatten the ids so they can be used in the model query. |
|
| 845 | - foreach ($registration_ids as $registration_id) { |
|
| 846 | - if (isset($registration_id['registration_id'])) { |
|
| 847 | - $ids_for_model_query[] = $registration_id['registration_id']; |
|
| 848 | - } |
|
| 849 | - } |
|
| 850 | - // construct query |
|
| 851 | - $_where = array( |
|
| 852 | - 'REG_ID' => array('IN', $ids_for_model_query), |
|
| 853 | - ); |
|
| 854 | - return $this->get_all(array($_where)); |
|
| 855 | - } |
|
| 856 | - |
|
| 857 | - |
|
| 858 | - |
|
| 859 | - /** |
|
| 860 | - * returns a count of registrations for the supplied event having the status as specified |
|
| 861 | - * |
|
| 862 | - * @param int $EVT_ID |
|
| 863 | - * @param array $statuses |
|
| 864 | - * @return int |
|
| 865 | - * @throws InvalidArgumentException |
|
| 866 | - * @throws InvalidStatusException |
|
| 867 | - * @throws EE_Error |
|
| 868 | - */ |
|
| 869 | - public function event_reg_count_for_statuses($EVT_ID, $statuses = array()) |
|
| 870 | - { |
|
| 871 | - $EVT_ID = absint($EVT_ID); |
|
| 872 | - if (! $EVT_ID) { |
|
| 873 | - throw new InvalidArgumentException( |
|
| 874 | - esc_html__('An invalid Event ID was supplied.', 'event_espresso') |
|
| 875 | - ); |
|
| 876 | - } |
|
| 877 | - $statuses = is_array($statuses) ? $statuses : array($statuses); |
|
| 878 | - $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved); |
|
| 879 | - $valid_reg_statuses = EEM_Registration::reg_statuses(); |
|
| 880 | - foreach ($statuses as $status) { |
|
| 881 | - if (! in_array($status, $valid_reg_statuses, true)) { |
|
| 882 | - throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso')); |
|
| 883 | - } |
|
| 884 | - } |
|
| 885 | - return $this->count( |
|
| 886 | - array( |
|
| 887 | - array( |
|
| 888 | - 'EVT_ID' => $EVT_ID, |
|
| 889 | - 'STS_ID' => array('IN', $statuses), |
|
| 890 | - ), |
|
| 891 | - ), |
|
| 892 | - 'REG_ID', |
|
| 893 | - true |
|
| 894 | - ); |
|
| 895 | - } |
|
| 839 | + $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A); |
|
| 840 | + if (empty($registration_ids)) { |
|
| 841 | + return array(); |
|
| 842 | + } |
|
| 843 | + $ids_for_model_query = array(); |
|
| 844 | + // let's flatten the ids so they can be used in the model query. |
|
| 845 | + foreach ($registration_ids as $registration_id) { |
|
| 846 | + if (isset($registration_id['registration_id'])) { |
|
| 847 | + $ids_for_model_query[] = $registration_id['registration_id']; |
|
| 848 | + } |
|
| 849 | + } |
|
| 850 | + // construct query |
|
| 851 | + $_where = array( |
|
| 852 | + 'REG_ID' => array('IN', $ids_for_model_query), |
|
| 853 | + ); |
|
| 854 | + return $this->get_all(array($_where)); |
|
| 855 | + } |
|
| 856 | + |
|
| 857 | + |
|
| 858 | + |
|
| 859 | + /** |
|
| 860 | + * returns a count of registrations for the supplied event having the status as specified |
|
| 861 | + * |
|
| 862 | + * @param int $EVT_ID |
|
| 863 | + * @param array $statuses |
|
| 864 | + * @return int |
|
| 865 | + * @throws InvalidArgumentException |
|
| 866 | + * @throws InvalidStatusException |
|
| 867 | + * @throws EE_Error |
|
| 868 | + */ |
|
| 869 | + public function event_reg_count_for_statuses($EVT_ID, $statuses = array()) |
|
| 870 | + { |
|
| 871 | + $EVT_ID = absint($EVT_ID); |
|
| 872 | + if (! $EVT_ID) { |
|
| 873 | + throw new InvalidArgumentException( |
|
| 874 | + esc_html__('An invalid Event ID was supplied.', 'event_espresso') |
|
| 875 | + ); |
|
| 876 | + } |
|
| 877 | + $statuses = is_array($statuses) ? $statuses : array($statuses); |
|
| 878 | + $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved); |
|
| 879 | + $valid_reg_statuses = EEM_Registration::reg_statuses(); |
|
| 880 | + foreach ($statuses as $status) { |
|
| 881 | + if (! in_array($status, $valid_reg_statuses, true)) { |
|
| 882 | + throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso')); |
|
| 883 | + } |
|
| 884 | + } |
|
| 885 | + return $this->count( |
|
| 886 | + array( |
|
| 887 | + array( |
|
| 888 | + 'EVT_ID' => $EVT_ID, |
|
| 889 | + 'STS_ID' => array('IN', $statuses), |
|
| 890 | + ), |
|
| 891 | + ), |
|
| 892 | + 'REG_ID', |
|
| 893 | + true |
|
| 894 | + ); |
|
| 895 | + } |
|
| 896 | 896 | } |
@@ -9,628 +9,628 @@ |
||
| 9 | 9 | class EEM_Message extends EEM_Base implements EEI_Query_Filter |
| 10 | 10 | { |
| 11 | 11 | |
| 12 | - // private instance of the Message object |
|
| 13 | - protected static $_instance = null; |
|
| 12 | + // private instance of the Message object |
|
| 13 | + protected static $_instance = null; |
|
| 14 | 14 | |
| 15 | 15 | |
| 16 | - /** |
|
| 17 | - * This priority indicates a message should be generated and sent ASAP |
|
| 18 | - * |
|
| 19 | - * @type int |
|
| 20 | - */ |
|
| 21 | - const priority_high = 10; |
|
| 22 | - |
|
| 23 | - |
|
| 24 | - /** |
|
| 25 | - * This priority indicates a message should be generated ASAP and queued for sending. |
|
| 26 | - * |
|
| 27 | - * @type |
|
| 28 | - */ |
|
| 29 | - const priority_medium = 20; |
|
| 30 | - |
|
| 31 | - |
|
| 32 | - /** |
|
| 33 | - * This priority indicates a message should be queued for generating. |
|
| 34 | - * |
|
| 35 | - * @type int |
|
| 36 | - */ |
|
| 37 | - const priority_low = 30; |
|
| 38 | - |
|
| 39 | - |
|
| 40 | - /** |
|
| 41 | - * indicates this message was sent at the time modified |
|
| 42 | - */ |
|
| 43 | - const status_sent = 'MSN'; |
|
| 44 | - |
|
| 45 | - |
|
| 46 | - /** |
|
| 47 | - * indicates this message is waiting to be sent |
|
| 48 | - */ |
|
| 49 | - const status_idle = 'MID'; |
|
| 50 | - |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * indicates an attempt was a made to send this message |
|
| 54 | - * at the scheduled time, but it failed at the time modified. This differs from MDO status in that it will ALWAYS |
|
| 55 | - * appear to the end user. |
|
| 56 | - */ |
|
| 57 | - const status_failed = 'MFL'; |
|
| 58 | - |
|
| 59 | - |
|
| 60 | - /** |
|
| 61 | - * indicates the message has been flagged for resending (at the time modified). |
|
| 62 | - */ |
|
| 63 | - const status_resend = 'MRS'; |
|
| 64 | - |
|
| 65 | - |
|
| 66 | - /** |
|
| 67 | - * indicates the message has been flagged for generation but has not been generated yet. Messages always start as |
|
| 68 | - * this status when added to the queue. |
|
| 69 | - */ |
|
| 70 | - const status_incomplete = 'MIC'; |
|
| 71 | - |
|
| 72 | - |
|
| 73 | - /** |
|
| 74 | - * Indicates everything was generated fine for the message, however, the messenger was unable to send. |
|
| 75 | - * This status means that its possible to retry sending the message. |
|
| 76 | - */ |
|
| 77 | - const status_retry = 'MRT'; |
|
| 78 | - |
|
| 79 | - |
|
| 80 | - /** |
|
| 81 | - * This is used for more informational messages that may not indicate anything is broken but still cannot be |
|
| 82 | - * generated or sent correctly. An example of a message that would get flagged this way would be when a not |
|
| 83 | - * approved message was queued for generation, but at time of generation, the attached registration(s) are |
|
| 84 | - * approved. So the message queued for generation is no longer valid. Messages for this status will only persist |
|
| 85 | - * in the db and be viewable in the message activity list table when the messages system is in debug mode. |
|
| 86 | - * |
|
| 87 | - * @see EEM_Message::debug() |
|
| 88 | - */ |
|
| 89 | - const status_debug_only = 'MDO'; |
|
| 90 | - |
|
| 91 | - |
|
| 92 | - /** |
|
| 93 | - * This status is given to messages it is processed by the messenger send method. |
|
| 94 | - * Messages with this status should rarely be seen in the Message List table, but if they are, that's usually |
|
| 95 | - * indicative of a PHP timeout or memory limit issue. |
|
| 96 | - */ |
|
| 97 | - const status_messenger_executing = 'MEX'; |
|
| 98 | - |
|
| 99 | - |
|
| 100 | - /** |
|
| 101 | - * Private constructor to prevent direct creation. |
|
| 102 | - * |
|
| 103 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and |
|
| 104 | - * any incoming timezone data that gets saved). Note this just sends the timezone info to |
|
| 105 | - * the date time model field objects. Default is null (and will be assumed using the set |
|
| 106 | - * timezone in the 'timezone_string' wp option) |
|
| 107 | - * @return EEM_Message |
|
| 108 | - */ |
|
| 109 | - protected function __construct($timezone = null) |
|
| 110 | - { |
|
| 111 | - $this->singular_item = __('Message', 'event_espresso'); |
|
| 112 | - $this->plural_item = __('Messages', 'event_espresso'); |
|
| 113 | - |
|
| 114 | - // used for token generator |
|
| 115 | - EE_Registry::instance()->load_helper('URL'); |
|
| 116 | - |
|
| 117 | - $this->_tables = array( |
|
| 118 | - 'Message' => new EE_Primary_Table('esp_message', 'MSG_ID'), |
|
| 119 | - ); |
|
| 120 | - |
|
| 121 | - $allowed_priority = array( |
|
| 122 | - self::priority_high => __('high', 'event_espresso'), |
|
| 123 | - self::priority_medium => __('medium', 'event_espresso'), |
|
| 124 | - self::priority_low => __('low', 'event_espresso'), |
|
| 125 | - ); |
|
| 126 | - |
|
| 127 | - $this->_fields = array( |
|
| 128 | - 'Message' => array( |
|
| 129 | - 'MSG_ID' => new EE_Primary_Key_Int_Field('MSG_ID', __('Message ID', 'event_espresso')), |
|
| 130 | - 'MSG_token' => new EE_Plain_Text_Field( |
|
| 131 | - 'MSG_token', |
|
| 132 | - __( |
|
| 133 | - 'Unique Token used to represent this row in publicly viewable contexts (eg. a url).', |
|
| 134 | - 'event_espresso' |
|
| 135 | - ), |
|
| 136 | - false, |
|
| 137 | - EEH_URL::generate_unique_token() |
|
| 138 | - ), |
|
| 139 | - 'GRP_ID' => new EE_Foreign_Key_Int_Field( |
|
| 140 | - 'GRP_ID', |
|
| 141 | - __('Foreign key to the EEM_Message_Template_Group table.', 'event_espresso'), |
|
| 142 | - true, |
|
| 143 | - 0, |
|
| 144 | - 'Message_Template_Group' |
|
| 145 | - ), |
|
| 146 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 147 | - 'TXN_ID', |
|
| 148 | - __( |
|
| 149 | - 'Foreign key to the related EE_Transaction. This is required to give context for regenerating the specific message', |
|
| 150 | - 'event_espresso' |
|
| 151 | - ), |
|
| 152 | - true, |
|
| 153 | - 0, |
|
| 154 | - 'Transaction' |
|
| 155 | - ), |
|
| 156 | - 'MSG_messenger' => new EE_Plain_Text_Field( |
|
| 157 | - 'MSG_messenger', |
|
| 158 | - __( |
|
| 159 | - 'Corresponds to the EE_messenger::name used to send this message. This will also be used to attempt any resending of the message.', |
|
| 160 | - 'event_espresso' |
|
| 161 | - ), |
|
| 162 | - false, |
|
| 163 | - 'email' |
|
| 164 | - ), |
|
| 165 | - 'MSG_message_type' => new EE_Plain_Text_Field( |
|
| 166 | - 'MSG_message_type', |
|
| 167 | - __('Corresponds to the EE_message_type::name used to generate this message.', 'event_espresso'), |
|
| 168 | - false, |
|
| 169 | - 'receipt' |
|
| 170 | - ), |
|
| 171 | - 'MSG_context' => new EE_Plain_Text_Field('MSG_context', __('Context', 'event_espresso'), false), |
|
| 172 | - 'MSG_recipient_ID' => new EE_Foreign_Key_Int_Field( |
|
| 173 | - 'MSG_recipient_ID', |
|
| 174 | - __('Recipient ID', 'event_espresso'), |
|
| 175 | - true, |
|
| 176 | - null, |
|
| 177 | - array('Registration', 'Attendee', 'WP_User') |
|
| 178 | - ), |
|
| 179 | - 'MSG_recipient_type' => new EE_Any_Foreign_Model_Name_Field( |
|
| 180 | - 'MSG_recipient_type', |
|
| 181 | - __('Recipient Type', 'event_espresso'), |
|
| 182 | - true, |
|
| 183 | - null, |
|
| 184 | - array('Registration', 'Attendee', 'WP_User') |
|
| 185 | - ), |
|
| 186 | - 'MSG_content' => new EE_Maybe_Serialized_Text_Field( |
|
| 187 | - 'MSG_content', |
|
| 188 | - __('Content', 'event_espresso'), |
|
| 189 | - true, |
|
| 190 | - '' |
|
| 191 | - ), |
|
| 192 | - 'MSG_to' => new EE_Maybe_Serialized_Text_Field( |
|
| 193 | - 'MSG_to', |
|
| 194 | - __('Address To', 'event_espresso'), |
|
| 195 | - true |
|
| 196 | - ), |
|
| 197 | - 'MSG_from' => new EE_Maybe_Serialized_Text_Field( |
|
| 198 | - 'MSG_from', |
|
| 199 | - __('Address From', 'event_espresso'), |
|
| 200 | - true |
|
| 201 | - ), |
|
| 202 | - 'MSG_subject' => new EE_Maybe_Serialized_Text_Field( |
|
| 203 | - 'MSG_subject', |
|
| 204 | - __('Subject', 'event_espresso'), |
|
| 205 | - true, |
|
| 206 | - '' |
|
| 207 | - ), |
|
| 208 | - 'MSG_priority' => new EE_Enum_Integer_Field( |
|
| 209 | - 'MSG_priority', |
|
| 210 | - __('Priority', 'event_espresso'), |
|
| 211 | - false, |
|
| 212 | - self::priority_low, |
|
| 213 | - $allowed_priority |
|
| 214 | - ), |
|
| 215 | - 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 216 | - 'STS_ID', |
|
| 217 | - __('Status', 'event_espresso'), |
|
| 218 | - false, |
|
| 219 | - self::status_incomplete, |
|
| 220 | - 'Status' |
|
| 221 | - ), |
|
| 222 | - 'MSG_created' => new EE_Datetime_Field( |
|
| 223 | - 'MSG_created', |
|
| 224 | - __('Created', 'event_espresso'), |
|
| 225 | - false, |
|
| 226 | - EE_Datetime_Field::now |
|
| 227 | - ), |
|
| 228 | - 'MSG_modified' => new EE_Datetime_Field( |
|
| 229 | - 'MSG_modified', |
|
| 230 | - __('Modified', 'event_espresso'), |
|
| 231 | - true, |
|
| 232 | - EE_Datetime_Field::now |
|
| 233 | - ), |
|
| 234 | - ), |
|
| 235 | - ); |
|
| 236 | - $this->_model_relations = array( |
|
| 237 | - 'Attendee' => new EE_Belongs_To_Any_Relation(), |
|
| 238 | - 'Registration' => new EE_Belongs_To_Any_Relation(), |
|
| 239 | - 'WP_User' => new EE_Belongs_To_Any_Relation(), |
|
| 240 | - 'Message_Template_Group' => new EE_Belongs_To_Relation(), |
|
| 241 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 242 | - ); |
|
| 243 | - parent::__construct($timezone); |
|
| 244 | - } |
|
| 245 | - |
|
| 246 | - |
|
| 247 | - /** |
|
| 248 | - * @return \EE_Message |
|
| 249 | - */ |
|
| 250 | - public function create_default_object() |
|
| 251 | - { |
|
| 252 | - /** @type EE_Message $message */ |
|
| 253 | - $message = parent::create_default_object(); |
|
| 254 | - if ($message instanceof EE_Message) { |
|
| 255 | - return EE_Message_Factory::set_messenger_and_message_type($message); |
|
| 256 | - } |
|
| 257 | - return null; |
|
| 258 | - } |
|
| 259 | - |
|
| 260 | - |
|
| 261 | - /** |
|
| 262 | - * @param mixed $cols_n_values |
|
| 263 | - * @return \EE_Message |
|
| 264 | - */ |
|
| 265 | - public function instantiate_class_from_array_or_object($cols_n_values) |
|
| 266 | - { |
|
| 267 | - /** @type EE_Message $message */ |
|
| 268 | - $message = parent::instantiate_class_from_array_or_object($cols_n_values); |
|
| 269 | - if ($message instanceof EE_Message) { |
|
| 270 | - return EE_Message_Factory::set_messenger_and_message_type($message); |
|
| 271 | - } |
|
| 272 | - return null; |
|
| 273 | - } |
|
| 274 | - |
|
| 275 | - |
|
| 276 | - /** |
|
| 277 | - * Returns whether or not a message of that type was sent for a given attendee. |
|
| 278 | - * |
|
| 279 | - * @param EE_Attendee|int $attendee |
|
| 280 | - * @param string $message_type the message type slug |
|
| 281 | - * @return boolean |
|
| 282 | - */ |
|
| 283 | - public function message_sent_for_attendee($attendee, $message_type) |
|
| 284 | - { |
|
| 285 | - $attendee_ID = EEM_Attendee::instance()->ensure_is_ID($attendee); |
|
| 286 | - return $this->exists(array( |
|
| 287 | - array( |
|
| 288 | - 'Attendee.ATT_ID' => $attendee_ID, |
|
| 289 | - 'MSG_message_type' => $message_type, |
|
| 290 | - 'STS_ID' => array('IN', $this->stati_indicating_sent()), |
|
| 291 | - ), |
|
| 292 | - )); |
|
| 293 | - } |
|
| 294 | - |
|
| 295 | - |
|
| 296 | - /** |
|
| 297 | - * Returns whether or not a message of that type was sent for a given registration |
|
| 298 | - * |
|
| 299 | - * @param EE_Registration|int $registration |
|
| 300 | - * @param string $message_type the message type slug |
|
| 301 | - * @return boolean |
|
| 302 | - */ |
|
| 303 | - public function message_sent_for_registration($registration, $message_type) |
|
| 304 | - { |
|
| 305 | - $registrationID = EEM_Registration::instance()->ensure_is_ID($registration); |
|
| 306 | - return $this->exists(array( |
|
| 307 | - array( |
|
| 308 | - 'Registration.REG_ID' => $registrationID, |
|
| 309 | - 'MSG_message_type' => $message_type, |
|
| 310 | - 'STS_ID' => array('IN', $this->stati_indicating_sent()), |
|
| 311 | - ), |
|
| 312 | - )); |
|
| 313 | - } |
|
| 314 | - |
|
| 315 | - |
|
| 316 | - /** |
|
| 317 | - * This retrieves an EE_Message object from the db matching the given token string. |
|
| 318 | - * |
|
| 319 | - * @param string $token |
|
| 320 | - * @return EE_Message |
|
| 321 | - */ |
|
| 322 | - public function get_one_by_token($token) |
|
| 323 | - { |
|
| 324 | - return $this->get_one(array( |
|
| 325 | - array( |
|
| 326 | - 'MSG_token' => $token, |
|
| 327 | - ), |
|
| 328 | - )); |
|
| 329 | - } |
|
| 330 | - |
|
| 331 | - |
|
| 332 | - /** |
|
| 333 | - * Returns stati that indicate the message HAS been sent |
|
| 334 | - * |
|
| 335 | - * @return array of strings for possible stati |
|
| 336 | - */ |
|
| 337 | - public function stati_indicating_sent() |
|
| 338 | - { |
|
| 339 | - return apply_filters('FHEE__EEM_Message__stati_indicating_sent', array(self::status_sent)); |
|
| 340 | - } |
|
| 341 | - |
|
| 342 | - |
|
| 343 | - /** |
|
| 344 | - * Returns stati that indicate the message is waiting to be sent. |
|
| 345 | - * |
|
| 346 | - * @return array of strings for possible stati. |
|
| 347 | - */ |
|
| 348 | - public function stati_indicating_to_send() |
|
| 349 | - { |
|
| 350 | - return apply_filters( |
|
| 351 | - 'FHEE__EEM_Message__stati_indicating_to_send', |
|
| 352 | - array(self::status_idle, self::status_resend) |
|
| 353 | - ); |
|
| 354 | - } |
|
| 355 | - |
|
| 356 | - |
|
| 357 | - /** |
|
| 358 | - * Returns stati that indicate the message has failed sending |
|
| 359 | - * |
|
| 360 | - * @return array array of strings for possible stati. |
|
| 361 | - */ |
|
| 362 | - public function stati_indicating_failed_sending() |
|
| 363 | - { |
|
| 364 | - $failed_stati = array( |
|
| 365 | - self::status_failed, |
|
| 366 | - self::status_retry, |
|
| 367 | - self::status_messenger_executing, |
|
| 368 | - ); |
|
| 369 | - // if WP_DEBUG is set, then let's include debug_only fails |
|
| 370 | - if (WP_DEBUG) { |
|
| 371 | - $failed_stati[] = self::status_debug_only; |
|
| 372 | - } |
|
| 373 | - return apply_filters('FHEE__EEM_Message__stati_indicating_failed_sending', $failed_stati); |
|
| 374 | - } |
|
| 375 | - |
|
| 376 | - |
|
| 377 | - /** |
|
| 378 | - * Returns filterable array of all EEM_Message statuses. |
|
| 379 | - * |
|
| 380 | - * @return array |
|
| 381 | - */ |
|
| 382 | - public function all_statuses() |
|
| 383 | - { |
|
| 384 | - return apply_filters( |
|
| 385 | - 'FHEE__EEM_Message__all_statuses', |
|
| 386 | - array( |
|
| 387 | - EEM_Message::status_sent, |
|
| 388 | - EEM_Message::status_incomplete, |
|
| 389 | - EEM_Message::status_idle, |
|
| 390 | - EEM_Message::status_resend, |
|
| 391 | - EEM_Message::status_retry, |
|
| 392 | - EEM_Message::status_failed, |
|
| 393 | - EEM_Message::status_messenger_executing, |
|
| 394 | - EEM_Message::status_debug_only, |
|
| 395 | - ) |
|
| 396 | - ); |
|
| 397 | - } |
|
| 398 | - |
|
| 399 | - /** |
|
| 400 | - * Detects any specific query variables in the request and uses those to setup appropriate |
|
| 401 | - * filter for any queries. |
|
| 402 | - * |
|
| 403 | - * @return array |
|
| 404 | - */ |
|
| 405 | - public function filter_by_query_params() |
|
| 406 | - { |
|
| 407 | - // expected possible query_vars, the key in this array matches an expected key in the request, |
|
| 408 | - // the value, matches the corresponding EEM_Base child reference. |
|
| 409 | - $expected_vars = $this->_expected_vars_for_query_inject(); |
|
| 410 | - $query_params[0] = array(); |
|
| 411 | - foreach ($expected_vars as $request_key => $model_name) { |
|
| 412 | - $request_value = EE_Registry::instance()->REQ->get($request_key); |
|
| 413 | - if ($request_value) { |
|
| 414 | - // special case |
|
| 415 | - switch ($request_key) { |
|
| 416 | - case '_REG_ID': |
|
| 417 | - $query_params[0]['AND**filter_by']['OR**filter_by_REG_ID'] = array( |
|
| 418 | - 'Transaction.Registration.REG_ID' => $request_value, |
|
| 419 | - ); |
|
| 420 | - break; |
|
| 421 | - case 'EVT_ID': |
|
| 422 | - $query_params[0]['AND**filter_by']['OR**filter_by_EVT_ID'] = array( |
|
| 423 | - 'Transaction.Registration.EVT_ID' => $request_value, |
|
| 424 | - ); |
|
| 425 | - break; |
|
| 426 | - default: |
|
| 427 | - $query_params[0]['AND**filter_by'][ 'OR**filter_by_' . $request_key ][ $model_name . '.' . $request_key ] = $request_value; |
|
| 428 | - break; |
|
| 429 | - } |
|
| 430 | - } |
|
| 431 | - } |
|
| 432 | - return $query_params; |
|
| 433 | - } |
|
| 434 | - |
|
| 435 | - |
|
| 436 | - /** |
|
| 437 | - * @return string |
|
| 438 | - */ |
|
| 439 | - public function get_pretty_label_for_results() |
|
| 440 | - { |
|
| 441 | - $expected_vars = $this->_expected_vars_for_query_inject(); |
|
| 442 | - $pretty_label = ''; |
|
| 443 | - $label_parts = array(); |
|
| 444 | - foreach ($expected_vars as $request_key => $model_name) { |
|
| 445 | - $model = EE_Registry::instance()->load_model($model_name); |
|
| 446 | - if ($model_field_value = EE_Registry::instance()->REQ->get($request_key)) { |
|
| 447 | - switch ($request_key) { |
|
| 448 | - case '_REG_ID': |
|
| 449 | - $label_parts[] = sprintf( |
|
| 450 | - esc_html__('Registration with the ID: %s', 'event_espresso'), |
|
| 451 | - $model_field_value |
|
| 452 | - ); |
|
| 453 | - break; |
|
| 454 | - case 'ATT_ID': |
|
| 455 | - /** @var EE_Attendee $attendee */ |
|
| 456 | - $attendee = $model->get_one_by_ID($model_field_value); |
|
| 457 | - $label_parts[] = $attendee instanceof EE_Attendee |
|
| 458 | - ? sprintf(esc_html__('Attendee %s', 'event_espresso'), $attendee->full_name()) |
|
| 459 | - : sprintf(esc_html__('Attendee ID: %s', 'event_espresso'), $model_field_value); |
|
| 460 | - break; |
|
| 461 | - case 'ID': |
|
| 462 | - /** @var EE_WP_User $wpUser */ |
|
| 463 | - $wpUser = $model->get_one_by_ID($model_field_value); |
|
| 464 | - $label_parts[] = $wpUser instanceof EE_WP_User |
|
| 465 | - ? sprintf(esc_html__('WP User: %s', 'event_espresso'), $wpUser->name()) |
|
| 466 | - : sprintf(esc_html__('WP User ID: %s', 'event_espresso'), $model_field_value); |
|
| 467 | - break; |
|
| 468 | - case 'TXN_ID': |
|
| 469 | - $label_parts[] = sprintf( |
|
| 470 | - esc_html__('Transaction with the ID: %s', 'event_espresso'), |
|
| 471 | - $model_field_value |
|
| 472 | - ); |
|
| 473 | - break; |
|
| 474 | - case 'EVT_ID': |
|
| 475 | - /** @var EE_Event $Event */ |
|
| 476 | - $Event = $model->get_one_by_ID($model_field_value); |
|
| 477 | - $label_parts[] = $Event instanceof EE_Event |
|
| 478 | - ? sprintf(esc_html__('for the Event: %s', 'event_espresso'), $Event->name()) |
|
| 479 | - : sprintf(esc_html__('for the Event with ID: %s', 'event_espresso'), $model_field_value); |
|
| 480 | - break; |
|
| 481 | - } |
|
| 482 | - } |
|
| 483 | - } |
|
| 484 | - |
|
| 485 | - if ($label_parts) { |
|
| 486 | - // prepend to the last element of $label_parts an "and". |
|
| 487 | - if (count($label_parts) > 1) { |
|
| 488 | - $label_parts_index_to_prepend = count($label_parts) - 1; |
|
| 489 | - $label_parts[ $label_parts_index_to_prepend ] = 'and' . $label_parts[ $label_parts_index_to_prepend ]; |
|
| 490 | - } |
|
| 491 | - |
|
| 492 | - $pretty_label .= sprintf( |
|
| 493 | - esc_html_x( |
|
| 494 | - 'Showing messages for %s', |
|
| 495 | - 'A label for the messages returned in a query that are filtered by items in the query. This could be Transaction, Event, Attendee, Registration, or WP_User.', |
|
| 496 | - 'event_espresso' |
|
| 497 | - ), |
|
| 498 | - implode(', ', $label_parts) |
|
| 499 | - ); |
|
| 500 | - } |
|
| 501 | - return $pretty_label; |
|
| 502 | - } |
|
| 503 | - |
|
| 504 | - |
|
| 505 | - /** |
|
| 506 | - * This returns the array of expected variables for the EEI_Query_Filter methods being implemented |
|
| 507 | - * The array is in the format: |
|
| 508 | - * array( |
|
| 509 | - * {$field_name} => {$model_name} |
|
| 510 | - * ); |
|
| 511 | - * |
|
| 512 | - * @since 4.9.0 |
|
| 513 | - * @return array |
|
| 514 | - */ |
|
| 515 | - protected function _expected_vars_for_query_inject() |
|
| 516 | - { |
|
| 517 | - return array( |
|
| 518 | - '_REG_ID' => 'Registration', |
|
| 519 | - 'ATT_ID' => 'Attendee', |
|
| 520 | - 'ID' => 'WP_User', |
|
| 521 | - 'TXN_ID' => 'Transaction', |
|
| 522 | - 'EVT_ID' => 'Event', |
|
| 523 | - ); |
|
| 524 | - } |
|
| 525 | - |
|
| 526 | - |
|
| 527 | - /** |
|
| 528 | - * This returns whether EEM_Message is in debug mode or not. |
|
| 529 | - * Currently "debug mode" is used to control the handling of the EEM_Message::debug_only status when |
|
| 530 | - * generating/sending messages. Debug mode can be set by either: |
|
| 531 | - * 1. Sending in a value for the $set_debug argument |
|
| 532 | - * 2. Defining `EE_DEBUG_MESSAGES` constant in wp-config.php |
|
| 533 | - * 3. Overriding the above via the provided filter. |
|
| 534 | - * |
|
| 535 | - * @param bool|null $set_debug If provided, then the debug mode will be set internally until reset via the |
|
| 536 | - * provided boolean. When no argument is provided (default null) then the debug |
|
| 537 | - * mode will be returned. |
|
| 538 | - * @return bool true means Messages is in debug mode. false means messages system is not in debug mode. |
|
| 539 | - */ |
|
| 540 | - public static function debug($set_debug = null) |
|
| 541 | - { |
|
| 542 | - static $is_debugging = null; |
|
| 543 | - |
|
| 544 | - // initialize (use constant if set). |
|
| 545 | - if (is_null($set_debug) && is_null($is_debugging)) { |
|
| 546 | - $is_debugging = defined('EE_DEBUG_MESSAGES') && EE_DEBUG_MESSAGES; |
|
| 547 | - } |
|
| 548 | - |
|
| 549 | - if (! is_null($set_debug)) { |
|
| 550 | - $is_debugging = filter_var($set_debug, FILTER_VALIDATE_BOOLEAN); |
|
| 551 | - } |
|
| 552 | - |
|
| 553 | - // return filtered value |
|
| 554 | - return apply_filters('FHEE__EEM_Message__debug', $is_debugging); |
|
| 555 | - } |
|
| 556 | - |
|
| 557 | - |
|
| 558 | - /** |
|
| 559 | - * Deletes old messages meeting certain criteria for removal from the database. |
|
| 560 | - * By default, this will delete messages that: |
|
| 561 | - * - are older than the value of the delete_threshold in months. |
|
| 562 | - * - have a STS_ID other than EEM_Message::status_idle |
|
| 563 | - * |
|
| 564 | - * @param int $delete_threshold This integer will be used to set the boundary for what messages are deleted in months. |
|
| 565 | - * @return bool|false|int Either the number of records affected or false if there was an error (you can call |
|
| 566 | - * $wpdb->last_error to find out what the error was. |
|
| 567 | - */ |
|
| 568 | - public function delete_old_messages($delete_threshold = 6) |
|
| 569 | - { |
|
| 570 | - $number_deleted = 0; |
|
| 571 | - /** |
|
| 572 | - * Allows code to change the boundary for what messages are kept. |
|
| 573 | - * Uses the value of the `delete_threshold` variable by default. |
|
| 574 | - * |
|
| 575 | - * @param int $seconds seconds that will be subtracted from the timestamp for now. |
|
| 576 | - * @return int |
|
| 577 | - */ |
|
| 578 | - $time_to_leave_alone = absint( |
|
| 579 | - apply_filters( |
|
| 580 | - 'FHEE__EEM_Message__delete_old_messages__time_to_leave_alone', |
|
| 581 | - ((int) $delete_threshold) * MONTH_IN_SECONDS |
|
| 582 | - ) |
|
| 583 | - ); |
|
| 584 | - |
|
| 585 | - |
|
| 586 | - /** |
|
| 587 | - * Allows code to change what message stati are ignored when deleting. |
|
| 588 | - * Defaults to only ignore EEM_Message::status_idle messages. |
|
| 589 | - * |
|
| 590 | - * @param string $message_stati_to_keep An array of message statuses that will be ignored when deleting. |
|
| 591 | - */ |
|
| 592 | - $message_stati_to_keep = (array) apply_filters( |
|
| 593 | - 'FHEE__EEM_Message__delete_old_messages__message_stati_to_keep', |
|
| 594 | - array( |
|
| 595 | - EEM_Message::status_idle |
|
| 596 | - ) |
|
| 597 | - ); |
|
| 598 | - |
|
| 599 | - // first get all the ids of messages being deleted |
|
| 600 | - $message_ids_to_delete = EEM_Message::instance()->get_col( |
|
| 601 | - array( |
|
| 602 | - 0 => array( |
|
| 603 | - 'STS_ID' => array('NOT_IN', $message_stati_to_keep), |
|
| 604 | - 'MSG_modified' => array('<', time() - $time_to_leave_alone) |
|
| 605 | - ), |
|
| 606 | - 'limit' => apply_filters( |
|
| 607 | - 'EEM_Message__delete_old_messages__limit', |
|
| 608 | - 2000, |
|
| 609 | - $delete_threshold |
|
| 610 | - ) |
|
| 611 | - ) |
|
| 612 | - ); |
|
| 613 | - |
|
| 614 | - if (! empty($message_ids_to_delete) && is_array($message_ids_to_delete)) { |
|
| 615 | - global $wpdb; |
|
| 616 | - $number_deleted = $wpdb->query(' |
|
| 16 | + /** |
|
| 17 | + * This priority indicates a message should be generated and sent ASAP |
|
| 18 | + * |
|
| 19 | + * @type int |
|
| 20 | + */ |
|
| 21 | + const priority_high = 10; |
|
| 22 | + |
|
| 23 | + |
|
| 24 | + /** |
|
| 25 | + * This priority indicates a message should be generated ASAP and queued for sending. |
|
| 26 | + * |
|
| 27 | + * @type |
|
| 28 | + */ |
|
| 29 | + const priority_medium = 20; |
|
| 30 | + |
|
| 31 | + |
|
| 32 | + /** |
|
| 33 | + * This priority indicates a message should be queued for generating. |
|
| 34 | + * |
|
| 35 | + * @type int |
|
| 36 | + */ |
|
| 37 | + const priority_low = 30; |
|
| 38 | + |
|
| 39 | + |
|
| 40 | + /** |
|
| 41 | + * indicates this message was sent at the time modified |
|
| 42 | + */ |
|
| 43 | + const status_sent = 'MSN'; |
|
| 44 | + |
|
| 45 | + |
|
| 46 | + /** |
|
| 47 | + * indicates this message is waiting to be sent |
|
| 48 | + */ |
|
| 49 | + const status_idle = 'MID'; |
|
| 50 | + |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * indicates an attempt was a made to send this message |
|
| 54 | + * at the scheduled time, but it failed at the time modified. This differs from MDO status in that it will ALWAYS |
|
| 55 | + * appear to the end user. |
|
| 56 | + */ |
|
| 57 | + const status_failed = 'MFL'; |
|
| 58 | + |
|
| 59 | + |
|
| 60 | + /** |
|
| 61 | + * indicates the message has been flagged for resending (at the time modified). |
|
| 62 | + */ |
|
| 63 | + const status_resend = 'MRS'; |
|
| 64 | + |
|
| 65 | + |
|
| 66 | + /** |
|
| 67 | + * indicates the message has been flagged for generation but has not been generated yet. Messages always start as |
|
| 68 | + * this status when added to the queue. |
|
| 69 | + */ |
|
| 70 | + const status_incomplete = 'MIC'; |
|
| 71 | + |
|
| 72 | + |
|
| 73 | + /** |
|
| 74 | + * Indicates everything was generated fine for the message, however, the messenger was unable to send. |
|
| 75 | + * This status means that its possible to retry sending the message. |
|
| 76 | + */ |
|
| 77 | + const status_retry = 'MRT'; |
|
| 78 | + |
|
| 79 | + |
|
| 80 | + /** |
|
| 81 | + * This is used for more informational messages that may not indicate anything is broken but still cannot be |
|
| 82 | + * generated or sent correctly. An example of a message that would get flagged this way would be when a not |
|
| 83 | + * approved message was queued for generation, but at time of generation, the attached registration(s) are |
|
| 84 | + * approved. So the message queued for generation is no longer valid. Messages for this status will only persist |
|
| 85 | + * in the db and be viewable in the message activity list table when the messages system is in debug mode. |
|
| 86 | + * |
|
| 87 | + * @see EEM_Message::debug() |
|
| 88 | + */ |
|
| 89 | + const status_debug_only = 'MDO'; |
|
| 90 | + |
|
| 91 | + |
|
| 92 | + /** |
|
| 93 | + * This status is given to messages it is processed by the messenger send method. |
|
| 94 | + * Messages with this status should rarely be seen in the Message List table, but if they are, that's usually |
|
| 95 | + * indicative of a PHP timeout or memory limit issue. |
|
| 96 | + */ |
|
| 97 | + const status_messenger_executing = 'MEX'; |
|
| 98 | + |
|
| 99 | + |
|
| 100 | + /** |
|
| 101 | + * Private constructor to prevent direct creation. |
|
| 102 | + * |
|
| 103 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and |
|
| 104 | + * any incoming timezone data that gets saved). Note this just sends the timezone info to |
|
| 105 | + * the date time model field objects. Default is null (and will be assumed using the set |
|
| 106 | + * timezone in the 'timezone_string' wp option) |
|
| 107 | + * @return EEM_Message |
|
| 108 | + */ |
|
| 109 | + protected function __construct($timezone = null) |
|
| 110 | + { |
|
| 111 | + $this->singular_item = __('Message', 'event_espresso'); |
|
| 112 | + $this->plural_item = __('Messages', 'event_espresso'); |
|
| 113 | + |
|
| 114 | + // used for token generator |
|
| 115 | + EE_Registry::instance()->load_helper('URL'); |
|
| 116 | + |
|
| 117 | + $this->_tables = array( |
|
| 118 | + 'Message' => new EE_Primary_Table('esp_message', 'MSG_ID'), |
|
| 119 | + ); |
|
| 120 | + |
|
| 121 | + $allowed_priority = array( |
|
| 122 | + self::priority_high => __('high', 'event_espresso'), |
|
| 123 | + self::priority_medium => __('medium', 'event_espresso'), |
|
| 124 | + self::priority_low => __('low', 'event_espresso'), |
|
| 125 | + ); |
|
| 126 | + |
|
| 127 | + $this->_fields = array( |
|
| 128 | + 'Message' => array( |
|
| 129 | + 'MSG_ID' => new EE_Primary_Key_Int_Field('MSG_ID', __('Message ID', 'event_espresso')), |
|
| 130 | + 'MSG_token' => new EE_Plain_Text_Field( |
|
| 131 | + 'MSG_token', |
|
| 132 | + __( |
|
| 133 | + 'Unique Token used to represent this row in publicly viewable contexts (eg. a url).', |
|
| 134 | + 'event_espresso' |
|
| 135 | + ), |
|
| 136 | + false, |
|
| 137 | + EEH_URL::generate_unique_token() |
|
| 138 | + ), |
|
| 139 | + 'GRP_ID' => new EE_Foreign_Key_Int_Field( |
|
| 140 | + 'GRP_ID', |
|
| 141 | + __('Foreign key to the EEM_Message_Template_Group table.', 'event_espresso'), |
|
| 142 | + true, |
|
| 143 | + 0, |
|
| 144 | + 'Message_Template_Group' |
|
| 145 | + ), |
|
| 146 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
| 147 | + 'TXN_ID', |
|
| 148 | + __( |
|
| 149 | + 'Foreign key to the related EE_Transaction. This is required to give context for regenerating the specific message', |
|
| 150 | + 'event_espresso' |
|
| 151 | + ), |
|
| 152 | + true, |
|
| 153 | + 0, |
|
| 154 | + 'Transaction' |
|
| 155 | + ), |
|
| 156 | + 'MSG_messenger' => new EE_Plain_Text_Field( |
|
| 157 | + 'MSG_messenger', |
|
| 158 | + __( |
|
| 159 | + 'Corresponds to the EE_messenger::name used to send this message. This will also be used to attempt any resending of the message.', |
|
| 160 | + 'event_espresso' |
|
| 161 | + ), |
|
| 162 | + false, |
|
| 163 | + 'email' |
|
| 164 | + ), |
|
| 165 | + 'MSG_message_type' => new EE_Plain_Text_Field( |
|
| 166 | + 'MSG_message_type', |
|
| 167 | + __('Corresponds to the EE_message_type::name used to generate this message.', 'event_espresso'), |
|
| 168 | + false, |
|
| 169 | + 'receipt' |
|
| 170 | + ), |
|
| 171 | + 'MSG_context' => new EE_Plain_Text_Field('MSG_context', __('Context', 'event_espresso'), false), |
|
| 172 | + 'MSG_recipient_ID' => new EE_Foreign_Key_Int_Field( |
|
| 173 | + 'MSG_recipient_ID', |
|
| 174 | + __('Recipient ID', 'event_espresso'), |
|
| 175 | + true, |
|
| 176 | + null, |
|
| 177 | + array('Registration', 'Attendee', 'WP_User') |
|
| 178 | + ), |
|
| 179 | + 'MSG_recipient_type' => new EE_Any_Foreign_Model_Name_Field( |
|
| 180 | + 'MSG_recipient_type', |
|
| 181 | + __('Recipient Type', 'event_espresso'), |
|
| 182 | + true, |
|
| 183 | + null, |
|
| 184 | + array('Registration', 'Attendee', 'WP_User') |
|
| 185 | + ), |
|
| 186 | + 'MSG_content' => new EE_Maybe_Serialized_Text_Field( |
|
| 187 | + 'MSG_content', |
|
| 188 | + __('Content', 'event_espresso'), |
|
| 189 | + true, |
|
| 190 | + '' |
|
| 191 | + ), |
|
| 192 | + 'MSG_to' => new EE_Maybe_Serialized_Text_Field( |
|
| 193 | + 'MSG_to', |
|
| 194 | + __('Address To', 'event_espresso'), |
|
| 195 | + true |
|
| 196 | + ), |
|
| 197 | + 'MSG_from' => new EE_Maybe_Serialized_Text_Field( |
|
| 198 | + 'MSG_from', |
|
| 199 | + __('Address From', 'event_espresso'), |
|
| 200 | + true |
|
| 201 | + ), |
|
| 202 | + 'MSG_subject' => new EE_Maybe_Serialized_Text_Field( |
|
| 203 | + 'MSG_subject', |
|
| 204 | + __('Subject', 'event_espresso'), |
|
| 205 | + true, |
|
| 206 | + '' |
|
| 207 | + ), |
|
| 208 | + 'MSG_priority' => new EE_Enum_Integer_Field( |
|
| 209 | + 'MSG_priority', |
|
| 210 | + __('Priority', 'event_espresso'), |
|
| 211 | + false, |
|
| 212 | + self::priority_low, |
|
| 213 | + $allowed_priority |
|
| 214 | + ), |
|
| 215 | + 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 216 | + 'STS_ID', |
|
| 217 | + __('Status', 'event_espresso'), |
|
| 218 | + false, |
|
| 219 | + self::status_incomplete, |
|
| 220 | + 'Status' |
|
| 221 | + ), |
|
| 222 | + 'MSG_created' => new EE_Datetime_Field( |
|
| 223 | + 'MSG_created', |
|
| 224 | + __('Created', 'event_espresso'), |
|
| 225 | + false, |
|
| 226 | + EE_Datetime_Field::now |
|
| 227 | + ), |
|
| 228 | + 'MSG_modified' => new EE_Datetime_Field( |
|
| 229 | + 'MSG_modified', |
|
| 230 | + __('Modified', 'event_espresso'), |
|
| 231 | + true, |
|
| 232 | + EE_Datetime_Field::now |
|
| 233 | + ), |
|
| 234 | + ), |
|
| 235 | + ); |
|
| 236 | + $this->_model_relations = array( |
|
| 237 | + 'Attendee' => new EE_Belongs_To_Any_Relation(), |
|
| 238 | + 'Registration' => new EE_Belongs_To_Any_Relation(), |
|
| 239 | + 'WP_User' => new EE_Belongs_To_Any_Relation(), |
|
| 240 | + 'Message_Template_Group' => new EE_Belongs_To_Relation(), |
|
| 241 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
| 242 | + ); |
|
| 243 | + parent::__construct($timezone); |
|
| 244 | + } |
|
| 245 | + |
|
| 246 | + |
|
| 247 | + /** |
|
| 248 | + * @return \EE_Message |
|
| 249 | + */ |
|
| 250 | + public function create_default_object() |
|
| 251 | + { |
|
| 252 | + /** @type EE_Message $message */ |
|
| 253 | + $message = parent::create_default_object(); |
|
| 254 | + if ($message instanceof EE_Message) { |
|
| 255 | + return EE_Message_Factory::set_messenger_and_message_type($message); |
|
| 256 | + } |
|
| 257 | + return null; |
|
| 258 | + } |
|
| 259 | + |
|
| 260 | + |
|
| 261 | + /** |
|
| 262 | + * @param mixed $cols_n_values |
|
| 263 | + * @return \EE_Message |
|
| 264 | + */ |
|
| 265 | + public function instantiate_class_from_array_or_object($cols_n_values) |
|
| 266 | + { |
|
| 267 | + /** @type EE_Message $message */ |
|
| 268 | + $message = parent::instantiate_class_from_array_or_object($cols_n_values); |
|
| 269 | + if ($message instanceof EE_Message) { |
|
| 270 | + return EE_Message_Factory::set_messenger_and_message_type($message); |
|
| 271 | + } |
|
| 272 | + return null; |
|
| 273 | + } |
|
| 274 | + |
|
| 275 | + |
|
| 276 | + /** |
|
| 277 | + * Returns whether or not a message of that type was sent for a given attendee. |
|
| 278 | + * |
|
| 279 | + * @param EE_Attendee|int $attendee |
|
| 280 | + * @param string $message_type the message type slug |
|
| 281 | + * @return boolean |
|
| 282 | + */ |
|
| 283 | + public function message_sent_for_attendee($attendee, $message_type) |
|
| 284 | + { |
|
| 285 | + $attendee_ID = EEM_Attendee::instance()->ensure_is_ID($attendee); |
|
| 286 | + return $this->exists(array( |
|
| 287 | + array( |
|
| 288 | + 'Attendee.ATT_ID' => $attendee_ID, |
|
| 289 | + 'MSG_message_type' => $message_type, |
|
| 290 | + 'STS_ID' => array('IN', $this->stati_indicating_sent()), |
|
| 291 | + ), |
|
| 292 | + )); |
|
| 293 | + } |
|
| 294 | + |
|
| 295 | + |
|
| 296 | + /** |
|
| 297 | + * Returns whether or not a message of that type was sent for a given registration |
|
| 298 | + * |
|
| 299 | + * @param EE_Registration|int $registration |
|
| 300 | + * @param string $message_type the message type slug |
|
| 301 | + * @return boolean |
|
| 302 | + */ |
|
| 303 | + public function message_sent_for_registration($registration, $message_type) |
|
| 304 | + { |
|
| 305 | + $registrationID = EEM_Registration::instance()->ensure_is_ID($registration); |
|
| 306 | + return $this->exists(array( |
|
| 307 | + array( |
|
| 308 | + 'Registration.REG_ID' => $registrationID, |
|
| 309 | + 'MSG_message_type' => $message_type, |
|
| 310 | + 'STS_ID' => array('IN', $this->stati_indicating_sent()), |
|
| 311 | + ), |
|
| 312 | + )); |
|
| 313 | + } |
|
| 314 | + |
|
| 315 | + |
|
| 316 | + /** |
|
| 317 | + * This retrieves an EE_Message object from the db matching the given token string. |
|
| 318 | + * |
|
| 319 | + * @param string $token |
|
| 320 | + * @return EE_Message |
|
| 321 | + */ |
|
| 322 | + public function get_one_by_token($token) |
|
| 323 | + { |
|
| 324 | + return $this->get_one(array( |
|
| 325 | + array( |
|
| 326 | + 'MSG_token' => $token, |
|
| 327 | + ), |
|
| 328 | + )); |
|
| 329 | + } |
|
| 330 | + |
|
| 331 | + |
|
| 332 | + /** |
|
| 333 | + * Returns stati that indicate the message HAS been sent |
|
| 334 | + * |
|
| 335 | + * @return array of strings for possible stati |
|
| 336 | + */ |
|
| 337 | + public function stati_indicating_sent() |
|
| 338 | + { |
|
| 339 | + return apply_filters('FHEE__EEM_Message__stati_indicating_sent', array(self::status_sent)); |
|
| 340 | + } |
|
| 341 | + |
|
| 342 | + |
|
| 343 | + /** |
|
| 344 | + * Returns stati that indicate the message is waiting to be sent. |
|
| 345 | + * |
|
| 346 | + * @return array of strings for possible stati. |
|
| 347 | + */ |
|
| 348 | + public function stati_indicating_to_send() |
|
| 349 | + { |
|
| 350 | + return apply_filters( |
|
| 351 | + 'FHEE__EEM_Message__stati_indicating_to_send', |
|
| 352 | + array(self::status_idle, self::status_resend) |
|
| 353 | + ); |
|
| 354 | + } |
|
| 355 | + |
|
| 356 | + |
|
| 357 | + /** |
|
| 358 | + * Returns stati that indicate the message has failed sending |
|
| 359 | + * |
|
| 360 | + * @return array array of strings for possible stati. |
|
| 361 | + */ |
|
| 362 | + public function stati_indicating_failed_sending() |
|
| 363 | + { |
|
| 364 | + $failed_stati = array( |
|
| 365 | + self::status_failed, |
|
| 366 | + self::status_retry, |
|
| 367 | + self::status_messenger_executing, |
|
| 368 | + ); |
|
| 369 | + // if WP_DEBUG is set, then let's include debug_only fails |
|
| 370 | + if (WP_DEBUG) { |
|
| 371 | + $failed_stati[] = self::status_debug_only; |
|
| 372 | + } |
|
| 373 | + return apply_filters('FHEE__EEM_Message__stati_indicating_failed_sending', $failed_stati); |
|
| 374 | + } |
|
| 375 | + |
|
| 376 | + |
|
| 377 | + /** |
|
| 378 | + * Returns filterable array of all EEM_Message statuses. |
|
| 379 | + * |
|
| 380 | + * @return array |
|
| 381 | + */ |
|
| 382 | + public function all_statuses() |
|
| 383 | + { |
|
| 384 | + return apply_filters( |
|
| 385 | + 'FHEE__EEM_Message__all_statuses', |
|
| 386 | + array( |
|
| 387 | + EEM_Message::status_sent, |
|
| 388 | + EEM_Message::status_incomplete, |
|
| 389 | + EEM_Message::status_idle, |
|
| 390 | + EEM_Message::status_resend, |
|
| 391 | + EEM_Message::status_retry, |
|
| 392 | + EEM_Message::status_failed, |
|
| 393 | + EEM_Message::status_messenger_executing, |
|
| 394 | + EEM_Message::status_debug_only, |
|
| 395 | + ) |
|
| 396 | + ); |
|
| 397 | + } |
|
| 398 | + |
|
| 399 | + /** |
|
| 400 | + * Detects any specific query variables in the request and uses those to setup appropriate |
|
| 401 | + * filter for any queries. |
|
| 402 | + * |
|
| 403 | + * @return array |
|
| 404 | + */ |
|
| 405 | + public function filter_by_query_params() |
|
| 406 | + { |
|
| 407 | + // expected possible query_vars, the key in this array matches an expected key in the request, |
|
| 408 | + // the value, matches the corresponding EEM_Base child reference. |
|
| 409 | + $expected_vars = $this->_expected_vars_for_query_inject(); |
|
| 410 | + $query_params[0] = array(); |
|
| 411 | + foreach ($expected_vars as $request_key => $model_name) { |
|
| 412 | + $request_value = EE_Registry::instance()->REQ->get($request_key); |
|
| 413 | + if ($request_value) { |
|
| 414 | + // special case |
|
| 415 | + switch ($request_key) { |
|
| 416 | + case '_REG_ID': |
|
| 417 | + $query_params[0]['AND**filter_by']['OR**filter_by_REG_ID'] = array( |
|
| 418 | + 'Transaction.Registration.REG_ID' => $request_value, |
|
| 419 | + ); |
|
| 420 | + break; |
|
| 421 | + case 'EVT_ID': |
|
| 422 | + $query_params[0]['AND**filter_by']['OR**filter_by_EVT_ID'] = array( |
|
| 423 | + 'Transaction.Registration.EVT_ID' => $request_value, |
|
| 424 | + ); |
|
| 425 | + break; |
|
| 426 | + default: |
|
| 427 | + $query_params[0]['AND**filter_by'][ 'OR**filter_by_' . $request_key ][ $model_name . '.' . $request_key ] = $request_value; |
|
| 428 | + break; |
|
| 429 | + } |
|
| 430 | + } |
|
| 431 | + } |
|
| 432 | + return $query_params; |
|
| 433 | + } |
|
| 434 | + |
|
| 435 | + |
|
| 436 | + /** |
|
| 437 | + * @return string |
|
| 438 | + */ |
|
| 439 | + public function get_pretty_label_for_results() |
|
| 440 | + { |
|
| 441 | + $expected_vars = $this->_expected_vars_for_query_inject(); |
|
| 442 | + $pretty_label = ''; |
|
| 443 | + $label_parts = array(); |
|
| 444 | + foreach ($expected_vars as $request_key => $model_name) { |
|
| 445 | + $model = EE_Registry::instance()->load_model($model_name); |
|
| 446 | + if ($model_field_value = EE_Registry::instance()->REQ->get($request_key)) { |
|
| 447 | + switch ($request_key) { |
|
| 448 | + case '_REG_ID': |
|
| 449 | + $label_parts[] = sprintf( |
|
| 450 | + esc_html__('Registration with the ID: %s', 'event_espresso'), |
|
| 451 | + $model_field_value |
|
| 452 | + ); |
|
| 453 | + break; |
|
| 454 | + case 'ATT_ID': |
|
| 455 | + /** @var EE_Attendee $attendee */ |
|
| 456 | + $attendee = $model->get_one_by_ID($model_field_value); |
|
| 457 | + $label_parts[] = $attendee instanceof EE_Attendee |
|
| 458 | + ? sprintf(esc_html__('Attendee %s', 'event_espresso'), $attendee->full_name()) |
|
| 459 | + : sprintf(esc_html__('Attendee ID: %s', 'event_espresso'), $model_field_value); |
|
| 460 | + break; |
|
| 461 | + case 'ID': |
|
| 462 | + /** @var EE_WP_User $wpUser */ |
|
| 463 | + $wpUser = $model->get_one_by_ID($model_field_value); |
|
| 464 | + $label_parts[] = $wpUser instanceof EE_WP_User |
|
| 465 | + ? sprintf(esc_html__('WP User: %s', 'event_espresso'), $wpUser->name()) |
|
| 466 | + : sprintf(esc_html__('WP User ID: %s', 'event_espresso'), $model_field_value); |
|
| 467 | + break; |
|
| 468 | + case 'TXN_ID': |
|
| 469 | + $label_parts[] = sprintf( |
|
| 470 | + esc_html__('Transaction with the ID: %s', 'event_espresso'), |
|
| 471 | + $model_field_value |
|
| 472 | + ); |
|
| 473 | + break; |
|
| 474 | + case 'EVT_ID': |
|
| 475 | + /** @var EE_Event $Event */ |
|
| 476 | + $Event = $model->get_one_by_ID($model_field_value); |
|
| 477 | + $label_parts[] = $Event instanceof EE_Event |
|
| 478 | + ? sprintf(esc_html__('for the Event: %s', 'event_espresso'), $Event->name()) |
|
| 479 | + : sprintf(esc_html__('for the Event with ID: %s', 'event_espresso'), $model_field_value); |
|
| 480 | + break; |
|
| 481 | + } |
|
| 482 | + } |
|
| 483 | + } |
|
| 484 | + |
|
| 485 | + if ($label_parts) { |
|
| 486 | + // prepend to the last element of $label_parts an "and". |
|
| 487 | + if (count($label_parts) > 1) { |
|
| 488 | + $label_parts_index_to_prepend = count($label_parts) - 1; |
|
| 489 | + $label_parts[ $label_parts_index_to_prepend ] = 'and' . $label_parts[ $label_parts_index_to_prepend ]; |
|
| 490 | + } |
|
| 491 | + |
|
| 492 | + $pretty_label .= sprintf( |
|
| 493 | + esc_html_x( |
|
| 494 | + 'Showing messages for %s', |
|
| 495 | + 'A label for the messages returned in a query that are filtered by items in the query. This could be Transaction, Event, Attendee, Registration, or WP_User.', |
|
| 496 | + 'event_espresso' |
|
| 497 | + ), |
|
| 498 | + implode(', ', $label_parts) |
|
| 499 | + ); |
|
| 500 | + } |
|
| 501 | + return $pretty_label; |
|
| 502 | + } |
|
| 503 | + |
|
| 504 | + |
|
| 505 | + /** |
|
| 506 | + * This returns the array of expected variables for the EEI_Query_Filter methods being implemented |
|
| 507 | + * The array is in the format: |
|
| 508 | + * array( |
|
| 509 | + * {$field_name} => {$model_name} |
|
| 510 | + * ); |
|
| 511 | + * |
|
| 512 | + * @since 4.9.0 |
|
| 513 | + * @return array |
|
| 514 | + */ |
|
| 515 | + protected function _expected_vars_for_query_inject() |
|
| 516 | + { |
|
| 517 | + return array( |
|
| 518 | + '_REG_ID' => 'Registration', |
|
| 519 | + 'ATT_ID' => 'Attendee', |
|
| 520 | + 'ID' => 'WP_User', |
|
| 521 | + 'TXN_ID' => 'Transaction', |
|
| 522 | + 'EVT_ID' => 'Event', |
|
| 523 | + ); |
|
| 524 | + } |
|
| 525 | + |
|
| 526 | + |
|
| 527 | + /** |
|
| 528 | + * This returns whether EEM_Message is in debug mode or not. |
|
| 529 | + * Currently "debug mode" is used to control the handling of the EEM_Message::debug_only status when |
|
| 530 | + * generating/sending messages. Debug mode can be set by either: |
|
| 531 | + * 1. Sending in a value for the $set_debug argument |
|
| 532 | + * 2. Defining `EE_DEBUG_MESSAGES` constant in wp-config.php |
|
| 533 | + * 3. Overriding the above via the provided filter. |
|
| 534 | + * |
|
| 535 | + * @param bool|null $set_debug If provided, then the debug mode will be set internally until reset via the |
|
| 536 | + * provided boolean. When no argument is provided (default null) then the debug |
|
| 537 | + * mode will be returned. |
|
| 538 | + * @return bool true means Messages is in debug mode. false means messages system is not in debug mode. |
|
| 539 | + */ |
|
| 540 | + public static function debug($set_debug = null) |
|
| 541 | + { |
|
| 542 | + static $is_debugging = null; |
|
| 543 | + |
|
| 544 | + // initialize (use constant if set). |
|
| 545 | + if (is_null($set_debug) && is_null($is_debugging)) { |
|
| 546 | + $is_debugging = defined('EE_DEBUG_MESSAGES') && EE_DEBUG_MESSAGES; |
|
| 547 | + } |
|
| 548 | + |
|
| 549 | + if (! is_null($set_debug)) { |
|
| 550 | + $is_debugging = filter_var($set_debug, FILTER_VALIDATE_BOOLEAN); |
|
| 551 | + } |
|
| 552 | + |
|
| 553 | + // return filtered value |
|
| 554 | + return apply_filters('FHEE__EEM_Message__debug', $is_debugging); |
|
| 555 | + } |
|
| 556 | + |
|
| 557 | + |
|
| 558 | + /** |
|
| 559 | + * Deletes old messages meeting certain criteria for removal from the database. |
|
| 560 | + * By default, this will delete messages that: |
|
| 561 | + * - are older than the value of the delete_threshold in months. |
|
| 562 | + * - have a STS_ID other than EEM_Message::status_idle |
|
| 563 | + * |
|
| 564 | + * @param int $delete_threshold This integer will be used to set the boundary for what messages are deleted in months. |
|
| 565 | + * @return bool|false|int Either the number of records affected or false if there was an error (you can call |
|
| 566 | + * $wpdb->last_error to find out what the error was. |
|
| 567 | + */ |
|
| 568 | + public function delete_old_messages($delete_threshold = 6) |
|
| 569 | + { |
|
| 570 | + $number_deleted = 0; |
|
| 571 | + /** |
|
| 572 | + * Allows code to change the boundary for what messages are kept. |
|
| 573 | + * Uses the value of the `delete_threshold` variable by default. |
|
| 574 | + * |
|
| 575 | + * @param int $seconds seconds that will be subtracted from the timestamp for now. |
|
| 576 | + * @return int |
|
| 577 | + */ |
|
| 578 | + $time_to_leave_alone = absint( |
|
| 579 | + apply_filters( |
|
| 580 | + 'FHEE__EEM_Message__delete_old_messages__time_to_leave_alone', |
|
| 581 | + ((int) $delete_threshold) * MONTH_IN_SECONDS |
|
| 582 | + ) |
|
| 583 | + ); |
|
| 584 | + |
|
| 585 | + |
|
| 586 | + /** |
|
| 587 | + * Allows code to change what message stati are ignored when deleting. |
|
| 588 | + * Defaults to only ignore EEM_Message::status_idle messages. |
|
| 589 | + * |
|
| 590 | + * @param string $message_stati_to_keep An array of message statuses that will be ignored when deleting. |
|
| 591 | + */ |
|
| 592 | + $message_stati_to_keep = (array) apply_filters( |
|
| 593 | + 'FHEE__EEM_Message__delete_old_messages__message_stati_to_keep', |
|
| 594 | + array( |
|
| 595 | + EEM_Message::status_idle |
|
| 596 | + ) |
|
| 597 | + ); |
|
| 598 | + |
|
| 599 | + // first get all the ids of messages being deleted |
|
| 600 | + $message_ids_to_delete = EEM_Message::instance()->get_col( |
|
| 601 | + array( |
|
| 602 | + 0 => array( |
|
| 603 | + 'STS_ID' => array('NOT_IN', $message_stati_to_keep), |
|
| 604 | + 'MSG_modified' => array('<', time() - $time_to_leave_alone) |
|
| 605 | + ), |
|
| 606 | + 'limit' => apply_filters( |
|
| 607 | + 'EEM_Message__delete_old_messages__limit', |
|
| 608 | + 2000, |
|
| 609 | + $delete_threshold |
|
| 610 | + ) |
|
| 611 | + ) |
|
| 612 | + ); |
|
| 613 | + |
|
| 614 | + if (! empty($message_ids_to_delete) && is_array($message_ids_to_delete)) { |
|
| 615 | + global $wpdb; |
|
| 616 | + $number_deleted = $wpdb->query(' |
|
| 617 | 617 | DELETE |
| 618 | 618 | FROM ' . $this->table() . ' |
| 619 | 619 | WHERE |
| 620 | 620 | MSG_ID IN (' . implode(",", $message_ids_to_delete) . ') |
| 621 | 621 | '); |
| 622 | - } |
|
| 623 | - |
|
| 624 | - /** |
|
| 625 | - * This will get called if the number of records deleted 0 or greater. So a successful deletion is one where |
|
| 626 | - * there were no errors. An unsuccessful deletion is where there were errors. Keep that in mind for the actions |
|
| 627 | - * below. |
|
| 628 | - */ |
|
| 629 | - if ($number_deleted !== false) { |
|
| 630 | - do_action('AHEE__EEM_Message__delete_old_messages__after_successful_deletion', $message_ids_to_delete, $number_deleted); |
|
| 631 | - } else { |
|
| 632 | - do_action('AHEE__EEM_Message__delete_old_messages__after_deletion_fail', $message_ids_to_delete, $number_deleted); |
|
| 633 | - } |
|
| 634 | - return $number_deleted; |
|
| 635 | - } |
|
| 622 | + } |
|
| 623 | + |
|
| 624 | + /** |
|
| 625 | + * This will get called if the number of records deleted 0 or greater. So a successful deletion is one where |
|
| 626 | + * there were no errors. An unsuccessful deletion is where there were errors. Keep that in mind for the actions |
|
| 627 | + * below. |
|
| 628 | + */ |
|
| 629 | + if ($number_deleted !== false) { |
|
| 630 | + do_action('AHEE__EEM_Message__delete_old_messages__after_successful_deletion', $message_ids_to_delete, $number_deleted); |
|
| 631 | + } else { |
|
| 632 | + do_action('AHEE__EEM_Message__delete_old_messages__after_deletion_fail', $message_ids_to_delete, $number_deleted); |
|
| 633 | + } |
|
| 634 | + return $number_deleted; |
|
| 635 | + } |
|
| 636 | 636 | } |
@@ -16,230 +16,230 @@ discard block |
||
| 16 | 16 | class EEM_Transaction extends EEM_Base |
| 17 | 17 | { |
| 18 | 18 | |
| 19 | - // private instance of the Transaction object |
|
| 20 | - protected static $_instance; |
|
| 21 | - |
|
| 22 | - /** |
|
| 23 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
| 24 | - * but payment is pending. This is the state for transactions where payment is promised |
|
| 25 | - * from an offline gateway. |
|
| 26 | - */ |
|
| 27 | - // const open_status_code = 'TPN'; |
|
| 28 | - |
|
| 29 | - /** |
|
| 30 | - * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
| 31 | - * either due to a technical reason (server or computer crash during registration), |
|
| 32 | - * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
| 33 | - */ |
|
| 34 | - const failed_status_code = 'TFL'; |
|
| 35 | - |
|
| 36 | - /** |
|
| 37 | - * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
| 38 | - * either due to a technical reason (server or computer crash during registration), |
|
| 39 | - * or due to an abandoned cart after registrant chose not to complete the registration process |
|
| 40 | - * HOWEVER... |
|
| 41 | - * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
| 42 | - * registrant |
|
| 43 | - */ |
|
| 44 | - const abandoned_status_code = 'TAB'; |
|
| 45 | - |
|
| 46 | - /** |
|
| 47 | - * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
| 48 | - * meaning that monies are still owing: TXN_paid < TXN_total |
|
| 49 | - */ |
|
| 50 | - const incomplete_status_code = 'TIN'; |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
| 54 | - * meaning that NO monies are owing: TXN_paid == TXN_total |
|
| 55 | - */ |
|
| 56 | - const complete_status_code = 'TCM'; |
|
| 57 | - |
|
| 58 | - /** |
|
| 59 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
| 60 | - * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
| 61 | - */ |
|
| 62 | - const overpaid_status_code = 'TOP'; |
|
| 63 | - |
|
| 64 | - |
|
| 65 | - /** |
|
| 66 | - * private constructor to prevent direct creation |
|
| 67 | - * |
|
| 68 | - * @Constructor |
|
| 69 | - * @access protected |
|
| 70 | - * |
|
| 71 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
| 72 | - * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
| 73 | - * date time model field objects. Default is NULL (and will be assumed using the set |
|
| 74 | - * timezone in the 'timezone_string' wp option) |
|
| 75 | - * |
|
| 76 | - * @return EEM_Transaction |
|
| 77 | - * @throws \EE_Error |
|
| 78 | - */ |
|
| 79 | - protected function __construct($timezone) |
|
| 80 | - { |
|
| 81 | - $this->singular_item = __('Transaction', 'event_espresso'); |
|
| 82 | - $this->plural_item = __('Transactions', 'event_espresso'); |
|
| 83 | - |
|
| 84 | - $this->_tables = array( |
|
| 85 | - 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
| 86 | - ); |
|
| 87 | - $this->_fields = array( |
|
| 88 | - 'TransactionTable' => array( |
|
| 89 | - 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
| 90 | - 'TXN_timestamp' => new EE_Datetime_Field( |
|
| 91 | - 'TXN_timestamp', |
|
| 92 | - __('date when transaction was created', 'event_espresso'), |
|
| 93 | - false, |
|
| 94 | - EE_Datetime_Field::now, |
|
| 95 | - $timezone |
|
| 96 | - ), |
|
| 97 | - 'TXN_total' => new EE_Money_Field( |
|
| 98 | - 'TXN_total', |
|
| 99 | - __('Total value of Transaction', 'event_espresso'), |
|
| 100 | - false, |
|
| 101 | - 0 |
|
| 102 | - ), |
|
| 103 | - 'TXN_paid' => new EE_Money_Field( |
|
| 104 | - 'TXN_paid', |
|
| 105 | - __('Amount paid towards transaction to date', 'event_espresso'), |
|
| 106 | - false, |
|
| 107 | - 0 |
|
| 108 | - ), |
|
| 109 | - 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 110 | - 'STS_ID', |
|
| 111 | - __('Status ID', 'event_espresso'), |
|
| 112 | - false, |
|
| 113 | - EEM_Transaction::failed_status_code, |
|
| 114 | - 'Status' |
|
| 115 | - ), |
|
| 116 | - 'TXN_session_data' => new EE_Serialized_Text_Field( |
|
| 117 | - 'TXN_session_data', |
|
| 118 | - __('Serialized session data', 'event_espresso'), |
|
| 119 | - true, |
|
| 120 | - '' |
|
| 121 | - ), |
|
| 122 | - 'TXN_hash_salt' => new EE_Plain_Text_Field( |
|
| 123 | - 'TXN_hash_salt', |
|
| 124 | - __('Transaction Hash Salt', 'event_espresso'), |
|
| 125 | - true, |
|
| 126 | - '' |
|
| 127 | - ), |
|
| 128 | - 'PMD_ID' => new EE_Foreign_Key_Int_Field( |
|
| 129 | - 'PMD_ID', |
|
| 130 | - __("Last Used Payment Method", 'event_espresso'), |
|
| 131 | - true, |
|
| 132 | - null, |
|
| 133 | - 'Payment_Method' |
|
| 134 | - ), |
|
| 135 | - 'TXN_reg_steps' => new EE_Serialized_Text_Field( |
|
| 136 | - 'TXN_reg_steps', |
|
| 137 | - __('Registration Steps', 'event_espresso'), |
|
| 138 | - false, |
|
| 139 | - array() |
|
| 140 | - ), |
|
| 141 | - ) |
|
| 142 | - ); |
|
| 143 | - $this->_model_relations = array( |
|
| 144 | - 'Registration' => new EE_Has_Many_Relation(), |
|
| 145 | - 'Payment' => new EE_Has_Many_Relation(), |
|
| 146 | - 'Status' => new EE_Belongs_To_Relation(), |
|
| 147 | - 'Line_Item' => new EE_Has_Many_Relation(false), |
|
| 148 | - // you can delete a transaction without needing to delete its line items |
|
| 149 | - 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
| 150 | - 'Message' => new EE_Has_Many_Relation() |
|
| 151 | - ); |
|
| 152 | - $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
| 153 | - parent::__construct($timezone); |
|
| 154 | - } |
|
| 155 | - |
|
| 156 | - |
|
| 157 | - /** |
|
| 158 | - * txn_status_array |
|
| 159 | - * get list of transaction statuses |
|
| 160 | - * |
|
| 161 | - * @access public |
|
| 162 | - * @return array |
|
| 163 | - */ |
|
| 164 | - public static function txn_status_array() |
|
| 165 | - { |
|
| 166 | - return apply_filters( |
|
| 167 | - 'FHEE__EEM_Transaction__txn_status_array', |
|
| 168 | - array( |
|
| 169 | - EEM_Transaction::overpaid_status_code, |
|
| 170 | - EEM_Transaction::complete_status_code, |
|
| 171 | - EEM_Transaction::incomplete_status_code, |
|
| 172 | - EEM_Transaction::abandoned_status_code, |
|
| 173 | - EEM_Transaction::failed_status_code, |
|
| 174 | - ) |
|
| 175 | - ); |
|
| 176 | - } |
|
| 177 | - |
|
| 178 | - /** |
|
| 179 | - * get the revenue per day for the Transaction Admin page Reports Tab |
|
| 180 | - * |
|
| 181 | - * @access public |
|
| 182 | - * |
|
| 183 | - * @param string $period |
|
| 184 | - * |
|
| 185 | - * @return \stdClass[] |
|
| 186 | - */ |
|
| 187 | - public function get_revenue_per_day_report($period = '-1 month') |
|
| 188 | - { |
|
| 189 | - $sql_date = $this->convert_datetime_for_query( |
|
| 190 | - 'TXN_timestamp', |
|
| 191 | - date('Y-m-d H:i:s', strtotime($period)), |
|
| 192 | - 'Y-m-d H:i:s', |
|
| 193 | - 'UTC' |
|
| 194 | - ); |
|
| 195 | - |
|
| 196 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
| 197 | - |
|
| 198 | - return $this->_get_all_wpdb_results( |
|
| 199 | - array( |
|
| 200 | - array( |
|
| 201 | - 'TXN_timestamp' => array('>=', $sql_date) |
|
| 202 | - ), |
|
| 203 | - 'group_by' => 'txnDate', |
|
| 204 | - 'order_by' => array('TXN_timestamp' => 'ASC') |
|
| 205 | - ), |
|
| 206 | - OBJECT, |
|
| 207 | - array( |
|
| 208 | - 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
| 209 | - 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
| 210 | - ) |
|
| 211 | - ); |
|
| 212 | - } |
|
| 213 | - |
|
| 214 | - |
|
| 215 | - /** |
|
| 216 | - * get the revenue per event for the Transaction Admin page Reports Tab |
|
| 217 | - * |
|
| 218 | - * @access public |
|
| 219 | - * |
|
| 220 | - * @param string $period |
|
| 221 | - * |
|
| 222 | - * @throws \EE_Error |
|
| 223 | - * @return mixed |
|
| 224 | - */ |
|
| 225 | - public function get_revenue_per_event_report($period = '-1 month') |
|
| 226 | - { |
|
| 227 | - global $wpdb; |
|
| 228 | - $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
| 229 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 230 | - $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
| 231 | - $event_table = $wpdb->posts; |
|
| 232 | - $payment_table = $wpdb->prefix . 'esp_payment'; |
|
| 233 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 234 | - $approved_payment_status = EEM_Payment::status_id_approved; |
|
| 235 | - $extra_event_on_join = ''; |
|
| 236 | - // exclude events not authored by user if permissions in effect |
|
| 237 | - if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 238 | - $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
| 239 | - } |
|
| 240 | - |
|
| 241 | - return $wpdb->get_results( |
|
| 242 | - "SELECT |
|
| 19 | + // private instance of the Transaction object |
|
| 20 | + protected static $_instance; |
|
| 21 | + |
|
| 22 | + /** |
|
| 23 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
| 24 | + * but payment is pending. This is the state for transactions where payment is promised |
|
| 25 | + * from an offline gateway. |
|
| 26 | + */ |
|
| 27 | + // const open_status_code = 'TPN'; |
|
| 28 | + |
|
| 29 | + /** |
|
| 30 | + * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
| 31 | + * either due to a technical reason (server or computer crash during registration), |
|
| 32 | + * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
| 33 | + */ |
|
| 34 | + const failed_status_code = 'TFL'; |
|
| 35 | + |
|
| 36 | + /** |
|
| 37 | + * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
| 38 | + * either due to a technical reason (server or computer crash during registration), |
|
| 39 | + * or due to an abandoned cart after registrant chose not to complete the registration process |
|
| 40 | + * HOWEVER... |
|
| 41 | + * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
| 42 | + * registrant |
|
| 43 | + */ |
|
| 44 | + const abandoned_status_code = 'TAB'; |
|
| 45 | + |
|
| 46 | + /** |
|
| 47 | + * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
| 48 | + * meaning that monies are still owing: TXN_paid < TXN_total |
|
| 49 | + */ |
|
| 50 | + const incomplete_status_code = 'TIN'; |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
| 54 | + * meaning that NO monies are owing: TXN_paid == TXN_total |
|
| 55 | + */ |
|
| 56 | + const complete_status_code = 'TCM'; |
|
| 57 | + |
|
| 58 | + /** |
|
| 59 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
| 60 | + * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
| 61 | + */ |
|
| 62 | + const overpaid_status_code = 'TOP'; |
|
| 63 | + |
|
| 64 | + |
|
| 65 | + /** |
|
| 66 | + * private constructor to prevent direct creation |
|
| 67 | + * |
|
| 68 | + * @Constructor |
|
| 69 | + * @access protected |
|
| 70 | + * |
|
| 71 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
| 72 | + * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
| 73 | + * date time model field objects. Default is NULL (and will be assumed using the set |
|
| 74 | + * timezone in the 'timezone_string' wp option) |
|
| 75 | + * |
|
| 76 | + * @return EEM_Transaction |
|
| 77 | + * @throws \EE_Error |
|
| 78 | + */ |
|
| 79 | + protected function __construct($timezone) |
|
| 80 | + { |
|
| 81 | + $this->singular_item = __('Transaction', 'event_espresso'); |
|
| 82 | + $this->plural_item = __('Transactions', 'event_espresso'); |
|
| 83 | + |
|
| 84 | + $this->_tables = array( |
|
| 85 | + 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
| 86 | + ); |
|
| 87 | + $this->_fields = array( |
|
| 88 | + 'TransactionTable' => array( |
|
| 89 | + 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
| 90 | + 'TXN_timestamp' => new EE_Datetime_Field( |
|
| 91 | + 'TXN_timestamp', |
|
| 92 | + __('date when transaction was created', 'event_espresso'), |
|
| 93 | + false, |
|
| 94 | + EE_Datetime_Field::now, |
|
| 95 | + $timezone |
|
| 96 | + ), |
|
| 97 | + 'TXN_total' => new EE_Money_Field( |
|
| 98 | + 'TXN_total', |
|
| 99 | + __('Total value of Transaction', 'event_espresso'), |
|
| 100 | + false, |
|
| 101 | + 0 |
|
| 102 | + ), |
|
| 103 | + 'TXN_paid' => new EE_Money_Field( |
|
| 104 | + 'TXN_paid', |
|
| 105 | + __('Amount paid towards transaction to date', 'event_espresso'), |
|
| 106 | + false, |
|
| 107 | + 0 |
|
| 108 | + ), |
|
| 109 | + 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
| 110 | + 'STS_ID', |
|
| 111 | + __('Status ID', 'event_espresso'), |
|
| 112 | + false, |
|
| 113 | + EEM_Transaction::failed_status_code, |
|
| 114 | + 'Status' |
|
| 115 | + ), |
|
| 116 | + 'TXN_session_data' => new EE_Serialized_Text_Field( |
|
| 117 | + 'TXN_session_data', |
|
| 118 | + __('Serialized session data', 'event_espresso'), |
|
| 119 | + true, |
|
| 120 | + '' |
|
| 121 | + ), |
|
| 122 | + 'TXN_hash_salt' => new EE_Plain_Text_Field( |
|
| 123 | + 'TXN_hash_salt', |
|
| 124 | + __('Transaction Hash Salt', 'event_espresso'), |
|
| 125 | + true, |
|
| 126 | + '' |
|
| 127 | + ), |
|
| 128 | + 'PMD_ID' => new EE_Foreign_Key_Int_Field( |
|
| 129 | + 'PMD_ID', |
|
| 130 | + __("Last Used Payment Method", 'event_espresso'), |
|
| 131 | + true, |
|
| 132 | + null, |
|
| 133 | + 'Payment_Method' |
|
| 134 | + ), |
|
| 135 | + 'TXN_reg_steps' => new EE_Serialized_Text_Field( |
|
| 136 | + 'TXN_reg_steps', |
|
| 137 | + __('Registration Steps', 'event_espresso'), |
|
| 138 | + false, |
|
| 139 | + array() |
|
| 140 | + ), |
|
| 141 | + ) |
|
| 142 | + ); |
|
| 143 | + $this->_model_relations = array( |
|
| 144 | + 'Registration' => new EE_Has_Many_Relation(), |
|
| 145 | + 'Payment' => new EE_Has_Many_Relation(), |
|
| 146 | + 'Status' => new EE_Belongs_To_Relation(), |
|
| 147 | + 'Line_Item' => new EE_Has_Many_Relation(false), |
|
| 148 | + // you can delete a transaction without needing to delete its line items |
|
| 149 | + 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
| 150 | + 'Message' => new EE_Has_Many_Relation() |
|
| 151 | + ); |
|
| 152 | + $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
| 153 | + parent::__construct($timezone); |
|
| 154 | + } |
|
| 155 | + |
|
| 156 | + |
|
| 157 | + /** |
|
| 158 | + * txn_status_array |
|
| 159 | + * get list of transaction statuses |
|
| 160 | + * |
|
| 161 | + * @access public |
|
| 162 | + * @return array |
|
| 163 | + */ |
|
| 164 | + public static function txn_status_array() |
|
| 165 | + { |
|
| 166 | + return apply_filters( |
|
| 167 | + 'FHEE__EEM_Transaction__txn_status_array', |
|
| 168 | + array( |
|
| 169 | + EEM_Transaction::overpaid_status_code, |
|
| 170 | + EEM_Transaction::complete_status_code, |
|
| 171 | + EEM_Transaction::incomplete_status_code, |
|
| 172 | + EEM_Transaction::abandoned_status_code, |
|
| 173 | + EEM_Transaction::failed_status_code, |
|
| 174 | + ) |
|
| 175 | + ); |
|
| 176 | + } |
|
| 177 | + |
|
| 178 | + /** |
|
| 179 | + * get the revenue per day for the Transaction Admin page Reports Tab |
|
| 180 | + * |
|
| 181 | + * @access public |
|
| 182 | + * |
|
| 183 | + * @param string $period |
|
| 184 | + * |
|
| 185 | + * @return \stdClass[] |
|
| 186 | + */ |
|
| 187 | + public function get_revenue_per_day_report($period = '-1 month') |
|
| 188 | + { |
|
| 189 | + $sql_date = $this->convert_datetime_for_query( |
|
| 190 | + 'TXN_timestamp', |
|
| 191 | + date('Y-m-d H:i:s', strtotime($period)), |
|
| 192 | + 'Y-m-d H:i:s', |
|
| 193 | + 'UTC' |
|
| 194 | + ); |
|
| 195 | + |
|
| 196 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
| 197 | + |
|
| 198 | + return $this->_get_all_wpdb_results( |
|
| 199 | + array( |
|
| 200 | + array( |
|
| 201 | + 'TXN_timestamp' => array('>=', $sql_date) |
|
| 202 | + ), |
|
| 203 | + 'group_by' => 'txnDate', |
|
| 204 | + 'order_by' => array('TXN_timestamp' => 'ASC') |
|
| 205 | + ), |
|
| 206 | + OBJECT, |
|
| 207 | + array( |
|
| 208 | + 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
| 209 | + 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
| 210 | + ) |
|
| 211 | + ); |
|
| 212 | + } |
|
| 213 | + |
|
| 214 | + |
|
| 215 | + /** |
|
| 216 | + * get the revenue per event for the Transaction Admin page Reports Tab |
|
| 217 | + * |
|
| 218 | + * @access public |
|
| 219 | + * |
|
| 220 | + * @param string $period |
|
| 221 | + * |
|
| 222 | + * @throws \EE_Error |
|
| 223 | + * @return mixed |
|
| 224 | + */ |
|
| 225 | + public function get_revenue_per_event_report($period = '-1 month') |
|
| 226 | + { |
|
| 227 | + global $wpdb; |
|
| 228 | + $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
| 229 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 230 | + $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
| 231 | + $event_table = $wpdb->posts; |
|
| 232 | + $payment_table = $wpdb->prefix . 'esp_payment'; |
|
| 233 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
| 234 | + $approved_payment_status = EEM_Payment::status_id_approved; |
|
| 235 | + $extra_event_on_join = ''; |
|
| 236 | + // exclude events not authored by user if permissions in effect |
|
| 237 | + if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 238 | + $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
| 239 | + } |
|
| 240 | + |
|
| 241 | + return $wpdb->get_results( |
|
| 242 | + "SELECT |
|
| 243 | 243 | Transaction_Event.event_name AS event_name, |
| 244 | 244 | SUM(Transaction_Event.paid) AS revenue |
| 245 | 245 | FROM |
@@ -267,233 +267,233 @@ discard block |
||
| 267 | 267 | $extra_event_on_join |
| 268 | 268 | ) AS Transaction_Event |
| 269 | 269 | GROUP BY event_name", |
| 270 | - OBJECT |
|
| 271 | - ); |
|
| 272 | - } |
|
| 273 | - |
|
| 274 | - |
|
| 275 | - /** |
|
| 276 | - * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
| 277 | - * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
| 278 | - * the registration pointed to by reg_url_link), if not returns null |
|
| 279 | - * |
|
| 280 | - * @param string $reg_url_link |
|
| 281 | - * |
|
| 282 | - * @return EE_Transaction |
|
| 283 | - */ |
|
| 284 | - public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
| 285 | - { |
|
| 286 | - return $this->get_one(array( |
|
| 287 | - array( |
|
| 288 | - 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get( |
|
| 289 | - 'e_reg_url_link', |
|
| 290 | - '' |
|
| 291 | - ) |
|
| 292 | - ) |
|
| 293 | - )); |
|
| 294 | - } |
|
| 295 | - |
|
| 296 | - |
|
| 297 | - /** |
|
| 298 | - * Updates the provided EE_Transaction with all the applicable payments |
|
| 299 | - * (or fetch the EE_Transaction from its ID) |
|
| 300 | - * |
|
| 301 | - * @deprecated |
|
| 302 | - * |
|
| 303 | - * @param EE_Transaction|int $transaction_obj_or_id |
|
| 304 | - * @param boolean $save_txn whether or not to save the transaction during this function call |
|
| 305 | - * |
|
| 306 | - * @return boolean |
|
| 307 | - * @throws \EE_Error |
|
| 308 | - */ |
|
| 309 | - public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
| 310 | - { |
|
| 311 | - EE_Error::doing_it_wrong( |
|
| 312 | - __CLASS__ . '::' . __FUNCTION__, |
|
| 313 | - sprintf( |
|
| 314 | - __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
| 315 | - 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
| 316 | - ), |
|
| 317 | - '4.6.0' |
|
| 318 | - ); |
|
| 319 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
| 320 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
| 321 | - |
|
| 322 | - return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
| 323 | - $this->ensure_is_obj($transaction_obj_or_id) |
|
| 324 | - ); |
|
| 325 | - } |
|
| 326 | - |
|
| 327 | - /** |
|
| 328 | - * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
| 329 | - * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
| 330 | - * and so we only use wpdb directly and only do minimal joins. |
|
| 331 | - * Transactions are considered "junk" if they're failed for longer than a week. |
|
| 332 | - * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
| 333 | - * it, it's probably not junk (regardless of what status it has). |
|
| 334 | - * The downside to this approach is that is addons are listening for object deletions |
|
| 335 | - * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
| 336 | - * to catch these types of deletions. |
|
| 337 | - * |
|
| 338 | - * @global WPDB $wpdb |
|
| 339 | - * @return mixed |
|
| 340 | - */ |
|
| 341 | - public function delete_junk_transactions() |
|
| 342 | - { |
|
| 343 | - /** @type WPDB $wpdb */ |
|
| 344 | - global $wpdb; |
|
| 345 | - $deleted = false; |
|
| 346 | - $time_to_leave_alone = apply_filters( |
|
| 347 | - 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', |
|
| 348 | - WEEK_IN_SECONDS |
|
| 349 | - ); |
|
| 350 | - |
|
| 351 | - |
|
| 352 | - /** |
|
| 353 | - * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
| 354 | - * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
| 355 | - * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
| 356 | - */ |
|
| 357 | - $ids_query = apply_filters( |
|
| 358 | - 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
| 359 | - array( |
|
| 360 | - 0 => array( |
|
| 361 | - 'STS_ID' => EEM_Transaction::failed_status_code, |
|
| 362 | - 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
| 363 | - 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
| 364 | - ), |
|
| 365 | - 'order_by' => ['TXN_timestamp' => 'ASC'], |
|
| 366 | - 'limit' => 1000 |
|
| 367 | - ), |
|
| 368 | - $time_to_leave_alone |
|
| 369 | - ); |
|
| 370 | - |
|
| 371 | - |
|
| 372 | - /** |
|
| 373 | - * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
| 374 | - * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
| 375 | - */ |
|
| 376 | - $txn_ids = apply_filters( |
|
| 377 | - 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
| 378 | - EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
| 379 | - $time_to_leave_alone |
|
| 380 | - ); |
|
| 381 | - // now that we have the ids to delete |
|
| 382 | - if (! empty($txn_ids) && is_array($txn_ids)) { |
|
| 383 | - // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
| 384 | - EEM_Transaction::unset_locked_transactions($txn_ids); |
|
| 385 | - |
|
| 386 | - // Create IDs placeholder. |
|
| 387 | - $placeholders = array_fill(0, count($txn_ids), '%d'); |
|
| 270 | + OBJECT |
|
| 271 | + ); |
|
| 272 | + } |
|
| 273 | + |
|
| 274 | + |
|
| 275 | + /** |
|
| 276 | + * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
| 277 | + * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
| 278 | + * the registration pointed to by reg_url_link), if not returns null |
|
| 279 | + * |
|
| 280 | + * @param string $reg_url_link |
|
| 281 | + * |
|
| 282 | + * @return EE_Transaction |
|
| 283 | + */ |
|
| 284 | + public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
| 285 | + { |
|
| 286 | + return $this->get_one(array( |
|
| 287 | + array( |
|
| 288 | + 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get( |
|
| 289 | + 'e_reg_url_link', |
|
| 290 | + '' |
|
| 291 | + ) |
|
| 292 | + ) |
|
| 293 | + )); |
|
| 294 | + } |
|
| 295 | + |
|
| 296 | + |
|
| 297 | + /** |
|
| 298 | + * Updates the provided EE_Transaction with all the applicable payments |
|
| 299 | + * (or fetch the EE_Transaction from its ID) |
|
| 300 | + * |
|
| 301 | + * @deprecated |
|
| 302 | + * |
|
| 303 | + * @param EE_Transaction|int $transaction_obj_or_id |
|
| 304 | + * @param boolean $save_txn whether or not to save the transaction during this function call |
|
| 305 | + * |
|
| 306 | + * @return boolean |
|
| 307 | + * @throws \EE_Error |
|
| 308 | + */ |
|
| 309 | + public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
| 310 | + { |
|
| 311 | + EE_Error::doing_it_wrong( |
|
| 312 | + __CLASS__ . '::' . __FUNCTION__, |
|
| 313 | + sprintf( |
|
| 314 | + __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
| 315 | + 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
| 316 | + ), |
|
| 317 | + '4.6.0' |
|
| 318 | + ); |
|
| 319 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
| 320 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
| 321 | + |
|
| 322 | + return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
| 323 | + $this->ensure_is_obj($transaction_obj_or_id) |
|
| 324 | + ); |
|
| 325 | + } |
|
| 326 | + |
|
| 327 | + /** |
|
| 328 | + * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
| 329 | + * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
| 330 | + * and so we only use wpdb directly and only do minimal joins. |
|
| 331 | + * Transactions are considered "junk" if they're failed for longer than a week. |
|
| 332 | + * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
| 333 | + * it, it's probably not junk (regardless of what status it has). |
|
| 334 | + * The downside to this approach is that is addons are listening for object deletions |
|
| 335 | + * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
| 336 | + * to catch these types of deletions. |
|
| 337 | + * |
|
| 338 | + * @global WPDB $wpdb |
|
| 339 | + * @return mixed |
|
| 340 | + */ |
|
| 341 | + public function delete_junk_transactions() |
|
| 342 | + { |
|
| 343 | + /** @type WPDB $wpdb */ |
|
| 344 | + global $wpdb; |
|
| 345 | + $deleted = false; |
|
| 346 | + $time_to_leave_alone = apply_filters( |
|
| 347 | + 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', |
|
| 348 | + WEEK_IN_SECONDS |
|
| 349 | + ); |
|
| 350 | + |
|
| 351 | + |
|
| 352 | + /** |
|
| 353 | + * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
| 354 | + * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
| 355 | + * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
| 356 | + */ |
|
| 357 | + $ids_query = apply_filters( |
|
| 358 | + 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
| 359 | + array( |
|
| 360 | + 0 => array( |
|
| 361 | + 'STS_ID' => EEM_Transaction::failed_status_code, |
|
| 362 | + 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
| 363 | + 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
| 364 | + ), |
|
| 365 | + 'order_by' => ['TXN_timestamp' => 'ASC'], |
|
| 366 | + 'limit' => 1000 |
|
| 367 | + ), |
|
| 368 | + $time_to_leave_alone |
|
| 369 | + ); |
|
| 370 | + |
|
| 371 | + |
|
| 372 | + /** |
|
| 373 | + * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
| 374 | + * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
| 375 | + */ |
|
| 376 | + $txn_ids = apply_filters( |
|
| 377 | + 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
| 378 | + EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
| 379 | + $time_to_leave_alone |
|
| 380 | + ); |
|
| 381 | + // now that we have the ids to delete |
|
| 382 | + if (! empty($txn_ids) && is_array($txn_ids)) { |
|
| 383 | + // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
| 384 | + EEM_Transaction::unset_locked_transactions($txn_ids); |
|
| 385 | + |
|
| 386 | + // Create IDs placeholder. |
|
| 387 | + $placeholders = array_fill(0, count($txn_ids), '%d'); |
|
| 388 | 388 | |
| 389 | - // Glue it together to use inside $wpdb->prepare. |
|
| 390 | - $format = implode(', ', $placeholders); |
|
| 391 | - |
|
| 392 | - // let's get deletin'... |
|
| 393 | - // We got the ids from the original query to get them FROM |
|
| 394 | - // the db (which is sanitized) so no need to prepare them again. |
|
| 395 | - $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
| 396 | - $deleted = $wpdb->query($query); |
|
| 397 | - } |
|
| 398 | - if ($deleted) { |
|
| 399 | - /** |
|
| 400 | - * Allows code to do something after the transactions have been deleted. |
|
| 401 | - */ |
|
| 402 | - do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
| 403 | - } |
|
| 404 | - |
|
| 405 | - return $deleted; |
|
| 406 | - } |
|
| 407 | - |
|
| 408 | - |
|
| 409 | - /** |
|
| 410 | - * @param array $transaction_IDs |
|
| 411 | - * |
|
| 412 | - * @return bool |
|
| 413 | - */ |
|
| 414 | - public static function unset_locked_transactions(array $transaction_IDs) |
|
| 415 | - { |
|
| 416 | - $locked_transactions = get_option('ee_locked_transactions', array()); |
|
| 417 | - $update = false; |
|
| 418 | - foreach ($transaction_IDs as $TXN_ID) { |
|
| 419 | - if (isset($locked_transactions[ $TXN_ID ])) { |
|
| 420 | - unset($locked_transactions[ $TXN_ID ]); |
|
| 421 | - $update = true; |
|
| 422 | - } |
|
| 423 | - } |
|
| 424 | - if ($update) { |
|
| 425 | - update_option('ee_locked_transactions', $locked_transactions); |
|
| 426 | - } |
|
| 427 | - |
|
| 428 | - return $update; |
|
| 429 | - } |
|
| 430 | - |
|
| 431 | - |
|
| 432 | - |
|
| 433 | - /** |
|
| 434 | - * returns an array of EE_Transaction objects whose timestamp is greater than |
|
| 435 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
| 436 | - * |
|
| 437 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
| 438 | - * @throws EE_Error |
|
| 439 | - * @throws InvalidArgumentException |
|
| 440 | - * @throws InvalidDataTypeException |
|
| 441 | - * @throws InvalidInterfaceException |
|
| 442 | - */ |
|
| 443 | - public function get_transactions_in_progress() |
|
| 444 | - { |
|
| 445 | - return $this->_get_transactions_in_progress(); |
|
| 446 | - } |
|
| 447 | - |
|
| 448 | - |
|
| 449 | - |
|
| 450 | - /** |
|
| 451 | - * returns an array of EE_Transaction objects whose timestamp is less than |
|
| 452 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
| 453 | - * |
|
| 454 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
| 455 | - * @throws EE_Error |
|
| 456 | - * @throws InvalidArgumentException |
|
| 457 | - * @throws InvalidDataTypeException |
|
| 458 | - * @throws InvalidInterfaceException |
|
| 459 | - */ |
|
| 460 | - public function get_transactions_not_in_progress() |
|
| 461 | - { |
|
| 462 | - return $this->_get_transactions_in_progress('<='); |
|
| 463 | - } |
|
| 464 | - |
|
| 465 | - |
|
| 466 | - |
|
| 467 | - /** |
|
| 468 | - * @param string $comparison |
|
| 469 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
| 470 | - * @throws EE_Error |
|
| 471 | - * @throws InvalidArgumentException |
|
| 472 | - * @throws InvalidDataTypeException |
|
| 473 | - * @throws InvalidInterfaceException |
|
| 474 | - */ |
|
| 475 | - private function _get_transactions_in_progress($comparison = '>=') |
|
| 476 | - { |
|
| 477 | - $comparison = $comparison === '>=' || $comparison === '<=' |
|
| 478 | - ? $comparison |
|
| 479 | - : '>='; |
|
| 480 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 481 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 482 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 483 | - ); |
|
| 484 | - return $this->get_all( |
|
| 485 | - array( |
|
| 486 | - array( |
|
| 487 | - 'TXN_timestamp' => array( |
|
| 488 | - $comparison, |
|
| 489 | - $session_lifespan->expiration() |
|
| 490 | - ), |
|
| 491 | - 'STS_ID' => array( |
|
| 492 | - '!=', |
|
| 493 | - EEM_Transaction::complete_status_code |
|
| 494 | - ), |
|
| 495 | - ) |
|
| 496 | - ) |
|
| 497 | - ); |
|
| 498 | - } |
|
| 389 | + // Glue it together to use inside $wpdb->prepare. |
|
| 390 | + $format = implode(', ', $placeholders); |
|
| 391 | + |
|
| 392 | + // let's get deletin'... |
|
| 393 | + // We got the ids from the original query to get them FROM |
|
| 394 | + // the db (which is sanitized) so no need to prepare them again. |
|
| 395 | + $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
| 396 | + $deleted = $wpdb->query($query); |
|
| 397 | + } |
|
| 398 | + if ($deleted) { |
|
| 399 | + /** |
|
| 400 | + * Allows code to do something after the transactions have been deleted. |
|
| 401 | + */ |
|
| 402 | + do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
| 403 | + } |
|
| 404 | + |
|
| 405 | + return $deleted; |
|
| 406 | + } |
|
| 407 | + |
|
| 408 | + |
|
| 409 | + /** |
|
| 410 | + * @param array $transaction_IDs |
|
| 411 | + * |
|
| 412 | + * @return bool |
|
| 413 | + */ |
|
| 414 | + public static function unset_locked_transactions(array $transaction_IDs) |
|
| 415 | + { |
|
| 416 | + $locked_transactions = get_option('ee_locked_transactions', array()); |
|
| 417 | + $update = false; |
|
| 418 | + foreach ($transaction_IDs as $TXN_ID) { |
|
| 419 | + if (isset($locked_transactions[ $TXN_ID ])) { |
|
| 420 | + unset($locked_transactions[ $TXN_ID ]); |
|
| 421 | + $update = true; |
|
| 422 | + } |
|
| 423 | + } |
|
| 424 | + if ($update) { |
|
| 425 | + update_option('ee_locked_transactions', $locked_transactions); |
|
| 426 | + } |
|
| 427 | + |
|
| 428 | + return $update; |
|
| 429 | + } |
|
| 430 | + |
|
| 431 | + |
|
| 432 | + |
|
| 433 | + /** |
|
| 434 | + * returns an array of EE_Transaction objects whose timestamp is greater than |
|
| 435 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
| 436 | + * |
|
| 437 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
| 438 | + * @throws EE_Error |
|
| 439 | + * @throws InvalidArgumentException |
|
| 440 | + * @throws InvalidDataTypeException |
|
| 441 | + * @throws InvalidInterfaceException |
|
| 442 | + */ |
|
| 443 | + public function get_transactions_in_progress() |
|
| 444 | + { |
|
| 445 | + return $this->_get_transactions_in_progress(); |
|
| 446 | + } |
|
| 447 | + |
|
| 448 | + |
|
| 449 | + |
|
| 450 | + /** |
|
| 451 | + * returns an array of EE_Transaction objects whose timestamp is less than |
|
| 452 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
| 453 | + * |
|
| 454 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
| 455 | + * @throws EE_Error |
|
| 456 | + * @throws InvalidArgumentException |
|
| 457 | + * @throws InvalidDataTypeException |
|
| 458 | + * @throws InvalidInterfaceException |
|
| 459 | + */ |
|
| 460 | + public function get_transactions_not_in_progress() |
|
| 461 | + { |
|
| 462 | + return $this->_get_transactions_in_progress('<='); |
|
| 463 | + } |
|
| 464 | + |
|
| 465 | + |
|
| 466 | + |
|
| 467 | + /** |
|
| 468 | + * @param string $comparison |
|
| 469 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
| 470 | + * @throws EE_Error |
|
| 471 | + * @throws InvalidArgumentException |
|
| 472 | + * @throws InvalidDataTypeException |
|
| 473 | + * @throws InvalidInterfaceException |
|
| 474 | + */ |
|
| 475 | + private function _get_transactions_in_progress($comparison = '>=') |
|
| 476 | + { |
|
| 477 | + $comparison = $comparison === '>=' || $comparison === '<=' |
|
| 478 | + ? $comparison |
|
| 479 | + : '>='; |
|
| 480 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
| 481 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
| 482 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
| 483 | + ); |
|
| 484 | + return $this->get_all( |
|
| 485 | + array( |
|
| 486 | + array( |
|
| 487 | + 'TXN_timestamp' => array( |
|
| 488 | + $comparison, |
|
| 489 | + $session_lifespan->expiration() |
|
| 490 | + ), |
|
| 491 | + 'STS_ID' => array( |
|
| 492 | + '!=', |
|
| 493 | + EEM_Transaction::complete_status_code |
|
| 494 | + ), |
|
| 495 | + ) |
|
| 496 | + ) |
|
| 497 | + ); |
|
| 498 | + } |
|
| 499 | 499 | } |
@@ -140,7 +140,7 @@ discard block |
||
| 140 | 140 | ), |
| 141 | 141 | ) |
| 142 | 142 | ); |
| 143 | - $this->_model_relations = array( |
|
| 143 | + $this->_model_relations = array( |
|
| 144 | 144 | 'Registration' => new EE_Has_Many_Relation(), |
| 145 | 145 | 'Payment' => new EE_Has_Many_Relation(), |
| 146 | 146 | 'Status' => new EE_Belongs_To_Relation(), |
@@ -205,7 +205,7 @@ discard block |
||
| 205 | 205 | ), |
| 206 | 206 | OBJECT, |
| 207 | 207 | array( |
| 208 | - 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
| 208 | + 'txnDate' => array('DATE('.$query_interval.')', '%s'), |
|
| 209 | 209 | 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
| 210 | 210 | ) |
| 211 | 211 | ); |
@@ -225,17 +225,17 @@ discard block |
||
| 225 | 225 | public function get_revenue_per_event_report($period = '-1 month') |
| 226 | 226 | { |
| 227 | 227 | global $wpdb; |
| 228 | - $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
| 229 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
| 230 | - $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
| 228 | + $transaction_table = $wpdb->prefix.'esp_transaction'; |
|
| 229 | + $registration_table = $wpdb->prefix.'esp_registration'; |
|
| 230 | + $registration_payment_table = $wpdb->prefix.'esp_registration_payment'; |
|
| 231 | 231 | $event_table = $wpdb->posts; |
| 232 | - $payment_table = $wpdb->prefix . 'esp_payment'; |
|
| 232 | + $payment_table = $wpdb->prefix.'esp_payment'; |
|
| 233 | 233 | $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
| 234 | 234 | $approved_payment_status = EEM_Payment::status_id_approved; |
| 235 | 235 | $extra_event_on_join = ''; |
| 236 | 236 | // exclude events not authored by user if permissions in effect |
| 237 | - if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 238 | - $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
| 237 | + if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
| 238 | + $extra_event_on_join = ' AND Event.post_author = '.get_current_user_id(); |
|
| 239 | 239 | } |
| 240 | 240 | |
| 241 | 241 | return $wpdb->get_results( |
@@ -309,7 +309,7 @@ discard block |
||
| 309 | 309 | public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
| 310 | 310 | { |
| 311 | 311 | EE_Error::doing_it_wrong( |
| 312 | - __CLASS__ . '::' . __FUNCTION__, |
|
| 312 | + __CLASS__.'::'.__FUNCTION__, |
|
| 313 | 313 | sprintf( |
| 314 | 314 | __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
| 315 | 315 | 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
@@ -359,7 +359,7 @@ discard block |
||
| 359 | 359 | array( |
| 360 | 360 | 0 => array( |
| 361 | 361 | 'STS_ID' => EEM_Transaction::failed_status_code, |
| 362 | - 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
| 362 | + 'Payment.PAY_ID' => array('IS NULL'), |
|
| 363 | 363 | 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
| 364 | 364 | ), |
| 365 | 365 | 'order_by' => ['TXN_timestamp' => 'ASC'], |
@@ -379,7 +379,7 @@ discard block |
||
| 379 | 379 | $time_to_leave_alone |
| 380 | 380 | ); |
| 381 | 381 | // now that we have the ids to delete |
| 382 | - if (! empty($txn_ids) && is_array($txn_ids)) { |
|
| 382 | + if ( ! empty($txn_ids) && is_array($txn_ids)) { |
|
| 383 | 383 | // first, make sure these TXN's are removed the "ee_locked_transactions" array |
| 384 | 384 | EEM_Transaction::unset_locked_transactions($txn_ids); |
| 385 | 385 | |
@@ -392,7 +392,7 @@ discard block |
||
| 392 | 392 | // let's get deletin'... |
| 393 | 393 | // We got the ids from the original query to get them FROM |
| 394 | 394 | // the db (which is sanitized) so no need to prepare them again. |
| 395 | - $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
| 395 | + $query = $wpdb->prepare("DELETE FROM ".$this->table()." WHERE TXN_ID IN ( $format )", $txn_ids); |
|
| 396 | 396 | $deleted = $wpdb->query($query); |
| 397 | 397 | } |
| 398 | 398 | if ($deleted) { |
@@ -416,8 +416,8 @@ discard block |
||
| 416 | 416 | $locked_transactions = get_option('ee_locked_transactions', array()); |
| 417 | 417 | $update = false; |
| 418 | 418 | foreach ($transaction_IDs as $TXN_ID) { |
| 419 | - if (isset($locked_transactions[ $TXN_ID ])) { |
|
| 420 | - unset($locked_transactions[ $TXN_ID ]); |
|
| 419 | + if (isset($locked_transactions[$TXN_ID])) { |
|
| 420 | + unset($locked_transactions[$TXN_ID]); |
|
| 421 | 421 | $update = true; |
| 422 | 422 | } |
| 423 | 423 | } |
@@ -38,103 +38,103 @@ |
||
| 38 | 38 | * @since 4.0 |
| 39 | 39 | */ |
| 40 | 40 | if (function_exists('espresso_version')) { |
| 41 | - if (! function_exists('espresso_duplicate_plugin_error')) { |
|
| 42 | - /** |
|
| 43 | - * espresso_duplicate_plugin_error |
|
| 44 | - * displays if more than one version of EE is activated at the same time |
|
| 45 | - */ |
|
| 46 | - function espresso_duplicate_plugin_error() |
|
| 47 | - { |
|
| 48 | - ?> |
|
| 41 | + if (! function_exists('espresso_duplicate_plugin_error')) { |
|
| 42 | + /** |
|
| 43 | + * espresso_duplicate_plugin_error |
|
| 44 | + * displays if more than one version of EE is activated at the same time |
|
| 45 | + */ |
|
| 46 | + function espresso_duplicate_plugin_error() |
|
| 47 | + { |
|
| 48 | + ?> |
|
| 49 | 49 | <div class="error"> |
| 50 | 50 | <p> |
| 51 | 51 | <?php |
| 52 | - echo esc_html__( |
|
| 53 | - 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
| 54 | - 'event_espresso' |
|
| 55 | - ); ?> |
|
| 52 | + echo esc_html__( |
|
| 53 | + 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
| 54 | + 'event_espresso' |
|
| 55 | + ); ?> |
|
| 56 | 56 | </p> |
| 57 | 57 | </div> |
| 58 | 58 | <?php |
| 59 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
| 60 | - } |
|
| 61 | - } |
|
| 62 | - add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
| 59 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
| 60 | + } |
|
| 61 | + } |
|
| 62 | + add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
| 63 | 63 | } else { |
| 64 | - define('EE_MIN_PHP_VER_REQUIRED', '5.4.0'); |
|
| 65 | - if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
| 66 | - /** |
|
| 67 | - * espresso_minimum_php_version_error |
|
| 68 | - * |
|
| 69 | - * @return void |
|
| 70 | - */ |
|
| 71 | - function espresso_minimum_php_version_error() |
|
| 72 | - { |
|
| 73 | - ?> |
|
| 64 | + define('EE_MIN_PHP_VER_REQUIRED', '5.4.0'); |
|
| 65 | + if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
| 66 | + /** |
|
| 67 | + * espresso_minimum_php_version_error |
|
| 68 | + * |
|
| 69 | + * @return void |
|
| 70 | + */ |
|
| 71 | + function espresso_minimum_php_version_error() |
|
| 72 | + { |
|
| 73 | + ?> |
|
| 74 | 74 | <div class="error"> |
| 75 | 75 | <p> |
| 76 | 76 | <?php |
| 77 | - printf( |
|
| 78 | - esc_html__( |
|
| 79 | - 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
| 80 | - 'event_espresso' |
|
| 81 | - ), |
|
| 82 | - EE_MIN_PHP_VER_REQUIRED, |
|
| 83 | - PHP_VERSION, |
|
| 84 | - '<br/>', |
|
| 85 | - '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
| 86 | - ); |
|
| 87 | - ?> |
|
| 77 | + printf( |
|
| 78 | + esc_html__( |
|
| 79 | + 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
| 80 | + 'event_espresso' |
|
| 81 | + ), |
|
| 82 | + EE_MIN_PHP_VER_REQUIRED, |
|
| 83 | + PHP_VERSION, |
|
| 84 | + '<br/>', |
|
| 85 | + '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
| 86 | + ); |
|
| 87 | + ?> |
|
| 88 | 88 | </p> |
| 89 | 89 | </div> |
| 90 | 90 | <?php |
| 91 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
| 92 | - } |
|
| 91 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
| 92 | + } |
|
| 93 | 93 | |
| 94 | - add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
| 95 | - } else { |
|
| 96 | - define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
| 97 | - /** |
|
| 98 | - * espresso_version |
|
| 99 | - * Returns the plugin version |
|
| 100 | - * |
|
| 101 | - * @return string |
|
| 102 | - */ |
|
| 103 | - function espresso_version() |
|
| 104 | - { |
|
| 105 | - return apply_filters('FHEE__espresso__espresso_version', '4.10.3.rc.026'); |
|
| 106 | - } |
|
| 94 | + add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
| 95 | + } else { |
|
| 96 | + define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
| 97 | + /** |
|
| 98 | + * espresso_version |
|
| 99 | + * Returns the plugin version |
|
| 100 | + * |
|
| 101 | + * @return string |
|
| 102 | + */ |
|
| 103 | + function espresso_version() |
|
| 104 | + { |
|
| 105 | + return apply_filters('FHEE__espresso__espresso_version', '4.10.3.rc.026'); |
|
| 106 | + } |
|
| 107 | 107 | |
| 108 | - /** |
|
| 109 | - * espresso_plugin_activation |
|
| 110 | - * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
| 111 | - */ |
|
| 112 | - function espresso_plugin_activation() |
|
| 113 | - { |
|
| 114 | - update_option('ee_espresso_activation', true); |
|
| 115 | - } |
|
| 108 | + /** |
|
| 109 | + * espresso_plugin_activation |
|
| 110 | + * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
| 111 | + */ |
|
| 112 | + function espresso_plugin_activation() |
|
| 113 | + { |
|
| 114 | + update_option('ee_espresso_activation', true); |
|
| 115 | + } |
|
| 116 | 116 | |
| 117 | - register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
| 117 | + register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
| 118 | 118 | |
| 119 | - require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
| 120 | - bootstrap_espresso(); |
|
| 121 | - } |
|
| 119 | + require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
| 120 | + bootstrap_espresso(); |
|
| 121 | + } |
|
| 122 | 122 | } |
| 123 | 123 | if (! function_exists('espresso_deactivate_plugin')) { |
| 124 | - /** |
|
| 125 | - * deactivate_plugin |
|
| 126 | - * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
| 127 | - * |
|
| 128 | - * @access public |
|
| 129 | - * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
| 130 | - * @return void |
|
| 131 | - */ |
|
| 132 | - function espresso_deactivate_plugin($plugin_basename = '') |
|
| 133 | - { |
|
| 134 | - if (! function_exists('deactivate_plugins')) { |
|
| 135 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
| 136 | - } |
|
| 137 | - unset($_GET['activate'], $_REQUEST['activate']); |
|
| 138 | - deactivate_plugins($plugin_basename); |
|
| 139 | - } |
|
| 124 | + /** |
|
| 125 | + * deactivate_plugin |
|
| 126 | + * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
| 127 | + * |
|
| 128 | + * @access public |
|
| 129 | + * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
| 130 | + * @return void |
|
| 131 | + */ |
|
| 132 | + function espresso_deactivate_plugin($plugin_basename = '') |
|
| 133 | + { |
|
| 134 | + if (! function_exists('deactivate_plugins')) { |
|
| 135 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
| 136 | + } |
|
| 137 | + unset($_GET['activate'], $_REQUEST['activate']); |
|
| 138 | + deactivate_plugins($plugin_basename); |
|
| 139 | + } |
|
| 140 | 140 | } |