SubscriptionBillingFrequency.php
4 years ago
SubscriptionEntity.php
4 years ago
SubscriptionFactory.php
4 years ago
SubscriptionStatus.php
4 years ago
SubscriptionTrialPeriod.php
4 years ago
index.php
4 years ago
SubscriptionEntity.php
682 lines
| 1 | <?php |
| 2 | |
| 3 | namespace ProfilePress\Core\Membership\Models\Subscription; |
| 4 | |
| 5 | use ProfilePress\Core\Classes\PROFILEPRESS_sql; |
| 6 | use ProfilePress\Core\Membership\Models\AbstractModel; |
| 7 | use ProfilePress\Core\Membership\Models\ModelInterface; |
| 8 | use ProfilePress\Core\Membership\Models\Order\OrderEntity as OrderEntity; |
| 9 | use ProfilePress\Core\Membership\Models\Order\OrderFactory; |
| 10 | use ProfilePress\Core\Membership\Models\Order\OrderStatus; |
| 11 | use ProfilePress\Core\Membership\PaymentMethods\PaymentMethods; |
| 12 | use ProfilePress\Core\Membership\Repositories\OrderRepository; |
| 13 | use ProfilePress\Core\Membership\Repositories\SubscriptionRepository; |
| 14 | use ProfilePress\Core\Membership\Services\Calculator; |
| 15 | use ProfilePress\Core\Membership\Services\OrderService; |
| 16 | use ProfilePressVendor\Carbon\CarbonImmutable; |
| 17 | |
| 18 | /** |
| 19 | * @property int $id |
| 20 | * @property int $parent_order_id |
| 21 | * @property int $plan_id |
| 22 | * @property int $customer_id |
| 23 | * @property string $billing_frequency |
| 24 | * @property string $initial_amount |
| 25 | * @property string $recurring_amount |
| 26 | * @property string $initial_tax |
| 27 | * @property string $initial_tax_rate |
| 28 | * @property string $recurring_tax |
| 29 | * @property string $recurring_tax_rate |
| 30 | * @property int $total_payments |
| 31 | * @property string $trial_period |
| 32 | * @property string $profile_id |
| 33 | * @property string $status |
| 34 | * @property array $notes |
| 35 | * @property string $created_date |
| 36 | * @property string $expiration_date |
| 37 | */ |
| 38 | class SubscriptionEntity extends AbstractModel implements ModelInterface |
| 39 | { |
| 40 | /** |
| 41 | * Subscription ID |
| 42 | * |
| 43 | * @var int |
| 44 | */ |
| 45 | protected $id = 0; |
| 46 | |
| 47 | /** |
| 48 | * Subscription Parent order ID |
| 49 | * |
| 50 | * @var int |
| 51 | */ |
| 52 | protected $parent_order_id = 0; |
| 53 | |
| 54 | /** |
| 55 | * The Plan ID that this subscription is for. |
| 56 | * |
| 57 | * @var int |
| 58 | */ |
| 59 | protected $plan_id = 0; |
| 60 | |
| 61 | /** |
| 62 | * Customer ID with this subscription. |
| 63 | * |
| 64 | * @var int |
| 65 | */ |
| 66 | protected $customer_id = 0; |
| 67 | |
| 68 | /** |
| 69 | * Billing frequency |
| 70 | * |
| 71 | * @var string |
| 72 | */ |
| 73 | protected $billing_frequency = SubscriptionBillingFrequency::MONTHLY; |
| 74 | |
| 75 | /** |
| 76 | * @var string |
| 77 | */ |
| 78 | protected $initial_amount = '0'; |
| 79 | |
| 80 | /** |
| 81 | * @var string |
| 82 | */ |
| 83 | protected $recurring_amount = '0'; |
| 84 | |
| 85 | /** |
| 86 | * @var string |
| 87 | */ |
| 88 | protected $initial_tax = '0'; |
| 89 | |
| 90 | /** |
| 91 | * @var string |
| 92 | */ |
| 93 | protected $initial_tax_rate = '0'; |
| 94 | |
| 95 | /** |
| 96 | * @var string |
| 97 | */ |
| 98 | protected $recurring_tax = '0'; |
| 99 | |
| 100 | /** |
| 101 | * @var string |
| 102 | */ |
| 103 | protected $recurring_tax_rate = '0'; |
| 104 | |
| 105 | /** |
| 106 | * @var int |
| 107 | */ |
| 108 | protected $total_payments = 0; |
| 109 | |
| 110 | /** |
| 111 | * @var string |
| 112 | */ |
| 113 | protected $trial_period = SubscriptionTrialPeriod::DISABLED; |
| 114 | |
| 115 | /** |
| 116 | * @var string |
| 117 | */ |
| 118 | protected $profile_id = ''; |
| 119 | |
| 120 | /** |
| 121 | * @var string |
| 122 | */ |
| 123 | protected $status = SubscriptionStatus::PENDING; |
| 124 | |
| 125 | /** |
| 126 | * @var string |
| 127 | */ |
| 128 | protected $notes = []; |
| 129 | |
| 130 | /** |
| 131 | * @var string |
| 132 | */ |
| 133 | protected $created_date = ''; |
| 134 | |
| 135 | /** |
| 136 | * @var string |
| 137 | */ |
| 138 | protected $expiration_date = ''; |
| 139 | |
| 140 | public function __construct($data = []) |
| 141 | { |
| 142 | if (is_array($data) && ! empty($data)) { |
| 143 | |
| 144 | foreach ($data as $key => $value) { |
| 145 | |
| 146 | if ($key == 'notes' && ! is_array($value)) { |
| 147 | $value = empty($value) ? '{}' : $value; |
| 148 | $this->$key = json_decode($value, true); |
| 149 | } else { |
| 150 | $this->$key = $value; |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * @return bool |
| 158 | */ |
| 159 | public function exists() |
| 160 | { |
| 161 | return ! empty($this->id); |
| 162 | } |
| 163 | |
| 164 | public function get_id() |
| 165 | { |
| 166 | return absint($this->id); |
| 167 | } |
| 168 | |
| 169 | public function is_active() |
| 170 | { |
| 171 | $ret = false; |
| 172 | |
| 173 | $active_statuses = [ |
| 174 | SubscriptionStatus::ACTIVE, |
| 175 | SubscriptionStatus::COMPLETED, |
| 176 | SubscriptionStatus::TRIALLING, |
| 177 | ]; |
| 178 | |
| 179 | if ( ! $this->is_expired() && in_array($this->status, $active_statuses, true)) { |
| 180 | $ret = true; |
| 181 | } |
| 182 | |
| 183 | return apply_filters('ppress_subscription_is_active', $ret, $this->id, $this); |
| 184 | } |
| 185 | |
| 186 | public function is_expired() |
| 187 | { |
| 188 | $ret = false; |
| 189 | |
| 190 | if ($this->status == SubscriptionStatus::EXPIRED) { |
| 191 | |
| 192 | $ret = true; |
| 193 | |
| 194 | } elseif ( ! $this->is_lifetime() && in_array($this->status, [SubscriptionStatus::ACTIVE, SubscriptionStatus::CANCELLED, SubscriptionStatus::TRIALLING])) { |
| 195 | |
| 196 | $ret = false; |
| 197 | |
| 198 | if (CarbonImmutable::parse($this->expiration_date, wp_timezone())->diffInDays() >= 2) { |
| 199 | |
| 200 | $ret = true; |
| 201 | |
| 202 | if (in_array($this->status, [SubscriptionStatus::ACTIVE, SubscriptionStatus::TRIALLING])) { |
| 203 | $this->expire(); |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | return apply_filters('ppress_subscription_is_expired', $ret, $this->id, $this); |
| 209 | } |
| 210 | |
| 211 | public function is_cancelled() |
| 212 | { |
| 213 | return $this->status == SubscriptionStatus::CANCELLED; |
| 214 | } |
| 215 | |
| 216 | public function is_completed() |
| 217 | { |
| 218 | return $this->status == SubscriptionStatus::COMPLETED; |
| 219 | } |
| 220 | |
| 221 | public function is_recurring() |
| 222 | { |
| 223 | return $this->billing_frequency != SubscriptionBillingFrequency::ONE_TIME; |
| 224 | } |
| 225 | |
| 226 | public function is_lifetime() |
| 227 | { |
| 228 | return ! $this->is_recurring() || Calculator::init($this->recurring_amount)->isNegativeOrZero(); |
| 229 | } |
| 230 | |
| 231 | public function has_trial() |
| 232 | { |
| 233 | return $this->is_recurring() && $this->trial_period != SubscriptionTrialPeriod::DISABLED; |
| 234 | } |
| 235 | |
| 236 | public function get_parent_order_id() |
| 237 | { |
| 238 | return absint($this->parent_order_id); |
| 239 | } |
| 240 | |
| 241 | public function get_plan_id() |
| 242 | { |
| 243 | return absint($this->plan_id); |
| 244 | } |
| 245 | |
| 246 | public function get_customer_id() |
| 247 | { |
| 248 | return absint($this->customer_id); |
| 249 | } |
| 250 | |
| 251 | /** |
| 252 | * Total sub initial amount including tax. |
| 253 | * |
| 254 | * @return string |
| 255 | */ |
| 256 | public function get_initial_amount() |
| 257 | { |
| 258 | return (string)$this->initial_amount; |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | * Total sub recurring amount including tax. |
| 263 | * |
| 264 | * @return string |
| 265 | */ |
| 266 | public function get_recurring_amount() |
| 267 | { |
| 268 | return (string)$this->recurring_amount; |
| 269 | } |
| 270 | |
| 271 | public function get_initial_tax() |
| 272 | { |
| 273 | return empty($this->initial_tax) ? '0' : (string)$this->initial_tax; |
| 274 | } |
| 275 | |
| 276 | public function get_initial_tax_rate() |
| 277 | { |
| 278 | return empty($this->initial_tax_rate) ? '0' : (string)$this->initial_tax_rate; |
| 279 | } |
| 280 | |
| 281 | public function get_recurring_tax() |
| 282 | { |
| 283 | return empty($this->recurring_tax) ? '0' : (string)$this->recurring_tax; |
| 284 | } |
| 285 | |
| 286 | public function get_recurring_tax_rate() |
| 287 | { |
| 288 | return empty($this->recurring_tax_rate) ? '0' : (string)$this->recurring_tax_rate; |
| 289 | } |
| 290 | |
| 291 | public function get_total_payments() |
| 292 | { |
| 293 | return absint($this->total_payments); |
| 294 | } |
| 295 | |
| 296 | public function get_completed_order_count() |
| 297 | { |
| 298 | return OrderRepository::init()->retrieveBy([ |
| 299 | 'subscription_id' => $this->id, |
| 300 | 'status' => OrderStatus::COMPLETED |
| 301 | ], true); |
| 302 | } |
| 303 | |
| 304 | public function set_trial_period($period) |
| 305 | { |
| 306 | $valid_periods = (new \ReflectionClass(SubscriptionTrialPeriod::class))->getConstants(); |
| 307 | |
| 308 | if (in_array($period, $valid_periods)) { |
| 309 | $this->trial_period = $period; |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | public function get_profile_id() |
| 314 | { |
| 315 | return apply_filters('ppress_subscription_profile_id', $this->profile_id, $this->get_id(), $this); |
| 316 | } |
| 317 | |
| 318 | protected function set_status($status) |
| 319 | { |
| 320 | $valid_statuses = (new \ReflectionClass(SubscriptionStatus::class))->getConstants(); |
| 321 | |
| 322 | if (in_array($status, $valid_statuses)) { |
| 323 | $this->status = $status; |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | public function get_status() |
| 328 | { |
| 329 | return apply_filters('ppress_subscription_status', $this->status, $this->get_id(), $this); |
| 330 | } |
| 331 | |
| 332 | public function get_payment_method() |
| 333 | { |
| 334 | return OrderFactory::fromId($this->parent_order_id)->payment_method; |
| 335 | } |
| 336 | |
| 337 | public function get_formatted_expiration_date() |
| 338 | { |
| 339 | $date = esc_html__('Lifetime', 'wp-user-avatar'); |
| 340 | |
| 341 | if ( ! $this->is_lifetime()) { |
| 342 | $date = ppress_format_date($this->expiration_date); |
| 343 | } |
| 344 | |
| 345 | return $date; |
| 346 | } |
| 347 | |
| 348 | public function get_notes() |
| 349 | { |
| 350 | return apply_filters('ppress_subscription_note', $this->notes, $this->get_id(), $this); |
| 351 | } |
| 352 | |
| 353 | public function add_note($note) |
| 354 | { |
| 355 | $notes = $this->notes; |
| 356 | |
| 357 | $notes[] = ppress_format_date_time(time()) . '|' . $note; |
| 358 | |
| 359 | return SubscriptionRepository::init()->updateColumn($this->id, 'notes', json_encode($notes)); |
| 360 | } |
| 361 | |
| 362 | public function get_subscription_terms() |
| 363 | { |
| 364 | $price = $this->get_recurring_amount(); |
| 365 | |
| 366 | if ($this->billing_frequency == SubscriptionBillingFrequency::ONE_TIME) { |
| 367 | $price = $this->get_initial_amount(); |
| 368 | } |
| 369 | |
| 370 | $cycle = ppress_display_amount( |
| 371 | $price, |
| 372 | OrderFactory::fromId($this->parent_order_id)->currency |
| 373 | ); |
| 374 | |
| 375 | $cycle .= ' / '; |
| 376 | |
| 377 | $cycle .= SubscriptionBillingFrequency::get_label($this->billing_frequency); |
| 378 | |
| 379 | return $cycle; |
| 380 | } |
| 381 | |
| 382 | /** |
| 383 | * Retrieve all subscription related payments. |
| 384 | * |
| 385 | * @return OrderEntity[]|string |
| 386 | */ |
| 387 | public function get_all_orders() |
| 388 | { |
| 389 | return OrderRepository::init()->retrieveBy([ |
| 390 | 'subscription_id' => $this->id, |
| 391 | 'number' => 0 |
| 392 | ]); |
| 393 | } |
| 394 | |
| 395 | /** |
| 396 | * @param $profile_id |
| 397 | * |
| 398 | * @return false|int |
| 399 | */ |
| 400 | public function activate_subscription($profile_id = '') |
| 401 | { |
| 402 | if ($this->is_active()) return false; |
| 403 | |
| 404 | $this->status = SubscriptionStatus::ACTIVE; |
| 405 | |
| 406 | if ( ! empty($profile_id)) { |
| 407 | $this->profile_id = $profile_id; |
| 408 | } |
| 409 | |
| 410 | $sub_id = $this->save(); |
| 411 | |
| 412 | do_action('ppress_subscription_activated', $this); |
| 413 | |
| 414 | $this->maybe_complete_subscription(); |
| 415 | |
| 416 | return $sub_id; |
| 417 | } |
| 418 | |
| 419 | /** |
| 420 | * @param $profile_id |
| 421 | * |
| 422 | * @return false|int |
| 423 | */ |
| 424 | public function enable_subscription_trial($profile_id = '') |
| 425 | { |
| 426 | if ($this->is_active()) return false; |
| 427 | |
| 428 | $this->status = SubscriptionStatus::TRIALLING; |
| 429 | |
| 430 | if ( ! empty($profile_id)) { |
| 431 | $this->profile_id = $profile_id; |
| 432 | } |
| 433 | |
| 434 | $sub_id = $this->save(); |
| 435 | |
| 436 | do_action('ppress_subscription_enabled_trial', $this); |
| 437 | |
| 438 | $this->maybe_complete_subscription(); |
| 439 | |
| 440 | return $sub_id; |
| 441 | } |
| 442 | |
| 443 | public function update_profile_id($val) |
| 444 | { |
| 445 | return SubscriptionRepository::init()->updateColumn($this->id, 'profile_id', $val); |
| 446 | } |
| 447 | |
| 448 | /** |
| 449 | * @param $subscription_status |
| 450 | * |
| 451 | * @return false|int |
| 452 | */ |
| 453 | public function update_status($subscription_status) |
| 454 | { |
| 455 | $old_status = $this->status; |
| 456 | |
| 457 | $this->status = $subscription_status; |
| 458 | |
| 459 | $response = $this->save(); |
| 460 | |
| 461 | $user = is_user_logged_in() ? wp_get_current_user()->user_login : esc_html__('payment method', 'wp-user-avatar'); |
| 462 | |
| 463 | $this->add_note( |
| 464 | sprintf(__('Subscription changed from %s to %s by %s', 'wp-user-avatar'), $old_status, $this->status, $user) |
| 465 | ); |
| 466 | |
| 467 | do_action('ppress_subscription_status_updated', $subscription_status, $old_status, $this); |
| 468 | |
| 469 | return $response; |
| 470 | } |
| 471 | |
| 472 | |
| 473 | /** |
| 474 | * Returns the number of times the subscription has been billed |
| 475 | * |
| 476 | * @return int |
| 477 | */ |
| 478 | public function get_times_billed() |
| 479 | { |
| 480 | $orders = OrderRepository::init()->retrieveBy([ |
| 481 | 'subscription_id' => $this->id, |
| 482 | 'status' => [OrderStatus::COMPLETED], |
| 483 | 'number' => 0 |
| 484 | ]); |
| 485 | |
| 486 | return count($orders); |
| 487 | } |
| 488 | |
| 489 | /** |
| 490 | * Determines if subscription can be cancelled |
| 491 | * |
| 492 | * This method is filtered by payment methods in order to return true on subscriptions |
| 493 | * that can be cancelled with a profile ID through the merchant processor |
| 494 | * |
| 495 | * @return bool |
| 496 | */ |
| 497 | public function can_cancel() |
| 498 | { |
| 499 | if ($this->is_lifetime()) return false; |
| 500 | |
| 501 | return apply_filters('ppress_subscription_can_cancel', false, $this); |
| 502 | } |
| 503 | |
| 504 | public function has_cancellation_requested() |
| 505 | { |
| 506 | $val = PROFILEPRESS_sql::get_meta_data_by_key('subscription_cancellation_requested_' . $this->id); |
| 507 | |
| 508 | return is_array($val) && isset($val[0]['meta_value']) && 'true' == $val[0]['meta_value']; |
| 509 | } |
| 510 | |
| 511 | public function add_cancellation_requested() |
| 512 | { |
| 513 | $this->delete_cancellation_requested(); // cleanup first |
| 514 | PROFILEPRESS_sql::add_meta_data('subscription_cancellation_requested_' . $this->id, 'true'); |
| 515 | } |
| 516 | |
| 517 | public function delete_cancellation_requested() |
| 518 | { |
| 519 | PROFILEPRESS_sql::delete_meta_data_by_meta_key('subscription_cancellation_requested_' . $this->id); |
| 520 | } |
| 521 | |
| 522 | /** |
| 523 | * @param bool $gateway_cancel set to true to cancel sub in gateway too. |
| 524 | * |
| 525 | * @return false|void |
| 526 | */ |
| 527 | public function cancel($gateway_cancel = false) |
| 528 | { |
| 529 | if ($this->is_cancelled()) return false; |
| 530 | |
| 531 | $sub = clone $this; // gateway cancel() check sub status first before cancelling. hence we need a copy of the sub before it's cancelled below. |
| 532 | |
| 533 | $old_status = $this->status; |
| 534 | |
| 535 | $this->update_status(SubscriptionStatus::CANCELLED); |
| 536 | |
| 537 | if ($gateway_cancel === true && $sub->can_cancel()) { |
| 538 | PaymentMethods::get_instance()->get_by_id($this->get_payment_method())->cancel($sub); |
| 539 | } |
| 540 | |
| 541 | $this->add_cancellation_requested(); |
| 542 | |
| 543 | do_action('ppress_subscription_cancelled', $this, $old_status); |
| 544 | } |
| 545 | |
| 546 | /** |
| 547 | * @return false|void |
| 548 | */ |
| 549 | public function complete() |
| 550 | { |
| 551 | // Prevent setting a subscription as complete if it was previously set as cancelled. |
| 552 | if ($this->is_cancelled()) return false; |
| 553 | |
| 554 | if ($this->update_status(SubscriptionStatus::COMPLETED)) { |
| 555 | |
| 556 | do_action('ppress_subscription_completed', $this); |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * @param bool $check_expiration |
| 562 | * |
| 563 | * @return false|void |
| 564 | */ |
| 565 | public function expire($check_expiration = false) |
| 566 | { |
| 567 | if ($this->is_lifetime()) return false; |
| 568 | |
| 569 | if ($check_expiration && time() < ppress_strtotime_utc($this->expiration_date)) { |
| 570 | return false; // Do not mark as expired since real expiration date is in the future |
| 571 | } |
| 572 | |
| 573 | $this->update_status(SubscriptionStatus::EXPIRED); |
| 574 | |
| 575 | do_action('ppress_subscription_expired', $this); |
| 576 | } |
| 577 | |
| 578 | public function renew($change_expiry_date = true, $expiration_date = '') |
| 579 | { |
| 580 | if ( ! empty($expiration_date)) { |
| 581 | $expiration = CarbonImmutable::createFromTimestampUTC($expiration_date); |
| 582 | } else { |
| 583 | |
| 584 | $old_expiry_date = ppress_date_to_utc_timestamp($this->expiration_date); |
| 585 | |
| 586 | // Determine what date to use as the start for the new expiration calculation |
| 587 | if ($old_expiry_date > time() && $this->is_active()) { |
| 588 | $base_date = $old_expiry_date; |
| 589 | } else { |
| 590 | $base_date = time(); |
| 591 | } |
| 592 | |
| 593 | $cabonInstance = CarbonImmutable::createFromTimestampUTC($base_date); |
| 594 | |
| 595 | switch ($this->billing_frequency) { |
| 596 | case SubscriptionBillingFrequency::DAILY : |
| 597 | $expiration = $cabonInstance->addDay(); |
| 598 | break; |
| 599 | case SubscriptionBillingFrequency::WEEKLY : |
| 600 | $expiration = $cabonInstance->addWeek(); |
| 601 | break; |
| 602 | case SubscriptionBillingFrequency::QUARTERLY : |
| 603 | $expiration = $cabonInstance->addMonths(3); |
| 604 | break; |
| 605 | case SubscriptionBillingFrequency::EVERY_6_MONTHS : |
| 606 | $expiration = $cabonInstance->addMonths(6); |
| 607 | break; |
| 608 | case SubscriptionBillingFrequency::YEARLY : |
| 609 | $expiration = $cabonInstance->addYear(); |
| 610 | break; |
| 611 | default: |
| 612 | $expiration = $cabonInstance->addMonth(); |
| 613 | break; |
| 614 | } |
| 615 | } |
| 616 | |
| 617 | $expiration = apply_filters('ppress_subscription_renewal_expiration', $expiration->toDateTimeString(), $this->id, $this); |
| 618 | |
| 619 | do_action('ppress_subscription_pre_renew', $this->id, $expiration, $this); |
| 620 | |
| 621 | if ($change_expiry_date === true) { |
| 622 | $this->expiration_date = $expiration; |
| 623 | } |
| 624 | |
| 625 | $this->status = SubscriptionStatus::ACTIVE; |
| 626 | $this->save(); |
| 627 | |
| 628 | $this->maybe_complete_subscription(); |
| 629 | |
| 630 | do_action('ppress_subscription_post_renew', $this->id, $expiration, $this); |
| 631 | } |
| 632 | |
| 633 | public function maybe_complete_subscription() |
| 634 | { |
| 635 | if ($this->is_completed()) return; |
| 636 | |
| 637 | $times_billed = $this->get_times_billed(); |
| 638 | |
| 639 | // Complete subscription if applicable |
| 640 | if ($this->total_payments > 0 && $times_billed >= $this->total_payments) { |
| 641 | $this->complete(); |
| 642 | } |
| 643 | } |
| 644 | |
| 645 | /** |
| 646 | * @param $args |
| 647 | * |
| 648 | * @return false|int |
| 649 | */ |
| 650 | public function add_renewal_order($args) |
| 651 | { |
| 652 | $result = OrderService::init()->record_subscription_renewal_order( |
| 653 | $args, |
| 654 | $this |
| 655 | ); |
| 656 | |
| 657 | do_action('ppress_subscription_renewal_order_added', $args, $this); |
| 658 | |
| 659 | return $result; |
| 660 | } |
| 661 | |
| 662 | /** |
| 663 | * @return false|int |
| 664 | */ |
| 665 | public function save() |
| 666 | { |
| 667 | if ($this->exists()) { |
| 668 | |
| 669 | $result = SubscriptionRepository::init()->update($this); |
| 670 | |
| 671 | do_action('ppress_membership_update_subscription', $result, $this); |
| 672 | |
| 673 | return $result; |
| 674 | } |
| 675 | |
| 676 | $result = SubscriptionRepository::init()->add($this); |
| 677 | |
| 678 | do_action('ppress_membership_add_subscription', $result, $this); |
| 679 | |
| 680 | return $result; |
| 681 | } |
| 682 | } |