Adyen / adyen-shopware5

MIT License
11 stars 12 forks source link

[PW-2748] Incomplete booking data on second transaction attempt #13

Closed floorjubbega closed 4 years ago

floorjubbega commented 4 years ago

Describe the bug The shopper attempted a transaction, where they were required to enter a 3DS code. The transaction attempt was rejected and the order was put in "canceled" state. After that the customer re-entered the creditcard info, the transaction was successfully completed and two order notifications were sent from Shopware. However, the second order did not contain the booking information of the initial order.

The impact of this bug is that it will break the booking process for the second order, since the required information is then missing from the order. For the customer this error is not visible.

To Reproduce Steps to reproduce the behavior:

  1. Complete a transaction with an invalid 3D secure code
  2. Attempt a second transaction
  3. By checking the second order in Shopware 5, there would be no order data

Expected behavior The second order should have all the required booking data.

runelaenen commented 4 years ago

What data exactly is missing from the second order? It seems you are expecting custom data to be added to the second order.

The second order is created from a second cart, generated based on the first cart. This means that, by default, only 'normal' Shopware data can be transferred to the second order. If you have any custom free text fields or other custom data, these will be indeed not be transferred automagically to the second order.

You can write a hook on \AdyenPayment\Components\BasketService::restoreFromOrder to restore the new cart from the old order.

acampos1916 commented 4 years ago

Hey @floorjubbega does this answer your question?

Byorun commented 4 years ago

How do we write a hook for this service? Afaik is the shopware hook system only for core classes or repositories. The method itself does not offer any events we could hook into in order to modify the new basket.

Replacing this service with our own would greatly reduce maintainability in case Adyen changes this service in a plugin update.

runelaenen commented 4 years ago

@Byorun I'm sorry, you are correct. I'm not working on SW5 full time anymore so things get confusing sometimes 😄

I have created a PR which adds an event in this function. As soon as this is added to the plugin, you will be able to subscribe to the new event.

New event: \AdyenPayment\Models\Event::BASKET_RESTORE_FROM_ORDER The old order object is passed to the event so you can update your basket using the core Basket() module.

https://github.com/Adyen/adyen-shopware5/pull/42

stm2roi3 commented 4 years ago

@runelaenen is there an estimate on when the next plugin version incl. the pull request is going to be released?

Byorun commented 4 years ago

The new event won't help in fixing the issue. I added a event handler for the new event which calls this code

public function basketRestoreFromOrder(Order $order)
    {
        $this->logger->debug(__METHOD__, [$order->getNumber()]);
        $orderData = new BookingOrderData($order, '');

        if ($orderData->hasNestPosition()) {
            $this->logger->debug('bookingDate', [$orderData->getBookingDate()]);
            $this->logger->debug('reservationId', [$orderData->getBookingId()]);
            if (!$orderData->getBookingDate() || !$orderData->getBookingId()) {
                $this->logger->warn('Booking without DATA!', [$order->getNumber()]);
                return;
            }
            foreach (Shopware()->Modules()->Basket()->sGetBasketData()['content'] as $item) {
                if ($item['ordernumber'] == $orderData->getNestArticleNumber()) {

                    $this->logger->debug('found nest position in basket', [$item['id']]);
                    $this->addBookingAttributes($item['id'], $orderData->getBookingDate(), $orderData->getBookingId());
                    return;
                }
            }
            $this->logger->warn('no booking article found in basket!');
        }

    }

    protected function addBookingAttributes(int $basketId, DateTime $startDateTime, string $reservationId)
    {
        /** @var DataLoader $dataLoaderService */
        $dataLoaderService = Shopware()->Container()->get('shopware_attribute.data_loader');
        /** @var DataPersister $dataPersisterService */
        $dataPersisterService = Shopware()->Container()->get('shopware_attribute.data_persister');

        $attributes = $dataLoaderService->load('s_order_basket_attributes', $basketId);

        if (false === $attributes) {
            $attributes = [];
        }

        $attributes = array_merge($attributes, [
            'start_date'     => $startDateTime->format('Y-m-d H:i'),
            'reservation_id' => $reservationId,
        ]);
        $this->logger->debug(__METHOD__,[$basketId, $attributes]);
        $dataPersisterService->persist(
            $attributes,
            's_order_basket_attributes',
            $basketId
        );
    }

with this we are able to allow a second try but it also fails for every try after