bankscrap-openbank 2.0.0 → 3.0.0
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.
- 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
|