0

I admit to being a Commerce -novice-. It's getting better, but it's still quite confusing in some spots. I've posted several questions here over the past year trying to skin the same cat in different ways. We have a Drupal 7 cart. The pricing is pulled in from an external web site via http_request which updates the unit price of all items in the cart on hook_form_alter().

The problem is that the -initial- price that displays in the cart is always 0. The user always has hit to refresh the page for that pricing to update the View. Commerce seems to want to pull the unit price in from the Product nodes so after a user hits the cart displays but with a 0 unit price. When they hit -then- our code fires and updates the price.

So... I need is either: a) a way to force that view to 'refresh' when the page is rendered (ie. it initially loads with the zero prices, runs the http_request code and -then- renders again). Yeah, it's ugly but I'm just sick of this.

b) Figure out a way using the Rules (which I haven't been able to do) to get the line item price to pull in from the http_request with PHP. This -never- seems to work. It -always- wants to use a rule based on an existing field. If someone could give me a tutorial on how to use PHP with Commerce for the Unit Price I'd buy them a CASE of virtual beer!

c) Figure out a way to assign that http_request price as the line item price when the user hits the 'Add' button. Again, probably a noob thing, but I cannot figure out how to override the Unit Price for the Line Item to the value I want. It -always- wants to use the Unit Price from the Product node.

ANY help would be most appreciated!

3
  • which updates the unit price of all items in the cart on hook_form_alter() Does that actually work? As in when you add the item to the cart and go through the checkout, does that price override stick?
    – Clive
    Nov 22, 2013 at 22:20
  • Wow. I didn't see your reply--SORRY! The code -does- 'work'.. ie. my function does get executed. The problem is that I need (in template terms) to set the -priority- of the execution. The code executes -after- the view renders so the view displays the -wrong- prices. When the user hits <F5> they see the correct pricing. SO: If I could force the code to execute -before- the view is rendered, I'd be in business!
    – jchwebdev
    Nov 25, 2013 at 4:27
  • Another possibility: If I could get the -same- code to fire -after- the Add Line Item button (different form.) Again, it's a priority issue... when I add my function to the Submit button on the Add form, it seems to execute -before- the actual line item add so again, when the user goes to the Cart, they see the wrong price. Maddening. Again: if I could force my code to run at the right priority (in this case -after- the Add Line Item) I'd be in business. Ideas? TIA!!!!! ---JC
    – jchwebdev
    Nov 25, 2013 at 4:29

1 Answer 1

2
+50

Implement a custom rules action and wire it to rules event Calculating the sell price of a product. The sell price of a line item can be forced to any value using the action Set the unit price to a specific amount. The missing piece is a custom rule action capable of retrieving the amount. As a starting point I propose the following (assuming the custom module is named acme):

/**
 * Implements hook_rules_action_info().
 */
function acme_rules_action_info() {
  return array(
    'acme_random_amount' => array(
      'label' => t('Generate random price (with params!)'),
      'group' => t('Examples'),
      'parameter' => array(
        'product_id' => array(
          'type' => 'text',
          'label' => t('Product SKU'),
          'description' => t('The SKU of a product.'),
        ),
        'account' => array(
          'type' => 'user',
          'label' => t('User'),
          'description' => t('A user account.'),
        ),
      ),
      'provides' => array(
        'amount' => array(
          'type' => 'decimal',
          'label' => t('Amount'),
          'description' => 'Return a random numeric amount, except for admin.',
        ),
      ),
    ),
  );
}

/**
 * Rules action: Generate and return random amount of money.
 */
function acme_random_amount($product_id, $account) {
  $amount = mt_rand(100, 1000);

  // Fix price for admin.
  if ($account && $account->uid == 1) {
    $amount = 420;
  }

  // Blue sells, let's boost the revenue.
  if (strpos($product_id, 'BLU') !== FALSE) {
    $amount *= 100;
  }

  return array(
    'amount' => $amount,
  );
}

The rule then looks something like this:

{ "rules_pick_random_price" : {
    "LABEL" : "Pick random price",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "rules", "acme", "commerce_line_item", "commerce_product_reference" ],
    "ON" : [ "commerce_product_calculate_sell_price" ],
    "IF" : [
      { "entity_has_field" : { "entity" : [ "commerce-line-item" ], "field" : "commerce_product" } }
    ],
    "DO" : [
      { "acme_random_amount" : {
          "USING" : {
            "product_id" : [ "commerce-line-item:commerce-product:sku" ],
            "account" : [ "commerce-line-item:order:owner" ]
          },
          "PROVIDE" : { "amount" : { "amount" : "Amount" } }
        }
      },
      { "commerce_line_item_unit_price_amount" : {
          "commerce_line_item" : [ "commerce_line_item" ],
          "amount" : [ "amount" ],
          "component_name" : "base_price",
          "round_mode" : "0"
        }
      },
      { "drupal_message" : { "message" : "Set the price of [commerce-line-item:commerce-product:sku] to amount: [amount:value] for user [commerce-line-item:order:owner:name]" } }
    ]
  }
}

Note that in order to get at the product SKU, it is necessary to introduce a condition Entity has field checking for the presence of the commerce_product field on the commerce-line-item variable.

Please keep in mind that this rule will be executed on every page request for every item in the cart. Additionally it is executed whenever an add-to-cart form is displayed. If this is on a high traffic site, you probably need to think about an appropriate caching strategy.

8
  • Thanks. I'm not at my computer this weekend. Will test first thing Monday morn. Hope yer around for any follow ups. I've had a DEVIL of a time getting -any- rules to work... CHEERS!
    – jchwebdev
    Nov 29, 2013 at 21:32
  • OK, I think I follow you. The only question I (think) I have is: in order to get the price I want from the external site I need to supply the Customer ID and Product ID for the order. How do I reference them from Rules? When I use hook_form_alter() I can get that by loading the global data ie. $order = commerce_cart_order_load($user->uid); Can I do this inside Rules?
    – jchwebdev
    Dec 2, 2013 at 19:46
  • @jchwebdev: Yes you can get at any property of your order. Example updated.
    – znerol
    Dec 2, 2013 at 22:05
  • THANKS! I -think- I get it. (Well, enough to move ahead a bit.) What I really don't get is where this is all documented. I hate to sound so -thick- but where would you recommend I learn more---hopefully with some examples? The Commerce forum seems -really- opaque. Lots of very similar questions to mine with no answers.
    – jchwebdev
    Dec 2, 2013 at 22:46
  • 1
    @jchwebdev: View all episodes of Coding for Rules 2 screencast by NodeOne and read the rules developer documentation. The calculation of product line item prices happens in commerce_cart_order_refresh. This is the function responsible for the prices being copied over from the product definition.
    – znerol
    Dec 3, 2013 at 20:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.