Подтвердить что ты не робот

Товары торговой позиции Drupal: изменить цену?

Мне нужно добавить в корзину некоторые позиции с пользовательской суммой. Продукт торговли сохраняется с ценой = 0, а мой модуль вычисляет цену и добавляет позицию в корзину/заказ, но я не понимаю, как установить программную цену.

Я читал об использовании Правил, но мне нужен мой модуль, чтобы иметь возможность устанавливать/изменять цену без вызова правил.

Я попытался с помощью обертки объекта, я попытался изменить позицию, созданную с помощью commerce_product_line_item_new(), но ничего, когда позиция попадает в корзину, всегда имеет исходную цену продукта (в моем случае - 0).

Как программно изменить цену позиции?

Мой код выглядит так:

// For debugging, this function is called by hook_menu()
function mymodule_test($product_id)
{
    global $user;
    $user = user_load($user->uid);

    $order = commerce_cart_order_load($user->uid);
    $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

    $product = commerce_product_load($product_id);

    $line_item = commerce_product_line_item_new(
            $product,
            1,
            0,
            array(
            ),
            'cover'
    );

    $line_item_wrapper = entity_metadata_wrapper("commerce_line_item", $line_item);

    $line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
            $line_item_wrapper->commerce_unit_price->value(),
            'base_price',
            array(
                            'amount' => 1234,
                            'currency_code' => 'EUR',
                            'data' => array(),
            ),
            TRUE
    );

    $insert_line_item = commerce_cart_product_add($user->uid, $line_item_wrapper->value(), FALSE);

    return 'done';
}

Странная вещь заключается в том, что я попытался адаптировать код commerce_line_item_unit_price_amount(), найденный в торговле /modules/line _item/commerce_line_item.rules.inc, но этот тест:

<?php
    global $user;
    $product = commerce_product_load(4); // my commerce product for test

    $line_item = commerce_product_line_item_new(
        $product,
        1,
        0,
        array(
        ),
        'cover' // I do have this line_items type
    );

    // manually set amount and component name
    $amount = 1234;
    $component_name = 'base_price'; // tryed with discount, nothing change

    $wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
    $unit_price = commerce_price_wrapper_value($wrapper, 'commerce_unit_price', TRUE);

    // Calculate the updated amount and create a price array representing the
    // difference between it and the current amount.
    $current_amount = $unit_price['amount'];
    $updated_amount = commerce_round(COMMERCE_ROUND_HALF_UP, $amount);

    $difference = array(
        'amount' => $updated_amount - $current_amount, 
        'currency_code' => $unit_price['currency_code'], 
        'data' => array(),
    );

    // Set the amount of the unit price and add the difference as a component.
    $wrapper->commerce_unit_price->amount = $updated_amount;

    $wrapper->commerce_unit_price->data = commerce_price_component_add(
        $wrapper->commerce_unit_price->value(), 
        $component_name, 
        $difference, 
        TRUE
    );

    $insert_line_item = commerce_cart_product_add($user->uid, $line_item, FALSE);
?>

все еще не удается, line_item попадает в корзину, но с исходной ценой упомянутого продукта.

Любая идея?

4b9b3361

Ответ 1

Для тех людей, которые не хотят использовать правила и надеются изменить цену напрямую. Вот мое решение:

// Alter the price in list and single product page.
function my_module_commerce_product_calculate_sell_price_line_item_alter($line_item){

    $price = 100; //1 dollar
    $line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;

}

// Alter the price in cart & order.
function my_module_commerce_cart_line_item_refresh($line_item, $order_wrapper){

    $price = 100; //1 dollar
    $line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;
    // Alter the base_price component.
    $line_item->commerce_unit_price[LANGUAGE_NONE]['0']['data']['components']['0']['price']['amount'] = $price;

}

Ответ 2

Если вы хотите игнорировать все предыдущие значения, сохраненные в позиции, и пересчитать сумму из вашей новой суммы, то функция, которую вы ищете, - commerce_line_item_rebase_unit_price.

Задайте новое значение суммы, а затем запустите свою позицию, сохраните позицию и порядок:

$line_item_wrapper->commerce_unit_price->amount = 13;

commerce_line_item_rebase_unit_price($line_item_wrapper->value());

commerce_line_item_save($line_item_wrapper->value());

Ответ 3

Я пробовал эту проблему весь день сегодня, и в итоге выяснил правильный путь к изменению цен на позиции. Проблема в том, что даже если вы успешно измените цену позиции на пользовательское значение, на следующей странице обновите корзину, reset позиции, соответствующие исходной цене продукта. Подробнее см. commerce_cart_order_refresh(). Эта функция выполняется каждый раз, когда на странице загружается заказ/тележка, и вокруг нее нет способа.

Оказывается, что правильный способ изменить цену позиции - либо использовать Правила, либо реализовать функцию hook_commerce_cart_line_item_refresh(). В любом случае, Drupal Commerce должна иметь возможность применять логику изменений каждый раз, когда загружается корзина/заказ.

В результате я создал настраиваемое поле в элементе позиции, где я сохранил желаемое значение цены, которое я хотел. Затем я использовал правило ценообразования, чтобы скопировать значение пользовательской цены в значение цены продукта, когда корзина обновляется.

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

http://commerceguys.com/blog/using-custom-line-items-provide-donation-feature-drupal-commerce

Ответ 4

Недавно мне пришлось внедрить форму для пожертвований в Commerce, но Commerce Express Checkout не обрабатывает персонализированные позиции. Поскольку это было пожертвование и все (кто пытается ввернуть дом?), Я счел уместным передать сумму пожертвования в качестве третьего параметра в URL-адресе, который предоставляет модуль Express Checkout. Вот как я начал взламывать модуль:

Я добавил новую запись на маршрутизатор:

$items['commerce-express-checkout/%/%/%'] = array(
      'title' => 'Express Checkout w/ extra argument',
      // 'page callback' => 'commerce_express_checkout_create_order',
      'page callback' => 'commerce_express_checkout_create_order_extra',
      'page arguments' => array(1, 2, 3),
      'access arguments' => array('access checkout'),
      'type' => MENU_CALLBACK,
  );

Я продублировал и настраивал обратный вызов по умолчанию и привязывал к нему "_extra". Обратите внимание, что свойство "data" кажется статическим хранилищем переменных для случаев, подобных этому, и сохраняет срок действия позиции.

function commerce_express_checkout_create_order_extra($product_id, $token, $amount) {

  if (drupal_hmac_base64($product_id, drupal_get_private_key().drupal_get_hash_salt()) == $token && is_numeric($amount)) {
    global $user;

    $product = commerce_product_load($product_id);

    $product->commerce_price['und'][0]['amount'] = (int)$amount;

    $order = ($user->uid) ? commerce_order_new($user->uid, 'checkout_checkout') : commerce_cart_order_new();

    commerce_order_save($order);

    $price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $amount), 'currency_code' => commerce_default_currency());

    $line_item = commerce_product_line_item_new($product, 1, $order->order_id);
    $line_item->data = array('und' => array('0' => $price));
    commerce_line_item_save($line_item);

    $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

    $order_wrapper->commerce_line_items[] = $line_item;

    $order->data['type'] = 'commerce_express_checkout_order';

    commerce_order_save($order);

    drupal_goto('checkout/' . $order->order_id);

    return "";
  }

   return "";
}

Вот часть, которая оказалась самой сложной из-за кривой обучения и не зная, какую функцию heck использовать:

/**                                                                             
 * Implements hook_commerce_cart_line_item_refresh().                           
 */                                                                             
function commerce_express_checkout_commerce_cart_line_item_refresh($line_item, $order_wrapper) { 
  if ($line_item->commerce_product['und'][0]['line_item_label'] == 'DONATE' || $line_item->commerce_product['und'][0]['product_id'] == '11') {
    $price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $line_item->data['und'][0]['amount']), 'currency_code' => commerce_default_currency());
    $line_item->commerce_unit_price = array('und' => array('0' => $price));
    $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
    $line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
      $line_item_wrapper->commerce_unit_price->value(), 'base_price', $price, TRUE
    );
  }
}

Каждый раз, когда тележка модифицируется, она обновляется и пытается установить продукты в тележке на их прототип внутри кода. Мне тоже кажется неэффективным, но я мог что-то упустить.

Ответ 5

Этот пост указал мне в правильном направлении для программного изменения позиции для торговли в Drupal, используя hook_commerce_cart_line_item_refersh(). Однако некоторые из ответов здесь либо совершенно ошибочны, либо очень неэффективны и неаккуратные.

Это было бы правильным рабочим решением для изменения типа позиции в Drupal Commerce:

/*  
 * implements hook_commerce_cart_line_item_refresh()
 *  
 */

function MYMODULE_commerce_cart_line_item_refresh($line_item, $order_wrapper){

    $line_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);

    $new_price = 100; //I use a function to calculate the value of $new_price

    if(!empty($new_price)){
        $line_wrapper->commerce_unit_price->amount->set($new_price);
        $line_wrapper->save();
    }
}