Drupal → Оплата доступа к ноде с помощью Робокассы

06.03.2015

Пример организации платного доступа к конкретной ноде с помощью модуля Robokassa Merchant и своего кода.

Будем продавать доступ к материалам типа article.

1. Настраиваем модуль робокассы и сам мерчант.

2. Добавляем типу материала Article два поля:

— Цена, field_price, тип Integer
— Покупатели, field_buyers, тип Entity reference

3. Скрываем контент для не оплативших пользователей — будем при просмотре full ноды переключать дисплей на teaser:

/**
 * Return TRUE if user paid node.
 */
function modulename_user_is_paid($node, $uid = NULL) {
  if ($uid === NULL) {
    $uid = $GLOBALS['user']->uid;
  }
  $node_wrapper = entity_metadata_wrapper('node', $node);
  return in_array($uid, $node_wrapper->field_buyers->raw());
}

/**
 * Implements hook_entity_view_mode_alter().
 */
function modulename_entity_view_mode_alter(&$view_mode, $context) {
  if ($context['entity_type'] == 'node'
  && $context['entity']->type == 'article'
  && $view_mode == 'full'
  && !modulename_user_is_paid($context['entity'])) {
    $view_mode = 'teaser';
  }
}

4. Выводим не оплатившим пользователям форму оплаты:

/**
 * Payment form.
 */
function modulename_payment_form($form, &$form_state, $nid) {
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Оплатить',
  );
  return $form;
}

/**
 * Implements hook_node_view().
 */
function modulename_node_view($node, $view_mode, $langcode) {
  if ($node->type == 'article' && !modulename_user_is_paid($node)) {
    $node->content['payment_form'] = drupal_get_form('modulename_payment_form', $node->nid);
    $node->content['payment_form']['#weight'] = 100;
  }
}

5. Реализуем submit callback формы оплаты, в нём создаём транзакцию и редиректим на промежуточную страницу:

/**
 * Submit callback.
 */
function modulename_payment_form_submit($form, &$form_state) {
  $nid = $form_state['build_info']['args'][0];
  $node_wrapper = entity_metadata_wrapper('node', $nid);

  $payment = robokassa_api('insert', array(
    'uid' => $GLOBALS['user']->uid,
    'created' => REQUEST_TIME,
    'amount' => $node_wrapper->field_price->value(),
    'currency' => 'RUB',
    'memo' => 'Оплата материала',
    'nid' => $nid,
  ));

  $form_state['redirect'] = 'robokassa/payment/' . $payment['pid'];
}

6. После успешной оплаты заносим юзера в поле field_buyers:

/**
* Implements hook_robokassa().
*/
function modulename_robokassa($op, $pid, $payment = array()){
  if ($op == 'enrolled' && $payment['memo'] == 'Оплата материала') {
    $params = unserialize($payment['params']);
    $node = node_load($params['nid']);
    $node->field_buyers['und'][]['target_id'] = $payment['uid'];
    node_save($node);
  }
}

7. Даём авторизованным пользователям право делать оплату своих платежей.

Profit.

В коде для краткости нет логики работы с анонимными пользователями.

Написанное актуально для
Drupal 7
Похожие записи

Комментарии

Игорь
08.03.2015, 23:36

$node->field_buyers['und'][]['target_id'] = $payment['uid'];
Возможно же появление вместо und - ru например?!
Может лучше тоже через entity_metadata_wrapper делать?

ну только если захочется раздельно продавать разные языковые версии ноды.
в entity_metadata_wrapper то же придётся указывать язык

Роман
13.03.2015, 13:19

Спасибо большое за материал.
Это, в принципе, то, что я спрашивал на dru.io.

Гость
02.04.2015, 09:13

А если мне нужно продавать контент незарегистрированным пользователям? Как тогда реализовать?

* требовать регистрацию
* регистрировать самостоятельно
* реализовать систему с уникальными ссылками

Гость
02.04.2015, 09:34

Я предполагал что-то вроде ключа (например передавать его через URL или сделать страницу-прослойку для ввода ключа)

Игорь
02.04.2015, 09:47

https://www.drupal.org/project/comment_notify - в этом модуле так и реализовано - ключ в урле. Можете попробовать понять как это сделано и не забудьте поделиться с нами ;-)
Но проще требовать email! Он есть у всех кому нужен ваш контент. Другое - это ваша головная боль при разработке - стоит ли она того?

Гость
02.04.2015, 16:04

Надо :)
Работаю над проектом, скажем, по продаже консультаций. Так вот статистика показывает, что пользователи уходят со страницы где нужно заполнить контактные данные... следовательно, не переходят на страницу оплаты.
Вот думаю как реализовать анонимную продажу консультаций. Если найду хороший способо - обязательно поделюсь

Виталий
11.01.2016, 22:46

Сделать бы тоже самое но через Yandex.Money миную Drupal Commerce. Возможно ли сие?

Вместо 'und' нужно использовать константу LANGUAGE_NONE (D7).

Есть константа и нужно использовать ее. Это тоже самое, если использовать \n вместо PHP_EOL.

Зачем использовать константу? Затем, что Вы на 100% уверены, что код будет работать так, как Вы ожидаете. Если в каком-нибудь 7.99 релизе друпала значение этой константы будет отличным от und, то Ваш код как минимум посыпет нотисы.

Я и с und уверен, что код будет работать так, как ожидаю. Ни в 7.99, ни в 8.99 und ни на что не поменяют, можете быть уверены.

Странный подход. Ну, делаете как считаете нужным.

Валерий
26.07.2017, 17:10

Статус "enrolled" устанавливается только если вручную поставить галочку в админке что платеж зачислен.
Пожалуйста, пожскажите, как сделать чтобы при успешной оплате статус "enrolled" ставился автоматом?
Спасибо!

Спасибо большое. А что делать, если каждая нода может продаваться только 1 раз? Т.е. когда купил доступ к одной ноде - она больше не возможна к продаже.

Здесь только coomerce спасёт?

А как прикрутить робокассу к форме создания ноды? Чтобы после создания появлялась форма оплаты и нода публиковалась

Николай
02.09.2018, 16:45

Спасибо, полезно. А можно ли таким макаром сделать доступ не к ноде а к полю? К примеру нода открыта для всех а поле скрыто модулем field-permission

Николай
04.09.2018, 01:15

Мистика какаято, хочу отправить письмо с аттачем после оплаты. Письмо приходит а аттача-файла нет. Если убрать условие if ($op == 'enrolled') то приходит 3 письма, 2 с аттачем третье без. Не подскажете - где проблема?

function my_module_robokassa($op, $pid, $payment = array()){
  if ($op == 'enrolled') {
	$attachment = array(
	'filepath' => 'README.txt'
	);
	drupal_mail('system', 'mail', 'mail@gmail.com', language_default(), array(
	  'context' => array(
		'subject' => 'Some txt',
		'message' => 'Some txt',
	  ),
	  'attachments' => array($attachment),
	));

  }
}

Добавить комментарий