swpm_handle_subsc_ipn.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <?php
  2. function swpm_handle_subsc_signup_stand_alone( $ipn_data, $subsc_ref, $unique_ref, $swpm_id = '' ) {
  3. global $wpdb;
  4. $settings = SwpmSettings::get_instance();
  5. $membership_level = $subsc_ref;
  6. if ( isset( $ipn_data['subscr_id'] ) && ! empty( $ipn_data['subscr_id'] ) ) {
  7. $subscr_id = $ipn_data['subscr_id'];
  8. } else {
  9. $subscr_id = $unique_ref;
  10. }
  11. swpm_debug_log_subsc( 'swpm_handle_subsc_signup_stand_alone(). Custom value: ' . $ipn_data['custom'] . ', Unique reference: ' . $unique_ref, true );
  12. parse_str( $ipn_data['custom'], $custom_vars );
  13. if ( empty( $swpm_id ) ) {
  14. // Lets try to find an existing user profile for this payment.
  15. $email = $ipn_data['payer_email'];
  16. $query_db = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}swpm_members_tbl WHERE email = %s", $email ), OBJECT ); // db call ok; no-cache ok.
  17. if ( ! $query_db ) { // try to retrieve the member details based on the unique_ref.
  18. swpm_debug_log_subsc( 'Could not find any record using the given email address (' . $email . '). Attempting to query database using the unique reference: ' . $unique_ref, true );
  19. if ( ! empty( $unique_ref ) ) {
  20. $query_db = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}swpm_members_tbl WHERE subscr_id = %s", $unique_ref ), OBJECT ); // db call ok; no-cache ok.
  21. if ( $query_db ) {
  22. $swpm_id = $query_db->member_id;
  23. swpm_debug_log_subsc( 'Found a match in the member database using unique reference. Member ID: ' . $swpm_id, true );
  24. } else {
  25. swpm_debug_log_subsc( 'Did not find a match for an existing member profile for the given reference. This must be a new payment from a new member.', true );
  26. }
  27. } else {
  28. swpm_debug_log_subsc( 'Unique reference is missing in the notification so we have to assume that this is not a payment for an existing member.', true );
  29. }
  30. } else {
  31. $swpm_id = $query_db->member_id;
  32. swpm_debug_log_subsc( 'Found a match in the member database. Member ID: ' . $swpm_id, true );
  33. }
  34. }
  35. if ( ! empty( $swpm_id ) ) {
  36. // This is payment from an existing member/user. Update the existing member account.
  37. swpm_debug_log_subsc( 'Modifying the existing membership profile... Member ID: ' . $swpm_id, true );
  38. // Upgrade the member account.
  39. $account_state = 'active'; // This is renewal or upgrade of a previously active account. So the status should be set to active.
  40. $resultset = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}swpm_members_tbl WHERE member_id = %d", $swpm_id ), OBJECT );
  41. if ( ! $resultset ) {
  42. swpm_debug_log_subsc( 'ERROR! Could not find a member account record for the given Member ID: ' . $swpm_id, false );
  43. return;
  44. }
  45. $old_membership_level = $resultset->membership_level;
  46. // If the payment is for the same/existing membership level, then this is a renewal. Refresh the start date as appropriate.
  47. $args = array(
  48. 'swpm_id' => $swpm_id,
  49. 'membership_level' => $membership_level,
  50. 'old_membership_level' => $old_membership_level,
  51. );
  52. $subscription_starts = SwpmMemberUtils::calculate_access_start_date_for_account_update( $args );
  53. $subscription_starts = apply_filters( 'swpm_account_update_subscription_starts', $subscription_starts, $args );
  54. swpm_debug_log_subsc( 'Setting access starts date value to: ' . $subscription_starts, true );
  55. swpm_debug_log_subsc( 'Updating the current membership level (' . $old_membership_level . ') of this member to the newly paid level (' . $membership_level . ')', true );
  56. // Set account status to active, update level to the newly paid level, update access start date, update subsriber ID (if applicable).
  57. $wpdb->query(
  58. $wpdb->prepare(
  59. "UPDATE {$wpdb->prefix}swpm_members_tbl SET account_state=%s, membership_level=%d,subscription_starts=%s,subscr_id=%s WHERE member_id=%d",
  60. $account_state,
  61. $membership_level,
  62. $subscription_starts,
  63. $subscr_id,
  64. $swpm_id
  65. )
  66. );
  67. // Trigger level changed/updated action hook.
  68. do_action(
  69. 'swpm_membership_level_changed',
  70. array(
  71. 'member_id' => $swpm_id,
  72. 'from_level' => $old_membership_level,
  73. 'to_level' => $membership_level,
  74. )
  75. );
  76. // Set Email details for the account upgrade notification.
  77. $email = $ipn_data['payer_email'];
  78. $subject = $settings->get_value( 'upgrade-complete-mail-subject' );
  79. if ( empty( $subject ) ) {
  80. $subject = 'Member Account Upgraded';
  81. }
  82. $body = $settings->get_value( 'upgrade-complete-mail-body' );
  83. if ( empty( $body ) ) {
  84. $body = 'Your account has been upgraded successfully';
  85. }
  86. $from_address = $settings->get_value( 'email-from' );
  87. $additional_args = array();
  88. $email_body = SwpmMiscUtils::replace_dynamic_tags( $body, $swpm_id, $additional_args );
  89. $headers = 'From: ' . $from_address . "\r\n";
  90. $subject = apply_filters( 'swpm_email_upgrade_complete_subject', $subject );
  91. $email_body = apply_filters( 'swpm_email_upgrade_complete_body', $email_body );
  92. if ( $settings->get_value( 'disable-email-after-upgrade' ) ) {
  93. swpm_debug_log_subsc( 'The disable upgrade email settings is checked. No account upgrade/update email will be sent.', true );
  94. //Nothing to do.
  95. } else {
  96. SwpmMiscUtils::mail( $email, $subject, $email_body, $headers );
  97. swpm_debug_log_subsc( 'Member upgrade/update completion email successfully sent to: ' . $email, true );
  98. }
  99. // End of existing user account upgrade/update.
  100. } else {
  101. // create new member account.
  102. $default_account_status = $settings->get_value( 'default-account-status', 'active' );
  103. $data = array();
  104. $data['user_name'] = '';
  105. $data['password'] = '';
  106. $data['first_name'] = $ipn_data['first_name'];
  107. $data['last_name'] = $ipn_data['last_name'];
  108. $data['email'] = $ipn_data['payer_email'];
  109. $data['membership_level'] = $membership_level;
  110. $data['subscr_id'] = $subscr_id;
  111. $data['gender'] = 'not specified';
  112. $data['address_street'] = $ipn_data['address_street'];
  113. $data['address_city'] = $ipn_data['address_city'];
  114. $data['address_state'] = $ipn_data['address_state'];
  115. $data['address_zipcode'] = isset( $ipn_data['address_zip'] ) ? $ipn_data['address_zip'] : '';
  116. $data['country'] = isset( $ipn_data['address_country'] ) ? $ipn_data['address_country'] : '';
  117. $data['member_since'] = $data['subscription_starts'] = $data['last_accessed'] = SwpmUtils::get_current_date_in_wp_zone();
  118. $data['account_state'] = $default_account_status;
  119. $reg_code = uniqid();
  120. $md5_code = md5( $reg_code );
  121. $data['reg_code'] = $md5_code;
  122. $data['referrer'] = $data['extra_info'] = $data['txn_id'] = '';
  123. $data['last_accessed_from_ip'] = isset( $custom_vars['user_ip'] ) ? $custom_vars['user_ip'] : ''; // Save the users IP address.
  124. swpm_debug_log_subsc( 'Creating new member account. Membership level ID: ' . $membership_level . ', Subscriber ID value: ' . $data['subscr_id'], true );
  125. $data = array_filter( $data ); // Remove any null values.
  126. $wpdb->insert( "{$wpdb->prefix}swpm_members_tbl", $data ); // Create the member record.
  127. $id = $wpdb->insert_id;
  128. if ( empty( $id ) ) {
  129. swpm_debug_log_subsc( 'Error! Failed to insert a new member record. This request will fail.', false );
  130. return;
  131. }
  132. $separator = '?';
  133. $url = $settings->get_value( 'registration-page-url' );
  134. if ( strpos( $url, '?' ) !== false ) {
  135. $separator = '&';
  136. }
  137. $reg_url = $url . $separator . 'member_id=' . $id . '&code=' . $md5_code;
  138. swpm_debug_log_subsc( 'Member signup URL: ' . $reg_url, true );
  139. $subject = $settings->get_value( 'reg-prompt-complete-mail-subject' );
  140. if ( empty( $subject ) ) {
  141. $subject = 'Please complete your registration';
  142. }
  143. $body = $settings->get_value( 'reg-prompt-complete-mail-body' );
  144. if ( empty( $body ) ) {
  145. $body = "Please use the following link to complete your registration. \n {reg_link}";
  146. }
  147. $from_address = $settings->get_value( 'email-from' );
  148. $body = html_entity_decode( $body );
  149. $additional_args = array( 'reg_link' => $reg_url );
  150. $email_body = SwpmMiscUtils::replace_dynamic_tags( $body, $id, $additional_args );
  151. $headers = 'From: ' . $from_address . "\r\n";
  152. $subject = apply_filters( 'swpm_email_complete_registration_subject', $subject );
  153. $email_body = apply_filters( 'swpm_email_complete_registration_body', $email_body );
  154. if ( empty( $email_body ) ) {
  155. swpm_debug_log_subsc( 'Notice: Member signup (prompt to complete registration) email body has been set empty via the filter hook. No email will be sent.', true );
  156. } else {
  157. SwpmMiscUtils::mail( $email, $subject, $email_body, $headers );
  158. swpm_debug_log_subsc( 'Member signup (prompt to complete registration) email successfully sent to: ' . $email, true );
  159. }
  160. }
  161. }
  162. /*
  163. * All in one function that can handle notification for refund, cancellation, end of term
  164. */
  165. function swpm_handle_subsc_cancel_stand_alone( $ipn_data, $refund = false ) {
  166. global $wpdb;
  167. $swpm_id = '';
  168. if ( isset( $ipn_data['custom'] ) ){
  169. $customvariables = SwpmTransactions::parse_custom_var( $ipn_data['custom'] );
  170. $swpm_id = $customvariables['swpm_id'];
  171. }
  172. swpm_debug_log_subsc( 'Refund/Cancellation check - lets see if a member account needs to be deactivated.', true );
  173. // swpm_debug_log_subsc("Parent txn id: " . $ipn_data['parent_txn_id'] . ", Subscr ID: " . $ipn_data['subscr_id'] . ", SWPM ID: " . $swpm_id, true);.
  174. if ( ! empty( $swpm_id ) ) {
  175. // This IPN has the SWPM ID. Retrieve the member record using member ID.
  176. swpm_debug_log_subsc( 'Member ID is present. Retrieving member account from the database. Member ID: ' . $swpm_id, true );
  177. $resultset = SwpmMemberUtils::get_user_by_id( $swpm_id );
  178. } elseif ( isset( $ipn_data['subscr_id'] ) && ! empty( $ipn_data['subscr_id'] ) ) {
  179. // This IPN has the subscriber ID. Retrieve the member record using subscr_id.
  180. $subscr_id = $ipn_data['subscr_id'];
  181. swpm_debug_log_subsc( 'Subscriber ID is present. Retrieving member account from the database. Subscr_id: ' . $subscr_id, true );
  182. $resultset = $wpdb->get_row(
  183. $wpdb->prepare(
  184. "SELECT * FROM {$wpdb->prefix}swpm_members_tbl where subscr_id LIKE %s",
  185. '%' . $wpdb->esc_like( $subscr_id ) . '%'
  186. ),
  187. OBJECT
  188. );
  189. } else {
  190. // Refund for a one time transaction. Use the parent transaction ID to retrieve the profile.
  191. $subscr_id = $ipn_data['parent_txn_id'];
  192. $resultset = $wpdb->get_row(
  193. $wpdb->prepare(
  194. "SELECT * FROM {$wpdb->prefix}swpm_members_tbl where subscr_id LIKE %s",
  195. '%' . $wpdb->esc_like( $subscr_id ) . '%'
  196. ),
  197. OBJECT
  198. );
  199. }
  200. if ( $resultset ) {
  201. // We have found a member profile for this notification.
  202. $member_id = $resultset->member_id;
  203. // First, check if this is a refund notification.
  204. if ( $refund ) {
  205. // This is a refund (not just a subscription cancellation or end). So deactivate the account regardless and bail.
  206. SwpmMemberUtils::update_account_state( $member_id, 'inactive' ); // Set the account status to inactive.
  207. swpm_debug_log_subsc( 'Subscription refund notification received! Member account deactivated.', true );
  208. return;
  209. }
  210. // This is a cancellation or end of subscription term (no refund).
  211. // Lets retrieve the membership level and details.
  212. $level_id = $resultset->membership_level;
  213. swpm_debug_log_subsc( 'Membership level ID of the member is: ' . $level_id, true );
  214. $level_row = SwpmUtils::get_membership_level_row_by_id( $level_id );
  215. $subs_duration_type = $level_row->subscription_duration_type;
  216. swpm_debug_log_subsc( 'Subscription duration type: ' . $subs_duration_type, true );
  217. if ( SwpmMembershipLevel::NO_EXPIRY == $subs_duration_type ) {
  218. // This is a level with "no expiry" or "until cancelled" duration.
  219. swpm_debug_log_subsc( 'This is a level with "no expiry" or "until cancelled" duration', true );
  220. // Deactivate this account as the membership level is "no expiry" or "until cancelled".
  221. $account_state = 'inactive';
  222. SwpmMemberUtils::update_account_state( $member_id, $account_state );
  223. swpm_debug_log_subsc( 'Subscription cancellation or end of term received! Member account deactivated. Member ID: ' . $member_id, true );
  224. } elseif ( SwpmMembershipLevel::FIXED_DATE == $subs_duration_type ) {
  225. // This is a level with a "fixed expiry date" duration.
  226. swpm_debug_log_subsc( 'This is a level with a "fixed expiry date" duration.', true );
  227. swpm_debug_log_subsc( 'Nothing to do here. The account will expire on the fixed set date.', true );
  228. } else {
  229. // This is a level with "duration" type expiry (example: 30 days, 1 year etc). subscription_period has the duration/period.
  230. $subs_period = $level_row->subscription_period;
  231. $subs_period_unit = SwpmMembershipLevel::get_level_duration_type_string( $level_row->subscription_duration_type );
  232. swpm_debug_log_subsc( 'This is a level with "duration" type expiry. Duration period: ' . $subs_period . ', Unit: ' . $subs_period_unit, true );
  233. swpm_debug_log_subsc( 'Nothing to do here. The account will expire after the duration time is over.', true );
  234. // TODO Later as an improvement. If you wanted to segment the members who have unsubscribed, you can set the account status to "unsubscribed" here.
  235. // Make sure the cronjob to do expiry check and deactivate the member accounts treat this status as if it is "active".
  236. }
  237. $ipn_data['member_id'] = $member_id;
  238. do_action( 'swpm_subscription_payment_cancelled', $ipn_data ); // Hook for recurring payment received.
  239. } else {
  240. swpm_debug_log_subsc( 'No associated active member record found for this notification.', false );
  241. return;
  242. }
  243. }
  244. function swpm_update_member_subscription_start_date_if_applicable( $ipn_data ) {
  245. global $wpdb;
  246. $email = isset( $ipn_data['payer_email'] ) ? $ipn_data['payer_email'] : '';
  247. $subscr_id = $ipn_data['subscr_id'];
  248. $account_state = SwpmSettings::get_instance()->get_value( 'default-account-status', 'active' );
  249. swpm_debug_log_subsc( 'Updating subscription start date if applicable for this subscription payment. Subscriber ID: ' . $subscr_id . ' Email: ' . $email, true );
  250. // We can also query using the email address or SWPM ID (if present in custom var).
  251. //Try to find the profile with the given subscr_id. It will exact match subscr_id or match subscr_id|123
  252. $query_db = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}swpm_members_tbl WHERE subscr_id = %s OR subscr_id LIKE %s", $subscr_id, $subscr_id.'|%' ), OBJECT );
  253. if ( $query_db ) {
  254. $swpm_id = $query_db->member_id;
  255. $current_primary_level = $query_db->membership_level;
  256. swpm_debug_log_subsc( 'Found a record in the member table. The Member ID of the account to check is: ' . $swpm_id . ' Membership Level: ' . $current_primary_level, true );
  257. $ipn_data['member_id'] = $swpm_id;
  258. do_action( 'swpm_recurring_payment_received', $ipn_data ); // Hook for recurring payment received.
  259. $subscription_starts = SwpmUtils::get_current_date_in_wp_zone();
  260. $wpdb->query(
  261. $wpdb->prepare(
  262. "UPDATE {$wpdb->prefix}swpm_members_tbl SET account_state=%s,subscription_starts=%s WHERE member_id=%d",
  263. $account_state,
  264. $subscription_starts,
  265. $swpm_id
  266. )
  267. );
  268. swpm_debug_log_subsc( 'Updated the member profile with current date as the subscription start date.', true );
  269. // Lets check to see if the subscriber ID and the subscription start date value was updated correctly.
  270. $member_record = SwpmMemberUtils::get_user_by_id( $swpm_id );
  271. swpm_debug_log_subsc( 'Value after update - Subscriber ID: ' . $member_record->subscr_id . ', Start Date: ' . $member_record->subscription_starts, true );
  272. } else {
  273. swpm_debug_log_subsc( 'Did not find an existing record in the members table for subscriber ID: ' . $subscr_id, true );
  274. swpm_debug_log_subsc( 'This could be a new subscription payment for a new subscription agreement.', true );
  275. }
  276. }
  277. function swpm_is_paypal_recurring_payment($payment_data){
  278. $recurring_payment = false;
  279. $transaction_type = $payment_data['txn_type'];
  280. if ($transaction_type == "recurring_payment") {
  281. $recurring_payment = true;
  282. } else if ($transaction_type == "subscr_payment") {
  283. $item_number = $payment_data['item_number'];
  284. $subscr_id = $payment_data['subscr_id'];
  285. swpm_debug_log_subsc('Is recurring payment check debug data: ' . $item_number . "|" . $subscr_id, true);
  286. $result = SwpmTransactions::get_transaction_row_by_subscr_id($subscr_id);
  287. if (isset($result)) {
  288. swpm_debug_log_subsc('This subscr_id exists in the transactions db. Recurring payment check flag value is true.', true);
  289. $recurring_payment = true;
  290. return $recurring_payment;
  291. }
  292. }
  293. if ($recurring_payment) {
  294. swpm_debug_log_subsc('Recurring payment check flag value is true.', true);
  295. }
  296. return $recurring_payment;
  297. }
  298. function swpm_debug_log_subsc( $message, $success, $end = false ) {
  299. $settings = SwpmSettings::get_instance();
  300. $debug_enabled = $settings->get_value( 'enable-debug' );
  301. if ( empty( $debug_enabled ) ) { // Debug is not enabled.
  302. return;
  303. }
  304. $debug_log_file_name = SIMPLE_WP_MEMBERSHIP_PATH . 'log.txt';
  305. // Timestamp.
  306. $log_timestamp = SwpmUtils::get_current_timestamp_for_debug_log();
  307. $text = '[' . $log_timestamp . '] - ' . ( ( $success ) ? 'SUCCESS: ' : 'FAILURE: ' ) . $message . "\n";
  308. if ( $end ) {
  309. $text .= "\n------------------------------------------------------------------\n\n";
  310. }
  311. // Write to log.
  312. $fp = fopen( $debug_log_file_name, 'a' );
  313. fwrite( $fp, $text );
  314. fclose( $fp ); // close file.
  315. }