-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcommerce_xpay.module
executable file
·425 lines (374 loc) · 14.9 KB
/
commerce_xpay.module
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
<?php
/**
* @file
* Implements X-Pay - Carta S“ Website Payments Standard in
* Drupal Commerce checkout.
*/
/**
* Implements hook_menu().
*/
function commerce_xpay_menu() {
// Define an always accessible path to receive IPNs.
$items['commerce_xpay/ipn'] = array(
'page callback' => 'commerce_xpay_process_ipn',
'page arguments' => array(),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
// Define an additional IPN path that is payment method / instance specific.
$items['commerce_xpay/ipn/%commerce_payment_method_instance'] = array(
'page callback' => 'commerce_xpay_process_ipn',
'page arguments' => array(2),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_commerce_payment_method_info().
*/
function commerce_xpay_commerce_payment_method_info() {
$payment_methods = array();
$path = base_path() . drupal_get_path('module', 'commerce_xpay');
$display_title = variable_get('commerce_xpay_method_title', t('Credit card on a secure server:'));
$display_title .= '<br /><img src="' . $path . '/images/xpay_cc.gif" alt="Mastercard and Visa" style="position: relative; left: 2.5em;">';
$payment_methods['commerce_xpay'] = array(
'method_id' => 'commerce_xpay',
'title' => t('X-Pay - Carta Sì'),
'short_title' => t('xPAy'),
'display_title' => $display_title,
'description' => t('Standard POS payment for X-Pay - Carta sì'),
'terminal' => FALSE,
'offsite' => TRUE,
'offsite_autoredirect' => FALSE,
);
return $payment_methods;
}
/**
* Payment method callback: settings form.
*/
function commerce_xpay_settings_form($settings = NULL) {
$form = array();
// Merge default settings into the stored settings array.
$default_currency = variable_get('commerce_default_currency', 'USD');
$xpay_languages = array(
'ITA' => t('Italian'),
'ENG' => t('English'),
// '3' => t('Espagnol'),
// '4' => t('Francaais'),
// '5' => t('Deutsch'),
);
$xpay_currencies = array(
// '1' => 'USD (US Dollar $)',
// '2' => 'GBP (Pound Sterling £)',
// '71' => 'JPY (Japanese Yen)',
// '71' => 'HKD (Hong Kong Dollar)',
'978' => 'EUR (Euro ‚€)',
// '234' => 'BRL Real',
);
$currency = in_array($default_currency, array_keys($xpay_currencies)) ? $default_currency : '978';
/* The hardcoded values for commerce_xpay_tid and commerce_xpay_mac are the
* standard values for the
* test server, keep them while testing, documentation for x-pay is horrible */
$settings = (array) $settings + array(
'commerce_xpay_tid' => 'T04_000000000005',
'commerce_xpay_mac' => 'AA88CCEWDKLSDJD3921ZZ',
'commerce_xpay_mode' => 'TEST',
'commerce_xpay_action_code' => 'VERI',
'commerce_xpay_language' => 'ITA',
'commerce_xpay_currency' => $currency,
'commerce_xpay_method_title' => t('Credit card on a secure server:'),
'commerce_xpay_method_title_icons' => TRUE,
'commerce_xpay_checkout_button' => t('Submit Order'),
);
$form['commerce_xpay_tid'] = array(
'#type' => 'textfield',
'#title' => t('Terminal ID'),
'#description' => t('Your X-Pay teminal id.'),
'#default_value' => $settings['commerce_xpay_tid'],
'#size' => 25,
);
$form['commerce_xpay_mac'] = array(
'#type' => 'textfield',
'#title' => t('Mac Key'),
'#description' => t('Your MAC key'),
'#default_value' => $settings['commerce_xpay_mac'],
'#size' => 25,
);
$form['commerce_xpay_mode'] = array(
'#type' => 'select',
'#title' => t('Mode'),
'#description' => t('Select NORMAL form normal usage or TEST for testing pourposes'),
'#options' => array(
'test' => t('TEST'),
'normal' => t('NORMAL'),
),
'#default_value' => $settings['commerce_xpay_mode'],
);
$form['commerce_xpay_action_code'] = array(
'#type' => 'select',
'#title' => t('Action Code'),
'#description' => t('Select the action code for the authorization request; from 21-02-2011 it has to be "VERI"'),
'#options' => array(
'VERI' => "VERI",
'AUT' => "AUT",
),
'#default_value' => $settings['commerce_xpay_action_code'],
);
$form['commerce_xpay_language'] = array(
'#type' => 'select',
'#title' => t('Language preference'),
'#description' => t('Adjust language on X-Pay pages.'),
'#options' =>$xpay_languages,
'#default_value' => $settings['commerce_xpay_language'],
);
$form['commerce_xpay_currency'] = array(
'#type' => 'select',
'#title' => t('Currency preference'),
'#description' => t('Adjust currency used with XPAY.'),
'#options' => $xpay_currencies,
'#default_value' => $settings['commerce_xpay_currency'],
);
$form['commerce_xpay_method_title'] = array(
'#type' => 'textfield',
'#title' => t('Payment method title'),
'#default_value' => $settings['commerce_xpay_method_title'],
);
$form['commerce_xpay_method_title_icons'] = array(
'#type' => 'checkbox',
'#title' => t('Show credit card icons beside the payment method title.'),
'#default_value' => $settings['commerce_xpay_method_title_icons'],
);
$form['commerce_xpay_checkout_button'] = array(
'#type' => 'textfield',
'#title' => t('Order review submit button text'),
'#description' => t('Provide XPAY specific text for the submit button on the order review page.'),
'#default_value' => $settings['commerce_xpay_checkout_button'],
);
return $form;
}
/**
* Builds a Website Payments Standard form from an order object.
*
* @param array $form
* Drupal form
* @param array $form_state
* Drupal form state
* @param array $order
* The fully loaded order being paid for.
* @param array $settings
* An array of settings used to build out the form, including:
* - commerce_xpay_mode: which server to use, either test or normal
* - commerce_xpay_tid: the Xpay teminal id to use
* - commerce_xpay_mac: the MAC that you got from X-Pay after activation
* - commerce_xpay_mode: the URL X-Pay should send the user to on
* cancellation
* - return: the URL X-Pay should send the user to on successful payment
* - cancel_return: the URL X-Pay should send the user to after a not
* successful payment
* - commerce_xpay_currency: the X-Pay currency code to use for this payment
* - commerce_xpay_language: the X-Pay language code to use on the payment
* form
* - commerce_xpay_action_code: the action code for the authorization request
*
* @return array
* A renderable form array.
*/
function commerce_xpay_order_form($form, &$form_state, $order, $settings) {
$wrapper = entity_metadata_wrapper('commerce_order', $order);
$mail = $wrapper->mail->value();
$currency_code = $wrapper->commerce_order_total->currency_code->value();
$amount = $wrapper->commerce_order_total->amount->value() / 100;
$site_url = url("", array('absolute' => TRUE));
$transaction_id = str_pad($order->order_id, 6, "0", STR_PAD_LEFT) . "O" . str_pad(time(), 13, "0", STR_PAD_LEFT);
$data = array(
'TERMINAL_ID' => $settings['commerce_xpay_tid'],
'TRANSACTION_ID' => $transaction_id,
'ACTION_CODE' => $settings['commerce_xpay_action_code'],
'AMOUNT' => str_pad(number_format($amount, 2, '', ''), 9, "0", STR_PAD_LEFT),
'CURRENCY' => $settings['commerce_xpay_currency'],
'LANGUAGE' => $settings['commerce_xpay_language'],
'RESULT_URL' => $settings['return'],
'NOTIFICATION_URL' => commerce_xpay_ipn_url($settings['payment_method']),
'ERROR_URL' => $settings['cancel_return'],
'ANNULMENT_URL' => $settings['cancel_return'],
'VERSION_CODE' => '01.00',
'EMAIL' => $mail,
'DESC_ORDER' => 'Order n. ' . $order->order_id . " - " . variable_get('site_name', "Site name"),
'CO_PLATFORM' => 'L',
);
// MAC Generation.
$mac_string = $data['TERMINAL_ID'];
$mac_string .= $data['TRANSACTION_ID'];
$mac_string .= $data['AMOUNT'];
$mac_string .= $data['CURRENCY'];
$mac_string .= $data['VERSION_CODE'];
$mac_string .= $data['CO_PLATFORM'];
$mac_string .= $data['ACTION_CODE'];
$mac_string .= $data['EMAIL'];
$mac_string .= $settings['commerce_xpay_mac'];
$data['MAC'] = strtoupper(sha1($mac_string));
$form['#action'] = commerce_xpay_post_url($settings['commerce_xpay_mode']);
$form['#method'] = 'post';
foreach ($data as $name => $value) {
$form[$name] = array('#type' => 'hidden', '#value' => $value);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => $settings['commerce_xpay_checkout_button'],
);
watchdog('xpay', 'GENERATED PARAMS FOR PAYMENT GATEWAY !data', array('!data' => json_encode($data)), WATCHDOG_NOTICE);
return $form;
}
/**
* Payment method callback: adds a message and CSS to the submission form.
*/
function commerce_xpay_submit_form($payment_method, $pane_values, $checkout_pane, $order) {
$form['xpay_information'] = array(
'#markup' => '<span class="commerce-xpay-info">' . t('(Continue with checkout to complete payment via X-Pay.)') . '</span>',
);
return $form;
}
/**
* Payment method callback: redirect form, a wrapper around
* the module's general
* use function for building a WPS form.
*/
function commerce_xpay_redirect_form($form, &$form_state, $order, $payment_method) {
// Return an error if the enabling action's settings haven't been configured.
if (empty($payment_method['settings']['commerce_xpay_tid'])) {
drupal_set_message(t('X-Pay is not configured for use. No X-Pay tid has been specified.'), 'error');
return array();
}
$settings = array(
// Return to the previous page when payment is canceled.
'cancel_return' => url('checkout/' . $order->order_id . '/payment/back/' . $order->data['payment_redirect_key'], array('absolute' => TRUE)),
// Return to the payment redirect page for processing successful payments.
'return' => url('checkout/' . $order->order_id . '/payment/return/' . $order->data['payment_redirect_key'], array('absolute' => TRUE)),
// Specify the current payment method instance ID in the notify_url.
'payment_method' => $payment_method['instance_id'],
);
return commerce_xpay_order_form($form, $form_state, $order, $payment_method['settings'] + $settings);
}
/**
* return test or normal url
*/
function commerce_xpay_post_url($setting) {
$post_url = $setting === 'normal' ? 'https://cartasi.x-pay.it/XPayVPOS/XPServlet' : 'https://cartasi-test.x-pay.it/XPayVPOSTEST/XPServlet';
return $post_url;
}
/**
* Processes an incoming transaction.
*
* @param String $payment_method
* The payment method instance array that originally made the payment.
*
* @return Boolean
* TRUE or FALSE indicating whether the IPN was successfully processed or not.
*/
function commerce_xpay_process_ipn($payment_method = NULL) {
// Check that the variables are set.
if (!isset($_POST["RESPONSE"]) || !isset($_POST["TRANSACTION_ID"]) || !isset($_POST["AUTH_CODE"]) || !isset($_POST["AMOUNT"]) || !isset($_POST["CURRENCY"])) {
return FALSE;
}
// If no payment method is passed, we can't verify.
if ($payment_method === NULL) {
return FALSE;
}
// Let's check that the message comes from the bank.
$mac_string = $_POST["TERMINAL_ID"];
$mac_string .= $_POST["TRANSACTION_ID"];
$mac_string .= $_POST["RESPONSE"];
$mac_string .= $_POST["AMOUNT"];
$mac_string .= $_POST["CURRENCY"];
$mac_string .= $payment_method["settings"]["commerce_xpay_mac"];
$mac = strtoupper(sha1($mac_string));
$mac_check = FALSE;
if ($_POST["MAC"] === $mac) {
$mac_check = TRUE;
}
$response = $_POST["RESPONSE"];
$transaction_id = $_POST["TRANSACTION_ID"];
$transaction_id_array = split('O', $transaction_id);
$order_id = (int) $transaction_id_array[0];
$auth_code = $_POST["AUTH_CODE"];
$amount = $_POST["AMOUNT"] / 100;
$currency = commerce_xpay_get_currency_code_from_value($_POST['CURRENCY']);
// Load the order from commerce.
$order = commerce_order_load($order_id);
// ERROR - ORDER NOT IN CHECKOUT.
if ($order === FALSE) {
watchdog('commerce_xpay', 'RETURN FROM PAYMENT GATEWAY - ORDER NOT IN CHECKOUT STATE OR NOT FOUND, received response !response for payment from gateway but order #!order_id is not in "in_checkout" state', array('!order_id' => $transaction_id, '!response' => $order_id), WATCHDOG_ERROR);
drupal_set_message(t('WARNING - ORDER #!order_id NOT FOUND, Please Retry.', array('!order_id' => $order_id)), 'warning');
return FALSE;
}
if ($mac_check === FALSE) {
$variables = array(
'!received_mac' => $_POST['MAC'],
'!response' => $response,
'!calc_mac' => $mac);
watchdog('commerce_xpay', 'RETURN FROM PAYMENT GATEWAY - MAC CHECK NOT PASSED, received response !response for payment. We received mac !received_mac but should have been !calc_mac', $variables, WATCHDOG_ERROR);
drupal_set_message(t('ERROR - An error occured while processing the transaction, Please Retry or choose another payment method.'), 'error');
commerce_payment_redirect_pane_previous_page($order);
}
// Create a new payment transaction for the order.
$transaction = commerce_payment_transaction_new('commerce_xpay', $order->order_id);
$transaction->instance_id = $payment_method['instance_id'];
$transaction->remote_id = $transaction_id;
$transaction->amount = commerce_currency_decimal_to_amount($amount, $currency);
$transaction->currency_code = $currency;
$transaction->payload[REQUEST_TIME] = $_POST;
// Set the transaction's statuses based on the IPN's payment_status.
$transaction->remote_status = $response;
$payed = FALSE;
// ERROR - PAYMENT NOT OK.
if ($response !== "TRANSACTION_OK") {
$transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
$transaction->message = t('ERROR - PAYMENT NOT OK, response: !response', array('!response' => $response));
}
else {
// NOTICE - PAYMENT OK.
$transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
$transaction->message = t('The payment has completed.');
$payed = TRUE;
}
// Save the transaction information.
commerce_payment_transaction_save($transaction);
/* If payment was ok,redirect the user to next page,
* else redirect to previous page. */
if ($payed) {
commerce_payment_redirect_pane_next_page($order);
}
else {
commerce_payment_redirect_pane_previous_page($order);
}
watchdog('commerce_xpay', 'Payment processed for Order @order_number with ID @txn_id.', array('@txn_id' => $transaction_id, '@order_number' => $order->order_number), WATCHDOG_INFO);
}
/**
* Returns the IPN URL.
*
* @param String $method_id
* Optionally specify a payment method ID to include in the URL.
*/
function commerce_xpay_ipn_url($method_id = NULL) {
$parts = array(
'commerce_xpay',
'ipn',
);
if (!empty($method_id)) {
$parts[] = $method_id;
}
return url(implode('/', $parts), array('absolute' => TRUE));
}
/**
* Returns the Currency code from the currency number.
*
* @param String $numeric_code
* The numerc code to look up
*/
function commerce_xpay_get_currency_code_from_value($numeric_code) {
$xpay_currencies = array(
'978' => 'EUR',
);
return $xpay_currencies[$numeric_code];
}