Payum action to mark payment paid and update order


#1

Hi Everyone,
I’m developing a new gateway, and I am painfully close to getting it working, but need advice on the final step.

An outline of where it’s at at the moment: After a customer leaves the order confirmation, Sylius correctly routes to the gateway’s capture action and the user is presented with a screen. The screen itself is just a twig that has an empty div with an ID. The merchant supplies a js file that replaces the div with an iframe with the form. Upon submission, the script runs a callback and sends the callback a token to reference the payment against. I have setup the callback to ajax send the token back to the server. At the moment it routes to the notify controller, but I don’t know if this is the right place for it. The controller then calls the notify action. This takes the token, loads the order from the payum hash, and the plugin sends the capture request to the merchant.
This all works.
The issue is that I don’t know how to mark the payment as paid and/or for the order’s status to be updated.
This is the code at the moment, but I don’t feel setting the statuses manually is the right thing to do.

public function execute($request)
{
    RequestNotSupportedException::assertSupports($this, $request);
    $model = ArrayObject::ensureArrayObject($request->getModel());
    $this->gateway->execute($httpRequest = new GetHttpRequest());

    $gatewayToken = (array_key_exists('token',$_POST)? $_POST['token'] : null);
    $ip = (array_key_exists('ip',$_POST)? $_POST['ip'] : null);
    $payumHash = (array_key_exists('hash',$_POST)? $_POST['hash'] : null);

    if ($gatewayToken == null) {
        header("HTTP/1.0 417 Expectation Failed");
        die("Gateway token not received. Please try again; you have not been charged");
    }

    if ($payumHash == null) {
        header("HTTP/1.0 417 Expectation Failed");
        die("Payum token not received. Please try again; you have not been charged");
    }

    /** @var Payment $order */
    $payment = $request->getFirstModel();
    try {
        $response = $this->api->capturePayment($payment, $gatewayToken, $ip);
    }catch(CustomGatewayException $ex){
        header("HTTP/1.0 417 Expectation Failed");
        die($ex->getMessage());
    }
    if($response['paymentStatus'] == "SUCCESS"){
        $model['status'] = 'captured';
        $payment->setState(OrderPaymentStates::STATE_PAID);

        /** @var Order $order */
        $order = $payment->getOrder();
        if($order->getTotal() <= $payment->getAmount()){
            $order->setPaymentState(PaymentInterface::STATE_COMPLETED);
        }

    }else{
        header("HTTP/1.0 417 Expectation Failed");
        die($response['paymentStatus']);
    }
}

The notify controller is:

    public function doAction(Request $request): Response{

    $gatewayToken = $request->request->get('token',null);
    $ip = $request->request->get('ip',null);
    $payumHash = $request->request->get('hash',null);

    if ($gatewayToken == null) {
        header("HTTP/1.0 417 Expectation Failed");
        die("Gateway token not received. Please try again; you have not been charged");
    }

    if ($payumHash == null) {
        header("HTTP/1.0 417 Expectation Failed");
        die("Payum token not received. Please try again; you have not been charged");
    }

    /** @var TokenInterface $payumToken */
    $payumToken = $this->payum->getTokenStorage()->find($payumHash);

    if (false === $payumToken) {
        throw new NotFoundHttpException("Payum token not received. Please try again; you have not been charged");
    }

    $gateway = $this->payum->getGateway($payumToken->getGatewayName());

    $gateway->execute(new Notify($payumToken));

    return new Response("[accepted]");

}

I know the $_POST is grim: I’m going to get rid later.
$this->api->capturePayment works perfectly. All I need to know is how to correctly mark the payment as paid, have the order be updated, and return something to the ajax request so it knows to either show an error or follow the $request->getToken()->getAfterUrl() to get to the success page.