Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Webengine and paypal/credits issue

Initiate Mage
Joined
Aug 26, 2021
Messages
2
Reaction score
1
Hello all,

I have an issue with Credit system on my website.
When credits are bought on website they do not appear on the history and no credits are awarded. I get money minus fee on paypal account.
Paypal history is empty, no credits altered.

I can add/subtract them manually via adminCP.

What should my troubleshooting steps be? Where should i start looking?

Regards,
Martynas
 

cMu

Elite Diviner
Joined
Jan 8, 2017
Messages
427
Reaction score
133
while paypal history is empty, means the IPN listener is probably die during the process.
check your php error log.
 
Upvote 0
Initiate Mage
Joined
Aug 26, 2021
Messages
2
Reaction score
1
Hello cMu,
Thanks for quick reply.
This is what i found:
PHP:
[13-Sep-2021 08:29:28 UTC] PHP Notice:  Undefined index: submit_changes in /public_html/admincp/modules/mconfig/paypal.php on line 48
[13-Sep-2021 08:30:06 UTC] PHP Fatal error:  Uncaught Exception: Missing POST Data in /public_html/includes/classes/paypal/PaypalIPN.php:64
Stack trace:
#0 /public_html/api/paypal.php(40): PaypalIPN->verifyIPN()
#1 {main}
  thrown in /public_html/includes/classes/paypal/PaypalIPN.php on line 64

You are probably right about IPN bit. Any thoughts on next step?
 
Upvote 0

cMu

Elite Diviner
Joined
Jan 8, 2017
Messages
427
Reaction score
133
Hello cMu,
Thanks for quick reply.
This is what i found:
PHP:
[13-Sep-2021 08:29:28 UTC] PHP Notice:  Undefined index: submit_changes in /public_html/admincp/modules/mconfig/paypal.php on line 48
[13-Sep-2021 08:30:06 UTC] PHP Fatal error:  Uncaught Exception: Missing POST Data in /public_html/includes/classes/paypal/PaypalIPN.php:64
Stack trace:
#0 /public_html/api/paypal.php(40): PaypalIPN->verifyIPN()
#1 {main}
  thrown in /public_html/includes/classes/paypal/PaypalIPN.php on line 64

You are probably right about IPN bit. Any thoughts on next step?

seems like the IPN does not get all the required POST that he needs. You can run advanced debug (such as listing all arriving POSTS into .txt file through the PHP, and start debugging.)
 
Upvote 0
Shh, quiet, you might piss somebody off
Developer
Joined
Dec 23, 2011
Messages
1,793
Reaction score
2,131
i'm not sure if this is something about the paypal API or what, but i never was able to put IPN to work properly, so i decide to use other approach like Rest API, for me works perfect and just required to set payment details, then right after user make the payment, you need to execute it in order to finish the trade, with this proccess complete you already can delivery the player reward, i'll drop here my class for paypal rest API.

pay attention that most of Settings::get() bring some data from main settings and Donate:: bring me model from database for donation.

PHP:
<?php

namespace App\Payments;

use Setting;
use App\Models\Donate;
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Api\Amount;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;

class PayPal implements GatewayInterface {

    use Processor;

    private $client_id = "";
    private $secret = "";
    private $api = null;
    //sandbox - live 
    private $env = "live";
    private $PAYPALstatus = [
        'created' => self::STATUS_CREATED,
        'approved' => self::STATUS_APPROVED,
        'failed' => self::STATUS_CANCEL
    ];

    public function __construct() {
        if (Setting::get('paypal_enable')) {
            $this->client_id = Setting::get('paypal_clientid');
            $this->secret = Setting::get('paypal_secret');
            $this->api = new ApiContext(
                    new OAuthTokenCredential($this->client_id, $this->secret)
            );
            $this->api->setConfig([
                //   'log.LogEnabled' => true,
                //  'log.FileName' => 'PayPal.log',
                // 'log.LogLevel' => 'DEBUG',
                'mode' => $this->env
            ]);
        }
    }

    public function createPayment(\App\Models\Donate $donate) {
        $payer = new Payer();
        $payer->setPaymentMethod("paypal");
        $item1 = new Item();
        $item1->setName(trans('strings.donation') . " - " . Setting::get('servername') . ' - ' . $donate->login . ' - ' . $donate->reward . " " . ($donate->type === self::PACKAGE_TYPE_CASH ? trans('strings.golds') : trans('strings.coins')), 1.00, doubleval($donate->price))
                ->setCurrency(Setting::get('currency'))
                ->setQuantity(1)
                ->setPrice(doubleval($donate->price));
        $itemList = new ItemList();
        $itemList->setItems(array($item1));

        $amount = new Amount();
        $amount->setCurrency(Setting::get('currency'))
                ->setTotal(doubleval($donate->price));
        $transaction = new Transaction();
        $transaction->setAmount($amount)
                ->setItemList($itemList)
                ->setDescription(trans('strings.donation') . Setting::get('servername'))
                ->setInvoiceNumber($donate->internal_code);
        $redirectUrls = new RedirectUrls();
        $redirectUrls->setReturnUrl(route('paypal::execute'))
                ->setCancelUrl(route('paypal::cancel'));
        $payment = new Payment();
        $payment->setIntent("sale")
                ->setPayer($payer)
                ->setRedirectUrls($redirectUrls)
                ->setTransactions(array($transaction));
        try {
            $payment->create($this->api);
        } catch (Exception $ex) {
            dd($ex);
        }
        $donate->transaction_code = $payment->getToken();
        $donate->save();
        $approvalUrl = $payment->getApprovalLink();
        return $approvalUrl;
    }

    public function notification() {
        $request = request();
        $paymentId = $request->paymentId;
        $payment = Payment::get($paymentId, $this->api);
        $execution = new PaymentExecution();
        $execution->setPayerId($request->PayerID);
        try {
            $result = $payment->execute($execution, $this->api);
            $transactions = $result->getTransactions();

            $donate = Donate::where('internal_code', $transactions[0]->getInvoiceNumber())->first();
            if (is_null($donate)) {
                die;
            } else {
                $this->updatePayment($donate, $result);
            }
        } catch (Exception $ex) {
            \Log::debug((array) $ex);
        }
        return $payment;
    }

    public function updatePayment($donate, $request) {
        $donate->transaction_code = $request->getId();
        $donate->status = $this->PAYPALstatus[$request->getState()];
        $donate->save();
        $this->processor($donate);
    }

    public function executeBan(\App\Models\User $user) {
        
    }

}
 
Upvote 0

cMu

Elite Diviner
Joined
Jan 8, 2017
Messages
427
Reaction score
133
i'm not sure if this is something about the paypal API or what, but i never was able to put IPN to work properly, so i decide to use other approach like Rest API, for me works perfect and just required to set payment details, then right after user make the payment, you need to execute it in order to finish the trade, with this proccess complete you already can delivery the player reward, i'll drop here my class for paypal rest API.

pay attention that most of Settings::get() bring some data from main settings and Donate:: bring me model from database for donation.

PHP:
<?php

namespace App\Payments;

use Setting;
use App\Models\Donate;
use PayPal\Rest\ApiContext;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Api\Amount;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;

class PayPal implements GatewayInterface {

    use Processor;

    private $client_id = "";
    private $secret = "";
    private $api = null;
    //sandbox - live 
    private $env = "live";
    private $PAYPALstatus = [
        'created' => self::STATUS_CREATED,
        'approved' => self::STATUS_APPROVED,
        'failed' => self::STATUS_CANCEL
    ];

    public function __construct() {
        if (Setting::get('paypal_enable')) {
            $this->client_id = Setting::get('paypal_clientid');
            $this->secret = Setting::get('paypal_secret');
            $this->api = new ApiContext(
                    new OAuthTokenCredential($this->client_id, $this->secret)
            );
            $this->api->setConfig([
                //   'log.LogEnabled' => true,
                //  'log.FileName' => 'PayPal.log',
                // 'log.LogLevel' => 'DEBUG',
                'mode' => $this->env
            ]);
        }
    }

    public function createPayment(\App\Models\Donate $donate) {
        $payer = new Payer();
        $payer->setPaymentMethod("paypal");
        $item1 = new Item();
        $item1->setName(trans('strings.donation') . " - " . Setting::get('servername') . ' - ' . $donate->login . ' - ' . $donate->reward . " " . ($donate->type === self::PACKAGE_TYPE_CASH ? trans('strings.golds') : trans('strings.coins')), 1.00, doubleval($donate->price))
                ->setCurrency(Setting::get('currency'))
                ->setQuantity(1)
                ->setPrice(doubleval($donate->price));
        $itemList = new ItemList();
        $itemList->setItems(array($item1));

        $amount = new Amount();
        $amount->setCurrency(Setting::get('currency'))
                ->setTotal(doubleval($donate->price));
        $transaction = new Transaction();
        $transaction->setAmount($amount)
                ->setItemList($itemList)
                ->setDescription(trans('strings.donation') . Setting::get('servername'))
                ->setInvoiceNumber($donate->internal_code);
        $redirectUrls = new RedirectUrls();
        $redirectUrls->setReturnUrl(route('paypal::execute'))
                ->setCancelUrl(route('paypal::cancel'));
        $payment = new Payment();
        $payment->setIntent("sale")
                ->setPayer($payer)
                ->setRedirectUrls($redirectUrls)
                ->setTransactions(array($transaction));
        try {
            $payment->create($this->api);
        } catch (Exception $ex) {
            dd($ex);
        }
        $donate->transaction_code = $payment->getToken();
        $donate->save();
        $approvalUrl = $payment->getApprovalLink();
        return $approvalUrl;
    }

    public function notification() {
        $request = request();
        $paymentId = $request->paymentId;
        $payment = Payment::get($paymentId, $this->api);
        $execution = new PaymentExecution();
        $execution->setPayerId($request->PayerID);
        try {
            $result = $payment->execute($execution, $this->api);
            $transactions = $result->getTransactions();

            $donate = Donate::where('internal_code', $transactions[0]->getInvoiceNumber())->first();
            if (is_null($donate)) {
                die;
            } else {
                $this->updatePayment($donate, $result);
            }
        } catch (Exception $ex) {
            \Log::debug((array) $ex);
        }
        return $payment;
    }

    public function updatePayment($donate, $request) {
        $donate->transaction_code = $request->getId();
        $donate->status = $this->PAYPALstatus[$request->getState()];
        $donate->save();
        $this->processor($donate);
    }

    public function executeBan(\App\Models\User $user) {
        
    }

}

here is the IPN listener from my CMS, and now just work with it:
PHP:
<?php    require 'autoloader.php';        date_default_timezone_set("America/Chicago");    $Database = new Database;    $Website = new Website;    $Account = new Account;    $req = 'cmd=_notify-validate';    foreach($_POST as $key => $value){        if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() == 1){            $value = stripslashes($value);        }        $value = urlencode($value);        $req .= "&$key=$value";    }    $ch = curl_init('https://ipnpb.paypal.com/cgi-bin/webscr');    curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);    curl_setopt($ch, CURLOPT_POST, 1);    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    curl_setopt($ch, CURLOPT_POSTFIELDS, $req);    curl_setopt($ch, CURLOPT_SSLVERSION, 6);    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);    curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/cert/cacert.pem');    curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);    curl_setopt($ch, CURLOPT_HTTPHEADER, array(        'User-Agent: PHP-IPN-Verification-Script',        'Connection: Close',    ));    $res = @curl_exec($ch);    if(!$res){        writelog('cURL error: ['.curl_errno($ch).'] '.curl_error($ch).'', 'Paypal');        die();    }    $info = curl_getinfo($ch);    if($info['http_code'] != 200){        writelog('PayPal responded with http code '.$info['http_code'].'', 'Paypal');        die();    }    curl_close($ch);
 
Upvote 0
Back
Top