bill_forward 1.2014.296

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.
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