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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1b65647a5159a87170071f62b9e436746cc82e0
4
- data.tar.gz: f29fa5cf4c2ab71265e6c73beb806e71ce92ea0d
3
+ metadata.gz: 7ecc804e009d7b76359f51dddb7fcf92bd1cf48f
4
+ data.tar.gz: 878ed70101cccb3a52f9a76068ac96a368269147
5
5
  SHA512:
6
- metadata.gz: 9e0d44b99398209c21b48c6c34ac64b6c6c2d9af3d3aaaa4ea5da443024f0bb5a5687493841b6d16a22c9738ef62ec4b2937efefa567b8f6cf94777759e0bbfd
7
- data.tar.gz: 7deac7f651ea8e0445b4bcd390358755a0ea89ec4af3976a706ebde8c6b1a642e2baff4df3eae68b2b7e34192d2ba72fba10fc71ce2979a72eca4fa138961fe5
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 = '/OPB_BAMOBI_WS_ENS/ws/BAMOBI_WS_Def_Listener'.freeze
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 end_page
24
- document = connection.post(ACCOUNT_ENDPOINT, fields: xml_account(connection, start_date, end_date, repo, importe_cta))
25
-
26
- transactions += document.xpath('//listadoMovimientos/movimiento').map { |data| build_transaction(data) }
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: value_at_xpath(data, 'numeroMovimiento'),
70
- amount: money(data, 'importe'),
71
- description: value_at_xpath(data, 'descripcion'),
72
- effective_date: Date.strptime(value_at_xpath(data, 'fechaValor'), '%Y-%m-%d'),
73
- # TODO: Bankscrap has no interface to add operation date
74
- balance: money(data, 'importeSaldo')
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://www.openbank.mobi'.freeze
17
- LOGIN_ENDPOINT = '/OPBMOV_IPAD_NSeg_ENS/ws/QUIZ_Def_Listener'.freeze
18
- PRODUCTS_ENDPOINT = '/OPB_BAMOBI_WS_ENS/ws/BAMOBI_WS_Def_Listener'.freeze
19
- USER_AGENT = 'Dalvik/1.6.0 (Linux; U; Android 4.4.4; XT1032 Build/KXB21.14-L1.40)'.freeze
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' => 'text/xml; charset=utf-8',
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
- post(LOGIN_ENDPOINT, fields: xml_login(public_ip))
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
- document = post(PRODUCTS_ENDPOINT, fields: xml_products)
44
- document.xpath('//cuentas/cuenta').map { |data| build_account(data) } +
45
- document.xpath('//tarjetas/tarjeta').map { |data| build_card(data) }
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 xml_security_header
57
- <<-security
58
- <soapenv:Header>
59
- <wsse:Security SOAP-ENV:actor="http://www.isban.es/soap/actor/wssecurityB64" SOAP-ENV:mustUnderstand="1" S12:role="wsssecurity" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:S12="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
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 post(method, fields: {})
77
- response = super(BASE_ENDPOINT + method, fields: fields)
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: value_at_xpath(data, 'comunes/contratoID/NUMERO_DE_CONTRATO'),
101
- name: value_at_xpath(data, 'comunes/descContrato'),
102
- available_balance: money(data, 'importeDispAut'),
103
- balance: money(data, 'impSaldoActual'),
104
- iban: value_at_xpath(data, 'IBAN').tr(' ', ''),
105
- description: value_at_xpath(data, 'comunes/alias') || value_at_xpath(data, 'comunes/descContrato'),
106
- contract_id: data.at_xpath('contratoIDViejo').children.to_s
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: value_at_xpath(data, 'pan'),
115
- name: value_at_xpath(data, 'comunes/descContrato'),
116
- available_balance: money(data, 'impDisponible'),
117
- balance: money(data, 'impSaldoDispuesto'),
118
- iban: value_at_xpath(data, 'comunes/contratoID'),
119
- description: "#{value_at_xpath(data, 'comunes/alias') || value_at_xpath(data, 'comunes/descContrato')} (#{value_at_xpath(data, 'descTipoTarjeta')})",
120
- contract_id: data.at_xpath('comunes/contratoID').children.to_s
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(xml)
125
- document = Nokogiri::XML(xml)
126
- @cookie_credential = value_at_xpath(document, '//cookieCredential', @cookie_credential)
127
- @token_credential = value_at_xpath(document, '//tokenCredential', @token_credential)
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 xml_login(public_ip)
144
- <<-login
145
- <v:Envelope xmlns:v="http://schemas.xmlsoap.org/soap/envelope/" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
146
- <v:Header />
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 < Account
5
+ class Card < ::Bankscrap::Card
6
6
  include Utils
7
7
 
8
- CARD_ENDPOINT = '/OPB_BAMOBI_WS_ENS/ws/BAMOBI_WS_Def_Listener'.freeze
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
- end_page = false
17
- repos = nil
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 end_page
21
- document = connection.post(CARD_ENDPOINT, fields: xml_card(connection, start_date, end_date, repos))
22
-
23
- transactions += document.xpath('//lista/dato').map { |data| build_transaction(data) }
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 xml_card(connection, from_date, to_date, repos)
33
- is_pagination = repos ? 'S' : 'N'
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: value_at_xpath(data, 'movimDia'),
66
- amount: money(data, 'importeMovto'),
67
- description: value_at_xpath(data, 'descMovimiento'),
68
- effective_date: Date.strptime(value_at_xpath(data, 'fechaAnota'), '%Y-%m-%d'),
69
- # operation_date: Date.strptime(value_at_xpath(data, 'fechaOpera'), "%Y-%m-%d"),
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, xpath)
5
+ def money(data)
10
6
  Money.new(
11
- value_at_xpath(data, xpath + '/IMPORTE').delete('.'),
12
- value_at_xpath(data, xpath + '/DIVISA')
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
@@ -1,5 +1,5 @@
1
1
  module Bankscrap
2
2
  module Openbank
3
- VERSION = '2.0.0'.freeze
3
+ VERSION = '3.0.0'.freeze
4
4
  end
5
5
  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: 2.0.0
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: 2017-04-29 00:00:00.000000000 Z
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.4.8
107
+ rubygems_version: 2.6.14
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Openbank adapter for Bankscrap