Вы здесь

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

1

Есть необходимость реализовать в проекте баланс денежных средств пользователя и платное членство: пополнять различными средствами, делать переводы между собой, выводить неиспользованные средства, статистику платежей. Без привязки к торговым модулям.
Гугл выдает примерно такие результаты: User hoints, Ubercart funds. Но все модули в лучшем случае 2013 года выпуска.

Какие модули, реализующие баланс пользователя, актуальны на данный момент и что можно использовать с перспективой на будущее?

Версия Drupal: 
7.x
Категория: 
E-commerce
Вопрос задан 05.02.2015 - 09:24

Ответы

3

Я делал примерно как описал adubovskoy, хотя, когда я начинал делать, он мне то же самое и посоветовал. Только у меня сущность содержит поля. Можно еще облегчить вариант. Тупо поле с json сделать. Самый шустрый вариант - своя таблица, но тут вообще полностью код, никаких кликаний. Свои UI писать и т.д.

В моём варианте по совету adubovskoy, но с полями суть такая, я взял:

Затем я создал сущность "Транзакция", которая имела следующие поля:

  • Тип транзакции (0 - вычитание, 1 - пополнение - селект текстовый).
  • Сумма транзакции (decimal).
  • Связь с пользователем (entityreference), к кому привязана транзакция.
  • Описание транзакции (для пользовательских интерфейсов).
  • Техническое описание (для админа и т.д., видит только админ).
  • И чекбокс "Реальный платеж". Ни на что не влияет, просто сделали, чтобы отличать то что пополнено из админки, а что пришло, допустим, из Яндекс.Деньги.

Далее сумма щитается очень просто. Делаем запрос и дёргаем все транзакции пользователя. Считаем сумму этих транзакций и получаем текущий баланс.

Вот мой код:

/**
 * Возвращает список всех транзакций пользователя.
 * @param $uid - User ID.
 */
function MYMODULE_get_user_transactions($uid) {
  $query = db_select('field_data_field_balance_transaction_user', 'bu');
  $query->innerJoin('field_data_field_balance_transaction_type', 'bt', 'bu.entity_id = bt.entity_id');
  $query->innerJoin('field_data_field_balance_transaction_amount', 'ba', 'bu.entity_id = ba.entity_id');
  $query->fields('bu', array('field_balance_transaction_user_target_id', 'entity_id'));
  $query->fields('ba', array('field_balance_transaction_amount_value'));
  $query->fields('bt', array('field_balance_transaction_type_value'));
  $query->condition('bu.field_balance_transaction_user_target_id', $uid);
  $result = $query->execute()->fetchAllAssoc('entity_id');

  return $result;
}

/**
 * Возвращает баланс пользователя.
 * @param $uid
 * @return int
 */
function MYMODULE_get_user_balance($uid) {
  $balance = 0;

  $transactions = MYMODULE_get_user_transactions($uid);

  // Подсчитываем баланс на основе транзакций.
  foreach ($transactions as $transaction) {
    if ($transaction->field_balance_transaction_type_value == 1) {
      $balance += $transaction->field_balance_transaction_amount_value;
    }
    else {
      $balance -= $transaction->field_balance_transaction_amount_value;
    }
  }

  return $balance;
}

Для оптимизации, думаю, имеет смысл кешировать баланс. И повесить какой-нибудь хук на обновление\добавление новой транзакции и сбрасывать кеш баланса у пользователя к которому транзакция относится, чтобы у него она обновилась.

Для перевода между пользователями сделать формочку, сумма и кому. И выполнять транзакцию. В общем тут вообще самая легкая часть.

Ответ дан 05.02.2015 - 13:05
Аватар пользователя Niklan
Niklan
445

А потом для оптимизации имеет смысл считать не на уровне php, а на средствами базы, экспрешном db_select
$query->addExpression('SUM(t.field_transaction_value)');

Комментарий оставлен 05.02.2015 - 20:51
1

Entity construction kit (или руками) + entity reference + cache_set() по необходимости.

Для того чтобы сделать хороший баланс, надо понимать что "баланса" не существует. Есть сумма транзакций, которая состоит из пополнений и списаний по каким-то правилам. Т.е. на каждую операцию у вас должна быть заведена запись(в entity это удобно хранить), по отдельному entity bundle на каждый тип транзакции.

Отображаемый результат - это по сути SUM значений пополнения/перевода/использования/вывода. Его можно в кэш.

Сами значения важно хранить в сущности, не в полях (иначе лишний запрос на каждое поле).
Получается очень гибкая и удобная штука. По производительности -- есть сейчас рабочий пример где так обрабатывается порядка 40млн. сущностей, все вполне шустро работает).

Ответ дан 05.02.2015 - 10:48
1

Вариантов не так много:
— поле с балансом + свой код
— userpoints + свой код
— вариант дубовского (читай свой код)

ничего готового не найдёте.

Можно попытаться сделать на Commerce:
https://www.drupal.org/project/commerce_funds или https://www.drupal.org/project/commerce_userpoints
но там много лишнего будет тянуться.

Ответ дан 05.02.2015 - 12:19
Аватар пользователя xandeadx
xandeadx
1542