insightly 0.1.1

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,46 @@
1
+ module Insightly
2
+ class OpportunityStateReason < ReadOnly
3
+ self.url_base = "OpportunityStateReasons"
4
+ STATES = ["Abandoned", "Lost", "Open", "Suspended", "Won"]
5
+ api_field "STATE_REASON_ID",
6
+ "FOR_OPPORTUNITY_STATE",
7
+ "STATE_REASON"
8
+
9
+
10
+ def self.find_by_state(state)
11
+ list = []
12
+ OpportunityStateReason.all.each.each do |x|
13
+ if x.for_opportunity_state && x.for_opportunity_state.match(state)
14
+ list << x
15
+ end
16
+ end
17
+ list
18
+ end
19
+
20
+ def self.find_by_state_reason(state,reason)
21
+ OpportunityStateReason.all.each.each do |x|
22
+ return x if x.for_opportunity_state && x.for_opportunity_state.match(state) && x.state_reason == reason
23
+ end
24
+ nil
25
+ end
26
+ STATES.each do |state|
27
+
28
+ (
29
+ class << self;
30
+ self;
31
+ end).instance_eval do
32
+ define_method state.downcase.to_sym do |*args|
33
+ reason = args.first
34
+ if reason
35
+ OpportunityStateReason.find_by_state_reason(state,reason)
36
+ else
37
+ OpportunityStateReason.find_by_state(state)
38
+ end
39
+
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,52 @@
1
+ module Insightly
2
+ class ReadOnly < Base
3
+ def initialize
4
+ @data = {}
5
+
6
+ end
7
+
8
+ def url_base
9
+ self.class.const_get(:URL_BASE)
10
+ end
11
+
12
+ def build(data)
13
+ @data = data
14
+ self
15
+ end
16
+ def self.build(data)
17
+ self.new.build(data)
18
+ end
19
+ def ==(other)
20
+ self.remote_data == other.remote_data
21
+ end
22
+ def remote_data
23
+ @data
24
+ end
25
+ def process(result, content_type)
26
+ puts result
27
+ if content_type == :json
28
+ JSON.parse(result.to_str)
29
+ elsif content_type == :xml
30
+ Hash.from_xml(result.to_str)
31
+ else
32
+ result.to_str
33
+ end
34
+ end
35
+
36
+ def config
37
+ Insightly::Configuration.instantiate
38
+ end
39
+
40
+ def get_collection(path, content_type = :json)
41
+ response = RestClient::Request.new(:method => :get,
42
+ :url => "#{config.endpoint}/#{path.to_s}",
43
+ :user => config.api_key,
44
+ :password => "",
45
+ :headers => {:accept => content_type, :content_type => content_type}).execute
46
+ process(response, content_type)
47
+ end
48
+
49
+
50
+
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ module Insightly
2
+ class ReadWrite < Base
3
+ def save
4
+ if !remote_id
5
+ @data = post_collection("#{url_base}", @data.to_json)
6
+ else
7
+
8
+ @data = put_collection("#{url_base}/#{remote_id}", @data.to_json)
9
+
10
+ end
11
+
12
+ end
13
+
14
+ def post_collection(path, params, content_selector = :json)
15
+ if content_selector == :xml_raw
16
+ content_type = :xml
17
+ else
18
+ content_type = content_selector
19
+ end
20
+ response = RestClient::Request.new(:method => :post,
21
+ :url => "#{config.endpoint}/#{path.to_s}",
22
+ :user => config.api_key,
23
+ :password => "",
24
+ :payload => params,
25
+ :headers => {:accept => content_type, :content_type => content_type}).execute
26
+ process(response, content_selector)
27
+ end
28
+
29
+ def put_collection(path, params, content_selector = :json)
30
+ if content_selector == :xml_raw
31
+ content_type = :xml
32
+ else
33
+ content_type = content_selector
34
+ end
35
+ response = RestClient::Request.new(:method => :put,
36
+ :url => "#{config.endpoint}/#{path.to_s}",
37
+ :user => config.api_key,
38
+ :password => "",
39
+ :payload => params,
40
+ :headers => {:accept => content_type, :content_type => content_type}).execute
41
+ process(response, content_selector)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,72 @@
1
+ #METODO Find a way to link a task to an opportunity
2
+
3
+ module Insightly
4
+ class Task < ReadWrite
5
+ self.url_base = "Tasks"
6
+
7
+ def comments
8
+ list = []
9
+ get_collection("#{url_base}/#{task_id}/comments").each do |d|
10
+ list << Insightly::Comment.build(d)
11
+ end
12
+ list
13
+ end
14
+ def comment_on(body)
15
+ comment = Insightly::Comment.new.build({ "BODY" => body})
16
+ result = post_collection("#{url_base}/#{task_id}/comments", comment.remote_data.to_json)
17
+ comment.build(result)
18
+ end
19
+ #def comment_on(body)
20
+ # user_id = 226277
21
+ # xml_data = '<?xml version="1.0" encoding="utf-8"?><Comment xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><BODY>&lt;p&gt;&amp;nbsp;Hello Nurse&lt;/p&gt;</BODY><OWNER_USER_ID>226277</OWNER_USER_ID><FILE_ATTACHMENTS/></Comment>'
22
+ #
23
+ #
24
+ # post_collection("#{url_base}/#{task_id}/comments", xml_data, :xml)
25
+ #end
26
+ #
27
+ #def comments
28
+ # data = get_collection("#{url_base}/#{task_id}/Comments")
29
+ # list = []
30
+ # data.each do |x|
31
+ # end
32
+ # list
33
+ #end
34
+
35
+ def status
36
+ @data["STATUS"]
37
+ end
38
+ def status=(new_status)
39
+ @data["STATUS"] = new_status
40
+ end
41
+ def not_started?
42
+ status == "NOT STARTED"
43
+ end
44
+
45
+ def in_progress?
46
+ status == "IN PROGRESS"
47
+ end
48
+
49
+ def waiting?
50
+ status == "WAITING"
51
+ end
52
+
53
+ def completed?
54
+ status == "COMPLETED"
55
+ end
56
+
57
+ def deferred?
58
+ status == "DEFERRED"
59
+ end
60
+
61
+ def task_id
62
+ @data["TASK_ID"]
63
+ end
64
+
65
+ def remote_id
66
+ task_id
67
+ end
68
+
69
+
70
+
71
+ end
72
+ end
@@ -0,0 +1,22 @@
1
+ module Insightly
2
+ class TaskLink < ReadOnly
3
+ self.url_base ="TaskLinks"
4
+
5
+ def opportunity_id
6
+ @data["OPPORTUNITY_ID"]
7
+ end
8
+ def task_id
9
+ @data["TASK_ID"]
10
+ end
11
+
12
+ def self.search_by_opportunity_id(opportunity_id)
13
+ list = []
14
+ TaskLink.all.each do |x|
15
+ if !x.task_id.nil? && x.opportunity_id == opportunity_id
16
+ list << x
17
+ end
18
+ end
19
+ list
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ #This file is based heavily off of the Braintree::Version
2
+ #Copyright (c) 2009-2010 Braintree Payment Solutions
3
+ module Insightly
4
+ module Version
5
+ Major = 0
6
+ Minor = 1
7
+ Tiny = 1
8
+ String = "#{Major}.#{Minor}.#{Tiny}"
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require "rubygems"
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
9
+
10
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
11
+ Bundler.require(:default, :testing) if defined?(Bundler)
12
+
13
+ require "insightly"
14
+ require File.expand_path(File.dirname(__FILE__) + "/../api_key")
15
+ RSpec.configure do |config|
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+
20
+ # Run specs in random order to surface order dependencies. If you find an
21
+ # order dependency and want to debug it, you can fix the order by providing
22
+ # the seed, which is printed after each run.
23
+ # --seed 1234
24
+ config.order = 'random'
25
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Insightly::Base do
4
+ before(:each) do
5
+ end
6
+ end
@@ -0,0 +1,92 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Insightly::Comment do
4
+ before(:each) do
5
+ Insightly::Configuration.api_key = INSIGHTLY_API_KEY
6
+ Insightly::Configuration.logger = Insightly::Configuration._debug_logger
7
+ @comment = Insightly::Comment.new.build({
8
+ "COMMENT_ID" => 132456,
9
+ "BODY" => "test comment",
10
+ "OWNER_USER_ID" => 12345,
11
+ "DATE_CREATED_UTC" => "2012-03-09 11:59:19",
12
+ "DATE_UPDATED_UTC" => "2012-03-09 11:59:19",
13
+ "FILE_ATTACHMENTS" =>
14
+ {
15
+ "FILE_ID" => 4567899,
16
+ "FILE_NAME" => "test.docx",
17
+ "CONTENT_TYPE" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
18
+ "FILE_SIZE" => 2489,
19
+ "FILE_CATEGORY_ID" => nil,
20
+ "OWNER_USER_ID" => 12345,
21
+ "DATE_CREATED_UTC" => "2012-03-09 11:59:20",
22
+ "DATE_UPDATED_UTC" => "2012-03-09 11:59:20",
23
+ "URL" => "/api/fileattachments/4567899"
24
+ }
25
+ }
26
+ )
27
+
28
+ # @comment = Insightly::Comment.new(3216775)
29
+ end
30
+ it "should be able to create a comment" do
31
+ end
32
+ it "should have a url base" do
33
+ @comment.url_base.should == "Comments"
34
+ end
35
+ it "should know the comment id" do
36
+ @comment.comment_id.should == 132456
37
+ end
38
+ it "should know that the remote id and the comment id are the same" do
39
+ @comment.remote_id.should == @comment.comment_id
40
+ end
41
+ it "should allow you to load based on an id" do
42
+ #METODO This should create the comment so we can make sure it exists - once that feature is available
43
+ @comment = Insightly::Comment.new(768880)
44
+ @comment.comment_id.should == 768880
45
+ end
46
+ it "should allow you to build an object from a hash" do
47
+ comment = Insightly::Comment.new.build({"BODY" => "Other"})
48
+ comment.remote_data.should == {"BODY" => "Other"}
49
+ end
50
+ context "xml" do
51
+ before(:each) do
52
+ @raw_xml = <<-END_XML
53
+ <?xml version="1.0" encoding="utf-8"?>
54
+ <Comment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
55
+ <COMMENT_ID>132456</COMMENT_ID>
56
+ <BODY>test comment</BODY>
57
+ <OWNER_USER_ID>12345</OWNER_USER_ID>
58
+ <DATE_CREATED_UTC>2012-03-09T23:59:19.503</DATE_CREATED_UTC>
59
+ <DATE_UPDATED_UTC>2012-03-09T23:59:19.503</DATE_UPDATED_UTC>
60
+ <FILE_ATTACHMENTS></FILE_ATTACHMENTS>
61
+ </Comment>
62
+ END_XML
63
+ end
64
+ it "should be able to parse the xml into a valid comment" do
65
+ @comment = Insightly::Comment.new.load_from_xml(@raw_xml)
66
+ @comment.comment_id.should == 132456
67
+ @comment.body.should == "test comment"
68
+ @comment.date_created_utc.should == "2012-03-09T23:59:19.503"
69
+ @comment.date_updated_utc.should == "2012-03-09T23:59:19.503"
70
+ @comment.owner_user_id.should == 12345
71
+
72
+ end
73
+ it "should be able to generate xml from the commment" do
74
+ @comment = Insightly::Comment.new.load_from_xml(@raw_xml)
75
+ @comment.to_xml.should == @raw_xml
76
+ end
77
+ end
78
+
79
+ it "should allow you to modify a comment" do
80
+ @comment = Insightly::Comment.new(769043)
81
+ before_body = @comment.body
82
+ value = "Test Comment Edit #{Time.now}"
83
+ @comment.body = value
84
+ @comment.save
85
+ @comment.body.should == value
86
+
87
+ @comment.reload
88
+ @comment.body.should == value
89
+ end
90
+
91
+
92
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Insightly::Configuration do
4
+ #customer_user_agent
5
+ #endpoint
6
+ #logger
7
+ #api_key
8
+ before(:each) do
9
+ Insightly::Configuration.custom_user_agent = nil
10
+ Insightly::Configuration.api_key = "123"
11
+ Insightly::Configuration.endpoint = nil
12
+ end
13
+ it "should provide a default user agent" do
14
+
15
+ Insightly::Configuration.instantiate.custom_user_agent.should be_nil
16
+ Insightly::Configuration.instantiate.user_agent.should == "Insightly Ruby Gem 0.1.0"
17
+ end
18
+ it "should allow you to override the user agent" do
19
+
20
+ Insightly::Configuration.custom_user_agent = "Bob"
21
+ Insightly::Configuration.instantiate.user_agent.should == "Insightly Ruby Gem 0.1.0 (Bob)"
22
+ end
23
+ it "should provide a default endpoint" do
24
+ Insightly::Configuration.instantiate.endpoint.should == "https://api.insight.ly/v1"
25
+ end
26
+ it "should allow you to override the endpoint" do
27
+ Insightly::Configuration.endpoint = "Bob"
28
+ Insightly::Configuration.instantiate.endpoint.should == "Bob"
29
+ end
30
+ it "should raise an error if you do not set an api key" do
31
+ Insightly::Configuration.instance_variable_set(:@api_key, nil)
32
+ expect do
33
+ Insightly::Configuration.api_key
34
+ end.to raise_error(Insightly::ConfigurationError, "Insightly::Configuration.api_key needs to be set")
35
+ expect do
36
+ Insightly::Configuration.instantiate.api_key
37
+ end.to raise_error(Insightly::ConfigurationError, "Insightly::Configuration.api_key needs to be set")
38
+ end
39
+ it "should allow you to set the api_key" do
40
+ Insightly::Configuration.api_key = "Bob"
41
+ Insightly::Configuration.api_key.should == "Bob"
42
+ Insightly::Configuration.instantiate.api_key.should == "Bob"
43
+ end
44
+ it "should be able to set custom fields for opportunities" do
45
+ Insightly::Opportunity.should_receive(:custom_fields).with(:rank, :branch_of_service)
46
+
47
+ Insightly::Configuration.custom_fields_for_opportunities(:rank, :branch_of_service)
48
+
49
+ end
50
+ end
@@ -0,0 +1,180 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe Insightly::Opportunity do
4
+ before(:each) do
5
+ Insightly::Configuration.api_key = INSIGHTLY_API_KEY
6
+ Insightly::Configuration.logger = Insightly::Configuration._debug_logger
7
+ @opportunity = Insightly::Opportunity.build({
8
+ "OPPORTUNITY_FIELD_10" => nil,
9
+ "OPPORTUNITY_FIELD_9" => nil,
10
+ "OPPORTUNITY_FIELD_8" => "Bob Roberts",
11
+ "OPPORTUNITY_FIELD_7" => "r26D Trucking",
12
+ "OPPORTUNITY_FIELD_6" => "TruckingOffice",
13
+ "OPPORTUNITY_FIELD_5" => "Owner/Operator",
14
+ "OPPORTUNITY_FIELD_4" => "Central",
15
+ "OPPORTUNITY_FIELD_3" => "210-555-1212",
16
+ "OPPORTUNITY_FIELD_2" => "http://www.truckingoffice.com/522",
17
+ "OPPORTUNITY_FIELD_1" => nil,
18
+ "VISIBLE_TO" => "EVERYONE",
19
+ "BID_TYPE" => "Fixed Bid",
20
+ "ACTUAL_CLOSE_DATE" => nil,
21
+ "DATE_UPDATED_UTC" => "2012-06-06 02:05:34",
22
+ "OWNER_USER_ID" => 226277,
23
+ "BID_DURATION" => nil,
24
+ "BID_CURRENTY" => "USD",
25
+ "PIPELINE_ID" => 24377,
26
+ "CATEGORY_ID" => 628187,
27
+ "PROBABILITY" => nil,
28
+ "TAGS" => [],
29
+ "IMAGE_URL" => "http://s3.amazonaws.com/insightly.userfiles/20562/",
30
+ "BID_AMOUNT" => 20,
31
+ "VISIBLE_TEAM_ID" => nil,
32
+ "STAGE_ID" => 71162,
33
+ "DATE_CREATED_UTC" => "2012-09-06 02:04:47",
34
+ "OPPORTUNITY_STATE" => "OPEN",
35
+ "FORECAST_CLOSE_DATE" => "2012-10-05 00:00:00",
36
+ "OPPORTUNITY_NAME" => "Sample Opportunity",
37
+ "OPPORTUNITY_ID" => 957168,
38
+ "VISIBLE_USER_IDS" => nil,
39
+ "LINKS" => [],
40
+ "RESPONSIBLE_USER_ID" => 226277,
41
+ "OPPORTUNITY_DETAILS" => "This is a description."
42
+
43
+ })
44
+ end
45
+ it "should be able to create a opportunity" do
46
+ end
47
+ it "should have a url base" do
48
+ @opportunity.url_base.should == "Opportunities"
49
+ end
50
+ it "should know the opportunity id" do
51
+ @opportunity.opportunity_id.should == 957168
52
+ end
53
+ it "should know that the remote id and the opportunity id are the same" do
54
+ @opportunity.remote_id.should == @opportunity.opportunity_id
55
+ end
56
+ it "should allow you to load based on an id"
57
+ it "should allow you to build an object from a hash" do
58
+ opportunity = Insightly::Opportunity.new.build({"TITLE" => "Other"})
59
+ opportunity.remote_data.should == {"TITLE" => "Other"}
60
+ end
61
+ it "should have allow you to read and write all fields" do
62
+ fields = Insightly::Opportunity.api_fields
63
+
64
+ Insightly::Opportunity.api_fields.each do |f|
65
+ @opportunity.send(f.downcase.to_sym).should == @opportunity.remote_data[f]
66
+ @opportunity.send("#{f.downcase}=".to_sym, "Bob")
67
+ @opportunity.send(f.downcase.to_sym).should == "Bob"
68
+ @opportunity.remote_data[f].should == "Bob"
69
+ end
70
+ end
71
+ it "should allow you to define custom field labels" do
72
+ Insightly::Opportunity.custom_fields(:dummy1, :dummy2, :dummy3)
73
+ @opportunity.dummy1.should == @opportunity.remote_data["OPPORTUNITY_FIELD_1"]
74
+ @opportunity.dummy2.should == "http://www.truckingoffice.com/522"
75
+ @opportunity.dummy3.should == @opportunity.remote_data["OPPORTUNITY_FIELD_3"]
76
+
77
+ @opportunity.dummy1 = "Bob1"
78
+ @opportunity.dummy2 = "Bob2"
79
+ @opportunity.dummy3 = "Bob3"
80
+
81
+ @opportunity.dummy1.should == "Bob1"
82
+ @opportunity.dummy2.should == "Bob2"
83
+ @opportunity.dummy3.should == "Bob3"
84
+ @opportunity.remote_data["OPPORTUNITY_FIELD_1"].should == "Bob1"
85
+ @opportunity.remote_data["OPPORTUNITY_FIELD_2"].should == "Bob2"
86
+ @opportunity.remote_data["OPPORTUNITY_FIELD_3"].should == "Bob3"
87
+ end
88
+ it "should handle special fields" do
89
+ Insightly::Opportunity.custom_fields(:dummy1, :admin_url, :phone_number, :timezone, :plan, :organization, :company_name, :contact_name)
90
+ @opportunity.admin_url.should == "http://www.truckingoffice.com/522"
91
+ @opportunity.phone_number.should == "210-555-1212"
92
+ @opportunity.timezone.should == "Central"
93
+ @opportunity.plan.should == "Owner/Operator"
94
+ @opportunity.organization.should == "TruckingOffice"
95
+ @opportunity.company_name.should == "r26D Trucking"
96
+ @opportunity.contact_name.should == "Bob Roberts"
97
+ end
98
+ context "search/find" do
99
+ before(:each) do
100
+ @opp1 = Insightly::Opportunity.build(@opportunity.remote_data.clone)
101
+ @opp1.opportunity_name = "Apple Sale"
102
+ @opp2 = Insightly::Opportunity.build(@opportunity.remote_data.clone)
103
+ @opp2.opportunity_name = "Apple Sale 2"
104
+ @opp3 = Insightly::Opportunity.build(@opportunity.remote_data.clone)
105
+ @opp3.opportunity_name = "Box Sale"
106
+ @opp4 = Insightly::Opportunity.build(@opportunity.remote_data.clone)
107
+ @opp4.opportunity_name = nil
108
+
109
+ Insightly::Opportunity.should_receive(:all).and_return([@opp1, @opp2, @opp3, @opp4])
110
+
111
+ end
112
+ it "should find all the names that match" do
113
+ Insightly::Opportunity.search_by_name("Apple").should == [@opp1, @opp2]
114
+ end
115
+ it "should return an empty array if there are not matches" do
116
+ Insightly::Opportunity.search_by_name("Cobra").should == []
117
+ end
118
+ it "should find the first one that is exactly the right" do
119
+ Insightly::Opportunity.find_by_name("Apple Sale 2").should == @opp2
120
+ end
121
+ it "should return nil if no opportunity name is found" do
122
+ Insightly::Opportunity.find_by_name("Cobra").should == nil
123
+ end
124
+ end
125
+
126
+ context "State" do
127
+ it "should have state booleans" do
128
+
129
+ states = Insightly::OpportunityStateReason::STATES
130
+ states.each do |state|
131
+ opportunity = Insightly::Opportunity.build({"OPPORTUNITY_STATE" => state})
132
+
133
+ states.each do |current_state|
134
+ if state == current_state
135
+ opportunity.send("#{current_state.downcase}?".to_sym).should be_true
136
+
137
+ else
138
+ opportunity.send("#{current_state.downcase}?".to_sym).should be_false
139
+ end
140
+ end
141
+ end
142
+
143
+ end
144
+ it "should be able to search by state" do
145
+
146
+ end
147
+ it "should allow you to change the state without a reason" do
148
+ @opportunity = Insightly::Opportunity.new(957168)
149
+
150
+ @opportunity.open!
151
+ @opportunity.lost!
152
+ @opportunity.should be_lost
153
+ @opportunity.reload
154
+ @opportunity.should be_lost
155
+ end
156
+ it "should allow you to provide a reason - and the state should change if the reason isn't valid" do
157
+ @opportunity = Insightly::Opportunity.new(957168)
158
+
159
+ @opportunity.open!
160
+ @opportunity.won!("Bobobob")
161
+ @opportunity.reload
162
+ @opportunity.should be_won
163
+ end
164
+
165
+ it "should allow you to change the state and set the reason" do
166
+ @opportunity = Insightly::Opportunity.new(957168)
167
+ Insightly::OpportunityStateReason.find_by_state_reason("Won", "They converted").should_not be_nil
168
+
169
+ @opportunity.open!
170
+ @opportunity.won!("They converted")
171
+ @opportunity.reload
172
+ @opportunity.should be_won
173
+ # Currently there is no way to test the reason is set
174
+
175
+ end
176
+ it "should set the reason to Created by API if you create an opportunity"
177
+
178
+ end
179
+
180
+ end