pag_seguro 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/Gemfile +5 -2
- data/README.md +71 -6
- data/lib/pag_seguro/checkout.xml.haml +24 -5
- data/lib/pag_seguro/convert_field_to_digit.rb +15 -0
- data/lib/pag_seguro/day_of_year.rb +35 -0
- data/lib/pag_seguro/item.rb +9 -11
- data/lib/pag_seguro/notification.rb +1 -1
- data/lib/pag_seguro/payment.rb +26 -19
- data/lib/pag_seguro/pre_approval.rb +84 -0
- data/lib/pag_seguro/query.rb +27 -1
- data/lib/pag_seguro/sender.rb +2 -2
- data/lib/pag_seguro/shipping.rb +2 -2
- data/lib/pag_seguro/transaction.rb +1 -1
- data/lib/pag_seguro/version.rb +1 -1
- data/lib/pag_seguro.rb +9 -1
- data/lib/pagseguro_decimal_validator.rb +9 -0
- data/pag_seguro.gemspec +1 -0
- data/spec/factories.rb +137 -0
- data/spec/fixtures/transaction_history.xml +40 -0
- data/spec/pag_seguro/checkout_xml_spec.rb +142 -159
- data/spec/pag_seguro/convert_field_to_digit_spec.rb +68 -0
- data/spec/pag_seguro/day_of_year_spec.rb +49 -0
- data/spec/pag_seguro/integration/checkout_spec.rb +34 -67
- data/spec/pag_seguro/integration/config.yml +4 -4
- data/spec/pag_seguro/integration/query_spec.rb +56 -34
- data/spec/pag_seguro/item_spec.rb +46 -72
- data/spec/pag_seguro/payment_method_spec.rb +58 -63
- data/spec/pag_seguro/payment_spec.rb +150 -123
- data/spec/pag_seguro/pre_approval_spec.rb +112 -0
- data/spec/pag_seguro/query_spec.rb +111 -4
- data/spec/pag_seguro/sender_spec.rb +50 -62
- data/spec/pag_seguro/shipping_spec.rb +36 -51
- data/spec/spec_helper.rb +11 -20
- data/spec/support/transaction_shared_examples.rb +7 -7
- metadata +32 -3
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -3,8 +3,11 @@ source "http://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in PagSeguro.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
# test gems
|
6
|
+
# test or development gems
|
7
7
|
gem 'rspec'
|
8
8
|
gem 'simplecov', require: false
|
9
9
|
gem 'guard-rspec'
|
10
|
-
gem '
|
10
|
+
gem 'shoulda-matchers'
|
11
|
+
gem "factory_girl", "~> 4.0"
|
12
|
+
gem 'growl'
|
13
|
+
gem 'pry'
|
data/README.md
CHANGED
@@ -73,7 +73,9 @@ Com exceção do atributo response (que é utilizado para armazenar a resposta e
|
|
73
73
|
|
74
74
|
### API de Notificação
|
75
75
|
|
76
|
-
As notificações de alteração no status da compra no PagSeguro serão enviadas para a URL que tiver configurado na [Notificação de transações](https://pagseguro.uol.com.br/v2/guia-de-integracao/consulta-de-transacoes-por-codigo.html).
|
76
|
+
As notificações de alteração no status da compra no PagSeguro serão enviadas para a URL que tiver configurado na [Notificação de transações](https://pagseguro.uol.com.br/v2/guia-de-integracao/consulta-de-transacoes-por-codigo.html). Se quiser configurar uma url dinâmica para envio das notificação é necessário ativar a página de redirecionamento dinâmico em [Integrações > Página de redirecionamento](https://pagseguro.uol.com.br/integracao/pagina-de-redirecionamento.jhtml), e passar o argumento `redirect_url` para o objeto PagSeguro::Payment:
|
77
|
+
|
78
|
+
PagSeguro::Payment.new(email, token, id: invoice.id, redirect_url: "http://lojamodelo.com.br/checkout")
|
77
79
|
|
78
80
|
O código da notificação é enviado pelo PagSeguro através do parâmentro `notificationCode` em uma requisição do tipo POST. Segue um exemplo de uso da notificação em uma aplicação rails (este exemplo supõe a existência de um `resources :notifications` em suas rotas, e um modelo `Invoice` responsável pelos pagamentos):
|
79
81
|
|
@@ -108,15 +110,28 @@ Para este exemplo, o url configurada na [Notificação de transações](https://
|
|
108
110
|
|
109
111
|
### Consulta de Transações
|
110
112
|
|
111
|
-
|
113
|
+
Há duas maneiras de se realizar a consulta das transações, a primeira delas buscando o código de uma transação, e outra buscando por todas as transações em um determinado período
|
112
114
|
|
113
|
-
|
115
|
+
#### Consulta de Transações por Período
|
114
116
|
|
115
|
-
|
117
|
+
Você pode consultar as transações por uma data através do método `PagSeguro::Query::find`, informando seu email, token, e algumas opções adicionais:
|
116
118
|
|
117
|
-
PagSeguro::
|
119
|
+
transactions = PagSeguro::Query.find(email, token, initial_date: 30.days.ago, final_date: Time.now)
|
120
|
+
|
121
|
+
transactions.each do |transaction|
|
122
|
+
puts "id: #{transaction.id}, transaction_id: #{transaction.transaction_id}"
|
123
|
+
...
|
124
|
+
end
|
125
|
+
|
126
|
+
Além das opções acima, você pode enviar também as opções `:page` (que pelo padrão é a primeira) e `:max_page_results` (que por padrão é 50). Obviamente a data final precisa ser maior que a inicial, não podem haver mais de 30 dias de diferença entre as duas, e a data inicial precisa estar dentro dos últimos 6 meses.
|
127
|
+
|
128
|
+
#### Consulta de Transação por código
|
118
129
|
|
119
|
-
|
130
|
+
O código das transações são enviadas nas Notificações de Transações do PagSeguro (de forma assíncrona), e podem ser obtidas através do método `notification.transaction_id`, e também podem ser obtidas de forma síncrona assim que o usuário retorna à loja após ter concluído a compra. Este código também pode ser encontrado através da busca de transações por período.
|
131
|
+
|
132
|
+
Para buscar informações da transação de forma síncrona, é necessário que acesse sua conta no PagSeguro, e clique em [Integrações > Página de redirecionamento](https://pagseguro.uol.com.br/integracao/pagina-de-redirecionamento.jhtml) e ative o redirecionamento com o código da transação, definindo o nome do parâmetro que será enviado para sua aplicação (e.g.: http://lojamodelo.com.br/checkout?transaction_id=E884542-81B3-4419-9A75-BCC6FB495EF1 ). O redirecionamento para esta página é executado através de uma requisição GET.
|
133
|
+
|
134
|
+
Você pode consultar as informações da transação instanciando a classe `PagSeguro::Query`, que possui os mesmos attributos e métodos que uma notificação:
|
120
135
|
|
121
136
|
query = PagSeguro::Query.new(email, token, "E884542-81B3-4419-9A75-BCC6FB495EF1")
|
122
137
|
|
@@ -124,6 +139,54 @@ Você pode consultar as informações da transação através do `PagSeguro::Que
|
|
124
139
|
# ...
|
125
140
|
end
|
126
141
|
|
142
|
+
### Pagamento Recorrente
|
143
|
+
|
144
|
+
**Primeiro de tudo vale ressaltar que a API de pagamento recorrente não está documentada oficialmente pelo pagseguro, apesar de ter sido lançada em dezembro de 2012. Esta funcionalidade foi criada com base em um post em um [blog](http://sounoob.com.br/requisicao-de-pagamento-do-pagseguro-com-assinatura-associada-usando-php/) e em tentativa e erro. Use por sua conta e risco.**
|
145
|
+
|
146
|
+
É possível enviar a requisição de uma pagamento recorrente juntamente com o pedido de compra (e por enquanto não é possível enviar um pedido de assinatura sem enviar adicionar nenhum ítem ao pagamento). Para usá-la, basta adicionar um `pre_approval` a um pagamento:
|
147
|
+
|
148
|
+
# suponho que uma variavel payment (do tipo PagSeguro::Payment) já foi instanciada, e que o payment.items não está vazio
|
149
|
+
payment.pre_approval = PagSeguro::PreApproval.new
|
150
|
+
|
151
|
+
# obrigatório. Recebe uma string (de até 100 caracteres) e representa o nome da sua assinatura
|
152
|
+
payment.pre_approval.name = "nome da minha assinatura"
|
153
|
+
|
154
|
+
# obrigatório. Recebe uma data e representa a data em que sua assinatura termina. Não pode ser maior do que a data de início (ou hoje) em mais de 744 dias (pouco menos de 3 anos)
|
155
|
+
payment.pre_approval.pre_approval.final_date = Date.new(2014, 6, 12)
|
156
|
+
|
157
|
+
# obrigatório. Valor máximo da assinatura por período/cobrança. Recebe uma string (formatada como "%.2f"), um float ou um BigDecimal
|
158
|
+
payment.pre_approval.max_amount_per_period = '200.00'
|
159
|
+
|
160
|
+
# obrigatório. Valor máximo total da assinatura. Recebe uma string (formatada como "%.2f"), um float ou um BigDecimal
|
161
|
+
payment.pre_approval.max_total_amount = '1000.00'
|
162
|
+
|
163
|
+
# obrigatório. Representa a periodicidade da cobraça. Recebe uma string ou símbolo e pode ser: weekly, monthly, bimonthly, trimonthly, semiannually, ou yearly
|
164
|
+
payment.pre_approval.period = :monthly
|
165
|
+
|
166
|
+
# obrigatório no caso de pagamentos de periodicidade monthly, bimonthly ou trimonthly. Recebe um número (dia do mês) de 1 à 28
|
167
|
+
payment.pre_approval.day_of_month = 10
|
168
|
+
|
169
|
+
# obrigatório no caso de pagamentos de periodicidade weekly. Recebe uma string ou símbolo representando o dia na semana, e pode ser monday, tuesday, wednesday, thursday, friday, saturday ou sunday
|
170
|
+
payment.pre_approval.day_of_week = :friday
|
171
|
+
|
172
|
+
# obrigatório no caso de pagamentos de periodicidade yearly. Recebe uma string representando o dia do mês e o mês do ano no formato 'MM-dd'. Para facilitar use a classe DayOfYear que gera a string no formato correto.
|
173
|
+
payment.pre_approval.day_of_year = PagSeguro::DayOfYear.new(day: 10, month: 4)
|
174
|
+
|
175
|
+
# estranhamente é opcional! Valor de cada cobrança. Recebe uma string (no formato "%.2f"), um float ou um BigDecimal
|
176
|
+
payment.pre_approval.amount_per_payment = '200.00'
|
177
|
+
|
178
|
+
# opcional. Recebe uma string (de até 255 caracteres) e representa os detalhes da assinatura
|
179
|
+
payment.pre_approval.details = "detalhes da assinatura"
|
180
|
+
|
181
|
+
# opcional. Recebe uma data de quando a assinatura passa a valer. Não pode ser maior do que 2 anos da data atual, e precisa ser inferior a data de final_date (que pode ser maior em até 744 dias da data de início)
|
182
|
+
payment.pre_approval.initial_date = Date.new(2014, 3, 12)
|
183
|
+
|
184
|
+
# opcional. Recebe uma string que supostamente deveria levar às condições da sua assinatura
|
185
|
+
payment.pre_approval.reviewURL = "http://seuproduto.com/assinatura"
|
186
|
+
|
187
|
+
# Por fim gere a URL do pagseguro da mesma forma como nas compras/pagamentos normais.
|
188
|
+
redirect_to_url = payment.checkout_payment_url
|
189
|
+
|
127
190
|
## Validações
|
128
191
|
|
129
192
|
Os modelos utilizados nesta gem utilizam as validações do ActiveModel (semelhantes às presentes em ActiveRecord/Rails) e incluem diversas validações, permitindo que se verifique a validade (utilizando object.valid?) dos dados antes de enviá-los ao PagSeguro. A gem não bloqueia o envio das informações caso os dados estejam inválidos, deixando este passo a cargo da sua aplicação, mas levanta erros caso o pag seguro retorne algum erro relativo às informações enviadas.
|
@@ -152,3 +215,5 @@ Desenvolvida por [Stefano Diem Benatti](mailto:stefano@heavenstudio.com.br)
|
|
152
215
|
Rafael Castilho (<http://github.com/castilhor>)
|
153
216
|
|
154
217
|
Rafael Ivan Garcia (https://github.com/rafaelivan)
|
218
|
+
|
219
|
+
efmiglioranza (https://github.com/efmiglioranza)
|
@@ -8,7 +8,7 @@
|
|
8
8
|
%redirectURL= payment.redirect_url
|
9
9
|
- if payment.max_uses.present?
|
10
10
|
%maxUses= payment.max_uses
|
11
|
-
- if payment.
|
11
|
+
- if payment.max_age.present?
|
12
12
|
%maxAge= payment.max_age
|
13
13
|
|
14
14
|
%currency BRL
|
@@ -39,10 +39,7 @@
|
|
39
39
|
|
40
40
|
- if shipping.present?
|
41
41
|
%shipping
|
42
|
-
|
43
|
-
%type= shipping.type
|
44
|
-
- else
|
45
|
-
%type 3
|
42
|
+
%type= shipping.type
|
46
43
|
- if shipping.cost.present?
|
47
44
|
%cost= shipping.cost
|
48
45
|
%address
|
@@ -61,3 +58,25 @@
|
|
61
58
|
%number= shipping.number
|
62
59
|
- if shipping.complement.present?
|
63
60
|
%complement= shipping.complement
|
61
|
+
|
62
|
+
- if pre_approval.present?
|
63
|
+
%preApproval
|
64
|
+
%name= pre_approval.name
|
65
|
+
%finalDate= pre_approval.final_date.iso8601
|
66
|
+
%maxAmountPerPeriod= pre_approval.max_amount_per_period
|
67
|
+
%maxTotalAmount= pre_approval.max_total_amount
|
68
|
+
%period= pre_approval.period
|
69
|
+
- if pre_approval.weekly?
|
70
|
+
%dayOfWeek= pre_approval.day_of_week
|
71
|
+
- if pre_approval.monthly?
|
72
|
+
%dayOfMonth= pre_approval.day_of_month
|
73
|
+
- if pre_approval.yearly?
|
74
|
+
%dayOfYear= pre_approval.day_of_year
|
75
|
+
- if pre_approval.details.present?
|
76
|
+
%details= pre_approval.details
|
77
|
+
- if pre_approval.amount_per_payment.present?
|
78
|
+
%amountPerPayment= pre_approval.amount_per_payment
|
79
|
+
- if pre_approval.initial_date.present?
|
80
|
+
%initialDate= pre_approval.initial_date.iso8601
|
81
|
+
- if pre_approval.review_URL.present?
|
82
|
+
%reviewURL= pre_approval.review_URL
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module PagSeguro
|
2
|
+
module ConvertFieldToDigit
|
3
|
+
def attr_reader_as_digit(*fields)
|
4
|
+
fields.each do |field|
|
5
|
+
define_method(field) do
|
6
|
+
begin
|
7
|
+
"%.2f" % instance_variable_get("@#{field}")
|
8
|
+
rescue ArgumentError, TypeError
|
9
|
+
instance_variable_get("@#{field}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module PagSeguro
|
2
|
+
module Error
|
3
|
+
class InvalidDayOfYear < Exception
|
4
|
+
def initialize(date_of_year)
|
5
|
+
super("DateOfYear should be a valid date: (month: #{date_of_year.month}, day: #{date_of_year.day})")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class DayOfYear
|
11
|
+
include Comparable
|
12
|
+
attr_accessor :day, :month
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
@day = options[:day]
|
16
|
+
@month = options[:month]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
raise Error::InvalidDayOfYear.new(self) unless valid?
|
21
|
+
"#{"%02d" % @month}-#{"%02d" % @day}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def valid?
|
25
|
+
# very simple date validation, just to smoke test possible errors of switching day with month
|
26
|
+
@day < 31 && @month < 12
|
27
|
+
end
|
28
|
+
|
29
|
+
def <=>(other_day_of_the_year)
|
30
|
+
return 1 if @month > other_day_of_the_year.month
|
31
|
+
return -1 if @month < other_day_of_the_year.month
|
32
|
+
@day <=> other_day_of_the_year.day
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/pag_seguro/item.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
module PagSeguro
|
2
2
|
class Item
|
3
3
|
include ActiveModel::Validations
|
4
|
+
extend PagSeguro::ConvertFieldToDigit
|
4
5
|
|
5
6
|
attr_accessor :id, :description, :amount, :quantity, :shipping_cost, :weight
|
7
|
+
attr_reader_as_digit :amount, :shipping_cost
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
validates :id, presence: true
|
10
|
+
validates :description, presence: true
|
11
|
+
validates :amount, pagseguro_decimal: true, presence: true
|
12
|
+
validates :shipping_cost, pagseguro_decimal: true
|
13
|
+
validates :weight, numericality: { only_integer: true, greater_than: 0, allow_blank: true }
|
14
|
+
validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0, less_than: 1000 }
|
12
15
|
|
13
16
|
def initialize(attributes = {})
|
14
17
|
@id = attributes[:id]
|
@@ -22,10 +25,5 @@ module PagSeguro
|
|
22
25
|
def description
|
23
26
|
@description.present? && @description.size > 100 ? @description[0..99] : @description
|
24
27
|
end
|
25
|
-
|
26
|
-
protected
|
27
|
-
def quantity_amount
|
28
|
-
errors.add(:quantity, " must be a number between 1 and 999") if @quantity.present? && (@quantity == "0" || @quantity.to_s !~ /^\d{1,3}$/)
|
29
|
-
end
|
30
|
-
end
|
28
|
+
end
|
31
29
|
end
|
@@ -10,7 +10,7 @@ module PagSeguro
|
|
10
10
|
|
11
11
|
private
|
12
12
|
def transaction_data(email, token, notification_code)
|
13
|
-
super
|
13
|
+
super RestClient.get "#{PAGSEGURO_TRANSACTIONS_URL}/notifications/#{notification_code}", params: {email: email, token: token}
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/pag_seguro/payment.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module PagSeguro
|
2
2
|
class Payment
|
3
3
|
include ActiveModel::Validations
|
4
|
-
|
5
|
-
|
4
|
+
extend PagSeguro::ConvertFieldToDigit
|
5
|
+
|
6
|
+
attr_accessor :id, :email, :token, :items, :sender, :shipping, :extra_amount,
|
7
|
+
:redirect_url, :max_uses, :max_age, :response, :pre_approval
|
8
|
+
attr_reader_as_digit :extra_amount
|
6
9
|
|
7
10
|
validates_presence_of :email, :token
|
8
|
-
|
11
|
+
validates :extra_amount, pagseguro_decimal: true
|
9
12
|
validates_format_of :redirect_url, with: URI::regexp(%w(http https)), message: " must give a correct url for redirection", allow_blank: true
|
10
|
-
validate :max_uses_number, :max_age_number
|
13
|
+
validate :max_uses_number, :max_age_number, :valid_pre_approval, :valid_items
|
11
14
|
|
12
15
|
def initialize(email = nil, token = nil, options = {})
|
13
16
|
@email = email unless email.nil?
|
@@ -20,6 +23,7 @@ module PagSeguro
|
|
20
23
|
@redirect_url = options[:redirect_url]
|
21
24
|
@max_uses = options[:max_uses]
|
22
25
|
@max_age = options[:max_age]
|
26
|
+
@pre_approval = options[:pre_approval]
|
23
27
|
end
|
24
28
|
|
25
29
|
def self.checkout_payment_url(code)
|
@@ -28,7 +32,7 @@ module PagSeguro
|
|
28
32
|
|
29
33
|
def checkout_xml
|
30
34
|
xml_content = File.open( File.dirname(__FILE__) + "/checkout.xml.haml" ).read
|
31
|
-
Haml::Engine.new(xml_content).render(nil, items: @items, payment: self, sender: @sender, shipping: @shipping)
|
35
|
+
Haml::Engine.new(xml_content).render(nil, items: @items, payment: self, sender: @sender, shipping: @shipping, pre_approval: @pre_approval)
|
32
36
|
end
|
33
37
|
|
34
38
|
def checkout_url_with_params
|
@@ -40,12 +44,12 @@ module PagSeguro
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def code
|
43
|
-
|
47
|
+
response || parse_checkout_response
|
44
48
|
parse_code
|
45
49
|
end
|
46
50
|
|
47
51
|
def date
|
48
|
-
|
52
|
+
response || parse_checkout_response
|
49
53
|
parse_date
|
50
54
|
end
|
51
55
|
|
@@ -61,30 +65,33 @@ module PagSeguro
|
|
61
65
|
def max_age_number
|
62
66
|
errors.add(:max_age, " must be an integer grater or equal to 30") if @max_age.present? && @max_age.to_i < 30
|
63
67
|
end
|
68
|
+
|
69
|
+
def valid_pre_approval
|
70
|
+
errors.add(:pre_approval, " must be valid") if pre_approval && !pre_approval.valid?
|
71
|
+
end
|
72
|
+
|
73
|
+
def valid_items
|
74
|
+
errors.add(:items, " must be all valid") if items.blank? || !items.all?(&:valid?)
|
75
|
+
end
|
64
76
|
|
65
77
|
def send_checkout
|
66
78
|
RestClient.post(checkout_url_with_params, checkout_xml, content_type: "application/xml"){|resp, request, result| resp }
|
67
79
|
end
|
68
80
|
|
69
81
|
def parse_checkout_response
|
70
|
-
|
71
|
-
if
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
elsif response.code == 400
|
76
|
-
raise Errors::InvalidData.new(response.body)
|
77
|
-
else
|
78
|
-
raise Errors::UnknownError.new(response)
|
79
|
-
end
|
82
|
+
res = send_checkout
|
83
|
+
raise Errors::Unauthorized if res.code == 401
|
84
|
+
raise Errors::InvalidData.new(res.body) if res.code == 400
|
85
|
+
raise Errors::UnknownError.new(res) if res.code != 200
|
86
|
+
@response = res.body
|
80
87
|
end
|
81
88
|
|
82
89
|
def parse_date
|
83
|
-
DateTime.iso8601( Nokogiri::XML(
|
90
|
+
DateTime.iso8601( Nokogiri::XML(response.body).css("checkout date").first.content )
|
84
91
|
end
|
85
92
|
|
86
93
|
def parse_code
|
87
|
-
Nokogiri::XML(
|
94
|
+
Nokogiri::XML(response.body).css("checkout code").first.content
|
88
95
|
end
|
89
96
|
end
|
90
97
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module PagSeguro
|
2
|
+
class PreApproval
|
3
|
+
include ActiveModel::Validations
|
4
|
+
extend PagSeguro::ConvertFieldToDigit
|
5
|
+
|
6
|
+
PERIOD_TYPES = %w(weekly monthly bimonthly trimonthly semiannually yearly)
|
7
|
+
DAYS_OF_WEEK = %w(monday tuesday wednesday thursday friday saturday sunday)
|
8
|
+
DATE_RANGE = 17856.hours
|
9
|
+
|
10
|
+
attr_accessor :name, :details, :amount_per_payment, :period, :day_of_week, :day_of_month,
|
11
|
+
:day_of_year, :initial_date, :final_date, :max_amount_per_period, :max_total_amount, :review_URL
|
12
|
+
attr_reader_as_digit :amount_per_payment, :max_amount_per_period, :max_total_amount
|
13
|
+
|
14
|
+
validates_presence_of :name, :period, :final_date, :max_total_amount, :max_amount_per_period
|
15
|
+
validates_inclusion_of :period, in: PERIOD_TYPES
|
16
|
+
validates_inclusion_of :day_of_week, in: DAYS_OF_WEEK, if: :weekly?
|
17
|
+
validates_inclusion_of :day_of_month, in: (1..28), if: :monthly?
|
18
|
+
validates_presence_of :day_of_year, if: :yearly?
|
19
|
+
validates_format_of :day_of_year, with: /^\d{2}-\d{2}$/, if: :yearly?
|
20
|
+
validate :initial_date_range, :final_date_range
|
21
|
+
validates :max_amount_per_period, pagseguro_decimal: true
|
22
|
+
validates :max_total_amount, pagseguro_decimal: true
|
23
|
+
|
24
|
+
def initialize(options = {})
|
25
|
+
@name = options[:name]
|
26
|
+
@details = options[:details]
|
27
|
+
@amount_per_payment = options[:amount_per_payment]
|
28
|
+
@period = options[:period]
|
29
|
+
@day_of_week = options[:day_of_week]
|
30
|
+
@day_of_month = options[:day_of_month]
|
31
|
+
@day_of_year = options[:day_of_year]
|
32
|
+
@initial_date = options[:initial_date]
|
33
|
+
@final_date = options[:final_date]
|
34
|
+
@max_amount_per_period = options[:max_amount_per_period]
|
35
|
+
@max_total_amount = options[:max_total_amount]
|
36
|
+
@review_URL = options[:review_URL]
|
37
|
+
end
|
38
|
+
|
39
|
+
def period
|
40
|
+
@period.to_s.downcase
|
41
|
+
end
|
42
|
+
|
43
|
+
def day_of_week
|
44
|
+
@day_of_week.to_s.downcase
|
45
|
+
end
|
46
|
+
|
47
|
+
def day_of_year
|
48
|
+
@day_of_year.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def initial_date
|
52
|
+
@initial_date.to_datetime if @initial_date.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
def final_date
|
56
|
+
@final_date.to_datetime if @final_date.present?
|
57
|
+
end
|
58
|
+
|
59
|
+
def weekly?
|
60
|
+
period == 'weekly'
|
61
|
+
end
|
62
|
+
|
63
|
+
def monthly?
|
64
|
+
%w(monthly bimonthly trimonthly).include? period
|
65
|
+
end
|
66
|
+
|
67
|
+
def yearly?
|
68
|
+
period == 'yearly'
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
def initial_date_range
|
73
|
+
return unless initial_date
|
74
|
+
errors.add(:initial_date) if initial_date < Time.now - 5.minutes
|
75
|
+
errors.add(:initial_date) if initial_date > DATE_RANGE.from_now
|
76
|
+
end
|
77
|
+
|
78
|
+
def final_date_range
|
79
|
+
return unless final_date
|
80
|
+
errors.add(:final_date) if final_date < (initial_date || Time.now) - 5.minutes
|
81
|
+
errors.add(:final_date) if final_date > (initial_date || Time.now) + DATE_RANGE
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/pag_seguro/query.rb
CHANGED
@@ -8,9 +8,35 @@ module PagSeguro
|
|
8
8
|
@data = transaction_data(email, token, transaction_code)
|
9
9
|
end
|
10
10
|
|
11
|
+
def self.find(email, token, options={})
|
12
|
+
url = Transaction::PAGSEGURO_TRANSACTIONS_URL
|
13
|
+
transactions_data = Nokogiri::XML(RestClient.get url, params: search_params(email, token, options))
|
14
|
+
transactions_data.css("transaction").map{|transaction_xml| Transaction.new(transaction_xml) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.search_params(email, token, options={})
|
18
|
+
params = {email: email, token: token}
|
19
|
+
params[:initialDate], params[:finalDate] = parse_dates(options)
|
20
|
+
params[:page] = options[:page] if options[:page]
|
21
|
+
params[:maxPageResults] = options[:max_page_results] if options[:max_page_results]
|
22
|
+
params
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.parse_dates(options={})
|
26
|
+
initial_date = (options[:initial_date] || Time.now - 1.day).to_time
|
27
|
+
final_date = (options[:final_date] || initial_date + 1.day).to_time
|
28
|
+
|
29
|
+
raise "Invalid initial date. Must be bigger than 6 months ago" if initial_date < 6.months.ago
|
30
|
+
raise "Invalid end date. Must be less than today" if final_date > Date.today.end_of_day
|
31
|
+
raise "Invalid end date. Must be bigger than initial date" if final_date < initial_date
|
32
|
+
raise "Invalid end date. Must not differ from initial date in more than 30 days" if (final_date.to_date - initial_date.to_date) > 30
|
33
|
+
|
34
|
+
return initial_date.to_time.iso8601, final_date.to_time.iso8601
|
35
|
+
end
|
36
|
+
|
11
37
|
private
|
12
38
|
def transaction_data(email, token, transaction_code)
|
13
|
-
super
|
39
|
+
super RestClient.get "#{PAGSEGURO_TRANSACTIONS_URL}/#{transaction_code}", params: {email: email, token: token}
|
14
40
|
end
|
15
41
|
end
|
16
42
|
end
|
data/lib/pag_seguro/sender.rb
CHANGED
@@ -27,11 +27,11 @@ module PagSeguro
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def phone_ddd
|
30
|
-
@phone_ddd if @phone_ddd =~ /^\d{2}$/
|
30
|
+
@phone_ddd if @phone_ddd.to_s =~ /^\d{2}$/
|
31
31
|
end
|
32
32
|
|
33
33
|
def phone_number
|
34
|
-
@phone_number if @phone_number =~/^\d{8,9}$/
|
34
|
+
@phone_number if @phone_number.to_s =~/^\d{8,9}$/
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/pag_seguro/shipping.rb
CHANGED
@@ -6,12 +6,12 @@ module PagSeguro
|
|
6
6
|
SEDEX = 2
|
7
7
|
UNIDENTIFIED = 3
|
8
8
|
|
9
|
-
|
9
|
+
validates :postal_code, numericality: true, length: {is: 8}
|
10
10
|
|
11
11
|
attr_accessor :type, :state, :city, :postal_code, :district, :street, :number, :complement, :cost
|
12
12
|
|
13
13
|
def initialize(attributes = {})
|
14
|
-
@type = attributes[:type]
|
14
|
+
@type = attributes[:type] || UNIDENTIFIED
|
15
15
|
@state = attributes[:state]
|
16
16
|
@city = attributes[:city]
|
17
17
|
@postal_code = attributes[:postal_code]
|
@@ -170,7 +170,7 @@ module PagSeguro
|
|
170
170
|
|
171
171
|
protected
|
172
172
|
def transaction_data(transaction_xml)
|
173
|
-
Nokogiri::XML(transaction_xml)
|
173
|
+
transaction_xml.instance_of?(Nokogiri::XML::Element) ? transaction_xml : Nokogiri::XML(transaction_xml)
|
174
174
|
end
|
175
175
|
|
176
176
|
def parse_item(data, attribute)
|
data/lib/pag_seguro/version.rb
CHANGED
data/lib/pag_seguro.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
$: << File.expand_path(File.dirname(__FILE__) + "/../lib/pag_seguro")
|
2
2
|
|
3
|
-
require
|
3
|
+
require "date"
|
4
|
+
require "bigdecimal"
|
4
5
|
|
5
6
|
# Third party gems
|
6
7
|
require "active_model"
|
7
8
|
require "nokogiri"
|
8
9
|
require "haml"
|
9
10
|
require "rest-client"
|
11
|
+
require "active_support"
|
12
|
+
require "active_support/time"
|
13
|
+
|
14
|
+
require "pagseguro_decimal_validator"
|
15
|
+
require "convert_field_to_digit"
|
10
16
|
|
11
17
|
# PagSeguro classes
|
12
18
|
require "item"
|
@@ -14,6 +20,8 @@ require "payment"
|
|
14
20
|
require "payment_method"
|
15
21
|
require "sender"
|
16
22
|
require "shipping"
|
23
|
+
require "day_of_year"
|
24
|
+
require "pre_approval"
|
17
25
|
require "transaction"
|
18
26
|
require "notification"
|
19
27
|
require "query"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class PagseguroDecimalValidator < ActiveModel::EachValidator
|
2
|
+
def validate_each(object, attribute, value)
|
3
|
+
object.errors.add(attribute, error_message) unless value.nil? || value =~ /^\d+\.\d{2}$/
|
4
|
+
end
|
5
|
+
|
6
|
+
def error_message
|
7
|
+
" must be a decimal and have 2 digits after the dot"
|
8
|
+
end
|
9
|
+
end
|
data/pag_seguro.gemspec
CHANGED