News:

SMF 2.1.2 has been released! Take it for a spin! Read more.

Main Menu

Paid Subscriptions - Help

Started by DMR123, April 16, 2012, 03:07:47 PM

Previous topic - Next topic

DMR123

Hi,
Regarding "Paid Subscriptions"...

I have setup the subscriptions. But in the "settings" it says..

"Note:
For subscriptions to be automatically updated for your users, you will need to setup a return URL for each of your payment methods. For all payment types, this return URL should be set as:

  •  http://domain.co.uk/subscriptions.php

You can edit the link for paypal directly, by clicking here"



So when I click to edit the link it asks for "Instant Payment Notification (IPN)"

What exactly do I enter into there?  is that where I enter  http://domain.co.uk/subscriptions.php 

Sir Osis of Liver


It is not necessary to enable or configure Paypal IPN for paid subscriptions to work.  Subscriptions-PayPal.php sends a notify_url to Paypal, which forces an IPN post to subscriptions.php.  Doesn't matter what the Paypal IPN settings are, notify_url overrides them.

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

I'm having the same kind of problem understanding this too. In testing of this it will take payment but then I get a system error email saying:

QuotePaid Subscription Error Occurred

Member,

The following error occurred when processing a paid subscription
---------------------------------------------------------------
Unknown Paid Subscriptions transaction type.

Plus the group I have added as the primary group to add after payment is also then not adding?

So how do I or where do I adjust this notify_url to work with the subscriptions.php


Sir Osis of Liver

You don't adjust notify_url - it posts the return url to your forum that PayPal uses to send the IPN -



$return_data['hidden']['notify_url'] = $boardurl . '/subscriptions.php';



You are recieving an IPN from PayPal, but your forum doesn't recognize it.

Post the error from your error log.

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

This is the error log, basically I've set up a test at .50c to change the user to the primary group "Town Clown" and have set up a group for this with its own permissions and a board for this group to see.


QuoteUnknown Paid Subscriptions transaction type.
transaction_subject: Town Clown Subscription
payment_date: 17:43:06 May 20, 2012 PDT
txn_type: subscr_payment
subscr_id: I-3J1D9F313EH1
last_name: "removed by Wazza"
residence_country: AU
item_name: Town Clown Subscription
payment_gross:
mc_currency: AUD
business: [email protected]
payment_type: instant
protection_eligibility: Ineligible
verify_sign: AGnfEDIRQZO9ANlAlrSro.f5Ox0EAIourA0ic2r0HycWD3MsYQANbBjD
payer_status: unverified
payer_email: "removed by Wazza"
txn_id: 6YT35705PW717764P
receiver_email: [email protected]
first_name: Jodie
payer_id: AYZ5QYZ4P53ZY
receiver_id: 8QH2A99EW8G8G
item_number: 28+9
payment_status: Completed
payment_fee:
mc_fee: 0.31
mc_gross: 0.50
charset: windows-1252
notify_version: 3.4
ipn_track_id: 76ae017f3f48e

Sir Osis of Liver


Looks like the IPN  is correct.  Are you allowing guests to browse the forum?

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

No I haven't as I have been doing all this testing on my test fourm

so had this option turned off

Sir Osis of Liver


Enable guest browsing and see if it works.

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

Just enabled guest browsing and tried but still the error messages and no group changes?

QuoteUnknown Paid Subscriptions transaction type.
transaction_subject: Town Clown Subscription
payment_date: 18:34:14 May 21, 2012 PDT
txn_type: subscr_payment
subscr_id: I-USV6NDEMLA1V
last_name: "removed by Wazza"
residence_country: AU
item_name: Town Clown Subscription
payment_gross:
mc_currency: AUD
business: [email protected]
payment_type: instant
protection_eligibility: Ineligible
verify_sign: APclMDPdWaSSAOtbaJrWk-DEAcR8AcHy11WoLROygteHb4nygVsnkxj.
payer_status: unverified
payer_email: "removed by Wazza"
txn_id: 4TG12241MN171601R
receiver_email: [email protected]
first_name: Jodie
payer_id: AYZ5QYZ4P53ZY
receiver_id: 8QH2A99EW8G8G
item_number: 28+9
payment_status: Completed
payment_fee:
mc_fee: 0.31
mc_gross: 0.50
charset: windows-1252
notify_version: 3.4
ipn_track_id: 69cb8dafe1b92

Sir Osis of Liver

The group won't change unless the subscription is completed successfully.  The IPN is showing the correct transaction type (txn_type: subscr_payment), but subscriptions.php is not recognizing it.  There was a bug in 2.0 that caused this problem when guest browsing was disabled, but that doesn't seem to be the case here. 

Are you running 2.0.2?

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza


Sir Osis of Liver

Have you checked the Active: box in the settings for that subscription?

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

yes this is active and i believe needs to be active for the member to be able select or otherwise it wont show on the list

Sir Osis of Liver

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

These are the mods I have and subscriptions.php below (i have never tried to modify this)

1. Login Security 1.0.2.2 
2. Additional Membergroups on Profile 1.1.2   
3. SMF Directory 1.0.4     
4. Menu Editor Lite 1.0.5   


Quotesubscriptions.php
PHP script text
<?php

/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0.2
*/

/*
   This file is the file which all subscription gateways should call
   when a payment has been received - it sorts out the user status.

   void generateSubscriptionError()
   // log the error for posterity
*/

// Start things rolling by getting SMF alive...
$ssi_guest_access = true;
if (!file_exists(dirname(__FILE__) . '/SSI.php'))
   die('Cannot find SSI.php');

require_once(dirname(__FILE__) . '/SSI.php');
require_once($sourcedir . '/ManagePaid.php');

// For any admin emailing.
require_once($sourcedir . '/Subs-Admin.php');

loadLanguage('ManagePaid');

// If there's literally nothing coming in, let's take flight!
if (empty($_POST))
   die($txt['paid_no_data']);

// I assume we're even active?
if (empty($modSettings['paid_enabled']))
   exit;

// If we have some custom people who find out about problems load them here.
$notify_users = array();
if (!empty($modSettings['paid_email_to']))
   foreach (explode(',', $modSettings['paid_email_to']) as $email)
      $notify_users[] = array(
         'email' => $email,
         'name' => $txt['who_member'],
         'id' => 0,
      );

// We need to see whether we can find the correct payment gateway,
// we'll going to go through all our gateway scripts and find out
// if they are happy with what we have.
$txnType = '';
$gatewayHandles = loadPaymentGateways();
foreach ($gatewayHandles as $gateway)
{
   $gatewayClass = new $gateway['payment_class']();
   if ($gatewayClass->isValid())
   {
      $txnType = $gateway['code'];
      break;
   }
}

if (empty($txnType))
   generateSubscriptionError($txt['paid_unknown_transaction_type']);

// Get the subscription and member ID amoungst others...
@list ($subscription_id, $member_id) = $gatewayClass->precheck();

// Integer these just in case.
$subscription_id = (int) $subscription_id;
$member_id = (int) $member_id;

// This would be bad...
if (empty($member_id))
   generateSubscriptionError($txt['paid_empty_member']);

// Verify the member.
$request = $smcFunc['db_query']('', '
   SELECT id_member, member_name, real_name, email_address
   FROM {db_prefix}members
   WHERE id_member = {int:current_member}',
   array(
      'current_member' => $member_id,
   )
);
// Didn't find them?
if ($smcFunc['db_num_rows']($request) == 0)
   generateSubscriptionError(sprintf($txt['paid_could_not_find_member'], $member_id));
$member_info = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);

// Get the subscription details.
$request = $smcFunc['db_query']('', '
   SELECT cost, length, name
   FROM {db_prefix}subscriptions
   WHERE id_subscribe = {int:current_subscription}',
   array(
      'current_subscription' => $subscription_id,
   )
);

// Didn't find it?
if ($smcFunc['db_num_rows']($request) == 0)
   generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription'], $member_id, $subscription_id));

$subscription_info = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);

// We wish to check the pending payments to make sure we are expecting this.
$request = $smcFunc['db_query']('', '
   SELECT id_sublog, payments_pending, pending_details, end_time
   FROM {db_prefix}log_subscribed
   WHERE id_subscribe = {int:current_subscription}
      AND id_member = {int:current_member}
   LIMIT 1',
   array(
      'current_subscription' => $subscription_id,
      'current_member' => $member_id,
   )
);
if ($smcFunc['db_num_rows']($request) == 0)
   generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription_log'], $member_id, $subscription_id));
$subscription_info += $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);

// Is this a refund etc?
if ($gatewayClass->isRefund())
{
   // If the end time subtracted by current time, is not greater
   // than the duration (ie length of subscription), then we close it.
   if ($subscription_info['end_time'] - time() < $subscription_info['length'])
   {
      // Delete user subscription.
      removeSubscription($subscription_id, $member_id);
      $subscription_act = time();
      $status = 0;
   }
   else
   {
      loadSubscriptions();
      $subscription_act = $subscription_info['end_time'] - $context['subscriptions'][$subscription_id]['num_length'];
      $status = 1;
   }

   // Mark it as complete so we have a record.
   $smcFunc['db_query']('', '
      UPDATE {db_prefix}log_subscribed
      SET end_time = {int:current_time}
      WHERE id_subscribe = {int:current_subscription}
         AND id_member = {int:current_member}
         AND status = {int:status}',
      array(
         'current_time' => $subscription_act,
         'current_subscription' => $subscription_id,
         'current_member' => $member_id,
         'status' => $status,
      )
   );

   // Receipt?
   if (!empty($modSettings['paid_email']) && $modSettings['paid_email'] == 2)
   {
      $replacements = array(
         'NAME' => $subscription_info['name'],
         'REFUNDNAME' => $member_info['member_name'],
         'REFUNDUSER' => $member_info['real_name'],
         'PROFILELINK' => $scripturl . '?action=profile;u=' . $member_id,
         'DATE' => timeformat(time(), false),
      );

      emailAdmins('paid_subscription_refund', $replacements, $notify_users);
   }

}
// Otherwise is it what we want, a purchase?
elseif ($gatewayClass->isPayment() || $gatewayClass->isSubscription())
{
   $cost = unserialize($subscription_info['cost']);
   $total_cost = $gatewayClass->getCost();
   $notify = false;

   // For one off's we want to only capture them once!
   if (!$gatewayClass->isSubscription())
   {
      $real_details = @unserialize($subscription_info['pending_details']);
      if (empty($real_details))
         generateSubscriptionError(sprintf($txt['paid_count_not_find_outstanding_payment'], $member_id, $subscription_id));
      // Now we just try to find anything pending.
      // We don't really care which it is as security happens later.
      foreach ($real_details as $id => $detail)
      {
         unset($real_details[$id]);
         if ($detail[3] == 'payback' && $subscription_info['payments_pending'])
            $subscription_info['payments_pending']--;
         break;
      }
      $subscription_info['pending_details'] = empty($real_details) ? '' : serialize($real_details);

      $smcFunc['db_query']('', '
         UPDATE {db_prefix}log_subscribed
         SET payments_pending = {int:payments_pending}, pending_details = {string:pending_details}
         WHERE id_sublog = {int:current_subscription_item}',
         array(
            'payments_pending' => $subscription_info['payments_pending'],
            'current_subscription_item' => $subscription_info['id_sublog'],
            'pending_details' => $subscription_info['pending_details'],
         )
      );
   }

   // Is this flexible?
   if ($subscription_info['length'] == 'F')
   {
      $found_duration = 0;
      // This is a little harder, can we find the right duration?
      foreach ($cost as $duration => $value)
      {
         if ($duration == 'fixed')
            continue;
         elseif ((float) $value == (float) $total_cost)
            $found_duration = strtoupper(substr($duration, 0, 1));
      }

      // If we have the duration then we're done.
      if ($found_duration!== 0)
      {
         $notify = true;
         addSubscription($subscription_id, $member_id, $found_duration);
      }
   }
   else
   {
      $actual_cost = $cost['fixed'];
      // It must be at least the right amount.
      if ($total_cost != 0 && $total_cost >= $actual_cost)
      {
         // Add the subscription.
         $notify = true;
         addSubscription($subscription_id, $member_id);
      }
   }

   // Send a receipt?
   if (!empty($modSettings['paid_email']) && $modSettings['paid_email'] == 2 && $notify)
   {
      $replacements = array(
         'NAME' => $subscription_info['name'],
         'SUBNAME' => $member_info['member_name'],
         'SUBUSER' => $member_info['real_name'],
         'SUBEMAIL' => $member_info['email_address'],
         'PRICE' => sprintf($modSettings['paid_currency_symbol'], $total_cost),
         'PROFILELINK' => $scripturl . '?action=profile;u=' . $member_id,
         'DATE' => timeformat(time(), false),
      );

      emailAdmins('paid_subscription_new', $replacements, $notify_users);
   }
}

// In case we have anything specific to do.
$gatewayClass->close();

// Log an error then die.
function generateSubscriptionError($text)
{
   global $modSettings, $notify_users, $smcFunc;

   // Send an email?
   if (!empty($modSettings['paid_email']))
   {
      $replacements = array(
         'ERROR' => $text,
      );

      emailAdmins('paid_subscription_error', $replacements, $notify_users);
   }

   // Maybe we can try to give them the post data?
   if (!empty($_POST))
      foreach ($_POST as $key => $val)
         $text .= '<br />' . $smcFunc['htmlspecialchars']($key) . ': ' . $smcFunc['htmlspecialchars']($val);

   // Then just log and die.
   log_error($text);

   exit;
}

?>

Sir Osis of Liver


Can't do anything with that.  Attach the file.

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza


Sir Osis of Liver

Nothing wrong with the file.  It appears that the subscription is being posted to PayPal, payment is being processed, and PayPal is posting a correct IPN to subscriptions.php, but transaction type is not being recognized.  That happens here:



$txnType = '';
$gatewayHandles = loadPaymentGateways();
foreach ($gatewayHandles as $gateway)
{
$gatewayClass = new $gateway['payment_class']();
if ($gatewayClass->isValid())
{
$txnType = $gateway['code'];
break;
}
}

if (empty($txnType))
generateSubscriptionError($txt['paid_unknown_transaction_type']);



The code is correct. 

If you click on the subscription name in 'View Subscriptions', does it show any pending payments?

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Wazza

In 'view Subscriptions' there are no listings for 'pending payments' or any other lisitngs for that matter

Sir Osis of Liver

Only thing I can suggest is uninstall all the mods, and see if that has any effect.  If it's a test forum, you can also try reinstalling 2.0.2 from scratch, and see if subscriptions works on a clean install.

"The best laid schemes o' mice an' men / Gang aft a-gley." - Robert Burns

Advertisement: