bankscrap-openbank 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bankscrap/openbank/account.rb +16 -47
- data/lib/bankscrap/openbank/bank.rb +63 -90
- data/lib/bankscrap/openbank/card.rb +22 -44
- data/lib/bankscrap/openbank/utils.rb +18 -7
- data/lib/bankscrap/openbank/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ecc804e009d7b76359f51dddb7fcf92bd1cf48f
|
4
|
+
data.tar.gz: 878ed70101cccb3a52f9a76068ac96a368269147
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9ef1956b469746dc95cabc64051a824018ff3e24655b553fe315b174dfe1d1dfb4cefc31c66ddc2ab028c4492f1cd55578d455ba88f9c1555d57f823c18bacf
|
7
|
+
data.tar.gz: 38274e655d05e2ba0f6a103d38cfc4e597c7e0101d88a02b0028921131473d607f3cdf2bfe0400b1380c9be8e72525f4fb5658954dd47a526c362870de1cad2c
|
@@ -7,7 +7,7 @@ module Bankscrap
|
|
7
7
|
|
8
8
|
attr_accessor :contract_id
|
9
9
|
|
10
|
-
ACCOUNT_ENDPOINT = '/
|
10
|
+
ACCOUNT_ENDPOINT = '/my-money/cuentas/movimientos'.freeze
|
11
11
|
|
12
12
|
# Fetch transactions for the given account.
|
13
13
|
# By default it fetches transactions for the last month,
|
@@ -15,63 +15,32 @@ module Bankscrap
|
|
15
15
|
# Returns an array of BankScrap::Transaction objects
|
16
16
|
def fetch_transactions_for(connection, start_date: Date.today - 1.month, end_date: Date.today)
|
17
17
|
transactions = []
|
18
|
-
end_page = false
|
19
|
-
repo = nil
|
20
|
-
importe_cta = nil
|
21
18
|
|
19
|
+
fields = { producto: contract_id,
|
20
|
+
numeroContrato: id,
|
21
|
+
fechaDesde: format_date(start_date),
|
22
|
+
fechaHasta: format_date(end_date),
|
23
|
+
concepto: '000' }
|
22
24
|
# Loop over pagination
|
23
|
-
until
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
repo = document.at_xpath('//methodResult/repo')
|
29
|
-
importe_cta = document.at_xpath('//methodResult/importeCta')
|
30
|
-
end_page = value_at_xpath(document, '//methodResult/finLista') != 'N'
|
25
|
+
until fields.empty?
|
26
|
+
data = connection.get(ACCOUNT_ENDPOINT, fields: fields)
|
27
|
+
transactions += data['movimientos'].map { |item| build_transaction(item) }
|
28
|
+
fields = next_page_fields(data)
|
31
29
|
end
|
32
30
|
|
33
31
|
transactions
|
34
32
|
end
|
35
33
|
|
36
|
-
def xml_account(connection, from_date, to_date, repo, importe_cta)
|
37
|
-
is_pagination = repo ? 'S' : 'N'
|
38
|
-
xml_from_date = xml_date(from_date)
|
39
|
-
xml_to_date = xml_date(to_date)
|
40
|
-
<<-account
|
41
|
-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.isban.es/webservices/BAMOBI/Cuentas/F_bamobi_cuentas_lip/internet/BAMOBICTA/v1">
|
42
|
-
#{connection.xml_security_header}
|
43
|
-
<soapenv:Body>
|
44
|
-
<v1:listaMovCuentasFechas_LIP facade="BAMOBICTA">
|
45
|
-
<entrada>
|
46
|
-
#{connection.xml_datos_cabecera}
|
47
|
-
<datosConexion>#{connection.user_data.children}</datosConexion>
|
48
|
-
<contratoID>#{contract_id}</contratoID>
|
49
|
-
<fechaDesde>#{xml_from_date}</fechaDesde>
|
50
|
-
<fechaHasta>#{xml_to_date}</fechaHasta>
|
51
|
-
#{importe_cta}
|
52
|
-
<esUnaPaginacion>#{is_pagination}</esUnaPaginacion>
|
53
|
-
#{repo}
|
54
|
-
</entrada>
|
55
|
-
</v1:listaMovCuentasFechas_LIP>
|
56
|
-
</soapenv:Body>
|
57
|
-
</soapenv:Envelope>
|
58
|
-
account
|
59
|
-
end
|
60
|
-
|
61
|
-
def xml_date(date)
|
62
|
-
"<dia>#{date.day}</dia><mes>#{date.month}</mes><anyo>#{date.year}</anyo>"
|
63
|
-
end
|
64
|
-
|
65
34
|
# Build a transaction object from API data
|
66
35
|
def build_transaction(data)
|
67
36
|
Transaction.new(
|
68
37
|
account: self,
|
69
|
-
id:
|
70
|
-
amount: money(data
|
71
|
-
description:
|
72
|
-
effective_date:
|
73
|
-
|
74
|
-
balance: money(data
|
38
|
+
id: data['nummov'],
|
39
|
+
amount: money(data['importe']),
|
40
|
+
description: data['conceptoTabla'],
|
41
|
+
effective_date: parse_date(data['fechaValor']),
|
42
|
+
operation_date: parse_date(data['fechaOperacion']),
|
43
|
+
balance: money(data['saldo'])
|
75
44
|
)
|
76
45
|
end
|
77
46
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'bankscrap'
|
2
2
|
require 'securerandom'
|
3
|
+
require 'json'
|
3
4
|
require 'byebug'
|
4
5
|
require_relative 'account.rb'
|
5
6
|
require_relative 'card.rb'
|
@@ -10,20 +11,18 @@ module Bankscrap
|
|
10
11
|
class Bank < ::Bankscrap::Bank
|
11
12
|
include Utils
|
12
13
|
|
13
|
-
attr_accessor :user_data
|
14
|
-
|
15
14
|
# Define the endpoints for the Bank API here
|
16
|
-
BASE_ENDPOINT = 'https://
|
17
|
-
LOGIN_ENDPOINT = '/
|
18
|
-
PRODUCTS_ENDPOINT = '/
|
19
|
-
USER_AGENT = '
|
15
|
+
BASE_ENDPOINT = 'https://api.openbank.es'.freeze
|
16
|
+
LOGIN_ENDPOINT = '/authenticationcomposite/login'.freeze
|
17
|
+
PRODUCTS_ENDPOINT = '/posicion-global-total'.freeze
|
18
|
+
USER_AGENT = 'okhttp/3.9.1'.freeze
|
20
19
|
|
21
20
|
def initialize(credentials = {})
|
21
|
+
@token_credential = nil
|
22
22
|
super do
|
23
23
|
add_headers(
|
24
|
-
'Content-Type' => '
|
24
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
25
25
|
'User-Agent' => USER_AGENT,
|
26
|
-
'Host' => 'www.openbank.mobi',
|
27
26
|
'Connection' => 'Keep-Alive',
|
28
27
|
'Accept-Encoding' => 'gzip'
|
29
28
|
)
|
@@ -32,7 +31,20 @@ module Bankscrap
|
|
32
31
|
|
33
32
|
def login
|
34
33
|
log 'login'
|
35
|
-
|
34
|
+
login_data = {
|
35
|
+
document: @user,
|
36
|
+
documentType: "N",
|
37
|
+
password: @password,
|
38
|
+
force: true,
|
39
|
+
osVersion: "8.1.0",
|
40
|
+
uuid: "#{SecureRandom.hex(10)[0..2]}-#{SecureRandom.hex(10)[0..6]}",
|
41
|
+
mobileDeviceInfo: { pushEnabled:false,
|
42
|
+
rooted: false,
|
43
|
+
version: "1.1.16",
|
44
|
+
device: "SAMSUNG",
|
45
|
+
platform: "ANDROID" }
|
46
|
+
}
|
47
|
+
post(LOGIN_ENDPOINT, fields: login_data)
|
36
48
|
end
|
37
49
|
|
38
50
|
# Fetch all the accounts for the given user
|
@@ -40,11 +52,19 @@ module Bankscrap
|
|
40
52
|
# Should returns an array of Bankscrap::Account objects
|
41
53
|
def fetch_accounts
|
42
54
|
log 'fetch_accounts'
|
43
|
-
|
44
|
-
|
45
|
-
|
55
|
+
data = get(PRODUCTS_ENDPOINT, fields: { carteras: false,listaSolicitada: 'TODOS',indicadorSaldoPreTarj: false })
|
56
|
+
cuentas = data['datosSalidaCuentas']['cuentas'].zip(data['datosSalidaCodIban']['datosIban'])
|
57
|
+
cuentas.map{ |data| build_account(data) }
|
46
58
|
end
|
47
59
|
|
60
|
+
# Fetch all the cards for the given user
|
61
|
+
#
|
62
|
+
# Should returns an array of Bankscrap::Card objects
|
63
|
+
def fetch_cards
|
64
|
+
log 'fetch_cards'
|
65
|
+
data = get(PRODUCTS_ENDPOINT, fields: { carteras: false,listaSolicitada: 'TODOS',indicadorSaldoPreTarj: false })
|
66
|
+
data['datosSalidaTarjetas']['tarjetas'].map{ |data| build_card(data) }
|
67
|
+
end
|
48
68
|
# Fetch transactions for the given account.
|
49
69
|
#
|
50
70
|
# Account should be a Bankscrap::Account object
|
@@ -53,57 +73,32 @@ module Bankscrap
|
|
53
73
|
product.fetch_transactions_for(self, start_date: start_date, end_date: end_date)
|
54
74
|
end
|
55
75
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
<wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SSOToken" ValueType="esquema" EncodingType="hwsse:Base64Binary">#{@token_credential}</wsse:BinarySecurityToken>
|
61
|
-
</wsse:Security>
|
62
|
-
</soapenv:Header>
|
63
|
-
security
|
64
|
-
end
|
65
|
-
|
66
|
-
def xml_datos_cabecera
|
67
|
-
<<-datos
|
68
|
-
<datosCabecera>
|
69
|
-
<version>3.0.4</version>
|
70
|
-
<terminalID>Android</terminalID>
|
71
|
-
<idioma>es-ES</idioma>
|
72
|
-
</datosCabecera>
|
73
|
-
datos
|
76
|
+
def post(method, fields: {})
|
77
|
+
set_auth_headers()
|
78
|
+
response = super(BASE_ENDPOINT + method, fields: JSON.generate(fields))
|
79
|
+
parse_context(response)
|
74
80
|
end
|
75
81
|
|
76
|
-
def
|
77
|
-
|
82
|
+
def get(method, fields: {})
|
83
|
+
set_auth_headers()
|
84
|
+
response = super(BASE_ENDPOINT + method, params: fields)
|
78
85
|
parse_context(response)
|
79
86
|
end
|
80
87
|
|
81
88
|
private
|
82
89
|
|
83
|
-
def xml_products
|
84
|
-
<<-products
|
85
|
-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.isban.es/webservices/BAMOBI/Posglobal/F_bamobi_posicionglobal_lip/internet/BAMOBIPGL/v1">
|
86
|
-
#{xml_security_header}
|
87
|
-
<soapenv:Body>
|
88
|
-
<v1:obtenerPosGlobal_LIP facade="BAMOBIPGL">
|
89
|
-
<entrada>#{xml_datos_cabecera}</entrada>
|
90
|
-
</v1:obtenerPosGlobal_LIP>
|
91
|
-
</soapenv:Body>
|
92
|
-
</soapenv:Envelope>
|
93
|
-
products
|
94
|
-
end
|
95
|
-
|
96
90
|
# Build an Account object from API data
|
97
91
|
def build_account(data)
|
92
|
+
account, iban = data
|
98
93
|
Account.new(
|
99
94
|
bank: self,
|
100
|
-
id:
|
101
|
-
name:
|
102
|
-
available_balance: money(
|
103
|
-
balance: money(
|
104
|
-
iban:
|
105
|
-
description:
|
106
|
-
contract_id:
|
95
|
+
id: account['cviejo']['numerodecontrato'],
|
96
|
+
name: account.fetch('descripcion', '').strip(),
|
97
|
+
available_balance: money(account['saldoActual']),
|
98
|
+
balance: money(account['saldoActual']),
|
99
|
+
iban: iban['codIban'].values().join.strip,
|
100
|
+
description: account.fetch('descripcion', '').strip(),
|
101
|
+
contract_id: account['cviejo']['subgrupo']
|
107
102
|
)
|
108
103
|
end
|
109
104
|
|
@@ -111,53 +106,31 @@ module Bankscrap
|
|
111
106
|
def build_card(data)
|
112
107
|
Card.new(
|
113
108
|
bank: self,
|
114
|
-
id:
|
115
|
-
name:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
description:
|
120
|
-
contract_id: data
|
109
|
+
id: data['contrato']['numerodecontrato'],
|
110
|
+
name: data['panmdp'],
|
111
|
+
avaliable: money(data['saldoDisponible']),
|
112
|
+
amount: money(data['saldoDispuesto']),
|
113
|
+
pan: data['panmdp'],
|
114
|
+
description: data['descripcion'],
|
115
|
+
contract_id: data['contrato']['producto'],
|
116
|
+
is_credit: data['tipoTarjeta'].to_s == "credit"
|
121
117
|
)
|
122
118
|
end
|
123
119
|
|
124
|
-
def parse_context(
|
125
|
-
|
126
|
-
@
|
127
|
-
|
128
|
-
self.user_data = document.at_xpath('//methodResult/datosUsuario') || user_data
|
129
|
-
document
|
130
|
-
end
|
131
|
-
|
132
|
-
def public_ip
|
133
|
-
log 'getting public ip'
|
134
|
-
ip = open('http://api.ipify.org').read
|
135
|
-
log "public ip: [#{ip}]"
|
136
|
-
ip
|
120
|
+
def parse_context(data)
|
121
|
+
context = JSON.parse(data)
|
122
|
+
@token_credential = context.fetch('tokenCredential', @token_credential)
|
123
|
+
context
|
137
124
|
end
|
138
125
|
|
139
126
|
def format_user(user)
|
140
127
|
user.upcase
|
141
128
|
end
|
142
129
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
<v:Body>
|
148
|
-
<n0:authenticateCredential xmlns:n0="http://www.isban.es/webservices/TECHNICAL_FACADES/Security/F_facseg_security/internet/loginServicesNSegWS/v1" facade="loginServicesNSegWS">
|
149
|
-
<CB_AuthenticationData i:type=":CB_AuthenticationData">
|
150
|
-
<documento i:type=":documento">
|
151
|
-
<CODIGO_DOCUM_PERSONA_CORP i:type="d:string">#{@user}</CODIGO_DOCUM_PERSONA_CORP>
|
152
|
-
<TIPO_DOCUM_PERSONA_CORP i:type="d:string">N</TIPO_DOCUM_PERSONA_CORP>
|
153
|
-
</documento>
|
154
|
-
<password i:type="d:string">#{@password}</password>
|
155
|
-
</CB_AuthenticationData>
|
156
|
-
<userAddress i:type="d:string">#{public_ip}</userAddress>
|
157
|
-
</n0:authenticateCredential>
|
158
|
-
</v:Body>
|
159
|
-
</v:Envelope>
|
160
|
-
login
|
130
|
+
def set_auth_headers
|
131
|
+
headers = {}
|
132
|
+
headers['openbankauthtoken'] = @token_credential unless @token_credential.nil?
|
133
|
+
add_headers(headers) unless headers.empty?
|
161
134
|
end
|
162
135
|
end
|
163
136
|
end
|
@@ -2,10 +2,12 @@ require_relative 'utils.rb'
|
|
2
2
|
|
3
3
|
module Bankscrap
|
4
4
|
module Openbank
|
5
|
-
class Card <
|
5
|
+
class Card < ::Bankscrap::Card
|
6
6
|
include Utils
|
7
7
|
|
8
|
-
|
8
|
+
attr_accessor :contract_id
|
9
|
+
|
10
|
+
CARD_ENDPOINT = '/my-money/tarjetas/movimientosCategoria'.freeze
|
9
11
|
|
10
12
|
# Fetch transactions for the given account.
|
11
13
|
# By default it fetches transactions for the last month,
|
@@ -13,60 +15,36 @@ module Bankscrap
|
|
13
15
|
# Returns an array of BankScrap::Transaction objects
|
14
16
|
def fetch_transactions_for(connection, start_date: Date.today - 1.month, end_date: Date.today)
|
15
17
|
transactions = []
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
fields = { producto: contract_id,
|
19
|
+
numeroContrato: id,
|
20
|
+
pan: pan,
|
21
|
+
fechaDesde: format_date(start_date),
|
22
|
+
fechaHasta: format_date(end_date)
|
23
|
+
}
|
19
24
|
# Loop over pagination
|
20
|
-
until
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
repos = document.at_xpath('//methodResult/repos')
|
26
|
-
end_page = value_at_xpath(document, '//methodResult/finLista') != 'N'
|
25
|
+
until fields.empty?
|
26
|
+
data = connection.get(CARD_ENDPOINT, fields: fields)
|
27
|
+
transactions += data['lista']['movimientos'].map { |data| build_transaction(data) }.compact
|
28
|
+
fields = next_page_fields(data)
|
27
29
|
end
|
28
30
|
|
29
31
|
transactions
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
33
|
-
|
34
|
-
xml_from_date = xml_date(from_date)
|
35
|
-
xml_to_date = xml_date(to_date)
|
36
|
-
<<-card
|
37
|
-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.isban.es/webservices/BAMOBI/Tarjetas/F_bamobi_tarjetas_lip/internet/BAMOBITAJ/v1">
|
38
|
-
#{connection.xml_security_header}
|
39
|
-
<soapenv:Body>
|
40
|
-
<v1:listaMovTarjetasFechas_LIP facade="BAMOBITAJ">
|
41
|
-
<entrada>
|
42
|
-
<datosConexion>#{connection.user_data.children}</datosConexion>
|
43
|
-
#{connection.xml_datos_cabecera}
|
44
|
-
<contratoTarjeta>#{contract_id}</contratoTarjeta>
|
45
|
-
<numeroTarj>#{id}</numeroTarj>
|
46
|
-
<fechaDesde>#{xml_from_date}</fechaDesde>
|
47
|
-
<fechaHasta>#{xml_to_date}</fechaHasta>
|
48
|
-
<esUnaPaginacion>#{is_pagination}</esUnaPaginacion>
|
49
|
-
#{repos}
|
50
|
-
</entrada>
|
51
|
-
</v1:listaMovTarjetasFechas_LIP>
|
52
|
-
</soapenv:Body>
|
53
|
-
</soapenv:Envelope>
|
54
|
-
card
|
55
|
-
end
|
56
|
-
|
57
|
-
def xml_date(date)
|
58
|
-
"<dia>#{date.day}</dia><mes>#{date.month}</mes><anyo>#{date.year}</anyo>"
|
34
|
+
def fetch_transactions(start_date: Date.today - 2.years, end_date: Date.today)
|
35
|
+
fetch_transactions_for(bank, start_date: start_date, end_date: end_date)
|
59
36
|
end
|
60
37
|
|
61
38
|
# Build a transaction object from API data
|
62
39
|
def build_transaction(data)
|
40
|
+
return if data['estadoPeticion'] == 'L'
|
63
41
|
Transaction.new(
|
64
42
|
account: self,
|
65
|
-
id:
|
66
|
-
amount: money(data
|
67
|
-
description:
|
68
|
-
effective_date:
|
69
|
-
|
43
|
+
id: data['numeroMovimintoEnDia'],
|
44
|
+
amount: money(data['impOperacion']),
|
45
|
+
description: data['txtCajero'],
|
46
|
+
effective_date: parse_date(data['fechaAnotacionMovimiento']),
|
47
|
+
operation_date: parse_date(data['fechaMovimiento']),
|
70
48
|
balance: Money.new(0, 'EUR') # TODO: Prepaid/debit cards don't have a Balance - maybe Credit ones do.
|
71
49
|
)
|
72
50
|
end
|
@@ -1,17 +1,28 @@
|
|
1
1
|
module Bankscrap
|
2
2
|
module Openbank
|
3
3
|
module Utils
|
4
|
-
def value_at_xpath(node, xpath, default = '')
|
5
|
-
value = node.at_xpath(xpath)
|
6
|
-
value ? value.content.strip : default
|
7
|
-
end
|
8
4
|
|
9
|
-
def money(data
|
5
|
+
def money(data)
|
10
6
|
Money.new(
|
11
|
-
|
12
|
-
|
7
|
+
data['importe'] * 100.0,
|
8
|
+
data['divisa'].presence || 'EUR'
|
13
9
|
)
|
14
10
|
end
|
11
|
+
|
12
|
+
def parse_date(date)
|
13
|
+
Date.strptime(date, '%Y-%m-%d')
|
14
|
+
end
|
15
|
+
|
16
|
+
def format_date(date)
|
17
|
+
"%04d-%02d-%02d" % [date.year, date.month, date.day]
|
18
|
+
end
|
19
|
+
|
20
|
+
def next_page_fields(data)
|
21
|
+
link = data&.fetch('_links', nil)&.fetch('nextPage', nil)&.fetch('href', nil)
|
22
|
+
return {} unless link
|
23
|
+
uri = URI.parse(link)
|
24
|
+
URI::decode_www_form(uri.query).to_h
|
25
|
+
end
|
15
26
|
end
|
16
27
|
end
|
17
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bankscrap-openbank
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zjuanma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bankscrap
|
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
106
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.6.14
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: Openbank adapter for Bankscrap
|