Search code examples
ruby-on-railspaymill

Paymill integration with rails - storing ids locally


I'm working on integrating a Rails app with the Paymill payment gateway (using the paymill-ruby gem), and was wondering if someone could give some advice to the best way to go about interacting with the API during a standard order process. I've managed to get the basics working, but there are very few resources on how to structure the full process.

I have a User model, where I want to store the paymill client id and payment id, and a Payment model, where I store details of every transaction (referencing the order id). My Payment model code is currently as follows:

class Payment < ActiveRecord::Base
  include ActiveModel::ForbiddenAttributesProtection
  attr_accessor :paymill_card_token, :email, :paymill_client_id, :paymill_payment_id

  belongs_to :order
  belongs_to :user
  validates_presence_of :order_id
  validates_presence_of :user_id

  def save_with_payment
    if valid?

      if paymill_client_id.blank?
        #if user hasn't paid before, create paymill client
        client = Paymill::Client.create email: email, description: user_id
        paymill_client_id = client.id
        # update current user with paymill client ID
        User.where("user_id = ?", user_id).update_attributes(:paymill_client_id => paymill_client_id)
      end

      if paymill_payment_id.blank?
        #if paymill_payment_id isn't present, create new payment
        payment = Paymill::Payment.create token: paymill_card_token, client: paymill_client_id
        paymill_payment_id = payment.id
        # update current user with paymill payment ID
        User.where("user_id = ?", user_id).update_attributes(:paymill_payment_id => paymill_payment_id)

      end

      transaction = Paymill::Transaction.create client: paymill_client_id, amount: "#{amount.to_s.gsub('.', '')}0", currency: 'GBP', description: "ORDER ID #{order_id}", payment: paymill_payment_id

      self.paymill_id = transaction.id
      save!
    end
  rescue Paymill::PaymillError => e
    logger.error "Paymill error while creating customer: #{e.message}"
    errors.add :base, "There was a problem with your credit card. Please try again."
    false
  end
end

I read somewhere in the documentation that the paymill payment object (a client's saved credit card details) is only valid for one year - is this correct? And if so how should this be dealt with? Is it a good idea to store this expiry date, as well as the users credit card expiry date, in my User model so I know when to ask them to enter their card info again?


Solution

  • Suggested changes:

    1. Use the Payment model to store the payment_card_token and payment_id. This will allow you to support multiple cards per client, in case you need to in the future
    2. Create a PaymentTransaction model and db table. Each time the user makes a payment, store the details in a PaymentTransaction model instead of Payment model.
    3. Look into the webhooks framework. I haven't used it myself, but it might help with your questions about expired tokens, etc

    Also, a general observation about your rails code

    • Instead of User.where("user_id = ?", user_id).update_attributes, just say user.update_attributes as you have already define the association.
    • Even better if you could move the if paymill_client_id block of code to the User model.