PrestaShop / prestashop-specs

Project specifications for PrestaShop's Core features and native modules
https://build.prestashop-project.org/prestashop-specs/
Other
32 stars 25 forks source link

Multiple Orders for a Cart #111

Open Matt75 opened 4 years ago

Matt75 commented 4 years ago

Order splitting

Sometime PrestaShop will split a Cart in multiple Order with same Reference after a Payment.

Because this splitting is made by PrestaShop after the Payment, Customer has only paid Shipping Costs for one Order.

So PrestaShop will display a warning on Order view page to notify merchant the total order amount is not equal to total cart amount.

Possible cases

  1. A product of Cart exceeds the price/weight range of carriers
  2. A product of Cart is restricted to one Carrier (case described bellow)
  3. Warehouse management in 1.6, removed in 1.7
  4. Multi-shipping functionnality in 1.5 removed in 1.6
  5. Others cases I don't know

➡️ Find every possible cases will cause Order splitting

How to handle that for PaymentModule

⚠️ This should be confirmed and documented

Related to https://github.com/PrestaShop/docs/issues/508

jf-viguier commented 4 years ago

For me, the best and easy way should be to remove order splitting. It's not needed anymore and upset ERP and accountants

eternoendless commented 4 years ago

ping @PrestaShop/prestashop-product-team @MatShir

LouiseBonnard commented 3 years ago

Hello @Matt75, thanks for your issue. What do you expect from the @PrestaShop/product-team on this issue, specifications for the multiple orders?

Matt75 commented 3 years ago

@LouiseBonnard Currently PrestaShop generate multiple Order from a Cart in some cases described in the issue. Module developers don't know how to manage this because we receive only the latest Order id created by PrestaShop. Core developers don't know how this works or should works.

So Product Team, please document how PrestaShop create Order from Cart, cases where PrestaShop create multiple Orders, check if current process is good because there are problems with shipping costs and invoices.

Currently modules developers receive many complaints about this and we don't know what to respond or what to improve. This is a huge pain point.

msaustral commented 3 years ago

Hi we have a client that the PS is randomly splitting orders by assigning different delivery address to each order.

Some times PS use deleted delivery address but the buyer select only one address during checkout

Same issue decribes here https://www.prestashop.com/forums/topic/1049013-prestashop-is-splitting-orders-using-deleted-delivery-addresses/

PS 1.7.6.9

jf-viguier commented 3 years ago

Thanks @Matt75 for this, I totally agree with you 👍

shpe11 commented 2 years ago

for us orders with products quantity<=0 got split and the order with the Q<=0 had a totally random address - same addres everytime with every user

msaustral commented 2 years ago

Hi we have some customers with split orders that have deleted address as a Shipping address, any idea?

oldlastman commented 2 years ago

Please, there is any information about this issue? the bad thing about this is that for me its imposible to replicate... i get this error, but copy exactly the same order and destination and every thing work fine i appreciate any method to track this problem

itsvahid commented 2 years ago

In our case we have not specified a carrier to certain products and this issue still happens. A temporary solution that I've found is to remove the part that does a where clause on id_address_delivery in Cart.php updateAddressId() function. Now when a customer goes through checkout steps and chooses an address, all the products will be updated in cart_product table to have the same id_address_delivery.

Change this:

$sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product`
        SET `id_address_delivery` = ' . (int) $id_address_new . '
        WHERE  `id_cart` = ' . (int) $this->id . '
            AND `id_address_delivery` = ' . (int) $id_address;
        Db::getInstance()->execute($sql);

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'customization`
            SET `id_address_delivery` = ' . (int) $id_address_new . '
            WHERE  `id_cart` = ' . (int) $this->id . '
                AND `id_address_delivery` = ' . (int) $id_address;
        Db::getInstance()->execute($sql);

To this:

$sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product`
        SET `id_address_delivery` = ' . (int) $id_address_new . '
        WHERE  `id_cart` = ' . (int) $this->id;
        Db::getInstance()->execute($sql);

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'customization`
            SET `id_address_delivery` = ' . (int) $id_address_new . '
            WHERE  `id_cart` = ' . (int) $this->id;
        Db::getInstance()->execute($sql);
javierrojas10 commented 2 years ago

In our case we have not specified a carrier to certain products and this issue still happens. A temporary solution that I've found is to remove the part that does a where clause on id_address_delivery in Cart.php updateAddressId() function. Now when a customer goes through checkout steps and chooses an address, all the products will be updated in cart_product table to have the same id_address_delivery.

Change this:

$sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product`
        SET `id_address_delivery` = ' . (int) $id_address_new . '
        WHERE  `id_cart` = ' . (int) $this->id . '
            AND `id_address_delivery` = ' . (int) $id_address;
        Db::getInstance()->execute($sql);

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'customization`
            SET `id_address_delivery` = ' . (int) $id_address_new . '
            WHERE  `id_cart` = ' . (int) $this->id . '
                AND `id_address_delivery` = ' . (int) $id_address;
        Db::getInstance()->execute($sql);

To this:

$sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product`
        SET `id_address_delivery` = ' . (int) $id_address_new . '
        WHERE  `id_cart` = ' . (int) $this->id;
        Db::getInstance()->execute($sql);

        $sql = 'UPDATE `' . _DB_PREFIX_ . 'customization`
            SET `id_address_delivery` = ' . (int) $id_address_new . '
            WHERE  `id_cart` = ' . (int) $this->id;
        Db::getInstance()->execute($sql);

Very good approach, I did some testing. review at car_product table, hope it fix the problem, from now on.

drc0 commented 2 years ago

I think the proposed patch by @itsvahid touches code involved by this patch, https://github.com/PrestaShop/PrestaShop/issues/9932 https://github.com/PrestaShop/PrestaShop/pull/15399/commits/87f351e767b0f537fffe42ca484a992eb74b7201

could the two be related? Because started noticing this cart splitting issue after applying the patch for issue 9932 on PrestaShop.

EDIT:another possible reason could be (need more debugging to confirm) if you have a cart discount rule that adds a product to the cart and sets free shipping = false, but you have a main cart rule to offer free shipping at a certain price so:

cart with a total amount 50€ (free shipping main rule matches) free product with free shipping = false =then=> order is split, so we see an order with the product and free shipping and another order with the free product but payed shipping.

msaustral commented 2 years ago

Hi @drc0 please confirm on any of the splitted order if they have on ether shipping or billing address an address id that on ps_address has on the field deleted "1"

drc0 commented 2 years ago

@msaustral yes ! in fact I was seeing strange placeholders in the order recap admin page regarding the address.. But the real customer address is in fact correct.. I have to say that I have installed a plugin that previews shipping prices by creating temporary addresses and setting them as deleted, do you see any other possible reason though?

msaustral commented 2 years ago

Hi, this is hard to solve, it is random, not because a shipping method or discount.

Prestashop is working on solved but it can not be reproduce.

The issue comes from v.1.6 that allow the customer to have different address by products in his cart.

On V. 1.7 this option is not present but the core still have the code.

msaustral commented 2 years ago

Please find the FINAL solution to split order:

1- modify class/PaymentModule.php line 320 -+ and add a break before the firs closing } like this:

foreach ($package_list as $id_address => $packageByAddress) {
                foreach ($packageByAddress as $id_package => $package) {
                    $orderData = $this->createOrderFromCart(
                        $this->context->cart,
                        $this->context->currency,
                        $package['product_list'],
                        $id_address,
                        $this->context,
                        $reference,
                        $secure_key,
                        $payment_method,
                        $this->name,
                        $dont_touch_amount,
                        $amount_paid,
                        $package_list[$id_address][$id_package]['id_warehouse'],
                        $cart_total_paid,
                        self::DEBUG_MODE,
                        $order_status,
                        $id_order_state,
                        isset($package['id_carrier']) ? $package['id_carrier'] : null
                    );
                    $order = $orderData['order'];
                    $order_list[] = $order;
                    $order_detail_list[] = $orderData['orderDetail'];
                    break; 
                } 
                break; 
            }

This will prevent the split order.

2 - Modify class/Cart.php line 322 and 327 and erase the condition AND id_address_delivery = ' . (int) $id_address; like this:

$sql = 'UPDATE `' . _DB_PREFIX_ . 'cart_product`
SET `id_address_delivery` = ' . (int) $id_address_new . '
WHERE  `id_cart` = ' . (int) $this->id;
Db::getInstance()->execute($sql);
$sql = 'UPDATE `' . _DB_PREFIX_ . 'customization`
SET `id_address_delivery` = ' . (int) $id_address_new . '
WHERE  `id_cart` = ' . (int) $this->id;
Db::getInstance()->execute($sql);

This will force to update the delivery address on the cart.

Hopes it helps!

ComonSoft commented 2 years ago

Hi, why this solution is not present in latest version, nor in any pull request? We have this issue randomly happens in many shops, seem to be caused when user change/create address in order process.

Matt75 commented 2 years ago

Probably because this solution works if you don't use the multiple package feature but it could breaks this feature if no deeper investigation is done.

Split order is a "normal" behavior when using carriers restrictions, warehouse or multishipping. But it's not documented, nobody know how it works or should works so before consider any code changes, product team have to studies and create specifications. (It's a legacy from PrestaShop 1.5)

@PrestaShop/product-team friendly reminder, I know it's a hard topic but everyone needs more knowledges on this.

ComonSoft commented 2 years ago

Ok @Matt75 I understand, but as you explained this feature is not yet implemented! So according to me it will be better for users to have a solution instead of a bug ;-) Sad effect on customers :-( We noticed it's happend when user delete an address used in cart. See sample database ps_cart_product: psbug

The id_address_delivery 41780 is marked deleted in database, and we don't have carrier restrictions.

Matt75 commented 2 years ago

@ComonSoft You misunderstand, the feature was implemented on PrestaShop 1.5, partially removed from Core and reintroduced to modules. Many merchants needs it so to restore it, they can install a module to have Warehouse, multishipping like before etc... So this change can breaks original behavior so it can breaks thoses modules. That's why this must be studied and specified before any code changes on PrestaShop Core.

immakdas commented 6 months ago

My module relies on the multishipping and split orders functionalities. please do not remove this feature.

madsoliver commented 6 months ago

For me order-splitting is a real pain, but I see that it might be needed for some merchants, like if they need different carriers for different products (like a cart with a fox, a chicken, and a sack of corn). Or modules that for different reasons use this.

But for the rest of us: it makes only issues.

  1. We really need to know how, why and when order splitting occurs.
  2. Since it's a feature that not many use, it should be optional. I suggest making it a config Allow order splitting. If disabled, then selecting product-specific carriers should be greyed out (maybe other things as well).

Any update @PrestaShop/product-team? Thank you