var.rb
6.73 KB
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
require 'var/version'
require 'conekta'
require 'paypal-sdk-rest'
# Main Module
module Var
# TODO: add paypal
VALID_SERVICES = [:conekta]
@@var_classes = []
def self.valid_services
VALID_SERVICES
end
def self.var_classes
@@var_classes
end
def self.add_var_class(class_name)
@@var_classes << class_name unless @@var_classes.include? class_name
end
def self.create_charge(service, object, options = {})
return { error_message: 'Service is not supported' } unless VALID_SERVICES.include? service
return { error_message: "#{object.class} doesn't support charges" } unless object.respond_to?(:charge_with)
charge = object.charge_with(service, options)
charge
end
def self.conekta_webhook(params)
payment = params[:data][:object]
object = Var.find_charge payment[:id]
object.update_columns(var_status: payment[:status])
object.update_columns(var_payment_at: Time.zone.now) if object.var_payed?
object
rescue Exception => exception
false
end
def self.find_charge(id)
Rails.application.eager_load! if Rails.env.development?
@@var_classes.map do |class_name|
class_name.where(var_id: id)
end.flatten.first
end
end
# Module for models
module ActsAsChargeable
extend ActiveSupport::Concern
# Class Methods
module ClassMethods
def acts_as_chargeable(keys = {})
include ChargeableInstanceMethods
cattr_accessor :sync_attributes
self.sync_attributes = keys
Var.add_var_class(self)
end
end
# Instance Methods
module ChargeableInstanceMethods
def charge_with(service, options)
unless instance_support?(service)
error_message = "#{self.class} doesn't support" \
" charges with #{service}"
return { error_message: error_message }
end
send("charge_with_#{service}", options)
rescue Exception => exception
{ error_message: exception.message }
end
def charge_with_conekta(options)
charge = conekta_charge(options)
update_columns(var_status: charge.status, var_id: charge.id,
var_service: 'conekta')
update_conekta_barcode(charge) if options[:conekta_type] == 'oxxo'
update_columns(var_payment_at: Time.zone.now) if var_payed?
charge
rescue Conekta::ParameterValidationError, Conekta::ProcessingError,
Conekta::Error => e
update_columns(var_status: 'failed')
{ error_message: e.message }
end
def conekta_charge(options)
@charge ||= Conekta::Charge.create({
description: sync(:conekta, 'description'),
amount: sync(:conekta, 'amount'), currency: 'MXN',
reference_id: sync(:conekta, 'reference_id'),
details: {
name: sync(:conekta, 'name'), email: sync(:conekta, 'email'),
line_items: [{
description: sync(:conekta, 'description'), quantity: 1,
unit_price: sync(:conekta, 'amount'), name: sync(:conekta, 'name')
}] }
}.merge(conekta_type_of_charge(options)))
end
def conekta_type_of_charge(options)
if options[:conekta_type] == 'card'
{ card: options[:card_token] }
elsif options[:conekta_type] == 'oxxo'
{ cash: { type: 'oxxo',
expires_at: (Time.zone.today + 3.days).strftime('%Y-%m-%d') }
}
end
end
def update_conekta_barcode(charge)
method = charge.payment_method
update_columns(var_barcode: method.barcode,
var_barcode_url: method.barcode_url,
var_payment_expires_at: Time.at(method.expires_at))
end
def manual_charge
update_columns(var_service: 'manual', var_status: 'paid',
var_payment_at: Time.zone.now)
# TODO: Create a new table with transaction
end
# def charge_with_paypal(options)
# if(!options.include? :card)
# error_message = "Paypal needs a card sent as a third paramater"
# return { error_message: error_message}
# end
# @payment = PayPal::SDK::REST::Payment.new({
# intent: "sale",
# payer: {
# payer_info: {
# email: self.sync(:paypal, 'email')},
# payment_method: "credit_card",
# funding_instruments: [{
# credit_card: {
# type: options[:card][:type],
# number: options[:card][:number],
# expire_month: options[:card][:expire_month],
# expire_year: options[:card][:expire_year],
# cvv2: options[:card][:cvv2]}}]},
# transactions: [{
# item_list: {
# items: [{
# name: self.sync(:paypal, 'name'),
# sku: self.sync(:paypal, 'sku'),
# price: self.sync(:paypal, 'price'),
# currency: "MXN",
# quantity: 1 }]},
# amount: {
# total: self.sync(:paypal, 'price'),
# currency: "MXN" },
# description: self.sync(:paypal, 'description') }]})
# end
def find_charge
return { error_message: 'Not charged yet' } unless var_service
send("find_#{var_service}_charge")
rescue Exception => exception
{ error_message: exception.message }
end
def charged?(service)
charge = find_charge(service)
charge.any? && !charge.include?(:error_message)
end
def find_conekta_charge
Conekta::Charge.find(var_id)
end
def instance_support?(service)
sync_attributes.include?(service)
end
def sync(service, key)
service_attributes = send("#{service}_attributes")
return send(key) unless service_attributes.include? key.to_sym
send(service_attributes[key.to_sym])
end
def conekta_attributes
sync_attributes[:conekta] || {}
end
def paypal_attributes
sync_attributes[:paypal] || {}
end
def var_payed?
var_status == 'paid'
end
def cancel_oxxo_payment
return { error_message: 'Already paid' } if var_payed?
return { error_message: 'Not charged yet' } unless var_service
return { error_message: 'Not charged with oxxo' } unless var_barcode
charge = find_charge
if charge.status == 'paid'
update_columns(var_status: 'paid',
var_payment_at: Time.zone.at(charge.paid_at))
return { error_message: 'Already paid' }
end
end
private
def clean_var_variables
if update_columns(var_status: nil, var_barcode: nil, var_barcode_url: nil,
var_id: nil, var_service: nil, var_payment_at: nil,
var_payment_expires_at: nil)
{ object: self }
else
{ error_message: 'Something went wrong' }
end
end
end
end
if defined? ActiveRecord::Base
ActiveRecord::Base.send(:include, ActsAsChargeable)
end