fake_bsmobil 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 63b52174e5d7028294318290e33ba350999a2f39
4
+ data.tar.gz: b661647384395a509587483e4f6af6601e396226
5
+ SHA512:
6
+ metadata.gz: 25074d725cea8cc8c5d871df6c3989ac2b6627e05bc8c009bbf6b5a2c61ea49c3d62287131ce4abd900ea112cc791910cae52f8e5c50c3c49a67687ce3931ba6
7
+ data.tar.gz: 16512f9b1b09b8e989bb9a4d69a7b8e952d495cfcf7a0605f43517bdc1a92ef930f3c912da2aa1c6d7fa175c9c6e3e1489feda5896269fc2ee5994dd6972405b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.1
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fake_bsmobil.gemspec
4
+ gemspec
5
+
6
+
7
+ group :development do
8
+ gem 'shotgun', require: false
9
+ gem 'pry-byebug'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Michal Cichra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # FakeBsmobil
2
+
3
+ FakeBsmobil is Ruby implementation of Fake Banc Sabadell API.
4
+
5
+ Useful for testing client libraries.
6
+
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'fake_bsmobil'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install fake_bsmobil
23
+
24
+ ## Usage
25
+
26
+
27
+ ```ruby
28
+ run FakeBsmobil.freeze.app
29
+ ```
30
+
31
+ ## Development
32
+
33
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
34
+
35
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
36
+
37
+ ## TODO
38
+
39
+ - Instead of generating new CC, Account, Movements, etc. info, have a data store
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it ( https://github.com/mikz/fake_bsmobil/fork )
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fake_bsmobil"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/config.ru ADDED
@@ -0,0 +1,3 @@
1
+ require 'fake_bsmobil'
2
+
3
+ run FakeBsmobil::Api.freeze.app
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'fake_bsmobil/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fake_bsmobil"
8
+ spec.version = FakeBsmobil::VERSION
9
+ spec.authors = ["Michal Cichra"]
10
+ spec.email = ["michal@o2h.cz"]
11
+
12
+ spec.summary = %q{Ruby server faking Bank Sabadell mobile API}
13
+ spec.description = %q{Ruby API faking Bank Sabadell API. Useful for testing clients.}
14
+ spec.homepage = "https://github.com/mikz/fake_bsmobil"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_runtime_dependency 'roda', '~> 2.1'
26
+ spec.add_runtime_dependency 'json-schema'
27
+ spec.add_runtime_dependency 'faker'
28
+ end
@@ -0,0 +1,140 @@
1
+ require 'fake_bsmobil'
2
+
3
+ require 'roda'
4
+
5
+ module FakeBsmobil
6
+
7
+ class Api < Roda
8
+
9
+ DEFAULT_HEADERS = {
10
+ 'Server' => 'BancSabadell',
11
+ 'Access-Control-Allow-Credentials' => 'true',
12
+ 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE',
13
+ 'Access-Control-Allow-Headers' => 'Content-Type, Accept, Content-Length, Accept-Language',
14
+ 'Access-Control-Max-Age' => '1800',
15
+ 'Content-Type' => 'application/vnd.idk.bsmobil-v2+json;charset=UTF-8',
16
+ 'P3P' => 'CP="NOI DEVa TAIa OUR BUS UNI STA OTC"'
17
+ # TODO: missing caching headers
18
+ }.freeze
19
+
20
+ plugin :json
21
+
22
+ def validation_error
23
+ {
24
+ error_message: 'Some of the data entered are invalid or a required field is empty. Please check the data and try again.',
25
+ code: ''
26
+ }
27
+ end
28
+
29
+ def session_id
30
+
31
+ end
32
+
33
+ plugin :param_matchers
34
+ plugin :header_matchers
35
+ plugin :hash_matcher
36
+
37
+ hash_matcher :content_type do |v|
38
+ self.content_type == v
39
+ end
40
+
41
+ JSON_TYPE = 'application/json'.freeze
42
+
43
+ route do |r|
44
+
45
+ def r.post(*args, &block)
46
+ args << { content_type: JSON_TYPE }
47
+ super
48
+ end
49
+
50
+ r.on 'bsmobil/api', accept: 'application/vnd.idk.bsmobil-v2+json', header: 'Content-Type' do |content_type|
51
+
52
+
53
+ response.headers.merge!(DEFAULT_HEADERS)
54
+
55
+ r.post 'session' do
56
+ response.status = 201
57
+
58
+ begin
59
+ user = FakeBsmobil.session(request.body.read)
60
+ session = FakeBsmobil.generate_session_id
61
+ response.headers['Set-Cookie'] = "JSESSIONID=#{session}; Path=/bsmobil"
62
+ user
63
+ rescue FakeBsmobil::ValidationError
64
+ validation_error
65
+ end
66
+ end
67
+
68
+ r.post 'activeagent' do
69
+ {
70
+ name: name = Generator.name,
71
+ phone: Generator.phone_number(prefix: nil),
72
+ email: Generator.email(name: name, domain: 'sabadellatlantico.com'),
73
+ office: "0140",
74
+ dni: Generator.dni,
75
+ activeAgent: false,
76
+ picture: '',
77
+ available: true
78
+ }
79
+ end
80
+
81
+ r.get 'products' do
82
+ FakeBsmobil.products
83
+ end
84
+
85
+ r.on 'accounts' do
86
+ r.is do
87
+ r.get do
88
+ FakeBsmobil.accounts
89
+ end
90
+ end
91
+
92
+ r.post 'movements' do
93
+ # request body is :
94
+ # {
95
+ # "moreRequest": false,
96
+ # "account": {
97
+ # "number": "0092-0230-39-0011343732"
98
+ # },
99
+ # "dateFrom": "",
100
+ # "dateTo": ""
101
+ # }
102
+ FakeBsmobil.account_movements(request.body.read)
103
+ end
104
+ end
105
+
106
+ r.on 'cards' do
107
+
108
+ r.is(param!: :filter) do |filter|
109
+ r.get do
110
+ FakeBsmobil.cards(filter)
111
+ end
112
+ end
113
+
114
+
115
+ r.on 'movements' do
116
+
117
+ r.post 'unconfirmed' do
118
+
119
+ # request body is:
120
+ # {"card":{"realNumber":"5402131445633169"}}
121
+ FakeBsmobil.unconfirmed_card_movements(request.body.read)
122
+ # NotFound: { "errorMessage": "Z10570: -", "code": "" }
123
+ # missing realNumber: { "errorMessage": "Z26454: Transaction not carried out. Please contact our Customer Care service.", "code": "" }
124
+ # invalid field: { "errorMessage": "Could not read JSON: Unrecognized field \"realNumberr\"", "code": "" }
125
+ end
126
+
127
+ r.post 'confirmed' do
128
+ # request body is:
129
+ # { card: { realNumber: "5402131445633169" }}
130
+ FakeBsmobil.confirmed_card_movements(request.body.read)
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,5 @@
1
+ module FakeBsmobil
2
+ class Datastore
3
+
4
+ end
5
+ end
@@ -0,0 +1,130 @@
1
+ module FakeBsmobil
2
+ module Generator
3
+ module Movements
4
+ module_function
5
+
6
+ def withdrawal(timestamp: Util.timestamp)
7
+ movement = Util.card(timestamp: timestamp, amount: Util.negative(1000))
8
+
9
+ movement.merge(
10
+ concept: "WITHDRAWAL ATM #{Util.card_number} #{timestamp.strftime('%d.%m')}",
11
+ conceptCode: "01",
12
+ conceptDetail: "CHECKS - WITHDRAWALS",
13
+ referencor: "#{movement[:referencor]} #{Generator.number(12)}",
14
+ )
15
+ end
16
+
17
+ def purchase
18
+ Util.card(amount: Util.negative(100)).merge(
19
+ concept: "PURCHASE WITH CARD #{Util.card_number} #{Util.company_name}",
20
+ conceptCode: "12",
21
+ conceptDetail: "CREDIT CARDS - DEBITS CARDS"
22
+ )
23
+ end
24
+
25
+ def commission
26
+ Util.card(amount: Util.negative(10)).merge(
27
+ concept: "NON-EURO CURRENCY COMMISSION ",
28
+ canSplit: false,
29
+ conceptCode: "06",
30
+ conceptDetail: "REMITTANCE OF BILLS"
31
+ )
32
+ end
33
+
34
+ def transfer(timestamp: Util.timestamp)
35
+ Util.basic(amount: Util.negative(1000), timestamp: timestamp).merge(
36
+ concept: "TRANSFER A #{Util.full_name}",
37
+ canSplit: false,
38
+ existDocument: true,
39
+ conceptCode: "04",
40
+ conceptDetail: "DRAFTS - INTERBANK TRANSFERS - INTRABANK TRANSFERS - CHECKS",
41
+ referencor: "#{Generator.number(4)}#{timestamp.strftime('%Y-%m-%d %H:%M:%S')} 01 EUR #{Generator.number(6)}DV #{Generator.number(29)}",
42
+ )
43
+ end
44
+
45
+ def salary
46
+ Util.basic(amount: Util.positive(5000)).merge(
47
+ concept: "SALARY PAYMENT #{Util.company_name}",
48
+ existDocument: true,
49
+ conceptCode: "15",
50
+ conceptDetail: "SALARIES - SOCIAL SECURITY",
51
+ referencor: "#{Generator.number(6)} #{Generator.number(15)} 01 P EUR #{Generator.number(20)}CAIX#{Generator.number(25)}",
52
+ )
53
+ end
54
+
55
+ def random
56
+ (self.methods - self.class.methods - [__method__]).sample
57
+ end
58
+
59
+ module Util
60
+ module_function
61
+
62
+ def basic(timestamp: Util.timestamp, amount:, balance: positive(1000))
63
+ puts "{ timestamp: #{timestamp}, amount: #{amount}, balance: #{balance} }"
64
+ {
65
+ date: date = timestamp.strftime('%d-%m-%y'),
66
+ valueDate: (timestamp + [0, 0, 0, 1].sample).strftime('%d-%m-%y'),
67
+ canSplit: amount < -200,
68
+ amount: Util.currency(amount),
69
+ balance: Util.currency(balance + amount),
70
+ apuntNumber: Generator.number(12),
71
+ existDocument: false,
72
+ cardNumber: '',
73
+ productCode: '0',
74
+ numPAN: '',
75
+ returnBillCode: '',
76
+ timeStamp: timestamp.strftime('%Y%m%d%H%M%S%6N'),
77
+ sessionDate: date
78
+ }
79
+ end
80
+
81
+ def timestamp
82
+ (Faker::Date.backward.to_time + rand(24*60*60)).to_datetime
83
+ end
84
+
85
+ def card(timestamp: Util.timestamp, **options)
86
+ puts "{timestamp: #{timestamp}, #{options}}"
87
+ basic(timestamp: timestamp, **options).merge(
88
+ numPAN: card = full_card_number,
89
+ referencor: "#{card} #{timestamp.strftime('%Y-%m-%d %H:%M:%S')}",
90
+ )
91
+ end
92
+
93
+ # TODO: let generator generate card
94
+ def card_number
95
+ card = full_card_number.scan(/(\d{4})/)
96
+ card[2] = card[1] = 'X' * 4
97
+ card.join
98
+ end
99
+
100
+ def company_name
101
+ Faker::Company.name.upcase
102
+ end
103
+
104
+ def full_name
105
+ Faker::Name.name
106
+ end
107
+
108
+ def full_card_number
109
+ "5402#{Generator.number(12)}"
110
+ end
111
+
112
+ def positive(value)
113
+ rand(value).to_f
114
+ end
115
+
116
+ def negative(value)
117
+ rand(value).to_f * -1
118
+ end
119
+
120
+ def currency(amount)
121
+ # FIXME: this is possibly buggy implementation taken from SO
122
+ value = amount.to_f.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
123
+ { value: value, currency: 'EUR' }
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+
130
+ end
@@ -0,0 +1,222 @@
1
+ require 'faker'
2
+
3
+ module FakeBsmobil
4
+ module Generator
5
+ autoload :Movements, 'fake_bsmobil/generator/movements'
6
+
7
+ module_function
8
+
9
+ def dni
10
+ letters = ['' , 'N', 'Y']
11
+ "#{letters.sample}#{Faker::Number.number(7)}#{letters.sample}"
12
+ end
13
+
14
+ def name
15
+ [ Faker::Name.first_name,
16
+ Faker::Name.last_name ].join(' ').upcase
17
+ end
18
+
19
+ def contract_name
20
+ [
21
+ Faker::Name.last_name,
22
+ Faker::Name.first_name
23
+ ].join(' ,').upcase
24
+ end
25
+
26
+ def phone_number(prefix: '+34')
27
+ "#{prefix}#{Faker::Number.number(9)}"
28
+ end
29
+
30
+ def sex
31
+ %w(H M).sample
32
+ end
33
+
34
+ def email(name: self.name, domain: Faker::Internet.domain_name)
35
+ [ Faker::Internet.user_name(name), domain].join('@')
36
+ end
37
+
38
+ def contract_number(length: 10)
39
+ "#{Faker::Number.number(length)}"
40
+ end
41
+
42
+ def person_number
43
+ "#{Faker::Number.number(7)}"
44
+ end
45
+
46
+ def card_id
47
+ "#{Faker::Number.number(7)}"
48
+ end
49
+
50
+ def number(value)
51
+ Faker::Number.number(value)
52
+ end
53
+
54
+ def amount(amount = rand(1_000.0..10_000.0))
55
+ num = ''
56
+
57
+ thousands = amount / 1000
58
+ if thousands > 0
59
+ num += "#{rand(thousands)}."
60
+ end
61
+
62
+ num += '%03d' % [amount, 999].min
63
+ num += '.' << ('%0.2f' % amount).split('.').last
64
+
65
+ { value: num, currency: 'EUR' }
66
+ end
67
+
68
+ def account_number
69
+ [4, 4, 2, 10].map(&Faker::Number.method(:number)).join('-')
70
+ end
71
+
72
+ def iban
73
+ "ES#{Faker::Number.number(22)}"
74
+ end
75
+
76
+ def account(override = {})
77
+ {
78
+ alias: '',
79
+ description: 'CUENTA EXPANSIÓN',
80
+ availability: '',
81
+ owner: name,
82
+ product: '',
83
+ productType: '',
84
+ entityCode: '',
85
+ contractCode: '',
86
+ bic: 'BSAB ESBB',
87
+ number: account_number,
88
+ iban: iban,
89
+ amount: amount,
90
+ numOwners: 0,
91
+ isOwner: false,
92
+ isSBPManaged: false,
93
+ isIberSecurities: false,
94
+ joint: '',
95
+ mobileWarning: ''
96
+ }.merge(override)
97
+ end
98
+
99
+ def full_account(override = {})
100
+ account(override).merge(
101
+ availability: 'TOTAL',
102
+ product: 'DV00083',
103
+ productType: '',
104
+ entityCode: '',
105
+ contractCode: '',
106
+ numOwners: 1,
107
+ isOwner: true,
108
+ isSBPManaged: false,
109
+ isIberSecurities: false,
110
+ joint: 'I',
111
+ mobileWarning: 'A')
112
+ end
113
+
114
+ def debit_card(override = {})
115
+ {
116
+ bsprotect: "S",
117
+ description: "BSCARD MASTERCARD BS",
118
+ isMarsans: "false",
119
+ name: name,
120
+ productType: "TD",
121
+ reference: "0",
122
+ type: "OPERAC.",
123
+ shortDescription: "BSCARD MASTERCARD BS",
124
+ number: "5402________#{card_tail = number(4)}",
125
+ realNumber: "5402#{number(8)}#{card_tail}",
126
+ numcard: "TA #{number(5)}",
127
+ isOwner: true,
128
+ activatedLE: "P",
129
+ codret: "",
130
+ contractCCC: number(20),
131
+ operativeCode: "4",
132
+ cvv2: " ",
133
+ dni: "",
134
+ entity: "",
135
+ mail: "",
136
+ mailChecked: "",
137
+ phoneNumber: "",
138
+ phoneNumberChecked: "",
139
+ alias: "",
140
+ expirationDate: "",
141
+ balance: {value: "", currency: ""},
142
+ availableBalance: {value: "", currency: ""},
143
+ dms: "",
144
+ indAlert: "",
145
+ selectableIndex: "",
146
+ canActivate: false,
147
+ cardType: {
148
+ background: "1",
149
+ type: "mastercard",
150
+ subtype: "debit",
151
+ textColor: "#ffffff",
152
+ iconColor: "#ffffff",
153
+ logo: "mastercard1"
154
+ },
155
+ status: "active",
156
+ availableOperations: [],
157
+ isInternational: true,
158
+ isInternet: true,
159
+ isSticker: true,
160
+ stickerCard: false,
161
+ nfcCard: {
162
+ isNfc: true,
163
+ isActive: false,
164
+ expirationDate: Faker::Date.forward.strftime('%d-%m-%y')
165
+ },
166
+ stickerPan: "",
167
+ deteriorationLock: false,
168
+ isPrepaidAnonymous: false
169
+ }.merge(override)
170
+ end
171
+
172
+
173
+ def movement
174
+ Movements.send(Movements.random)
175
+ end
176
+
177
+ def confirmed_card_movement
178
+ city = Faker::Address.city
179
+
180
+ concept = case %w(cajero company).sample
181
+ when 'cajero'
182
+ "CAJERO #{Faker::Company.name[0, 10].ljust(10, ' ')} OF.#{number(4)}".upcase
183
+ when 'company'
184
+ company = Faker::Company.name
185
+ rand > 0.7 ? company.upcase : company
186
+ end
187
+ {
188
+ movementNumber: number(4),
189
+ concept: concept,
190
+ date: Faker::Date.backward.strftime('%d-%m-%Y'),
191
+ city: city = rand > 0.7 ? city.upcase : city,
192
+ canSplit: false,
193
+ amount: a = amount(rand(1..300)),
194
+ indFracEnabled: true,
195
+ indMov: "1",
196
+ isTraspasable: false,
197
+ commission: {:value => "0,00", :currency => "EUR"},
198
+ originAmount: a,
199
+ address: city,
200
+ point: nil
201
+ }
202
+ end
203
+
204
+ def unconfirmed_card_movement
205
+ confirmed_card_movement.merge(movementNumber: '')
206
+ end
207
+
208
+ def confirmed_card_movements(n = 10)
209
+ n.times.map { confirmed_card_movement }
210
+ end
211
+
212
+ def unconfirmed_card_movements(n = 10)
213
+ n.times.map { unconfirmed_card_movement }
214
+ end
215
+
216
+ def movements(account)
217
+ {account: full_account(account),
218
+ accountMovements: 10.times.map { movement },
219
+ moreElements: true}
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,10 @@
1
+ module FakeBsmobil
2
+ module Schema
3
+ # generated from http://jsonschema.net/
4
+
5
+ SESSION = '{"$schema":"http://json-schema.org/draft-04/schema#","id":"http://jsonschema.net","type":"object","properties":{"deviceInfo":{"id":"http://jsonschema.net/deviceInfo","type":"string"},"password":{"id":"http://jsonschema.net/password","type":"string"},"userName":{"id":"http://jsonschema.net/userName","type":"string"},"newDevice":{"id":"http://jsonschema.net/newDevice","type":"boolean"},"contract":{"id":"http://jsonschema.net/contract","type":"string"},"brand":{"id":"http://jsonschema.net/brand","type":"string"},"devicePrint":{"id":"http://jsonschema.net/devicePrint","type":"string"},"requestId":{"id":"http://jsonschema.net/requestId","type":"string"},"geolocationData":{"id":"http://jsonschema.net/geolocationData","type":"string"},"loginType":{"id":"http://jsonschema.net/loginType","type":"integer"}},"required":["deviceInfo","password","userName","newDevice","contract","brand","devicePrint","requestId","geolocationData","loginType"]}'.freeze
6
+ USER = '{"$schema":"http://json-schema.org/draft-04/schema#","id":"http://jsonschema.net","type":"object","properties":{"user":{"id":"http://jsonschema.net/user","type":"object","properties":{"dni":{"id":"http://jsonschema.net/user/dni","type":"string"},"name":{"id":"http://jsonschema.net/user/name","type":"string"},"sex":{"id":"http://jsonschema.net/user/sex","type":"string"},"phoneNumber":{"id":"http://jsonschema.net/user/phoneNumber","type":"string"},"contractNumber":{"id":"http://jsonschema.net/user/contractNumber","type":"string"},"hasMoreContracts":{"id":"http://jsonschema.net/user/hasMoreContracts","type":"boolean"},"customization":{"id":"http://jsonschema.net/user/customization","type":"string"},"isNewUser":{"id":"http://jsonschema.net/user/isNewUser","type":"boolean"},"pendingSignOperations":{"id":"http://jsonschema.net/user/pendingSignOperations","type":"integer"},"personNumber":{"id":"http://jsonschema.net/user/personNumber","type":"string"},"idType":{"id":"http://jsonschema.net/user/idType","type":"string"},"loginType":{"id":"http://jsonschema.net/user/loginType","type":"integer"},"promoLayer":{"id":"http://jsonschema.net/user/promoLayer","type":"object","properties":{"code":{"id":"http://jsonschema.net/user/promoLayer/code","type":"string"},"url":{"id":"http://jsonschema.net/user/promoLayer/url","type":"string"},"nShows":{"id":"http://jsonschema.net/user/promoLayer/nShows","type":"integer"},"exist":{"id":"http://jsonschema.net/user/promoLayer/exist","type":"boolean"}}},"cardId":{"id":"http://jsonschema.net/user/cardId","type":"string"},"refreshActiveAgent":{"id":"http://jsonschema.net/user/refreshActiveAgent","type":"integer"},"signatureType":{"id":"http://jsonschema.net/user/signatureType","type":"string"},"vTPCInscriptionKey":{"id":"http://jsonschema.net/user/vTPCInscriptionKey","type":"string"}},"required":["dni","name","sex","phoneNumber","contractNumber","hasMoreContracts","customization","isNewUser","pendingSignOperations","personNumber","idType","loginType","promoLayer","cardId","refreshActiveAgent","signatureType","vTPCInscriptionKey"]},"isInputTypeNumberSupported":{"id":"http://jsonschema.net/isInputTypeNumberSupported","type":"boolean"}},"required":["user","isInputTypeNumberSupported"]}'.freeze
7
+ CARD = '{"$schema":"http://json-schema.org/draft-04/schema#","id":"http://jsonschema.net","type":"object","properties":{"card":{"id":"http://jsonschema.net/card","type":"object","properties":{"alias":{"id":"http://jsonschema.net/card/alias","type":"string"},"stickerPan":{"id":"http://jsonschema.net/card/stickerPan","type":"string"},"availableBalance":{"id":"http://jsonschema.net/card/availableBalance","type":"object","properties":{"value":{"id":"http://jsonschema.net/card/availableBalance/value","type":"string"},"currency":{"id":"http://jsonschema.net/card/availableBalance/currency","type":"string"}},"additionalProperties":false},"bsprotect":{"id":"http://jsonschema.net/card/bsprotect","type":"string"},"expirationDate":{"id":"http://jsonschema.net/card/expirationDate","type":"null"},"isInternational":{"id":"http://jsonschema.net/card/isInternational","type":"boolean"},"description":{"id":"http://jsonschema.net/card/description","type":"string"},"dms":{"id":"http://jsonschema.net/card/dms","type":"string"},"activatedLE":{"id":"http://jsonschema.net/card/activatedLE","type":"string"},"isMarsans":{"id":"http://jsonschema.net/card/isMarsans","type":"boolean"},"phoneNumberChecked":{"id":"http://jsonschema.net/card/phoneNumberChecked","type":"string"},"type":{"id":"http://jsonschema.net/card/type","type":"string"},"number":{"id":"http://jsonschema.net/card/number","type":"string"},"shortDescription":{"id":"http://jsonschema.net/card/shortDescription","type":"string"},"isPrepaidAnonymous":{"id":"http://jsonschema.net/card/isPrepaidAnonymous","type":"boolean"},"isOwner":{"id":"http://jsonschema.net/card/isOwner","type":"boolean"},"productType":{"id":"http://jsonschema.net/card/productType","type":"string"},"operativeCode":{"id":"http://jsonschema.net/card/operativeCode","type":"string"},"name":{"id":"http://jsonschema.net/card/name","type":"string"},"entity":{"id":"http://jsonschema.net/card/entity","type":"string"},"phoneNumber":{"id":"http://jsonschema.net/card/phoneNumber","type":"string"},"dni":{"id":"http://jsonschema.net/card/dni","type":"string"},"stickerCard":{"id":"http://jsonschema.net/card/stickerCard","type":"boolean"},"mailChecked":{"id":"http://jsonschema.net/card/mailChecked","type":"boolean"},"contractCCC":{"id":"http://jsonschema.net/card/contractCCC","type":"string"},"indAlert":{"id":"http://jsonschema.net/card/indAlert","type":"string"},"isInternet":{"id":"http://jsonschema.net/card/isInternet","type":"boolean"},"codret":{"id":"http://jsonschema.net/card/codret","type":"string"},"cardType":{"id":"http://jsonschema.net/card/cardType","type":"object","properties":{"textColor":{"id":"http://jsonschema.net/card/cardType/textColor","type":"string"},"iconColor":{"id":"http://jsonschema.net/card/cardType/iconColor","type":"string"},"logo":{"id":"http://jsonschema.net/card/cardType/logo","type":"string"},"type":{"id":"http://jsonschema.net/card/cardType/type","type":"string"},"subtype":{"id":"http://jsonschema.net/card/cardType/subtype","type":"string"},"background":{"id":"http://jsonschema.net/card/cardType/background","type":"string"}},"additionalProperties":false},"cvv2":{"id":"http://jsonschema.net/card/cvv2","type":"string"},"selectableIndex":{"id":"http://jsonschema.net/card/selectableIndex","type":"string"},"canActivate":{"id":"http://jsonschema.net/card/canActivate","type":"boolean"},"mail":{"id":"http://jsonschema.net/card/mail","type":"string"},"reference":{"id":"http://jsonschema.net/card/reference","type":"string"},"balance":{"id":"http://jsonschema.net/card/balance","type":"object","properties":{"value":{"id":"http://jsonschema.net/card/balance/value","type":"string"},"currency":{"id":"http://jsonschema.net/card/balance/currency","type":"string"}},"additionalProperties":false},"isSticker":{"id":"http://jsonschema.net/card/isSticker","type":"boolean"},"realNumber":{"id":"http://jsonschema.net/card/realNumber","type":"string"},"numcard":{"id":"http://jsonschema.net/card/numcard","type":"string"}},"additionalProperties":false,"required":["realNumber"]},"paginator":{"id":"http://jsonschema.net/paginator","type":"object","properties":{"itemsPerPage":{"id":"http://jsonschema.net/paginator/itemsPerPage","type":"integer"},"order":{"id":"http://jsonschema.net/paginator/order","type":"string"},"totalItems":{"id":"http://jsonschema.net/paginator/totalItems","type":"integer"},"page":{"id":"http://jsonschema.net/paginator/page","type":"integer"}},"additionalProperties":false}},"additionalProperties":false,"required":["card"]}'.freeze
8
+ ACCOUNT = '{"$schema":"http://json-schema.org/draft-04/schema#","id":"http://jsonschema.net","type":"object","properties":{"moreRequest":{"id":"http://jsonschema.net/moreRequest","type":"boolean"},"account":{"id":"http://jsonschema.net/account","type":"object","properties":{"description":{"id":"http://jsonschema.net/account/description","type":"string"},"mobileWarning":{"id":"http://jsonschema.net/account/mobileWarning","type":"string"},"amount":{"id":"http://jsonschema.net/account/amount","type":"object","properties":{"value":{"id":"http://jsonschema.net/account/amount/value","type":"string"},"currency":{"id":"http://jsonschema.net/account/amount/currency","type":"string"}},"additionalProperties":false},"owner":{"id":"http://jsonschema.net/account/owner","type":"string"},"product":{"id":"http://jsonschema.net/account/product","type":"string"},"isOwner":{"id":"http://jsonschema.net/account/isOwner","type":"boolean"},"iban":{"id":"http://jsonschema.net/account/iban","type":"string"},"isIberSecurities":{"id":"http://jsonschema.net/account/isIberSecurities","type":"boolean"},"availability":{"id":"http://jsonschema.net/account/availability","type":"string"},"alias":{"id":"http://jsonschema.net/account/alias","type":"string"},"number":{"id":"http://jsonschema.net/account/number","type":"string"},"bic":{"id":"http://jsonschema.net/account/bic","type":"string"},"isSBPManaged":{"id":"http://jsonschema.net/account/isSBPManaged","type":"boolean"},"joint":{"id":"http://jsonschema.net/account/joint","type":"string"},"numOwners":{"id":"http://jsonschema.net/account/numOwners","type":"integer"}},"additionalProperties":false},"dateFrom":{"id":"http://jsonschema.net/dateFrom","type":"string"},"dateTo":{"id":"http://jsonschema.net/dateTo","type":"string"}},"additionalProperties":false}'
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module FakeBsmobil
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,201 @@
1
+ require 'fake_bsmobil/version'
2
+ require 'json-schema'
3
+ require 'logger'
4
+ require 'securerandom'
5
+
6
+ module FakeBsmobil
7
+ autoload :Datastore, 'fake_bsmobil/datastore'
8
+ autoload :Api, 'fake_bsmobil/api'
9
+ autoload :Schema, 'fake_bsmobil/schema'
10
+ autoload :Generator, 'fake_bsmobil/generator'
11
+
12
+ module_function
13
+
14
+ def user
15
+ @user
16
+ end
17
+
18
+ def user=(user)
19
+ @user = user
20
+ end
21
+
22
+ def datastore
23
+ @datastore ||= Datastore.new
24
+ end
25
+
26
+ def validator
27
+ JSON::Validator
28
+ end
29
+
30
+ ValidationError = JSON::Schema::ValidationError
31
+
32
+ def logger
33
+ @logger = Logger.new($stdout)
34
+ end
35
+
36
+ def generate_session_id
37
+ @sessions ||= Set.new
38
+ session_id = SecureRandom.base64(18) + '.pmobil3'
39
+ @sessions.add(session_id)
40
+ session_id
41
+ end
42
+
43
+ def generate_user
44
+ {
45
+ dni: Generator.dni,
46
+ name: Generator.name,
47
+ sex: Generator.sex,
48
+ phoneNumber: Generator.phone_number,
49
+ contractNumber: Generator.contract_number,
50
+ hasMoreContracts: false,
51
+ customization: '1H4XX000000032010011010211301211000000000010110011',
52
+ isNewUser: false,
53
+ pendingSignOperations: 0,
54
+ personNumber: Generator.person_number,
55
+ idType: '01',
56
+ loginType: 5,
57
+ promoLayer: {code: '', url: 'resources/mobapp/layers//', nShows: 0, exist: false},
58
+ cardId: Generator.card_id,
59
+ refreshActiveAgent: 10,
60
+ signatureType: 'tpc',
61
+ vTPCInscriptionKey: ''
62
+ }
63
+ end
64
+
65
+ def session(info)
66
+ logger.info info
67
+ validator.validate!(Schema::SESSION, info)
68
+
69
+ {
70
+ user: self.user ||= generate_user,
71
+ isInputTypeNumberSupported: true
72
+
73
+ }
74
+ end
75
+
76
+ def products
77
+ {
78
+ accountProduct: {
79
+ amount: amount = Generator.amount,
80
+ accounts: [ Generator.account(amount: amount) ]
81
+ },
82
+ cardProduct: {
83
+ amount: {value: "0,00", currency: "EUR"},
84
+ cards: [Generator.debit_card]
85
+ },
86
+ investmentProduct: {
87
+ amount: {:value => "", :currency => ""},
88
+ securities: {:amount => {:value => "", :currency => ""}, :accounts => [], :type => ""},
89
+ pensionPlan: {amount: {:value => "", :currency => ""}, accounts: [], type: ""},
90
+ insuredPlanForecast: {amount: {:value => "", :currency => ""}, policies: []},
91
+ investmentFund: {:amount => {:value => "", :currency => ""}, :accounts => [], :type => ""},
92
+ depositProduct: {:amount => {:value => "", :currency => ""}, :accounts => []},
93
+ unknowns: []
94
+ },
95
+ financialProduct: {
96
+ amount: {:value => "0,00", :currency => "EUR"},
97
+ loan: {:amount => {:value => "", :currency => ""}, :accounts => []},
98
+ credit: {:amount => {:value => "", :currency => ""}, :accounts => []},
99
+ expansionLineGP: {amount: {:value => "0,00", :currency => "EUR"},
100
+ expansionLines: []},
101
+ unknowns: []
102
+ },
103
+ other: {amount: {value: "", currency: ""}, unknowns: []}
104
+ }
105
+ end
106
+
107
+ def account_movements(json)
108
+ logger.info json
109
+ validator.validate!(Schema::ACCOUNT, json)
110
+
111
+ account_info = JSON.parse(json).fetch('account') # FIXME: string keys :(
112
+ account = Generator.full_account(account_info)
113
+
114
+ movements(account)
115
+ end
116
+
117
+ def movements(account)
118
+ Generator.movements(account)
119
+ end
120
+
121
+ def accounts
122
+ {
123
+ accounts: [Generator.full_account],
124
+ }.merge(paginator)
125
+ end
126
+
127
+ def cards(_filter)
128
+ {
129
+ cards: [ Generator.debit_card ]
130
+ }.merge(paginator)
131
+ end
132
+
133
+ def unconfirmed_card_movements(json)
134
+ card = load_card(json)
135
+
136
+ card_movements(card).merge(cardMovements: Generator.unconfirmed_card_movements)
137
+ end
138
+
139
+ def card_movements(card)
140
+ {
141
+ contractNumber: Generator.contract_number(length: 15),
142
+ contractOwner: name = Generator.contract_name,
143
+ paymentType: "",
144
+ ptorete: "",
145
+ previousBalance: {value: "0,00", currency: "EUR"},
146
+ currentMonthBalance: {:value => "0,00", :currency => "EUR"},
147
+ totalAmount: Generator.amount,
148
+ pendingLiquidationBalance: {:value => "0,00", :currency => "EUR"},
149
+ availableBalance: {:value => "0,00", :currency => "EUR"},
150
+ willingBalance: {:value => "0,00", :currency => "EUR"},
151
+ chargeAccount: {
152
+ description: "",
153
+ availability: "",
154
+ owner: name,
155
+ product: "",
156
+ productType: "",
157
+ entityCode: "",
158
+ contractCode: "",
159
+ bic: "",
160
+ number: Generator.account_number,
161
+ iban: "",
162
+ amount: {:value => "", :currency => ""},
163
+ numOwners: 0,
164
+ isOwner: false,
165
+ isSBPManaged: false,
166
+ isIberSecurities: false,
167
+ joint: "",
168
+ mobileWarning: ""
169
+ },
170
+ card: card,
171
+ hasUnconfirmedMovements: true
172
+ }.merge(paginator)
173
+ end
174
+
175
+ def confirmed_card_movements(json)
176
+ card = load_card(json)
177
+
178
+ card_movements(card).merge(cardMovements: Generator.confirmed_card_movements)
179
+ end
180
+
181
+ def paginator
182
+ {
183
+ paginator: {
184
+ page: 0,
185
+ itemsPerPage: 20,
186
+ order: 'desc',
187
+ totalItems: 1
188
+ }
189
+ }
190
+ end
191
+
192
+ def load_card(json)
193
+ logger.info json
194
+ validator.validate!(Schema::CARD, json)
195
+
196
+ card_info = JSON.parse(json).fetch('card') # FIXME: string keys :(
197
+
198
+ Generator.debit_card(card_info)
199
+ end
200
+
201
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fake_bsmobil
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michal Cichra
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-04-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: roda
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json-schema
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faker
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ruby API faking Bank Sabadell API. Useful for testing clients.
84
+ email:
85
+ - michal@o2h.cz
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - bin/console
98
+ - bin/setup
99
+ - config.ru
100
+ - fake_bsmobil.gemspec
101
+ - lib/fake_bsmobil.rb
102
+ - lib/fake_bsmobil/api.rb
103
+ - lib/fake_bsmobil/datastore.rb
104
+ - lib/fake_bsmobil/generator.rb
105
+ - lib/fake_bsmobil/generator/movements.rb
106
+ - lib/fake_bsmobil/schema.rb
107
+ - lib/fake_bsmobil/version.rb
108
+ homepage: https://github.com/mikz/fake_bsmobil
109
+ licenses:
110
+ - MIT
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.4.6
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Ruby server faking Bank Sabadell mobile API
132
+ test_files: []