bvr 0.0.1 → 0.1.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.
@@ -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