Pojedyncza transakcja

Przygotuj dane potrzebne do przeprowadzenia płatności jak w przykładzie poniżej.

1
2
3
4
5
6
7
8
$paypal_params = array(
    'sale'     => array(
        'amount'      => 19.99,
        'currency'    => 'EUR',
        'description' => 'Product #1'
    ),
    'back_url'  => 'http://example-page.com',
);
1
2
3
4
5
6
7
8
paypal_params = {
    'sale' => {
        'amount'      => 19.99,
        'currency'    => 'EUR',
        'description' => 'Product #1'
    },
    'back_url' => 'http://example-page.com'
}
1
2
3
4
5
6
7
8
paypal_params = {
  'sale' : {
    'amount'      : 19.99,
    'currency'    : 'EUR',
    'description' : 'Product #1'
  },
  'back_url' : 'http://example.com'
}
1
Sale sale = new Sale(19.99, "EUR", "Product #1");

Teraz po prostu wykonaj płatność używając metody paypalSale.

Możesz sprawdzić, czy płatność się powiodła, wywołując metodę isSuccess.
Pozyskanie numeru ID transakcji (lub informacji o błędzie, jeśli coś pójdzie nie tak), jest również bardzo proste i może wyglądać jak na poniższym przykładzie.

Jeśli metoda paypalSale nie zwróciła błędu, możesz przekierować klienta na stronę PayPala, gdzie dokona płatności. Użyj adresu URL zwróconego przez metodę paypalSale.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try {
    $status = $client->paypalSale($paypal_params);
} catch (Exception $e) {
    // handle exceptions here
}  

if ($client->isSuccess()) {
    echo "Success, id_sale: {$status['id_sale']} \n";
} else {
    die("Error ID: {$status['error']['id_error']}, \n".
        "Error number: {$status['error']['error_number']}, \n".
        "Error description: {$status['error']['error_description']}");
}

header('Location: ' . $status['redirect_url']);
die;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
begin
    status = client.paypal_sale(paypal_params)
rescue PayLane::ClientError => e
    # handle exceptions here
end

if client.success?
    puts "Success, id_sale: #{status["id_sale"]}"
else
    puts "Error ID: #{status["error"]["id_error"]}, \n"\
         "Error number: #{status["error"]["error_number"]}, \n"\
         "Error description: #{status["error"]["error_description"]}"
end

# redirect to url in status['redirect_url']
exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
try:
    status = client.paypal_sale(paypal_params)
except Exception, e:
    # handle exceptions here

if client.is_success():
    print 'Success, id_sale: %s' % status['id_sale']
else:
    print 'Error (%s), %s - %s' % (status['error'].get('id_error'),
                                   status['error'].get('error_number'),
                                   status['error'].get('error_description'))

# redirect to url in status['redirect_url']
sys.exit()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
api.payPalSale(sale,"http://example-page.com",new Callback<RedirectSaleResult>(){

    @Override
    public void onFinish(RedirectSaleResult result) {
        WebView webview =...;
        webview.loadUrl(result.getRedirectUrl());
    }

    @HandleException
    public void onProtocolError(ProtocolException e) {
        // invoke if not success
        // e.getCode() - error code
        // e.getMessage() - error message
    }

    @Override
    public void onError(Exception e) {
        // connection error etc.
    }
});

Uwaga dot. Ruby:
W Ruby nie ma natywnej funkcji służącej do przekierowania na inną stronę – musisz albo skorzystać z funkcji oferowanych przez framework, z którego korzystasz, albo napisać własną funkcję.
Uwaga dot. Pythona:
W Pythonie nie ma natywnej funkcji służącej do przekierowania na inną stronę – musisz albo skorzystać z funkcji oferowanych przez framework, z którego korzystasz, albo napisać własną funkcję.

W przypadku Django możesz użyć:
1
2
from django.http import HttpResponseRedirect
HttpResponseRedirect('http://example.com/')
W przypadku Pylons możesz użyć:
1
2
from pylons.controllers.util import redirect
redirect('http://example.com/')

Po zatwierdzeniu płatności na stronie PayPala, klient zostanie przekierowany z powrotem na Twoją stronę (zgodnie z parametrem back_url). Powinieneś teraz zweryfikować zwrócone dane, aby uniknąć ewentualnych prób oszustwa i sprawdzić status transakcji.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$salt        = 'YOUR_HASH_SALT';
$status      = $_GET['status'];
$description = $_GET['description'];
$amount      = $_GET['amount'];
$currency    = $_GET['currency'];
$hash        = $_GET['hash'];

$id = '';
if ($status !== 'ERROR') // success, get id_sale
    $id = $_GET['id_sale'];

$calc_hash = sha1("{$salt}|{$status}|{$description}|{$amount}|{$currency}|{$id}");

// check hash salt
if ( $calc_hash !== $hash ) {
    die ("Error, wrong hash");
}

 // check transaction status
switch ($status) {
    case 'PERFORMED':
        echo "Success, transaction completed, id_sale: {$_GET['id_sale']}";
        break;
       
    default:
        die("Error, transaction declined, {$_GET['error_description']}");
        break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Simple controller action code in Rails
# it's just an example - most of the logic should be moved to model

salt        = 'YOUR_HASH_SALT'
status      = params['status']
description = params['description']
amount      = params['amount']
currency    = params['currency']
hash        = params['hash']

id = ''
unless status == 'ERROR'
    id = params['id_sale']
else
# redirect to an index action to correct the payment + simple notice
# for Rails: redirect_to :index, :notice => "Error, transaction declined, #{description}"
end

calc_hash = Digest::SHA1.hexdigest("#{salt}|#{status}|#{description}|#{amount}|#{currency}|#{id}")

unless calc_hash == hash
# redirect to an index action to correct payment
# for Rails: redirect_to :index, :notice => "Wrong hash"
end


# check transaction status

if status = 'PERFORMED'
# redirect to some index action to correct payment and simple notice
# for rails: redirect_to :index, :notice => "Success, transaction completed, id_sale: #{id}"
else
# redirect to some index action to correct payment and simple notice
# for rails: redirect_to :index, :notice => "Transaction pending"
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# after back redirect
salt        = 'YOUR_HASH_SALT'
status      = get_request_param('status')
description = get_request_param('description')
amount      = get_request_param('amount')
currency    = get_request_param('currency')
hash        = get_request_param('hash')
id_sale     = None

# success, get id_sale
if status != 'ERROR':
    id_sale = get_request_param('id_sale')

calc_hash = hashlib.sha1(
    '|'.join([salt, status, description, amount, currency, id_sale])).hexdigest()

# check hash salt
if calc_hash != hash:
    sys.exit('Error, wrong hash')

# check transaction status
if status == 'PERFORMED':
    print 'Success, transaction completed, id_sale: %s' % id_sale
else:
    sys.exit('Error, transaction declined, %s' % \
        get_request_param('error_description'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
webview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {

        if (url.contains(redirectUrl)) {
            try {
                Map<String, String> map = getQueryMap(new URL(url).getQuery());
                String salt = "YOUR_HASH_SALT";
                String status = map.get("status");
                String description = map.get("description");
                String amount = map.get("amount");
                String currency = map.get("currency");
                String id = map.get("id_sale");

                String calcHash = sha1(String.format("%1$s|%2$s|%3$s|%4$s|%5$s|%6$s", salt, status, description, amount, currency, id));

                // check hash salt
                if (!calcHash.equals(hash)) {
                    // Error, wrong hash
                }

                if (status.equals("PERFORMED")) {
                   String idSale=map.get("id_sale");
                    // Success, transaction completed

                } else {
                    String errorDescription=map.get("error_description");
                    // Error, transaction declined
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else {
            view.loadUrl(url);
        }
        return true;
    }
});

public static Map<String, String> getQueryMap(String query) {
    String[] params = query.split("&");
    Map<String, String> map = new HashMap<String, String>();
    for (String param : params) {
        String name = param.split("=")[0];
        String value = param.split("=")[1];
        map.put(name, value);
    }
    return map;
}

private static String convertToHex(byte[] data) {
    StringBuilder buf = new StringBuilder();
    for (byte b : data) {
        int halfbyte = (b >>> 4) & 0x0F;
        int two_halfs = 0;
        do {
            buf.append((0 <= halfbyte) && (halfbyte <= 9) ? (char) ('0' + halfbyte) : (char) ('a' + (halfbyte - 10)));
            halfbyte = b & 0x0F;
        } while (two_halfs++ < 1);
    }
    return buf.toString();
}

public static String sha1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    md.update(text.getBytes("utf-8"), 0, text.length());
    byte[] sha1hash = md.digest();
    return convertToHex(sha1hash);
}
Uwaga dot. Pythona:
Funkcja get_request_param ma za zadanie pobrać wartości GET. Użyj odpowiednich funkcji oferowanych przez framework, z którego korzystasz, lub napisz własną funkcję.

W przypadku Django możesz użyć:
1
param_from_get = request.GET.get('param_name')
W przypadku Pylons możesz użyć:
1
2
from pylons import request
param_from_get = request.GET.get('param_name')