Open Monograph Press  1.1
 All Classes Namespaces Functions Variables Groups Pages
PayPalPlugin.inc.php
1 <?php
2 
16 import('classes.plugins.PaymethodPlugin');
17 
22  function PayPalPlugin() {
23  parent::PaymethodPlugin();
24  }
25 
30  function getName() {
31  return 'Paypal';
32  }
33 
38  function getDisplayName() {
39  return __('plugins.paymethod.paypal.displayName');
40  }
41 
46  function getDescription() {
47  return __('plugins.paymethod.paypal.description');
48  }
49 
54  function register($category, $path) {
55  if (parent::register($category, $path)) {
56  if (!Config::getVar('general', 'installed') || defined('RUNNING_UPGRADE')) return true;
57  $this->addLocaleData();
58  $this->import('PayPalDAO');
59  $payPalDao = new PayPalDAO();
60  DAORegistry::registerDAO('PayPalDAO', $payPalDao);
61  return true;
62  }
63  return false;
64  }
65 
71  return array('paypalurl', 'selleraccount');
72  }
73 
78  function isCurlInstalled() {
79  return (function_exists('curl_init'));
80  }
81 
86  function isConfigured() {
87  $request = $this->getRequest();
88  $press = $request->getPress();
89  if (!$press) return false;
90 
91  // Make sure CURL support is included.
92  if (!$this->isCurlInstalled()) return false;
93 
94  // Make sure that all settings form fields have been filled in
95  foreach ($this->getSettingsFormFieldNames() as $settingName) {
96  $setting = $this->getSetting($press->getId(), $settingName);
97  if (empty($setting)) return false;
98  }
99  return true;
100  }
101 
107  function displayPaymentSettingsForm(&$params, &$smarty) {
108  $smarty->assign('isCurlInstalled', $this->isCurlInstalled());
109  return parent::displayPaymentSettingsForm($params, $smarty);
110  }
111 
118  function displayPaymentForm($queuedPaymentId, &$queuedPayment, $request) {
119  if (!$this->isConfigured()) return false;
120  $press = $request->getPress();
121  $user = $request->getUser();
122 
123  $params = array(
124  'charset' => Config::getVar('i18n', 'client_charset'),
125  'business' => $this->getSetting($press->getId(), 'selleraccount'),
126  'item_name' => $queuedPayment->getName(),
127  'item_description' => $queuedPayment->getDescription(), // not a paypal parameter (PayPal uses item_name)
128  'amount' => sprintf('%.2F', $queuedPayment->getAmount()),
129  'quantity' => 1,
130  'no_note' => 1,
131  'no_shipping' => 1,
132  'currency_code' => $queuedPayment->getCurrencyCode(),
133  'lc' => String::substr(AppLocale::getLocale(), 3),
134  'custom' => $queuedPaymentId,
135  'notify_url' => $request->url(null, 'payment', 'plugin', array($this->getName(), 'ipn')),
136  'return' => $queuedPayment->getRequestUrl(),
137  'cancel_return' => $request->url(null, 'payment', 'plugin', array($this->getName(), 'cancel')),
138  'first_name' => ($user)?$user->getFirstName():'',
139  'last_name' => ($user)?$user->getLastname():'',
140  'item_number' => $queuedPayment->getAssocId(),
141  'cmd' => '_xclick'
142  );
143 
144  AppLocale::requireComponents(LOCALE_COMPONENT_APP_COMMON);
145  $templateMgr = TemplateManager::getManager($request);
146  $templateMgr->assign('params', $params);
147  $templateMgr->assign('paypalFormUrl', $this->getSetting($press->getId(), 'paypalurl'));
148  $templateMgr->display($this->getTemplatePath() . 'paymentForm.tpl');
149  }
150 
156  function handle($args, $request) {
157  $templateMgr = TemplateManager::getManager($request);
158  $press = $request->getPress();
159  if (!$press) return parent::handle($args, $request);
160 
161  // Just in case we need to contact someone
162  import('lib.pkp.classes.mail.MailTemplate');
163 
164  // Prefer technical support contact
165  $contactName = $press->getSetting('supportName');
166  $contactEmail = $press->getSetting('supportEmail');
167  if (!$contactEmail) { // Fall back on primary contact
168  $contactName = $press->getSetting('contactName');
169  $contactEmail = $press->getSetting('contactEmail');
170  }
171  $mail = new MailTemplate('PAYPAL_INVESTIGATE_PAYMENT');
172  $mail->setReplyTo($contactEmail, $contactName);
173  $mail->addRecipient($contactEmail, $contactName);
174 
175  $paymentStatus = $request->getUserVar('payment_status');
176 
177  switch (array_shift($args)) {
178  case 'ipn':
179  // Build a confirmation transaction.
180  $req = 'cmd=_notify-validate';
181  if (get_magic_quotes_gpc()) {
182  foreach ($_POST as $key => $value) $req .= '&' . urlencode(stripslashes($key)) . '=' . urlencode(stripslashes($value));
183  } else {
184  foreach ($_POST as $key => $value) $req .= '&' . urlencode($key) . '=' . urlencode($value);
185  }
186  // Create POST response
187  $ch = curl_init();
188  curl_setopt($ch, CURLOPT_URL, $this->getSetting($press->getId(), 'paypalurl'));
189  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
190  curl_setopt($ch, CURLOPT_POST, 1);
191  curl_setopt($ch, CURLOPT_HTTPHEADER, Array('Content-Type: application/x-www-form-urlencoded', 'Content-Length: ' . strlen($req)));
192  curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
193  $ret = curl_exec ($ch);
194  curl_close ($ch);
195 
196  // Check the confirmation response and handle as necessary.
197  if (strcmp($ret, 'VERIFIED') == 0) switch ($paymentStatus) {
198  case 'Completed':
199  $payPalDao = DAORegistry::getDAO('PayPalDAO');
200  $transactionId = $request->getUserVar('txn_id');
201  if ($payPalDao->transactionExists($transactionId)) {
202  // A duplicate transaction was received; notify someone.
203  $mail->assignParams(array(
204  'pressName' => $press->getLocalizedTitle(),
205  'postInfo' => print_r($_POST, true),
206  'additionalInfo' => "Duplicate transaction ID: $transactionId",
207  'serverVars' => print_r($_SERVER, true)
208  ));
209  $mail->send();
210  exit();
211  } else {
212  // New transaction succeeded. Record it.
213  $payPalDao->insertTransaction(
214  $transactionId,
215  $request->getUserVar('txn_type'),
216  $request->getUserVar('payer_email'),
217  $request->getUserVar('receiver_email'),
218  $request->getUserVar('item_number'),
219  $request->getUserVar('payment_date'),
220  $request->getUserVar('payer_id'),
221  $request->getUserVar('receiver_id')
222  );
223  $queuedPaymentId = $request->getUserVar('custom');
224 
225  import('classes.payment.omp.OMPPaymentManager');
226  $ompPaymentManager = new OMPPaymentManager($request);
227 
228  // Verify the cost and user details as per PayPal spec.
229  $queuedPayment =& $ompPaymentManager->getQueuedPayment($queuedPaymentId);
230  if (!$queuedPayment) {
231  // The queued payment entry is missing. Complain.
232  $mail->assignParams(array(
233  'pressName' => $press->getLocalizedName(),
234  'postInfo' => print_r($_POST, true),
235  'additionalInfo' => "Missing queued payment ID: $queuedPaymentId",
236  'serverVars' => print_r($_SERVER, true)
237  ));
238  $mail->send();
239  exit();
240  }
241 
242  //NB: if/when paypal subscriptions are enabled, these checks will have to be adjusted
243  // because subscription prices may change over time
244  if (
245  (($queuedAmount = $queuedPayment->getAmount()) != ($grantedAmount = $request->getUserVar('mc_gross')) && $queuedAmount > 0) ||
246  ($queuedCurrency = $queuedPayment->getCurrencyCode()) != ($grantedCurrency = $request->getUserVar('mc_currency')) ||
247  ($grantedEmail = $request->getUserVar('receiver_email')) != ($queuedEmail = $this->getSetting($press->getId(), 'selleraccount'))
248  ) {
249  // The integrity checks for the transaction failed. Complain.
250  $mail->assignParams(array(
251  'pressName' => $press->getLocalizedTitle(),
252  'postInfo' => print_r($_POST, true),
253  'additionalInfo' =>
254  "Granted amount: $grantedAmount\n" .
255  "Queued amount: $queuedAmount\n" .
256  "Granted currency: $grantedCurrency\n" .
257  "Queued currency: $queuedCurrency\n" .
258  "Granted to PayPal account: $grantedEmail\n" .
259  "Configured PayPal account: $queuedEmail",
260  'serverVars' => print_r($_SERVER, true)
261  ));
262  $mail->send();
263  exit();
264  }
265 
266  // Update queued amount if amount set by user (e.g. donation)
267  if ($queuedAmount == 0 && $grantedAmount > 0) {
268  $queuedPaymentDao = DAORegistry::getDAO('QueuedPaymentDAO');
269  $queuedPayment->setAmount($grantedAmount);
270  $queuedPayment->setCurrencyCode($grantedCurrency);
271  $queuedPaymentDao->updateQueuedPayment($queuedPaymentId, $queuedPayment);
272  }
273 
274  // Fulfill the queued payment.
275  if ($ompPaymentManager->fulfillQueuedPayment($request, $queuedPayment, $this->getName())) exit();
276 
277  // If we're still here, it means the payment couldn't be fulfilled.
278  $mail->assignParams(array(
279  'pressName' => $press->getLocalizedTitle(),
280  'postInfo' => print_r($_POST, true),
281  'additionalInfo' => "Queued payment ID $queuedPaymentId could not be fulfilled.",
282  'serverVars' => print_r($_SERVER, true)
283  ));
284  $mail->send();
285  }
286  exit();
287  case 'Pending':
288  // Ignore.
289  exit();
290  default:
291  // An unhandled payment status was received; notify someone.
292  $mail->assignParams(array(
293  'pressName' => $press->getLocalizedTitle(),
294  'postInfo' => print_r($_POST, true),
295  'additionalInfo' => "Payment status: $paymentStatus",
296  'serverVars' => print_r($_SERVER, true)
297  ));
298  $mail->send();
299  exit();
300  } else {
301  // An unknown confirmation response was received; notify someone.
302  $mail->assignParams(array(
303  'pressName' => $press->getLocalizedTitle(),
304  'postInfo' => print_r($_POST, true),
305  'additionalInfo' => "Confirmation return: $ret",
306  'serverVars' => print_r($_SERVER, true)
307  ));
308  $mail->send();
309  exit();
310  }
311 
312  break;
313  case 'cancel':
315  $templateMgr->assign(array(
316  'currentUrl' => $request->url(null, 'index'),
317  'pageTitle' => 'plugins.paymethod.paypal.purchase.cancelled.title',
318  'message' => 'plugins.paymethod.paypal.purchase.cancelled',
319  'backLink' => $request->getUserVar('ompReturnUrl'),
320  'backLinkLabel' => 'common.continue'
321  ));
322  $templateMgr->display('common/message.tpl');
323  exit();
324  break;
325  }
326  parent::handle($args); // Don't know what to do with it
327  }
328 
332  function getInstallSchemaFile() {
333  return ($this->getPluginPath() . DIRECTORY_SEPARATOR . 'schema.xml');
334  }
335 
340  return ($this->getPluginPath() . DIRECTORY_SEPARATOR . 'emailTemplates.xml');
341  }
342 
347  return ($this->getPluginPath() . '/locale/{$installedLocale}/emailTemplates.xml');
348  }
349 }
350 
351 ?>
static & getDAO($name, $dbconn=null)
& getRequest()
Definition: Plugin.inc.php:755
static substr($string, $start, $length=false)
Definition: String.inc.php:187
Abstract class for paymethod plugins.
static requireComponents()
handle($args, $request)
displayPaymentForm($queuedPaymentId, &$queuedPayment, $request)
setupTemplate($request)
static registerDAO($name, $dao)
displayPaymentSettingsForm(&$params, &$smarty)
static getLocale()
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
Provides payment management functions.
getTemplatePath($inCore=false)
getPluginPath()
Definition: Plugin.inc.php:324
getSetting($contextId, $name)
Definition: Plugin.inc.php:366
addLocaleData($locale=null)
Definition: Plugin.inc.php:347
Subclass of Mail for mailing a template email.
PayPal Paymethod plugin class.
Operations for retrieving and modifying Transactions objects.