bvr 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ 0.1.0
2
+ -----
3
+ * [More Customer Centric] [https://github.com/gregory/bvr/tree/v0.1.0]
4
+ * Matched all the API in a customer centric way
5
+
6
+ 0.0.1
7
+ -----
8
+ * [Initial release] [https://github.com/gregory/bvr/tree/v0.0.1]
data/Guardfile CHANGED
@@ -9,6 +9,6 @@ guard :minitest do
9
9
 
10
10
  # with Minitest::Spec
11
11
  watch(%r{^spec/(.*)_spec\.rb})
12
- watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
13
  watch(%r{^spec/spec_helper\.rb}) { 'spec' }
14
14
  end
data/README.md CHANGED
@@ -24,11 +24,27 @@ Bvr.configure do |config|
24
24
  config.username, config.password = ['username', 'password']
25
25
  end
26
26
  `
27
- ### Retreiving Call Overview
27
+ ### Retreiving All the info and form, and manage a customer
28
28
  `
29
- Bvr::CallOverview.find('a customer id')
29
+ customer = Bvr::Customer.find('customer_id')
30
+ customer.phones
31
+ customer.phones.add( Bvr::Phone.new('+4412345678') )
32
+ customer.balance
33
+ customer.credit.add(10.20)
34
+ customer.credit.rm(1.20)
35
+ customer.block!
36
+ customer.unblock!
37
+ calls = customer.calls({recordcount: 100})
38
+ calls.count = 250
39
+ calls.size #=> 100
40
+ calls.next? # => true, 150 are left
41
+
42
+ Bvr::Customer.authenticate('customer_id', 'pass')
43
+
30
44
  `
31
45
 
46
+ A lot of class methods are available, just have a look at the specs
47
+
32
48
 
33
49
  ## Contributing
34
50
 
@@ -6,11 +6,11 @@ require 'bvr/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "bvr"
8
8
  spec.version = Bvr::VERSION
9
- spec.authors = ["gregory"]
9
+ spec.authors = ["Gregory Horion"]
10
10
  spec.email = ["greg2502@gmail.com"]
11
11
  spec.description = %q{A ruby interface to Bestvoipreselling API}
12
12
  spec.summary = spec.description
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/gregory/bvr"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "rake"
23
- spec.add_development_dependency 'rack'
24
- spec.add_development_dependency "faraday"
25
- spec.add_development_dependency "happymapper"
22
+ spec.add_development_dependency "rake", "~> 10.1.1"
23
+ spec.add_development_dependency 'rack', "~> 1.5.2"
24
+ spec.add_development_dependency "faraday", "~> 0.8.8"
25
+ spec.add_development_dependency "xml-simple", "~> 1.1.3"
26
26
  end
data/lib/bvr.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'happymapper'
2
1
  Dir[File.dirname(__FILE__) + '/bvr/*.rb'].each{ |file| require file }
3
2
 
4
3
  module Bvr
@@ -11,6 +10,8 @@ module Bvr
11
10
  end
12
11
 
13
12
  def connection
13
+ raise ::Exception.new("Please provide username and password") if @config.nil?
14
+
14
15
  @connection ||= Bvr::Connection.new
15
16
  end
16
17
  end
@@ -1,18 +1,28 @@
1
- require_relative 'phone'
2
1
  module Bvr
3
2
  class Call
4
- include HappyMapper
3
+ attr_accessor :id, :calltype, :raw_start_time, :raw_dest, :raw_duration, :charge
5
4
 
6
- tag 'Call'
7
- attribute :id, String, tag: 'CallId'
8
- attribute :calltype, String, tag: 'CallType'
9
- attribute :start_time, Time, tag: 'StartTime'
10
- attribute :dest, Phone, tag: 'Destination', parser: :phone_number_parser
11
- attribute :duration, String, tag: 'Duration'
12
- attribute :charge, String, tag: 'Charge' #? currency
5
+ def self.new_from_response(h)
6
+ self.new.tap do |call|
7
+ call.id = h['CallId']
8
+ call.calltype = h['CallType']
9
+ call.raw_start_time = h['StartTime']
10
+ call.raw_dest = h['Destination']
11
+ call.raw_duration = h['Duration']
12
+ call.charge = h['Charge']
13
+ end
14
+ end
15
+
16
+ def duration
17
+ @_duration ||= Time.parse(self.raw_duration, self.start_time)
18
+ end
19
+
20
+ def dest
21
+ @_dest ||= Bvr::Phone.new(self.raw_dest)
22
+ end
13
23
 
14
- def relative_duration
15
- Time.parse(self.duration, start_time)
24
+ def start_time
25
+ @_start_time ||= Time.parse(self.raw_start_time)
16
26
  end
17
27
  end
18
28
  end
@@ -0,0 +1,62 @@
1
+ module Bvr
2
+ class CallCollection
3
+ # Valid Options:
4
+ # Variable Value Option Description
5
+ # command calloverview Mandatory
6
+ # username X..140 Mandatory the username of the reseller
7
+ # password X..100 Mandatory the password of the reseller
8
+ # customer X..140 Mandatory the username of the customer
9
+ # date YYYY-MM-DD hh:nn:ss Optional the datetime from which to start retrieving the history, current datetime is default
10
+ # callid N..1000000 Optional the callid from which to start retrieving the history, 0 is default
11
+ # recordcount 1 - 500 Optional the maximum number of records returned, 10 is default, 500 is maximum
12
+ # direction forward / backward Optional the direction to search, backward is default
13
+ VALID_OPTIONS = [:date, :callid, :recordcount, :direction, :customer, :command]
14
+ API_COMMANDS= {
15
+ find_by_customer_id: 'calloverview'
16
+ }
17
+
18
+ attr_accessor :query_params, :raw_count, :raw_more_data, :collection
19
+
20
+ def self.find_by_customer_id(customer_id, options={})
21
+ raise ArgumentError.new('Unknown Argument') unless self.valid_options?(options)
22
+
23
+
24
+ params = {
25
+ command: API_COMMANDS[:find_by_customer_id],
26
+ customer: customer_id
27
+ }
28
+
29
+ response = Bvr.connection.get(params.merge(options))
30
+
31
+ return [] if response['Calls'].nil?
32
+
33
+ self.new_from_response(response).tap do |call_collection|
34
+ call_collection.query_params = options
35
+ end
36
+ end
37
+
38
+ def self.new_from_response(h)
39
+ self.new.tap do |calls_collection|
40
+ calls_collection.raw_more_data = h['MoreData']
41
+ calls_collection.raw_count = h['Calls']['Count']
42
+ calls_collection.collection = h['Calls']['Call'].each_with_object([]) do |callH, array|
43
+ array << Call.new_from_response(callH)
44
+ end
45
+ end
46
+ end
47
+
48
+ def count
49
+ Integer(self.raw_count)
50
+ end
51
+
52
+ def next?
53
+ self.raw_more_data == 'True'
54
+ end
55
+
56
+ private
57
+
58
+ def self.valid_options?(options)
59
+ options.empty? ? true : options.keys.all? { |option| VALID_OPTIONS.include? option }
60
+ end
61
+ end
62
+ end
@@ -1,5 +1,6 @@
1
1
  require 'faraday'
2
2
  require 'rack'
3
+ require 'xmlsimple'
3
4
 
4
5
  module Bvr
5
6
  class Connection
@@ -20,11 +21,11 @@ module Bvr
20
21
  end
21
22
 
22
23
  def get(params)
23
- #TODO: prase body for 500
24
- self.faraday_connection.get(uri(params)).body
24
+ body = self.faraday_connection.get(self.class.uri_from_h(params)).body
25
+ ::XmlSimple.xml_in body, {ForceArray: false}
25
26
  end
26
27
 
27
- def uri(queryH)
28
+ def self.uri_from_h(queryH)
28
29
  params = {
29
30
  username: Bvr.config.username,
30
31
  password: Bvr.config.password
@@ -0,0 +1,47 @@
1
+ module Bvr
2
+ class Credit < Struct.new(:raw_specific_balance, :raw_balance, :customer)
3
+ API_COMMANDS= {
4
+ add: 'settransaction'
5
+ }
6
+
7
+ def self.add(id, amount)
8
+ params = {
9
+ command: API_COMMANDS[:add],
10
+ customer: id,
11
+ amount: amount
12
+ }
13
+
14
+ Bvr.connection.get(params)
15
+ end
16
+
17
+ def add(amount)
18
+ response = Bvr::Credit.add(self.customer.id, amount)
19
+ return false unless response['Result'] == 'Success'
20
+
21
+ add_amount(amount) && true
22
+ end
23
+
24
+
25
+ def balance
26
+ @_balance ||= Float(self.raw_balance)
27
+ end
28
+
29
+ def rm(amount)
30
+ self.add(-1 * amount)
31
+ end
32
+
33
+ def specific_balance
34
+ @_specific_balance ||= Float(self.raw_specific_balance)
35
+ end
36
+
37
+ private
38
+
39
+ def add_amount(amount)
40
+ @_specific_balance = self.specific_balance + Float("%.5f" % amount)
41
+ @_balance = self.balance + Float("%.2f" % amount)
42
+
43
+ self.raw_specific_balance = "#{@_specific_balance}"
44
+ self.raw_balance = "#{@_balance}"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,149 @@
1
+ module Bvr
2
+ class Customer
3
+ API_COMMANDS = {
4
+ find: "getuserinfo",
5
+ create: "createcustomer",
6
+ block: "changeuserinfo",
7
+ authenticate: "validateuser",
8
+ changepassword: 'changepassword'
9
+ }
10
+
11
+ BLOCKED_VALUES = {
12
+ true => 'True',
13
+ false => 'False'
14
+ }
15
+
16
+ CREATE_OPTIONS = {
17
+ mendatory: [
18
+ :username,
19
+ :password,
20
+ :command,
21
+ :customer,
22
+ :customerpassword
23
+ ],
24
+ optional: [
25
+ :geocalicli,
26
+ :tariffrate
27
+ ]
28
+ }
29
+
30
+ attr_accessor :id, :email, :raw_blocked, :credit, :password, :phones
31
+
32
+ def initialize(id)
33
+ @id = id
34
+ @phones = Bvr::PhoneCollection.new(id)
35
+ end
36
+
37
+ def self.authenticate(id, password)
38
+ params = {
39
+ command: API_COMMANDS[:authenticate],
40
+ customer: id,
41
+ customerpassword: password
42
+ }
43
+
44
+ response = Bvr.connection.get(params)
45
+ response['Result'] == 'Success'
46
+ end
47
+
48
+ def self.block(id, block=true)
49
+ params = {
50
+ command: API_COMMANDS[:changeuserinfo],
51
+ customer: id,
52
+ customerblocked: block
53
+ }
54
+
55
+ raise ArgumentError.new('Please provide a boolean') unless !!block == block
56
+
57
+ Bvr.connection.get(params)
58
+ end
59
+
60
+ def self.change_password(id, old_password, new_password)
61
+ params = {
62
+ command: API_COMMANDS[:changepassword],
63
+ customer: id,
64
+ oldcustomerpassword: old_password,
65
+ newcustomerpassword: new_password
66
+ }
67
+
68
+ Bvr.connection.get(params)
69
+ end
70
+
71
+ def self.create(options)
72
+ params = { command: API_COMMANDS[:create] }
73
+
74
+ options.merge!(params)
75
+ raise ArgumentError.new('Invalid or unknown Argument') unless self.valid_create_options?(options)
76
+
77
+ Bvr.connection.get(options)
78
+ end
79
+
80
+ def self.find(id)
81
+ params = {
82
+ command: API_COMMANDS[:find],
83
+ customer: id
84
+ }
85
+
86
+ response = Bvr.connection.get(params)
87
+
88
+ response['Failed'].nil? ? self.new_from_response(response) : nil
89
+ end
90
+
91
+ def self.new_from_response(h)
92
+ self.new(h["Customer"]).tap do |customer|
93
+ customer.email = h["EmailAddress"]
94
+ customer.raw_blocked = h["Blocked"]
95
+ customer.credit = Bvr::Credit.new(h["SpecificBalance"], h["Balance"], customer)
96
+ h['GeocallCLI'].each{ |number| customer.phones << Bvr::Phone.new(number)}
97
+ end
98
+ end
99
+
100
+ def balance
101
+ self.credit.balance
102
+ end
103
+
104
+ def blocked?
105
+ self.raw_blocked == BLOCKED_VALUES[true]
106
+ end
107
+
108
+ def block!
109
+ response = Bvr::Customer.block(self.id, true)
110
+
111
+ if response['Result'][0] == 'Success'
112
+ self.raw_blocked = BLOCKED_VALUES[true]
113
+ end
114
+
115
+ return response['Result'][0] == 'Success'
116
+ end
117
+
118
+ def change_password(new_password)
119
+ response = Bvr::Customer.change_password(self.id, self.password, new_password)
120
+ return false if response['Result'] != 'Success'
121
+
122
+ self.password = new_password
123
+ end
124
+
125
+ def unblock!
126
+ response = Bvr::Customer.block(self.id, false)
127
+
128
+ if response['Result'][0] == 'Success'
129
+ self.raw_blocked = BLOCKED_VALUES[false]
130
+ end
131
+
132
+ return response['Result'][0] == 'Success'
133
+ end
134
+
135
+ def calls(options={})
136
+ return @_calls if @_calls && @_calls.query_params == options
137
+ @_calls = Bvr::CallCollection.find_by_customer_id(self.id, options)
138
+ end
139
+
140
+ private
141
+
142
+ def self.valid_create_options?(options)
143
+ return false if options.empty?
144
+ valid_options = CREATE_OPTIONS.values.flatten
145
+ return false unless options.keys.all? { |option| valid_options.include? option }
146
+ CREATE_OPTIONS[:mendatory].all? { |option| options.keys.include? option }
147
+ end
148
+ end
149
+ end
@@ -1,13 +1,4 @@
1
1
  module Bvr
2
- class Phone
3
- attr_accessor :number
4
-
5
- def initialize(phone_number)
6
- @number = phone_number
7
- end
8
-
9
- def self.phone_number_parser(phone_number)
10
- self.new(phone_number)
11
- end
2
+ class Phone < Struct.new(:number)
12
3
  end
13
4
  end
@@ -0,0 +1,59 @@
1
+ module Bvr
2
+ class PhoneCollection
3
+ include Enumerable
4
+
5
+ API_COMMANDS = {
6
+ add: 'changeuserinfo'
7
+ }
8
+
9
+ attr_reader :collection, :customer_id
10
+
11
+ def initialize(customer_id)
12
+ @collection = []
13
+ @customer_id = customer_id
14
+ end
15
+
16
+ def self.add(customer_id, phone, add="add")
17
+ params = {
18
+ command: API_COMMANDS[:add],
19
+ customer: customer_id,
20
+ geocallcli_options: add,
21
+ geocallcli: phone
22
+ }
23
+
24
+ Bvr.connection.get(params)
25
+ end
26
+
27
+ def add(phone)
28
+ return true if self.collection.include? phone
29
+
30
+ response = Bvr::PhoneCollection.add(self.customer_id, phone.number)
31
+ return false unless response['Result'][0] == 'Success'
32
+
33
+ self.collection << phone
34
+ true
35
+ end
36
+
37
+ def each(&block)
38
+ @collection.each { |em| block.call(em) }
39
+ end
40
+
41
+ def rm(phone)
42
+ return false unless self.collection.include? phone
43
+
44
+ response = Bvr::PhoneCollection.add(self.customer_id, phone.number, "delete")
45
+ return false unless response['Result'][0] == 'Success'
46
+
47
+ self.collection.delete phone
48
+ true
49
+ end
50
+
51
+ private
52
+
53
+ def method_missing(method, arg, &block)
54
+ return super unless self.collection.respond_to? method
55
+
56
+ self.collection.send(method, arg, &block)
57
+ end
58
+ end
59
+ end