Drupal Commerce payment gateway module for Payfirma PayHQ. It uses (optional) Javascript tokenization on credit card information for additional security and easier PCI compliance.

There are no other modules for this payment gateway.

Sponsored by: Payfirma

Project Page: https://drupal.org/sandbox/sleepingmonk/2219871
Git: git clone --branch 7.x-1.x http://git.drupal.org/sandbox/sleepingmonk/2219871.git commerce_payfirma

Reviews:
https://drupal.org/node/2263319#comment-8774547
https://drupal.org/node/2264709#comment-8774603 & https://drupal.org/node/2264709#comment-8774879
https://drupal.org/node/2259343#comment-8775161

Thank You!

CommentFileSizeAuthor
#18 pareview_results.txt2.31 KBmpdonadio
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

PA robot’s picture

We are currently quite busy with all the project applications and we prefer projects with a review bonus. Please help reviewing and put yourself on the high priority list, then we will take a look at your project right away :-)

Also, you should get your friends, colleagues or other community members involved to review this application. Let them go through the review checklist and post a comment that sets this issue to "needs work" (they found some problems with the project) or "reviewed & tested by the community" (they found no major flaws).

I'm a robot and this is an automated message from Project Applications Scraper.

Botto’s picture

No negative output from code sniffer, which is great

  1. Don't use echo, always use print in the .module line 320
  2. The code could do with a little polish, a lot of newlines that don't need to be there.
  3. Use $form['#redirect'] instead of drupal_goto in your submit handler
mpdonadio’s picture

Status: Needs review » Needs work

Manual Review (visual only; I don't have a working Commerce install right now)

You should remove the commented out tests in the .info file

I would add a dependency on entity. Commerce requires this, but you are explicitly using entity_metadata_wrapper(), so the dependency is best in case Commerce changes.

You may want to add an index on order_id since you are declaring this as an FK.

The commented out code in the JS should be removed for the public (eg, lines 26, 74--77)

The naked items in commerce_payfirma_menu() give me pause. Can you point to best practice / other commerce payment modules that have handlers w/ access checks?

Is there a reason you have to use cURL directly and not drupal_http_request()?

You can probably get rid of the empty page arguments on line 19.

Setting this back to Needs Work, pending an answer about the naked hook_menu() items. Otherwise, I didn't see anything wrong that wasn't mentioned yet.

sleepingmonk’s picture

Status: Needs work » Needs review

Thanks for the feedback!

@Botto

Don't use echo, always use print in the .module line 320
Fixed.

The code could do with a little polish, a lot of newlines that don't need to be there.
Newlines removed.
Code restructured a bit to model Authorize.net module a little closer.

Use $form['#redirect'] instead of drupal_goto in your submit handler
Because of the way this payment gateway can "tokenize" card information in the browser with javascript before transmitting data to the server we end up bypassing the form_submit. We have to move the checkout process along on our own so the #redirect doesn't work in this case. Side note: this changed a bit in D7 https://drupal.org/update/modules/6/7#fapi_changes

--
@mpdonadio

You should remove the commented out tests in the .info file
Done.

I would add a dependency on entity. Commerce requires this, but you are explicitly using entity_metadata_wrapper(), so the dependency is best in case Commerce changes.
Good advice. Done.

You may want to add an index on order_id since you are declaring this as an FK.
Done.

The commented out code in the JS should be removed for the public (eg, lines 26, 74--77)
Done.

The naked items in commerce_payfirma_menu() give me pause. Can you point to best practice / other commerce payment modules that have handlers w/ access checks?
These menu items are needed to capture responses from Payfirma's Tokenization and Push features. Tokenization is done through their included javascript which routes it's response to the /handler. Push is similar to PayPal's IPN so the /response is available to the payment notification that can be sent from Payfirma in the background if the user configures their account to do so. These _menu() items were modeled from PayPal WPS module.

Is there a reason you have to use cURL directly and not drupal_http_request()?
cURL is used to be consistent with Payfirma's API documentation. cURL is also used in the Authorize.net module referenced in the creation of this module.

You can probably get rid of the empty page arguments on line 19.
Removed. Thanks.

--
Thanks again for the review and feedback!

mpdonadio’s picture

OK, I checked out commerce_paypal, and saw the 'access callback' => TRUE,. I am trusting Commerce Guys in this case, that this is OK.

Understood about curl. Add a comment to the effect about being modeled after the API docs, and also provide the link. Any other Payfirm API references would be good, as they may aid in debug if this module breaks at some point in the future.

Also comment the bit about the drupal_goto(). Any time you need to deviate from best practices or the API, it is always best to comment why.

Leaving this as Needs Review, but I will give everything a proper look over tomorrow.

mpdonadio’s picture

Status: Needs review » Needs work

Sorry, noticed a few more small things.

1. You aren't using the context in your JS behavior. This is important for AJAX.

2. You are using Drupal.settings.commerce_payfirma directly instead of the settings passed into the attached.

3. You have a unused variable on line 37 in the JS.

4. commerce_payfirma_submit_form() You should really use #attached on the form instead of drupal_add_js() and drupal_add_css().

As a side note, using a IDE like PhpStorm can help identify unused variables and arguments.

sleepingmonk’s picture

Thanks mpdonadio!

pareview.sh comes back clean now.
http://pareview.sh/pareview/httpgitdrupalorgsandboxsleepingmonk2219871git

Added the suggested comments from #5 above, as well as a link to the API docs in the README.txt

1. You aren't using the context in your JS behavior. This is important for AJAX.
2. You are using Drupal.settings.commerce_payfirma directly instead of the settings passed into the attached.

I wasn't used to doing this. I have now, and will do so in the future.

3. You have a unused variable on line 37 in the JS.
Fixed.

4. commerce_payfirma_submit_form() You should really use #attached on the form instead of drupal_add_js() and drupal_add_css().
Fixed.

--
Thanks very much! I've learned a few things. I appreciate your time and effort!

sleepingmonk’s picture

Status: Needs work » Needs review
heddn’s picture

Issue summary: View changes
heddn’s picture

Status: Needs review » Needs work

.module
PHPDoc comment does not match function or method signature (at line 218)
PHPDoc comment does not match function or method signature (at line 375)
hook_menu: Consider using https://api.drupal.org/api/drupal/includes%21menu.inc/constant/MENU_CALL.... That seems a better fit.
hook_commerce_payment_method_info: use l() for the link in the display title and pass it in via t() as a variable. Current approach isn't easily translatable.
commerce_payfirma_settings_form:

$form['logo'] = array(
    '#markup' => "<img src='/$path/images/powered-by-payfirma-large.png' />",
  );

Use '#type' => 'image' (see theme_image)
commerce_payfirma_process_response: Consider using php://input vs $_POST. See http://stackoverflow.com/questions/8893574/php-php-input-vs-post
No check if all the input values are passed. Null values are quite possible to a menu callback.
drupal_set_message(t('ERROR: @error'), array('@error' => check_plain($response['error'])), 'error');
No need to pass through checkplain. t() can do that for you.

.install
Duplicate array key (at line 80)

.info
No explicit dependency on commerce_customer.module

.js
Code comments should follow all the same standards as PHP code i.e. end in full stops. See https://drupal.org/node/172169
Alert should use Drupal.t(). See https://drupal.org/node/323109
Single letter variable names r, z, v make reading the js difficult. Consider using more meaningful names.

images:
Are all the images usable via GPL v2?

Moving back to needs work, primarily because of the non-translatable string and missing dependency.

In general comment, consider doing the extra work to make commerce_payfirma data an entity. This will make it usable by views and will mean you won't have to write code for loading, saving and deleting a payment. It's almost there already, you mostly need to add in the hook_entity_info. See http://www.phase2technology.com/blog/developing-a-custom-drupal-entity/

sleepingmonk’s picture

Status: Needs work » Needs review

Thanks heddn,

I've made the changes you suggested, with the exception of '#type' => 'image'. I looked at theme_image and the forms api and could find documentation or examples of '#type' => 'image' in a form. I tried setting '#type' => 'image' and then using the structure from theme_image for the rest. It didn't seem to work.

Regardless, the images have been removed for now. I don't believe they're GPL. They were provided by the sponsor Payfirma. I'll follow up with them on the licensing before I add them in again.

I'll consider making this data a new entity in a future update, once I look into it more.

Thanks for the review and guidance!

heddn’s picture

Status: Needs review » Needs work

Great progress.

commerce_payfirma_process_response and commerce_payfirma_handler still don't check for !empty (or equivalent) for all values being gathered from the URL.

sleepingmonk’s picture

Status: Needs work » Needs review

Ah! Sorry I missed that.

I updated the function arguments as a few were unused now. Checks are done for each argument.

Thanks again!

heddn’s picture

Status: Needs review » Needs work

There's still an inherent assumption that certain values exist.

  if (!$order_id) {
    $order_id = $response['order_id'];
  }
  $order = commerce_order_load($order_id);

If this isn't called from commerce_payfirma_handler and it doesn't have a POST operation, then $response will be NULL and $order_id will be NULL and so will $order. Try entering the menu path into a browser without any parameters and see what happens.

In commerce_payfirma_handler, rather than using $_REQUEST super global directly, try using drupal_get_query_parameters.

Also, this was introduced:
397 | ERROR | Variable "payRement_method" is camel caps format. do not use
| | mixed case (camelCase), use lower case and _
Plus that value will always be empty (there's no assignment previously).

Last example:

  if (isset($pane_values['token'])) {
    $data['token'] = $pane_values['token'];
  }
  else {
    $data['card_number'] = $pane_values['credit_card']['number'];
    $data['card_expiry_month'] = $pane_values['credit_card']['exp_month'];
    $data['card_expiry_year'] = $pane_values['credit_card']['exp_year'];
    $data['cvv2'] = $pane_values['credit_card']['code'];
  }

This assumes that the $_REQUEST has card_number, etc populated. It wouldn't if someone only entered the menu path without any parameters.

sleepingmonk’s picture

Status: Needs work » Needs review

Hello again,

Also, this was introduced:
397 | ERROR | Variable "payRement_method" is camel caps format. do not use
| | mixed case (camelCase), use lower case and _
Plus that value will always be empty (there's no assignment previously).

I don't see this in my local working copy or in the previous commits to the repo. Is it possible this was accidentally inserted on your end?

--
As for the rest. Sorry I didn't understand what you were expecting here. Only Payfirma processes would access these URLs, with data in an expected format, but I understand why we need these checks. I've referred to the Commerce PayPal module to see how they handle the IPN response which is similar to what we have in this module.

I've added a check for empty $response and a valid $order object in the _process_response function. It also checks for an order id in the $pane_values (passed in or loaded from $_REQUEST), in the _handler function. It returns FALSE if any of these checks fail.

I don't understand the benefit to using drupal_get_query_parameters rather than $_REQUEST, or $_POST.

--
I hope this is sufficient now, and I appreciate your time and guidance in this review process.

heddn’s picture

Status: Needs review » Reviewed & tested by the community

@sleepingmonk, sorry about that. It must have been inserted. Moving to RTBCed. The next step is to wait for a git admin to promote.

sleepingmonk’s picture

Awesome!

Thanks for all the help!

mpdonadio’s picture

FileSize
2.31 KB

Sorry for the delay, it took me longer than expected to confirm the hook_menu() issue mentioned above.

Automated Review

Review of the 7.x-1.x branch:

  • Coder Sniffer has found some issues with your code (please check the Drupal coding standards). See attachment.
  • DrupalPractice has found some issues with your code, but could be false positives, and may be duplicate results from Coder Sniffer. See attachment.

This automated report was generated with PAReview.sh, your friendly project application review script. You can also use the online version to check your project. You have to get a review bonus to get a review from me.

Nothing major; fix when you can.

Manual Review

Add a comment somewhere in the code that Commerce Paypal was used as a model.

I think the second jQuery selector on line 25 is missing the context that was passed in.

Missing t() on commerce_payfirma.module, line 120.

It would be best to have some comments w/ URL that refer to the Payfirm API when you are programming against it (eg, the cURL, the responses).

Your date() functions should use format_date() w/ a custom string, and also explictly use REQUEST_TIME.

Form API #default_value gets plained internally. See https://drupal.org/node/28984

I am not seeing any blocking issues on this.

mpdonadio’s picture

Status: Reviewed & tested by the community » Fixed

Thanks for your contribution, sleepingmonk!

I updated your account so you can promote this to a full project and also create new projects as either a sandbox or a "full" project.

Here are some recommended readings to help with excellent maintainership:

You can find lots more contributors chatting on IRC in #drupal-contribute. So, come hang out and stay involved!

Thanks, also, for your patience with the review process. Anyone is welcome to participate in the review process. Please consider reviewing other projects that are pending review. I encourage you to learn more about that process and join the group of reviewers.

Thanks to the dedicated reviewer(s) as well.

sleepingmonk’s picture

Thanks very much everyone! I learned a few things and enjoyed review a few other modules. I'll definitely help out with more reviews in the future. I imagine I'll learn even more in the process.

Thanks again!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.