bill_forward 1.2014.296

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.gitignore +27 -0
  2. data/.idea/.name +1 -0
  3. data/.idea/compiler.xml +23 -0
  4. data/.idea/copyright/profiles_settings.xml +3 -0
  5. data/.idea/encodings.xml +5 -0
  6. data/.idea/inspectionProfiles/Project_Default.xml +11 -0
  7. data/.idea/inspectionProfiles/profiles_settings.xml +7 -0
  8. data/.idea/misc.xml +23 -0
  9. data/.idea/modules.xml +9 -0
  10. data/.idea/scopes/scope_settings.xml +5 -0
  11. data/.idea/vcs.xml +7 -0
  12. data/.rspec +2 -0
  13. data/Gemfile +9 -0
  14. data/LICENSE.md +22 -0
  15. data/README.md +227 -0
  16. data/Rakefile +73 -0
  17. data/bill_forward.gemspec +29 -0
  18. data/bill_forward.iml +28 -0
  19. data/lib/bill_forward.rb +18 -0
  20. data/lib/bill_forward/billing_entity.rb +263 -0
  21. data/lib/bill_forward/client.rb +355 -0
  22. data/lib/bill_forward/custom_hash.rb +14 -0
  23. data/lib/bill_forward/deny_method.rb +4 -0
  24. data/lib/bill_forward/entities/account.rb +19 -0
  25. data/lib/bill_forward/entities/address.rb +25 -0
  26. data/lib/bill_forward/entities/amendments/amendment.rb +11 -0
  27. data/lib/bill_forward/entities/amendments/invoice_recalculation_amendment.rb +10 -0
  28. data/lib/bill_forward/entities/api_configuration.rb +11 -0
  29. data/lib/bill_forward/entities/authorize_net_token.rb +9 -0
  30. data/lib/bill_forward/entities/credit_note.rb +13 -0
  31. data/lib/bill_forward/entities/invoice.rb +25 -0
  32. data/lib/bill_forward/entities/invoice_parts/invoice_line.rb +37 -0
  33. data/lib/bill_forward/entities/invoice_parts/invoice_payment.rb +29 -0
  34. data/lib/bill_forward/entities/invoice_parts/tax_line.rb +23 -0
  35. data/lib/bill_forward/entities/invoice_parts/taxation_link.rb +5 -0
  36. data/lib/bill_forward/entities/organisation.rb +37 -0
  37. data/lib/bill_forward/entities/payment_method.rb +5 -0
  38. data/lib/bill_forward/entities/payment_method_subscription_link.rb +5 -0
  39. data/lib/bill_forward/entities/pricing_component.rb +21 -0
  40. data/lib/bill_forward/entities/pricing_component_tier.rb +5 -0
  41. data/lib/bill_forward/entities/pricing_component_value.rb +5 -0
  42. data/lib/bill_forward/entities/pricing_component_value_change.rb +5 -0
  43. data/lib/bill_forward/entities/product.rb +5 -0
  44. data/lib/bill_forward/entities/product_rate_plan.rb +19 -0
  45. data/lib/bill_forward/entities/profile.rb +15 -0
  46. data/lib/bill_forward/entities/role.rb +4 -0
  47. data/lib/bill_forward/entities/subscription.rb +53 -0
  48. data/lib/bill_forward/entities/unit_of_measure.rb +5 -0
  49. data/lib/bill_forward/insertable_entity.rb +32 -0
  50. data/lib/bill_forward/mutable_entity.rb +47 -0
  51. data/lib/bill_forward/resource_path.rb +11 -0
  52. data/lib/bill_forward/type_check.rb +21 -0
  53. data/lib/bill_forward/version.rb +4 -0
  54. data/spec/component/account_spec.rb +200 -0
  55. data/spec/component/billing_entity_spec.rb +153 -0
  56. data/spec/component/invoice_spec.rb +155 -0
  57. data/spec/component/subscription_spec.rb +357 -0
  58. data/spec/functional/account_spec.rb +25 -0
  59. data/spec/functional/bad_citizen/account_spec.rb +103 -0
  60. data/spec/functional/bad_citizen/credit_note_spec.rb +41 -0
  61. data/spec/functional/bad_citizen/payment_method_spec.rb +34 -0
  62. data/spec/functional/bad_citizen/product_rate_plan_spec.rb +105 -0
  63. data/spec/functional/bad_citizen/product_spec.rb +22 -0
  64. data/spec/functional/bad_citizen/situational/authorize_net_token_spec.rb +27 -0
  65. data/spec/functional/bad_citizen/situational/invoice_recalculation_amendment_spec.rb +27 -0
  66. data/spec/functional/bad_citizen/situational/invoice_spec.rb +22 -0
  67. data/spec/functional/bad_citizen/situational/malordered_entity_spec.rb +43 -0
  68. data/spec/functional/bad_citizen/situational/organisation_spec.rb +39 -0
  69. data/spec/functional/bad_citizen/situational/payment_method_spec.rb +47 -0
  70. data/spec/functional/bad_citizen/situational/subscription_chargeable_spec.rb +255 -0
  71. data/spec/functional/bad_citizen/subscription_spec.rb +179 -0
  72. data/spec/functional/bad_citizen/subscription_with_credit_spec.rb +240 -0
  73. data/spec/functional/bad_citizen/unit_of_measure_spec.rb +20 -0
  74. data/spec/functional/billing_entity_spec.rb +22 -0
  75. data/spec/functional/client_spec.rb +24 -0
  76. data/spec/functional/organisation_spec.rb +28 -0
  77. data/spec/setup_test_constants.rb +73 -0
  78. data/spec/spec_helper.rb +11 -0
  79. data/spec/syntax/account_spec.rb +24 -0
  80. data/spec/syntax/address_spec.rb +19 -0
  81. data/spec/syntax/api_configuration_spec.rb +13 -0
  82. data/spec/syntax/billing_entity_spec.rb +93 -0
  83. data/spec/syntax/client_spec.rb +8 -0
  84. metadata +287 -0
@@ -0,0 +1,5 @@
1
+ module BillForward
2
+ class UnitOfMeasure < MutableEntity
3
+ @resource_path = BillForward::ResourcePath.new('units-of-measure', 'unitOfMeasure')
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ module BillForward
2
+ class InsertableEntity < BillingEntity
3
+ def initialize(*args)
4
+ raise AbstractInstantiateError.new('This abstract class cannot be instantiated!') if self.class == InsertableEntity
5
+ super
6
+ end
7
+
8
+ class << self
9
+ # Asks API to create a real instance of specified entity,
10
+ # based on provided model.
11
+ # @param options=nil [self] the Entity to create
12
+ #
13
+ # @return [self] The created Entity
14
+ def create(entity = nil)
15
+ entity = self.new if entity.nil?
16
+ TypeCheck.verifyObj(self, entity, 'entity')
17
+
18
+ serial = entity.serialize
19
+ client = entity._client
20
+
21
+ route = entity.class.resource_path.path
22
+ endpoint = ''
23
+ url_full = "#{route}/#{endpoint}"
24
+
25
+ response = client.post_first(url_full, serial)
26
+
27
+ created_entity = self.new(response, client)
28
+ created_entity
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ module BillForward
2
+ class MutableEntity < InsertableEntity
3
+ def initialize(*args)
4
+ raise AbstractInstantiateError.new('This abstract class cannot be instantiated!') if self.class == MutableEntity
5
+ super
6
+ end
7
+
8
+ # Asks API to update existing instance of this entity,
9
+ # based on current model.
10
+ #
11
+ # @return [self] The updated Entity
12
+ def save()
13
+ serial = serialize
14
+ client = _client
15
+
16
+ route = self.class.resource_path.path
17
+ endpoint = ''
18
+ url_full = "#{route}/#{endpoint}"
19
+
20
+ response = client.put_first(url_full, serial)
21
+
22
+ updated_entity = self.class.new(response, client)
23
+ updated_entity
24
+ end
25
+
26
+ # Asks API to retire existing instance of this entity.
27
+ # @note Many BillForward entities do not support RETIRE
28
+ # @note As-yet untested
29
+ #
30
+ # @return [self] The retired Entity
31
+ def delete()
32
+ serial = serialize
33
+ client = _client
34
+
35
+ id = serial.id
36
+
37
+ route = self.class.resource_path.path
38
+ endpoint = ''
39
+ url_full = "#{route}/#{endpoint}#{id}"
40
+
41
+ response = client.retire_first(url_full)
42
+
43
+ retired_entity = self.class.new(response, client)
44
+ retired_entity
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module BillForward
2
+ class ResourcePath
3
+ attr_reader :path
4
+ attr_reader :entity_name
5
+
6
+ def initialize(path, entity_name)
7
+ @path = path
8
+ @entity_name = entity_name
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module BillForward
2
+ class TypeCheck
3
+ # ensure that the provided object extends the expected class
4
+ def self.verifyObj(expectedClass, obj, argName)
5
+ expectedClassName = expectedClass.name
6
+ actualClassName = obj.class.name
7
+ raise TypeError.new("Expected instance of '#{expectedClassName}' at argument '#{argName}'. "+
8
+ "Instead received: '#{actualClassName}'") unless obj.kind_of?(expectedClass) || obj.kind_of?(RSpec::Mocks::Double)
9
+ end
10
+ # ensure that the provided class extends the expected class
11
+ def self.verifyClass(expectedClass, actualClass, argName)
12
+ expectedClassName = expectedClass.name
13
+ actualClassName = actualClass.name
14
+ raise TypeError.new("Expected instance of '#{expectedClassName}' at argument '#{argName}'. "+
15
+ "Instead received: '#{actualClassName}'") unless actualClass<=expectedClass || actualClass<=RSpec::Mocks::Double
16
+ end
17
+ end
18
+
19
+ class AbstractInstantiateError < StandardError
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module BillForward
2
+ # in an rspec run, the gemspec and bill_forward.rb loader will both visit this
3
+ VERSION = "1.2014.296" unless const_defined?(:VERSION)
4
+ end
@@ -0,0 +1,200 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "..", "spec_helper")
2
+
3
+ describe BillForward::Account do
4
+ before :all do
5
+ @client = BillForwardTest::TEST_CLIENT
6
+ BillForward::Client.default_client = @client
7
+ end
8
+ before :each do
9
+ # skip OAuth request
10
+ allow_any_instance_of(BillForward::Client).to receive(:get_token).and_return('fake token')
11
+ end
12
+ describe '::get_by_id' do
13
+ context 'where account does not exist' do
14
+ let(:RestClient) { double :RestClient }
15
+ it "gets empty list" do
16
+ response = double
17
+ allow(response).to receive(:to_str).and_return(canned_noresults)
18
+ allow(RestClient::Request).to receive(:execute).and_return(response)
19
+
20
+ expect{BillForward::Account.get_by_id 'anything'}.to raise_error(IndexError)
21
+ end
22
+ end
23
+ context 'where account exists' do
24
+ it "gets the account" do
25
+ account_id = '74DA7D63-EAEB-431B-9745-76F9109FD842'
26
+
27
+ response = double
28
+ allow(response).to receive(:to_str).and_return(canned_account_get)
29
+ allow(RestClient::Request).to receive(:execute).and_return(response)
30
+
31
+ account = BillForward::Account.get_by_id account_id
32
+
33
+ expect(account.id).to eq(account_id)
34
+ end
35
+ end
36
+ end
37
+ describe '::create' do
38
+ context 'upon creating minimal account' do
39
+ let(:RestClient) { double :RestClient }
40
+ it "can get property" do
41
+ response = double
42
+ allow(response).to receive(:to_str).and_return(canned_account_create_minimal)
43
+ allow(RestClient::Request).to receive(:execute).and_return(response)
44
+
45
+ created_account = BillForward::Account.create
46
+ expect(created_account['@type']).to eq(BillForward::Account.resource_path.entity_name)
47
+ end
48
+ end
49
+ context 'upon creating account with profile' do
50
+ let(:RestClient) { double :RestClient }
51
+ email = 'always@testing.is.moe'
52
+ before :each do
53
+ profile = BillForward::Profile.new({
54
+ 'email' => email,
55
+ 'firstName' => 'Test',
56
+ })
57
+ account = BillForward::Account.new({
58
+ 'profile' => profile
59
+ })
60
+ response = double
61
+ allow(response).to receive(:to_str).and_return(canned_account_create_with_profile)
62
+ allow(RestClient::Request).to receive(:execute).and_return(response)
63
+
64
+ @created_account = BillForward::Account.create account
65
+ end
66
+ subject (:account) { @created_account }
67
+ it "can get property" do
68
+ expect(account['@type']).to eq(BillForward::Account.resource_path.entity_name)
69
+ end
70
+ it "has profile" do
71
+ profile = account.profile
72
+ expect(profile.email).to eq(email)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def canned_noresults
79
+ '{
80
+ "executionTime": 1070093,
81
+ "results": []
82
+ }'
83
+ end
84
+
85
+ def canned_account_create_with_profile
86
+ '{
87
+ "results": [
88
+ {
89
+ "profile": {
90
+ "accountID": "5037E4EF-9DD1-4BC3-8920-425D9159C41A",
91
+ "updated": "2014-09-18T22:29:15.079Z",
92
+ "email": "always@testing.is.moe",
93
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3",
94
+ "id": "C7A63931-709D-4F1A-B8F9-B5EC0E6C2D29",
95
+ "created": "2014-09-18T22:29:15.079Z",
96
+ "addresses": [
97
+
98
+ ],
99
+ "firstName": "Test",
100
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60"
101
+ },
102
+ "updated": "2014-09-18T22:29:14.783Z",
103
+ "deleted": false,
104
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3",
105
+ "id": "5037E4EF-9DD1-4BC3-8920-425D9159C41A",
106
+ "crmID": null,
107
+ "created": "2014-09-18T22:29:14.783Z",
108
+ "roles": [
109
+
110
+ ],
111
+ "paymentMethods": [
112
+
113
+ ],
114
+ "successfulSubscriptions": 0,
115
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
116
+ "@type": "account"
117
+ }
118
+ ],
119
+ "executionTime": 647946
120
+ }'
121
+ end
122
+
123
+ def canned_account_create_minimal
124
+ '{
125
+ "results": [
126
+ {
127
+ "updated": "2014-09-18T18:27:22.258Z",
128
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
129
+ "id": "904DAE81-B63C-4F25-86C5-E1A1CDCEEB88",
130
+ "@type": "account",
131
+ "deleted": false,
132
+ "successfulSubscriptions": 0,
133
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3",
134
+ "crmID": null,
135
+ "paymentMethods": [
136
+
137
+ ],
138
+ "created": "2014-09-18T18:27:22.258Z",
139
+ "roles": [
140
+
141
+ ]
142
+ }
143
+ ],
144
+ "executionTime": 492653
145
+ }'
146
+ end
147
+
148
+ def canned_account_get
149
+ '{
150
+ "executionTime": 1070093,
151
+ "results": [
152
+ {
153
+ "successfulSubscriptions": 0,
154
+ "@type": "account",
155
+ "roles": [
156
+
157
+ ],
158
+ "profile": {
159
+ "firstName": "Test",
160
+ "addresses": [
161
+ {
162
+ "landline": "02000000000",
163
+ "addressLine3": "address line 3",
164
+ "addressLine2": "address line 2",
165
+ "addressLine1": "address line 1",
166
+ "country": "United Kingdom",
167
+ "deleted": false,
168
+ "city": "London",
169
+ "profileID": "1B07A310-8B0F-4CFA-B2CF-48D206DC79C3",
170
+ "id": "34B5A980-A133-4B5F-9045-F1A41F20F2D6",
171
+ "primaryAddress": true,
172
+ "province": "London",
173
+ "created": "2014-09-04T17:43:44Z",
174
+ "postcode": "SW1 1AS",
175
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
176
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3"
177
+ }
178
+ ],
179
+ "id": "1B07A310-8B0F-4CFA-B2CF-48D206DC79C3",
180
+ "updated": "2014-09-04T17:43:44Z",
181
+ "email": "always@testing.is.moe",
182
+ "created": "2014-09-04T17:43:44Z",
183
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
184
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3",
185
+ "accountID": "74DA7D63-EAEB-431B-9745-76F9109FD842"
186
+ },
187
+ "deleted": false,
188
+ "crmID": null,
189
+ "id": "74DA7D63-EAEB-431B-9745-76F9109FD842",
190
+ "updated": "2014-09-04T17:43:43Z",
191
+ "created": "2014-09-04T17:43:43Z",
192
+ "paymentMethods": [
193
+
194
+ ],
195
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
196
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3"
197
+ }
198
+ ]
199
+ }'
200
+ end
@@ -0,0 +1,153 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "..", "spec_helper")
2
+
3
+ describe BillForward::BillingEntity do
4
+ before :all do
5
+ @client = BillForwardTest::TEST_CLIENT
6
+ BillForward::Client.default_client = @client
7
+ end
8
+ before :each do
9
+ # skip OAuth request
10
+ allow_any_instance_of(BillForward::Client).to receive(:get_token).and_return('fake token')
11
+ end
12
+ context 'upon getting entity' do
13
+ before :each do
14
+ response = double
15
+ allow(response).to receive(:to_str).and_return(canned_entity)
16
+ allow(RestClient::Request).to receive(:execute).and_return(response)
17
+
18
+ @entity = BillForward::Account.get_by_id 'anything'
19
+ end
20
+ subject (:entity) { @entity }
21
+ context 'using dot syntax' do
22
+ it "can get property" do
23
+ expect(entity.id).to eq('74DA7D63-EAEB-431B-9745-76F9109FD842')
24
+ end
25
+ it "can change property" do
26
+ newid = 'whatever'
27
+ entity.id = newid
28
+ expect(entity.id).to eq(newid)
29
+ end
30
+ it "can add property" do
31
+ value = 'whatever'
32
+ entity.fun = value
33
+ expect(entity.fun).to eq(value)
34
+ end
35
+ describe 'nested array of entities' do
36
+ context 'once unserialized' do
37
+ subject :roles do
38
+ roles = entity.roles
39
+ end
40
+ subject :role do
41
+ roles.first
42
+ end
43
+ it 'is an array' do
44
+ expect(roles.class).to eq(Array)
45
+ end
46
+ describe 'some element' do
47
+ it 'is an entity' do
48
+ expect(role.class).to eq(BillForward::Role)
49
+ end
50
+ it 'has expected properties' do
51
+ expect(role.role).to eq('user')
52
+ end
53
+ it 'has mutable properties' do
54
+ expect(role.role).to eq('user')
55
+ new_role = 'abuser'
56
+ role.role = new_role
57
+ expect(role.role).to eq(new_role)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ describe 'nested entity' do
63
+ context 'once unserialized' do
64
+ subject :profile do
65
+ profile = entity.profile
66
+ end
67
+ it 'is an entity' do
68
+ expect(profile.class).to eq(BillForward::Profile)
69
+ end
70
+ it 'has expected properties' do
71
+ expect(profile.firstName).to eq('Test')
72
+ end
73
+ it 'has mutable properties' do
74
+ expect(profile.firstName).to eq('Test')
75
+ new_name = 'Best'
76
+ profile.firstName = new_name
77
+ expect(profile.firstName).to eq(new_name)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ context 'using array access syntax' do
83
+ it "can get property" do
84
+ expect(entity['@type']).to eq('account')
85
+ end
86
+ it "can change property" do
87
+ newid = 'notever'
88
+ entity['id'] = newid
89
+ expect(entity['id']).to eq(newid)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ def canned_entity
96
+ '{
97
+ "executionTime": 1070093,
98
+ "results": [
99
+ {
100
+ "successfulSubscriptions": 0,
101
+ "@type": "account",
102
+ "roles": [
103
+ {
104
+ "id": "B4E623C2-2CE0-11E3-894A-FA163E717A7F",
105
+ "accountID": "74DA7D63-EAEB-431B-9745-76F9109FD842",
106
+ "role": "user",
107
+ "created": "2014-09-04T17:43:44Z",
108
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60"
109
+ }
110
+ ],
111
+ "profile": {
112
+ "firstName": "Test",
113
+ "addresses": [
114
+ {
115
+ "landline": "02000000000",
116
+ "addressLine3": "address line 3",
117
+ "addressLine2": "address line 2",
118
+ "addressLine1": "address line 1",
119
+ "country": "United Kingdom",
120
+ "deleted": false,
121
+ "city": "London",
122
+ "profileID": "1B07A310-8B0F-4CFA-B2CF-48D206DC79C3",
123
+ "id": "34B5A980-A133-4B5F-9045-F1A41F20F2D6",
124
+ "primaryAddress": true,
125
+ "province": "London",
126
+ "created": "2014-09-04T17:43:44Z",
127
+ "postcode": "SW1 1AS",
128
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
129
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3"
130
+ }
131
+ ],
132
+ "id": "1B07A310-8B0F-4CFA-B2CF-48D206DC79C3",
133
+ "updated": "2014-09-04T17:43:44Z",
134
+ "email": "always@testing.is.moe",
135
+ "created": "2014-09-04T17:43:44Z",
136
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
137
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3",
138
+ "accountID": "74DA7D63-EAEB-431B-9745-76F9109FD842"
139
+ },
140
+ "deleted": false,
141
+ "crmID": null,
142
+ "id": "74DA7D63-EAEB-431B-9745-76F9109FD842",
143
+ "updated": "2014-09-04T17:43:43Z",
144
+ "created": "2014-09-04T17:43:43Z",
145
+ "paymentMethods": [
146
+
147
+ ],
148
+ "changedBy": "7872F2F4-ED96-4038-BC82-39F7DDFECE60",
149
+ "organizationID": "F60667D7-583A-4A01-B4DC-F74CC45ACAE3"
150
+ }
151
+ ]
152
+ }'
153
+ end