wagnerwagner / merx

Merx is a plugin to create online shops with Kirby.
https://merx.wagnerwagner.de
102 stars 10 forks source link

Allow donation or 'pay what you want' #68

Closed rhjp92 closed 1 year ago

rhjp92 commented 1 year ago

Hello,

I'm wondering if there would be a way with merx to allow an option where the customer determines the price they want to pay for a particular product? We have one new upcoming product in our store which will be sold a little differently, on a sort of 'donation' system where the customer pays what they want to recieve a book which will be physically shipped. Looking for a per-product solution rather than site wide.

Thanks!

tobiasfabian commented 1 year ago

I think what you want to do is already possible with Merx. Usually you add a new product to the cart like this:

$cart->add([
  'id' => 'new-shoes',
]);

The price of the cart item is generated from the product page (in this case, new-shoes). If you add the price directly to the add() method, the price from the product page will be ignored. You can do something like this:

// get the value of the price input
$userPrice = floatval(get('price'));
if ($userPrice >= 5) {
  $cart->add([
    'id' => 'new-shoes',
    'price' => $userPrice,
  ]);
} else {
  // tell user that minimum price is $5
}
rhjp92 commented 1 year ago

Thanks for your help @tobiasfabian - I'm using the merx starterkit so would the best way to do this be inside cart-post.php? I tried overriding the price in that function but that seemed to break it and now the item wont be added to the cart

tobiasfabian commented 1 year ago

It would be helpful if you could share the code you used inside the cart-post.php file to override the price. Based on that, I can look into the problem you have.

rhjp92 commented 1 year ago

Say if I do this in cart-post.php

<?php

return [
    'pattern' => 'shop/cart',
    'auth' => false,
    'method' => 'POST',
    'action'  => function () {
        $cart = cart();
        $key = $this->requestBody('id');
        $quantity = $this->requestBody('quantity', 1);
        $price = 5;
        // if item (id) is already in cart, add up quantities.
        if ($cartItem = $cart->get($key)) {
            $quantity = $cartItem['quantity'] + $quantity;
        }
        checkStock(page($key), $quantity);
        $cart->add([
            'id' => $key,
            'quantity' => compact('quantity'),
            'price' => $price
        ]);
        return $this->cart();
    },
];

I have an error message Unsupported operand types: int * array

tobiasfabian commented 1 year ago

Thanks @rhjp92 for giving additional details.

It would be good to know where exactly the error occurs - in which file, in which line. If you have not yet activated the debug mode, you can activate it, then you will get a more detailed error message.

The error message Unsupported operand types: int * array means that at some point an array should be multiplied by an integer, which is not possible.

rhjp92 commented 1 year ago

Thanks for your help and patience tobias!

image

The error is occurring in this line within ProductList.php:

$value['sum'] = (float)($value['price'] * $value['quantity']);
tobiasfabian commented 1 year ago

Can you please double check the Request of this POST. Is quantity a number or an array? If present, it has to be a number.

rhjp92 commented 1 year ago
image

Here's the Request, quantity is 1.

tobiasfabian commented 1 year ago

I think I’ve found your problem.

This is what you do in your code: 'quantity' => compact('quantity'),

The compact() function creates an array.

You should pass the $quantity variable directly. To ensure that a float is passed, you can prepend (float) to the variable.

 $cart->add([
  'id' => $key,
  'quantity' => (float)$quantity,
  'price' => (float)$price,
]);
rhjp92 commented 1 year ago

Appreciate your help! From there on was fairly straightforward to implement a donation option on products. Thanks!

hansgohr commented 1 year ago

Hi both of you :)

I was really happy I stumbled upon your conversation, since I need exactly that function for a social project of mine. Could you maybe give me a hint how the template side looks like? I implemented the same code to the cart-post.php (I'm using the starterkit as well), but whenever I call get('price') on my <input type="number" name="price" id="price"> it returns 0 in the cart.

I tried different names for the variables and the input, I put everything in a form element, but somehow I didn't get it to work.

Any little hint would be super helpful to me, since time is kind of rare to finish this. :scream:

Thank you already! :pray:

This is my current cart-post.php

return [
    'pattern' => 'shop/cart',
    'auth' => false,
    'method' => 'POST',
    'action'  => function () {
        $cart = cart();
        $key = $this->requestBody('id');
        $quantity = $this->requestBody('quantity', 1);
        $userPrice = floatval(get('price'));
        // if item (id) is already in cart, add up quantities.
        if ($cartItem = $cart->get($key)) {
            $quantity = $cartItem['quantity'] + $quantity;
        }
        checkStock(page($key), $quantity);
        $cart->add([
            'id' => $key,
            'quantity' => (float)$quantity,
            'price' => (float)$userPrice
        ]);
        return $this->cart();
    },
];