* @copyright 2009 Deon George * @link http://osb.leenooks.net * * @link http://www.agileco.com/ * @copyright 2004-2008 Agileco, LLC. * @license http://www.agileco.com/agilebill/license1-4.txt * @author Tony Landis * @package AgileBill * @subpackage Checkout:Paypal */ if (defined('PATH_MODULES')) include_once(PATH_PLUGINS.'checkout/PAYPAL/PAYPAL.php'); else include_once('PAYPAL/PAYPAL.php'); /** * The main AgileBill Paypal Payment Class * * @package AgileBill * @subpackage Checkout:Paypal */ class plg_chout_PAYPAL_RECURRING extends plg_chout_base_PAYPAL { public function __construct($checkout_id=false,$multi=false) { $this->name = 'PAYPAL_RECURRING'; parent::__construct($checkout_id,$multi); $this->recurr_only = true; } # Perform the checkout transaction (new purchase): public function bill_checkout($amount,$invoice,$currency_iso,$acct_fields,$total_recurring=false,$recurr_bill_arr=array()) { global $C_debug; # Validate we have configured the account if (! $this->cfg['email']) { $C_debug->alert(_('Sorry, unable to use this payment method, it has not been configured properly.')); return false; } # Validate the currency: if (! $this->validate_currency($currency_iso)) return false; # Special JPY formatting: if ($currency_iso == 'JPY') $amount = round($amount); # Get the regular period for this subscription: switch($recurr_bill_arr[0]['recurr_schedule']) { case 0: $p3 = '1'; $t3 = 'W'; break; case 1: $p3 = '1'; $t3 = 'M'; break; case 2: $p3 = '3'; $t3 = 'M'; break; case 3: $p3 = '6'; $t3 = 'M'; break; case 4: $p3 = '1'; $t3 = 'Y'; break; case 5: $p3 = '2'; $t3 = 'Y'; break; default: $C_debug->error(__FILE__,__METHOD__,sprintf('Unknown recurr_schedule %s',$recurr_bill_arr[0]['recurr_schedule'])); return false; } # Calculate the payment fee to be adde $fee = $fee_recurring = 0; switch ($this->cfg['feetype']) { case '2': $fee = $fee_recurring = $this->cfg['fee']; printf('', sprintf(_('Please note, a payment processing fee of %3.2f will automatically be added to this payment schedule.'),$this->cfg['fee'])); break; case '1': $fee = round($amount*$this->cfg['fee'],2); $fee_recurring = round($total_recurring*$this->cfg['fee'],2); printf('', sprintf(_('Please note, a payment processing fee of %3.2f%% will automatically be added to this payment schedule.'),$this->cfg['fee']*100)); break; } $amount += $fee; $total_recurring += $fee_recurring; # Set the vars $vals = array( array('cmd','_xclick-subscriptions'), array('txn_type','subscr_signup'), array('bn','osb_BuyNow_WPS_AU'), array('no_shipping','1'), array('no_note','1'), array('rm','2'), array('business',$this->cfg['email']), array('tax_cart','0'), array('return',$this->success_url.$invoice), array('cancel_return',$this->decline_url.$invoice), array('notify_url',$this->return_url), array('currency_code',$currency_iso), array('invoice',$invoice), array('first_name',$acct_fields['first_name']), array('last_name',$acct_fields['last_name']), array('payer_business_name',$acct_fields['company']), array('address_street',$acct_fields['address1']), array('address_city',$acct_fields['city']), array('address_state',$acct_fields['state']), array('address_zip',$acct_fields['zip']), array('address_country',$acct_fields['country_id']), array('payer_email',$acct_fields['email']), array('payer_id',$acct_fields['id']), array('a1',$amount), array('a3',$total_recurring), array('p3',$p3), array('t3',$t3), array('sra',1), array('src',1), array('item_name','Automatic Payment'), array('usr_manage',0) ); # Get the next bill date for this subscription: # @todo Dont we already know this next date? if ($recurr_bill_arr[0]['recurr_type'] == '1') { # Pro-rate billing: include_once(PATH_MODULES.'product/product.inc.php'); $product = new product; $arr = $product->recurrDates($recurr_bill_arr[0]['recurr_schedule'],$recurr_bill_arr[0]['recurr_weekday'],$recurr_bill_arr[0]['recurr_week']); $remain_time = $arr['end']-$arr['date']; $period1 = round($remain_time/86400); switch($recurr_bill_arr[0]['recurr_schedule']) { case 0: array_push($vals,array('p1',round($period1/7))); array_push($vals,array('t1','W')); break; case 1: case 2: case 3: array_push($vals,array('p1',round($period1/365*12))); array_push($vals,array('t1','M')); break; case 4: case 5: array_push($vals,array('p1',round($period1/365))); array_push($vals,array('t1','Y')); break; default: $C_debug->error(__FILE__,__METHOD__,sprintf('Unknown recurr_schedule %s',$recurr_bill_arr[0]['recurr_schedule'])); return false; } # Bill on anniversary: } else { array_push($vals,array('p1',$p3)); array_push($vals,array('t1',$t3)); } $this->post_vars(sprintf('%s/cgi-bin/webscr',$this->getLocation()),$vals); return true; } # Postback Validation public function postback() { # Read the post from PayPal system and add 'cmd' global $_POST,$C_debug; $req = 'cmd=_notify-validate'; foreach ($_POST as $key => $value) { $value = urlencode(stripslashes($value)); $req .= sprintf('&%s=%s',$key,$value); } $C_debug->error(__FILE__,__METHOD__,sprintf("%s: %s - Invoice: %s\r\n%s",$this->name,$_POST['txn_type'],$_POST['invoice'],$req)); # Post back to PayPal system to validate $header = "POST /cgi-bin/webscr HTTP/1.0\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= sprintf("Content-Length: %s\r\n\r\n",strlen($req)); $fp = fsockopen($this->getLocation(false,true),80,$errno,$errstr,30); # Needed for validation $ret['invoice_id'] = $_POST['invoice']; $ret['transaction_id'] = $_POST['txn_id']; $ret['currency'] = $_POST['mc_currency']; if (! empty($_POST['mc_gross'])) $ret['amount'] = $_POST['mc_gross']; else $ret['amount'] = $_POST['payment_gross']; $ret['subscription_id'] = $_POST['subscr_id']; # Validate if (! $fp) { $C_debug->error(__FILE__,__METHOD__,sprintf('Unable to connect to %s',$this->getLocation(false,true))); } else { fputs($fp,$header.$req); while (! feof($fp)) { $res = trim(strtoupper(fgets($fp,1024))); # HTTP traffic if (! $res || preg_match('/^HTTP/',$res) || preg_match('/^DATE/',$res) || preg_match('/^SERVER/',$res) || preg_match('/^SET-COOKIE/',$res) || preg_match('/^CONNECTION/',$res) || preg_match('/^CONTENT-TYPE/',$res)) continue; switch ($res) { case 'VERIFIED': # Get the payment status $ret['status'] = true; switch($_POST['txn_type']) { case 'subscr_cancel': $ret['status'] = false; break; case 'subscr_failed': $ret['status'] = false; break; case 'subscr_eot': $ret['status'] = false; break; } if ($ret['status'] != false) { switch($_POST['payment_status']) { case 'Canceled_Reversal': $ret['status'] = true; break; case 'Completed': $ret['status'] = true; break; default: $ret['status'] = false; break; } } # Get the processor details $this->getDetailsName($this->name); $cfg = unserialize($this->flds['plugin_data']); if ($_POST['receiver_email'] == $cfg['email']) { include_once(PATH_MODULES.'checkout/checkout.inc.php'); $checkout = new checkout; $checkout->postback($ret); } fclose($fp); header('HTTP/1.1 200 OK'); header('Status: 200 OK'); return; break; default: # Log for manual investigation $C_debug->error(__FILE__,__METHOD__,sprintf('Postback for Invoice %s is %s, PayPal subscription id %s',$ret['invoice_id'],$res,$ret['subscription_id'])); fclose($fp); header('HTTP/1.0 404 Not Found'); return false; } } } header('HTTP/1.0 500 Temporary Failure'); } } # Postback Function if (empty($VAR) && empty($VAR['do'])) { include_once('../../config.inc.php'); require_once(PATH_ADODB.'adodb.inc.php'); require_once(PATH_CORE.'database.inc.php'); require_once(PATH_CORE.'setup.inc.php'); $C_debug = new CORE_debugger; $C_db = &DB(); $C_setup = new CORE_setup; $plg = new plg_chout_PAYPAL_RECURRING; $plg->postback(); } ?>