Account
model. These tokens are useless without our public_id and secret password in cloudpayments class Account include Mongoid::Document include Mongoid::Timestamps extend Enumerize # associations belongs_to :user, index: true # fields field :card_first_six, type: String field :card_last_four, type: String field :card_type, type: String field :issuer_bank_country, type: String field :token, type: String field :card_exp_date, type: String # validations validates :card_first_six, :card_last_four, :card_type, :user, presence: true end
token
card in the response to the result of the payment. <script src="https://widget.cloudpayments.ru/bundles/checkout"></script>
<form id="paymentFormSample" autocomplete="off"> <input type="text" data-cp="cardNumber"> <input type="text" data-cp="name"> <input type="text" data-cp="expDateMonthYear"> <input type="text" data-cp="cvv"> <button type="submit"> </button> </form>
data-cp="cardNumber" — data-cp="name" — data-cp="expDateMonthYear" — MMYY data-cp="expDateMonth" — data-cp="expDateYear" — data-cp="cvv" — CVV
createCryptogram = function () { var result = checkout.createCryptogramPacket(); if (result.success) { cryptogram = result.packet // , purchase, success, , 3ds } }; $(function () { /* checkout */ checkout = new cp.Checkout( // public id "test_api_00000000000000000000001", // , document.getElementById("paymentFormSample")); });
def purchase updating_card = current_user.account.present? options = { :IpAddress => request.ip, :AccountId => current_user.email, :Name => params[:name], :JsonData => { plan: params[:plan], updating_card: updating_card }.to_json, :Currency => current_subscription.currency, :Description => "Storing card details" } current_subscription.plan = Plan.find(params[:plan]) if params[:plan].present? amount = updating_card ? 1 : current_subscription.amount response = gateway.purchase(params[:cryptogram], amount, options, true) # making response as action controller params @params = parametrize(response.params) if response.success? resp = { json: success_transaction(@params) } else # if 3d-secure needed if @params and @params['PaReq'].present? resp = { json: { response: @params, type: '3ds' }, status: 422 } else resp = { json: { response: response, type: 'error' }, status: 422 } end end render resp end private def gateway ActiveMerchant::Billing::CloudpaymentsGateway.new(public_id: configatron.cloudpayments.public_id, api_secret: configatron.cloudpayments.api_secret) end
next_payment_due
, which stores the date of the next payment. class Subscription include Mongoid::Document include Mongoid::Timestamps include AASM extend Enumerize belongs_to :user, index: true belongs_to :plan, index: true has_many :transactions, dependent: :restrict default_scope -> { order_by(:created_at.desc) } field :aasm_state field :last_charge_error, type: String field :next_payment_due, type: Date field :trial_due, type: Date field :failed_transactions_number, type: Integer, default: 0 field :successful_transactions_number, type: Integer, default: 0 field :plan_duration enumerize :plan_duration, in: [:month, :year], default: :month, predicates: true, scope: true scope :billable, -> { self.or({aasm_state: 'active'}, {aasm_state: 'past_due'}) } scope :billable_on, -> (date) { where(next_payment_due: date) } scope :trial_due_on, -> (date) { where(trial_due: date) } validates :plan_duration, presence: true # callbacks before_validation :set_trial, on: :create # [...] def gateway ActiveMerchant::Billing::CloudpaymentsGateway.new(public_id: configatron.cloudpayments.public_id, api_secret: configatron.cloudpayments.api_secret) end # , def amount if plan_duration.year? user.language.ru? ? plan.clear_price(plan.year_price_rub) : plan.clear_price(plan.year_price_usd) else user.language.ru? ? plan.clear_price(plan.price_rub) : plan.clear_price(plan.price_usd) end end def account user.account end # def renew! opts = {:Currency => currency, :AccountId => user.email} response = gateway.purchase(account.token, amount, opts) update_subscription! response end def currency user.language.ru? ? 'RUB' : 'USD' end def update_subscription!(response) if response.success? activate_subscription! else logger.error "****Subscription Error****" logger.error response.message self.next_payment_due = self.next_payment_due + configatron.retry_days_number # n- self.last_charge_error = response.message self.failed_transactions_number += 1 # n – , n+1 – , if self.failed_transactions_number < configatron.retry_number self.past_due! || self.save! else self.to_pending! do UserMailer.delay.subscription_cancelled(self.user.id) end end end record_transaction!(response.params) end # , , (, 1 . , .. ) def activate_subscription!(plan=nil, params=nil) record_transaction!(params) if params.present? self.plan = Plan.find(plan) if plan.present? self.last_charge_error = nil self.next_payment_due = next_billing_date(next_payment_due) self.failed_transactions_number = 0 self.successful_transactions_number += 1 self.activate! # Saves next_payment_due too end # def next_billing_date(date=Date.today) date ||= Date.today period = plan_duration.month? ? 1.month : 1.year date + period end # def self.renew! billable.billable_on(Date.today).each do |subscription| subscription.renew! end end # trial pending , – active def self.pending! trial.trial_due_on(Date.today).each do |subscription| subscription.to_pending! do UserMailer.delay.trial_over(subscription.user.id) end end end private def set_trial self.trial_due = Date.today + configatron.trial end def record_transaction!(params) transactions.create! cp_transaction_attrs(params) end def cp_transaction_attrs(attrs) attrs = ActionController::Parameters.new attrs p = attrs.permit(:TransactionId, :Amount, :Currency, :DateTime, :IpAddress, :IpCountry, :IpCity, :IpRegion, :IpDistrict, :Description, :Status, :Reason, :AuthCode).transform_keys!{ |key| key.to_s.underscore rescue key } p[:status] = p[:status].underscore if p[:status].present? p[:reason] = p[:reason].titleize if p[:reason].present? p[:date_time] = DateTime.parse(attrs[:CreatedDateIso]) if attrs[:CreatedDateIso].present? p end end
every :day, at: '0:00 am' do runner "Subscription.renew!" end every :day, at: '0:00 am' do runner "Subscription.pending!" end
Source: https://habr.com/ru/post/236453/
All Articles