// Path: adyenv6core/src/com/adyen/v6/actions/AbstractWaitableAction.java
// abstract public class AbstractWaitableAction<T extends BusinessProcessModel> extends AbstractAction<T> {
//     public enum Transition {
//         OK, NOK, WAIT;
// 
//         public static Set<String> getStringValues() {
//             Set<String> res = new HashSet<>();
//             for (final Transition transitions : Transition.values()) {
//                 res.add(transitions.toString());
//             }
//             return res;
//         }
//     }
// 
//     @Override
//     public Set<String> getTransitions() {
//         return Transition.getStringValues();
//     }
// }
// 
// Path: adyenv6core/src/com/adyen/v6/service/AdyenTransactionService.java
// public interface AdyenTransactionService {
//     /**
//      * Get TX entry by type and status
//      */
//     static PaymentTransactionEntryModel getTransactionEntry(PaymentTransactionModel paymentTransactionModel, PaymentTransactionType paymentTransactionType, TransactionStatus transactionStatus) {
//         PaymentTransactionEntryModel result = paymentTransactionModel.getEntries().stream()
//                 .filter(
//                         entry -> paymentTransactionType.equals(entry.getType())
//                                 && transactionStatus.name().equals(entry.getTransactionStatus())
//                 )
//                 .findFirst()
//                 .orElse(null);
// 
//         return result;
//     }
// 
//     /**
//      * Get TX entry by type, status and details
//      */
//     static PaymentTransactionEntryModel getTransactionEntry(PaymentTransactionModel paymentTransactionModel,
//                                                             PaymentTransactionType paymentTransactionType,
//                                                             TransactionStatus transactionStatus,
//                                                             TransactionStatusDetails transactionStatusDetails) {
//         PaymentTransactionEntryModel result = paymentTransactionModel.getEntries().stream()
//                 .filter(
//                         entry -> paymentTransactionType.equals(entry.getType())
//                                 && transactionStatus.name().equals(entry.getTransactionStatus())
//                                 && transactionStatusDetails.name().equals(entry.getTransactionStatusDetails())
//                 )
//                 .findFirst()
//                 .orElse(null);
// 
//         return result;
//     }
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=CAPTURE from NotificationItemModel
//      */
//     PaymentTransactionEntryModel createCapturedTransactionFromNotification(PaymentTransactionModel paymentTransaction, NotificationItemModel notificationItemModel);
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=REFUND_FOLLOW_ON from NotificationItemModel
//      */
//     PaymentTransactionEntryModel createRefundedTransactionFromNotification(PaymentTransactionModel paymentTransaction, NotificationItemModel notificationItemModel);
// 
//     /**
//      * Stores the authorization transactions for an order
//      */
//     PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference);
// 
//     /**
//      * Store failed authorization transaction entry
//      */
//     PaymentTransactionModel storeFailedAuthorizationFromNotification(NotificationItemModel notificationItemModel, AbstractOrderModel abstractOrderModel);
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=CANCEL
//      */
//     PaymentTransactionEntryModel createCancellationTransaction(PaymentTransactionModel paymentTransaction, String merchantCode, String pspReference);
// 
//     /**
//      * Creates a PaymentTransactionModel
//      */
//     PaymentTransactionModel createPaymentTransactionFromResultCode(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference, PaymentsResponse.ResultCodeEnum resultCodeEnum);
// 
//     /**
//      * Stores the authorization transactions for an order
//      */
//     PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference, BigDecimal paymentAmount);
// }


import org.apache.log4j.Logger;
import java.math.BigDecimal;
import java.util.Set;
import com.adyen.v6.actions.AbstractWaitableAction;
import com.adyen.v6.service.AdyenTransactionService;
import de.hybris.platform.core.enums.OrderStatus;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.payment.dto.TransactionStatusDetails;
import de.hybris.platform.payment.enums.PaymentTransactionType;
import de.hybris.platform.payment.model.PaymentTransactionEntryModel;
import de.hybris.platform.payment.model.PaymentTransactionModel;
/*
 *                        ######
 *                        ######
 *  ############    ####( ######  #####. ######  ############   ############
 *  #############  #####( ######  #####. ######  #############  #############
 *         ######  #####( ######  #####. ######  #####  ######  #####  ######
 *  ###### ######  #####( ######  #####. ######  #####  #####   #####  ######
 *  ###### ######  #####( ######  #####. ######  #####          #####  ######
 *  #############  #############  #############  #############  #####  ######
 *   ############   ############  #############   ############  #####  ######
 *                                       ######
 *                                #############
 *                                ############
 *
 *  Adyen Hybris Extension
 *
 *  Copyright (c) 2017 Adyen B.V.
 *  This file is open source and available under the MIT license.
 *  See the LICENSE file for more info.
 */
package com.adyen.v6.actions.order;



/**
 * Check if order is captured
 */
public class AdyenCheckCaptureAction extends AbstractWaitableAction<OrderProcessModel> {
    private static final Logger LOG = Logger.getLogger(AdyenCheckCaptureAction.class);

    @Override
    public Set<String> getTransitions() {
        return Transition.getStringValues();
    }

    @Override
    public String execute(final OrderProcessModel process) {
        LOG.debug("Process: " + process.getCode() + " in step " + getClass().getSimpleName());

        final OrderModel order = process.getOrder();

        if (order.getPaymentInfo().getAdyenPaymentMethod() == null) {
            LOG.debug("Not Adyen Payment");
            return Transition.OK.toString();
        }

        /*
        TakePaymentAction will move the order to PAYMENT_CAPTURED state
        Revert it back to PAYMENT_NOT_CAPTURED
         */
        order.setStatus(OrderStatus.PAYMENT_NOT_CAPTURED);
        modelService.save(order);

        BigDecimal remainingAmount = new BigDecimal(order.getTotalPrice());
        for (final PaymentTransactionModel paymentTransactionModel : order.getPaymentTransactions()) {
            boolean isRejected = AdyenTransactionService.getTransactionEntry(
                    paymentTransactionModel,
                    PaymentTransactionType.CAPTURE,
                    TransactionStatus.REJECTED
            ) != null;

// Path: adyenv6core/src/com/adyen/v6/actions/AbstractWaitableAction.java
// abstract public class AbstractWaitableAction<T extends BusinessProcessModel> extends AbstractAction<T> {
//     public enum Transition {
//         OK, NOK, WAIT;
// 
//         public static Set<String> getStringValues() {
//             Set<String> res = new HashSet<>();
//             for (final Transition transitions : Transition.values()) {
//                 res.add(transitions.toString());
//             }
//             return res;
//         }
//     }
// 
//     @Override
//     public Set<String> getTransitions() {
//         return Transition.getStringValues();
//     }
// }
// 
// Path: adyenv6core/src/com/adyen/v6/service/AdyenTransactionService.java
// public interface AdyenTransactionService {
//     /**
//      * Get TX entry by type and status
//      */
//     static PaymentTransactionEntryModel getTransactionEntry(PaymentTransactionModel paymentTransactionModel, PaymentTransactionType paymentTransactionType, TransactionStatus transactionStatus) {
//         PaymentTransactionEntryModel result = paymentTransactionModel.getEntries().stream()
//                 .filter(
//                         entry -> paymentTransactionType.equals(entry.getType())
//                                 && transactionStatus.name().equals(entry.getTransactionStatus())
//                 )
//                 .findFirst()
//                 .orElse(null);
// 
//         return result;
//     }
// 
//     /**
//      * Get TX entry by type, status and details
//      */
//     static PaymentTransactionEntryModel getTransactionEntry(PaymentTransactionModel paymentTransactionModel,
//                                                             PaymentTransactionType paymentTransactionType,
//                                                             TransactionStatus transactionStatus,
//                                                             TransactionStatusDetails transactionStatusDetails) {
//         PaymentTransactionEntryModel result = paymentTransactionModel.getEntries().stream()
//                 .filter(
//                         entry -> paymentTransactionType.equals(entry.getType())
//                                 && transactionStatus.name().equals(entry.getTransactionStatus())
//                                 && transactionStatusDetails.name().equals(entry.getTransactionStatusDetails())
//                 )
//                 .findFirst()
//                 .orElse(null);
// 
//         return result;
//     }
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=CAPTURE from NotificationItemModel
//      */
//     PaymentTransactionEntryModel createCapturedTransactionFromNotification(PaymentTransactionModel paymentTransaction, NotificationItemModel notificationItemModel);
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=REFUND_FOLLOW_ON from NotificationItemModel
//      */
//     PaymentTransactionEntryModel createRefundedTransactionFromNotification(PaymentTransactionModel paymentTransaction, NotificationItemModel notificationItemModel);
// 
//     /**
//      * Stores the authorization transactions for an order
//      */
//     PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference);
// 
//     /**
//      * Store failed authorization transaction entry
//      */
//     PaymentTransactionModel storeFailedAuthorizationFromNotification(NotificationItemModel notificationItemModel, AbstractOrderModel abstractOrderModel);
// 
//     /**
//      * Creates a PaymentTransactionEntryModel with type=CANCEL
//      */
//     PaymentTransactionEntryModel createCancellationTransaction(PaymentTransactionModel paymentTransaction, String merchantCode, String pspReference);
// 
//     /**
//      * Creates a PaymentTransactionModel
//      */
//     PaymentTransactionModel createPaymentTransactionFromResultCode(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference, PaymentsResponse.ResultCodeEnum resultCodeEnum);
// 
//     /**
//      * Stores the authorization transactions for an order
//      */
//     PaymentTransactionModel authorizeOrderModel(AbstractOrderModel abstractOrderModel, String merchantTransactionCode, String pspReference, BigDecimal paymentAmount);
// }


// Path: adyenv6core/src/com/adyen/v6/actions/order/AdyenCheckCaptureAction.java
import org.apache.log4j.Logger;
import java.math.BigDecimal;
import java.util.Set;
import com.adyen.v6.actions.AbstractWaitableAction;
import com.adyen.v6.service.AdyenTransactionService;
import de.hybris.platform.core.enums.OrderStatus;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.payment.dto.TransactionStatus;
import de.hybris.platform.payment.dto.TransactionStatusDetails;
import de.hybris.platform.payment.enums.PaymentTransactionType;
import de.hybris.platform.payment.model.PaymentTransactionEntryModel;
import de.hybris.platform.payment.model.PaymentTransactionModel;

/*
 *                        ######
 *                        ######
 *  ############    ####( ######  #####. ######  ############   ############
 *  #############  #####( ######  #####. ######  #############  #############
 *         ######  #####( ######  #####. ######  #####  ######  #####  ######
 *  ###### ######  #####( ######  #####. ######  #####  #####   #####  ######
 *  ###### ######  #####( ######  #####. ######  #####          #####  ######
 *  #############  #############  #############  #############  #####  ######
 *   ############   ############  #############   ############  #####  ######
 *                                       ######
 *                                #############
 *                                ############
 *
 *  Adyen Hybris Extension
 *
 *  Copyright (c) 2017 Adyen B.V.
 *  This file is open source and available under the MIT license.
 *  See the LICENSE file for more info.
 */
package com.adyen.v6.actions.order;



/**
 * Check if order is captured
 */
public class AdyenCheckCaptureAction extends AbstractWaitableAction<OrderProcessModel> {
    private static final Logger LOG = Logger.getLogger(AdyenCheckCaptureAction.class);

    @Override
    public Set<String> getTransitions() {
        return Transition.getStringValues();
    }

    @Override
    public String execute(final OrderProcessModel process) {
        LOG.debug("Process: " + process.getCode() + " in step " + getClass().getSimpleName());

        final OrderModel order = process.getOrder();

        if (order.getPaymentInfo().getAdyenPaymentMethod() == null) {
            LOG.debug("Not Adyen Payment");
            return Transition.OK.toString();
        }

        /*
        TakePaymentAction will move the order to PAYMENT_CAPTURED state
        Revert it back to PAYMENT_NOT_CAPTURED
         */
        order.setStatus(OrderStatus.PAYMENT_NOT_CAPTURED);
        modelService.save(order);

        BigDecimal remainingAmount = new BigDecimal(order.getTotalPrice());
        for (final PaymentTransactionModel paymentTransactionModel : order.getPaymentTransactions()) {
            boolean isRejected = AdyenTransactionService.getTransactionEntry(
                    paymentTransactionModel,
                    PaymentTransactionType.CAPTURE,
                    TransactionStatus.REJECTED
            ) != null;

            boolean isErroneous = AdyenTransactionService.getTransactionEntry(