agree2 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.
- data/History.txt +0 -0
- data/License.txt +20 -0
- data/README.rdoc +165 -0
- data/Rakefile +97 -0
- data/lib/agree2/agreement.rb +71 -0
- data/lib/agree2/base.rb +147 -0
- data/lib/agree2/client.rb +101 -0
- data/lib/agree2/party.rb +23 -0
- data/lib/agree2/proxy_collection.rb +76 -0
- data/lib/agree2/template.rb +100 -0
- data/lib/agree2/user.rb +73 -0
- data/lib/agree2.rb +34 -0
- data/spec/agreement_spec.rb +190 -0
- data/spec/client_spec.rb +49 -0
- data/spec/fixtures/agreement.json +50 -0
- data/spec/fixtures/party.json +15 -0
- data/spec/party_spec.rb +138 -0
- data/spec/proxy_collection_spec.rb +124 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/template_spec.rb +89 -0
- data/spec/user_spec.rb +77 -0
- metadata +118 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'json'
|
2
|
+
module Agree2
|
3
|
+
class ProxyCollection
|
4
|
+
alias_method :proxy_respond_to?, :respond_to? #:nodoc:
|
5
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_)/ }
|
6
|
+
attr_accessor :user,:path,:singular
|
7
|
+
def initialize(container,path,class_name=nil,values=nil)
|
8
|
+
@container=container
|
9
|
+
@user=(container.is_a?(User) ? container : container.user)
|
10
|
+
@path=path
|
11
|
+
path=~/(\w+)$/
|
12
|
+
@singular=(class_name||$1.singularize).downcase.classify
|
13
|
+
@klass=eval "Agree2::#{@singular}"
|
14
|
+
if values
|
15
|
+
@target=instantiate_items(values)
|
16
|
+
else
|
17
|
+
reset
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Builds an instance of the record
|
22
|
+
def build(attributes={})
|
23
|
+
@klass.new @container,attributes
|
24
|
+
end
|
25
|
+
|
26
|
+
# Builds and saves and instance of the record
|
27
|
+
def create(attributes={})
|
28
|
+
build(attributes).save
|
29
|
+
end
|
30
|
+
|
31
|
+
# Finds the instance given the id
|
32
|
+
def find(id)
|
33
|
+
@klass.get @container,id
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to?(symbol, include_priv = false) #:nodoc:
|
37
|
+
proxy_respond_to?(symbol, include_priv) || (load_target && @target.respond_to?(symbol, include_priv))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Explicitly proxy === because the instance method removal above
|
41
|
+
# doesn't catch it.
|
42
|
+
def ===(other) #:nodoc:
|
43
|
+
load_target
|
44
|
+
other === @target
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def parse_json(json) #:nodoc:
|
50
|
+
instantiate_items(JSON.parse(json))
|
51
|
+
end
|
52
|
+
|
53
|
+
def instantiate_items(list=[]) #:nodoc:
|
54
|
+
list.collect{|e|instantiate_item(e)}
|
55
|
+
end
|
56
|
+
|
57
|
+
def instantiate_item(attributes={}) #:nodoc:
|
58
|
+
@klass.new @container,attributes
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_target #:nodoc:
|
62
|
+
@target||=parse_json(@user.get("#{self.path}"))
|
63
|
+
end
|
64
|
+
|
65
|
+
def reset #:nodoc:
|
66
|
+
@target=nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def method_missing(method, *args, &block) #:nodoc:
|
70
|
+
if load_target
|
71
|
+
@target.send(method, *args, &block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Agree2
|
2
|
+
# The Template allows you to create agreements based on a template. You can pick between existing community created templates or
|
3
|
+
# create your own that fits your application.
|
4
|
+
#
|
5
|
+
# To review some of the public templates available go to: https://agree2.com/masters/public
|
6
|
+
#
|
7
|
+
# If you plan on creating and signing an agreement for your user to accept the process is like this:
|
8
|
+
#
|
9
|
+
# 1. Load your template
|
10
|
+
# 2. Prepare and Sign the agreement, which fills out the template, invites your user and signs it on your behalf
|
11
|
+
# 3. Redirect the User to Accept
|
12
|
+
# 4. User Accepts agreement
|
13
|
+
# 5. Agree2 optional calls an "endpoint" web service on your web service.
|
14
|
+
# 6. User is redirected back to your application to a URL you designate
|
15
|
+
#
|
16
|
+
class Template<Agreement
|
17
|
+
|
18
|
+
def self.collection_name #:nodoc:
|
19
|
+
"masters"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Prepares a template and optionally invites parties.
|
23
|
+
#
|
24
|
+
# === optional fields
|
25
|
+
#
|
26
|
+
# <tt>fields</tt> - a hash of parameters to be used to fill out the template. eg:
|
27
|
+
#
|
28
|
+
# {:amount=>100,:valid_to=>1.month.from_now,:service=>'Ruby Developer'}
|
29
|
+
#
|
30
|
+
# <tt>parties</tt> - a hash of parties. The hash should follow this format:
|
31
|
+
#
|
32
|
+
# { :client=>{:first_name=>'Bob',:last_name=>'Bryson',:email=>'bob@bob.inv',:organization_name=>'Big Client Inc'}}
|
33
|
+
#
|
34
|
+
# The above adds a party with the role *client*. The first_name, last_name and email fields are all required.
|
35
|
+
#
|
36
|
+
# <tt>application_role</tt> if you would like to add your applications user as a party set this to the role that you want:
|
37
|
+
#
|
38
|
+
# @template.prepare {},{},"broker"
|
39
|
+
#
|
40
|
+
# Adds your application as a party with the role broker.
|
41
|
+
#
|
42
|
+
# A typical example for a consulting agreement:
|
43
|
+
#
|
44
|
+
# @template.prepare {:rate=>"140",:valid_to=>"1 month from today"},
|
45
|
+
# {
|
46
|
+
# :consultant=>{:first_name=>'Alice',:last_name=>'Springs',:email=>'alice@example.com'},
|
47
|
+
# :client=>{:first_name=>'Bob',:last_name=>'Bryson',:email=>'bob@bob.inv',
|
48
|
+
# :organization_name=>'Big Client Inc'}
|
49
|
+
# }
|
50
|
+
# }
|
51
|
+
#
|
52
|
+
def prepare(fields={},parties={},application_role=nil)
|
53
|
+
Party.validate_parties_hash(parties)
|
54
|
+
parties[application_role]=:application if application_role
|
55
|
+
raw_prepare(:fields=>fields,:parties=>parties)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Prepares a template, invites parties and signs it with your application
|
59
|
+
#
|
60
|
+
# === required fields
|
61
|
+
#
|
62
|
+
# <tt>fields</tt> - a hash of parameters to be used to fill out the template. eg:
|
63
|
+
#
|
64
|
+
# {:amount=>100,:valid_to=>1.month.from_now,:service=>'Ruby Developer'}
|
65
|
+
#
|
66
|
+
# <tt>parties</tt> - a hash of parties. The hash should follow this format:
|
67
|
+
#
|
68
|
+
# { :client=>{:first_name=>'Bob',:last_name=>'Bryson',:email=>'bob@bob.inv',:organization_name=>'Big Client Inc'}}
|
69
|
+
#
|
70
|
+
# The above adds a party with the role *client*. The first_name, last_name and email fields are all required.
|
71
|
+
#
|
72
|
+
# <tt>application_role</tt> if you would like to add your applications user as a party set this to the role that you want:
|
73
|
+
#
|
74
|
+
# @template.prepare_and_sign {},{},"broker"
|
75
|
+
#
|
76
|
+
# Adds your application as a party with the role broker.
|
77
|
+
#
|
78
|
+
# A typical example for a user agreement:
|
79
|
+
#
|
80
|
+
# @template.prepare_and_sign {:name=>"Alice Springs"},
|
81
|
+
# {
|
82
|
+
# :user=>{:first_name=>'Alice',:last_name=>'Springs',:email=>'alice@example.com'}
|
83
|
+
# },'service'
|
84
|
+
# }
|
85
|
+
#
|
86
|
+
|
87
|
+
def prepare_and_sign(fields={},parties={},application_role='application')
|
88
|
+
raise ArgumentError,"You need to add at least one party" if parties.empty?
|
89
|
+
Party.validate_parties_hash(parties)
|
90
|
+
parties[application_role]=:application
|
91
|
+
raw_prepare(:fields=>fields,:parties=>parties,:sign=>application_role)
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def raw_prepare(params={}) #:nodoc:
|
97
|
+
Agreement.new @user, user.post("/masters/#{permalink}/prepare",params)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/agree2/user.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
AGREE2_JSON_HEADERS={'Content-Type'=>'application/json','Accept'=>'application/json'}
|
2
|
+
module Agree2
|
3
|
+
class User
|
4
|
+
attr_accessor :client,:access_token
|
5
|
+
def initialize(client,key,secret)
|
6
|
+
@client=client
|
7
|
+
@access_token=OAuth::AccessToken.new @client.consumer,key,secret
|
8
|
+
end
|
9
|
+
|
10
|
+
def agreements
|
11
|
+
@agreements||=Agree2::ProxyCollection.new self,'/agreements','Agreement'
|
12
|
+
end
|
13
|
+
|
14
|
+
def templates
|
15
|
+
@templates||=Agree2::ProxyCollection.new self,'/masters','Template'
|
16
|
+
end
|
17
|
+
|
18
|
+
def get(path)
|
19
|
+
handle_response @access_token.get(path,AGREE2_JSON_HEADERS)
|
20
|
+
end
|
21
|
+
|
22
|
+
def head(path)
|
23
|
+
handle_response @access_token.head(path,AGREE2_JSON_HEADERS)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post(path,data=nil)
|
27
|
+
handle_response @access_token.post(path,(data ? data.to_json : nil),AGREE2_JSON_HEADERS)
|
28
|
+
end
|
29
|
+
|
30
|
+
def put(path,data=nil)
|
31
|
+
handle_response @access_token.put(path,(data ? data.to_json : nil),AGREE2_JSON_HEADERS )
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(path)
|
35
|
+
handle_response @access_token.delete(path,AGREE2_JSON_HEADERS)
|
36
|
+
end
|
37
|
+
|
38
|
+
# OAuth Stuff below here
|
39
|
+
|
40
|
+
# The AccessToken token
|
41
|
+
def token
|
42
|
+
@access_token.token
|
43
|
+
end
|
44
|
+
|
45
|
+
# The AccessToken secret
|
46
|
+
def secret
|
47
|
+
@access_token.secret
|
48
|
+
end
|
49
|
+
|
50
|
+
def path #:nodoc:
|
51
|
+
""
|
52
|
+
end
|
53
|
+
protected
|
54
|
+
|
55
|
+
def handle_response(response)#:nodoc:
|
56
|
+
case response.code
|
57
|
+
when "200"
|
58
|
+
response.body
|
59
|
+
when "201"
|
60
|
+
response.body
|
61
|
+
when "302"
|
62
|
+
if response['Location']=~/(#{AGREE2_URL})\/(.*)$/
|
63
|
+
parts=$2.split('/')
|
64
|
+
(('Agree2::'+parts[0].classify).constantize).get self,parts[1]
|
65
|
+
else
|
66
|
+
#todo raise hell
|
67
|
+
end
|
68
|
+
else
|
69
|
+
response
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/agree2.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'rubygems'
|
3
|
+
gem 'oauth', ">= 0.2.4"
|
4
|
+
require 'oauth'
|
5
|
+
gem 'json'
|
6
|
+
gem 'activesupport'
|
7
|
+
require 'activesupport'
|
8
|
+
AGREE2_ENV = :production unless defined?(AGREE2_ENV)
|
9
|
+
AGREE2_URL = (AGREE2_ENV==:development) ? 'http://agree2.dev' : 'https://agree2.com'
|
10
|
+
module Agree2
|
11
|
+
class Agree2Exception < RuntimeError #:nodoc:
|
12
|
+
end
|
13
|
+
end
|
14
|
+
require 'agree2/client'
|
15
|
+
require 'agree2/proxy_collection'
|
16
|
+
require 'agree2/user'
|
17
|
+
require 'agree2/base'
|
18
|
+
require 'agree2/agreement'
|
19
|
+
require 'agree2/party'
|
20
|
+
require 'agree2/template'
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
# FireEagle addition to the <code>OAuth::Consumer</code> class. Taken from Yahoo FireEagle GEM
|
25
|
+
class OAuth::Consumer
|
26
|
+
alias_method :create_http_with_verify, :create_http
|
27
|
+
# Monkey patch to silence the SSL warnings
|
28
|
+
def create_http_without_verify #:nodoc:
|
29
|
+
http_object = create_http_with_verify
|
30
|
+
http_object.verify_mode = OpenSSL::SSL::VERIFY_NONE if uri.scheme=="https"
|
31
|
+
http_object
|
32
|
+
end
|
33
|
+
alias_method :create_http, :create_http_without_verify
|
34
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"spec_helper")
|
2
|
+
describe Agree2::Agreement do
|
3
|
+
before(:each) do
|
4
|
+
@client=Agree2::Client.new "client_key","client_secret"
|
5
|
+
@user=Agree2::User.new(@client,"token","token_secret")
|
6
|
+
@json=IO.read(File.join(File.dirname(__FILE__),"fixtures","agreement.json"))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Built from hash" do
|
10
|
+
before(:each) do
|
11
|
+
@agreement=Agree2::Agreement.new(@user,{:title=>"My Title",:body=>"My Body"})
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have attribute hash" do
|
15
|
+
@agreement.attributes.should=={:title=>"My Title",:body=>"My Body"}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a user" do
|
19
|
+
@agreement.user.should==@user
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have title" do
|
23
|
+
@agreement.title.should=="My Title"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have body" do
|
27
|
+
@agreement.body.should=="My Body"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be new record" do
|
31
|
+
@agreement.should be_new_record
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "Save to Server" do
|
35
|
+
before(:each) do
|
36
|
+
@user.should_receive(:post).with("/agreements",{'agreement'=>{:title=>"My Title",:body=>"My Body"}}).and_return(@json)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should save and return true" do
|
40
|
+
@agreement.save
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should no longer be new record" do
|
44
|
+
@agreement.save
|
45
|
+
@agreement.should_not be_new_record
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have a permalink" do
|
49
|
+
@agreement.save
|
50
|
+
@agreement.permalink.should_not be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "from json" do
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
@agreement=Agree2::Agreement.new(@user,@json)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should have a user" do
|
62
|
+
@agreement.user.should==@user
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should have title" do
|
66
|
+
@agreement.title.should=="Agreement to pay [currency=USD] [amount=100] to [recipient]"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have permalink" do
|
70
|
+
@agreement.permalink.should=="hello"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should have a nil body" do
|
74
|
+
@agreement.body.should be_nil
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have a path" do
|
78
|
+
@agreement.path.should=="/agreements/hello"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should have a url" do
|
82
|
+
@agreement.to_url.should=="https://agree2.com/agreements/hello"
|
83
|
+
end
|
84
|
+
|
85
|
+
[:created_at,:updated_at,:fields,:state,:active_version,:version,
|
86
|
+
:digest,:finalized_at,:finalized_at,:terminated_at,:activated_at,:valid_to].each do |field|
|
87
|
+
it "should have #{field}" do
|
88
|
+
@agreement.send(field).should_not be_nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should have fields" do
|
93
|
+
@agreement.fields.should=={
|
94
|
+
"amount"=> "100",
|
95
|
+
"currency"=> "USD"
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should have methods defined for fields" do
|
100
|
+
@agreement.amount.should=="100"
|
101
|
+
@agreement.currency.should=="USD"
|
102
|
+
end
|
103
|
+
[:amount,:currency].each do |field|
|
104
|
+
it "should support setting the value" do
|
105
|
+
@agreement.send("#{field.to_s}=".to_sym,"test this")
|
106
|
+
@agreement.send(field).should=="test this"
|
107
|
+
@agreement.fields[field.to_s].should=="test this"
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should have respond_to wired for field accessor" do
|
111
|
+
@agreement.respond_to?(field).should==true
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should have respond_to wired for field setter" do
|
115
|
+
@agreement.respond_to?("#{field.to_s}=".to_sym).should==true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should not be new record" do
|
120
|
+
@agreement.should_not be_new_record
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should reload" do
|
124
|
+
@user.should_receive(:get).with("/agreements/hello").and_return(@json)
|
125
|
+
@agreement.reload
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should destroy" do
|
129
|
+
@user.should_receive(:delete).with("/agreements/hello").and_return("")
|
130
|
+
@agreement.destroy
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should finalize" do
|
134
|
+
@user.should_receive(:post).with("/agreements/hello/finalize").and_return(" ")
|
135
|
+
@agreement.finalize!.should==true
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "Save to Server" do
|
139
|
+
before(:each) do
|
140
|
+
@user.should_receive(:put).with("/agreements/hello",{"fields"=>@agreement.fields}).and_return(@json)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should save and return true" do
|
144
|
+
@agreement.save
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should not a be new record" do
|
148
|
+
@agreement.save
|
149
|
+
@agreement.should_not be_new_record
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should have a permalink" do
|
153
|
+
@agreement.save
|
154
|
+
@agreement.permalink.should_not be_nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "load from server" do
|
160
|
+
before(:each) do
|
161
|
+
@user.should_receive(:get).with("/agreements/hello").and_return(@json)
|
162
|
+
end
|
163
|
+
|
164
|
+
def do_get
|
165
|
+
@agreement=Agree2::Agreement.get(@user,"hello")
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should have a user" do
|
169
|
+
do_get
|
170
|
+
@agreement.user.should==@user
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should have title" do
|
174
|
+
do_get
|
175
|
+
@agreement.title.should=="Agreement to pay [currency=USD] [amount=100] to [recipient]"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should have permalink" do
|
179
|
+
do_get
|
180
|
+
@agreement.permalink.should=="hello"
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should not be new record" do
|
184
|
+
do_get
|
185
|
+
@agreement.should_not be_new_record
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"spec_helper")
|
2
|
+
|
3
|
+
describe Agree2::Client do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@client=Agree2::Client.new "client_key","client_secret"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should contain key and secret" do
|
10
|
+
@client.key.should=="client_key"
|
11
|
+
@client.secret.should=="client_secret"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have consumer" do
|
15
|
+
consumer=@client.consumer
|
16
|
+
consumer.key.should==@client.key
|
17
|
+
consumer.secret.should==@client.secret
|
18
|
+
consumer.site.should=="https://agree2.com"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should create user" do
|
22
|
+
user=@client.user("token","token_secret")
|
23
|
+
user.client.should==@client
|
24
|
+
user.access_token.consumer.should==@client.consumer
|
25
|
+
user.token.should=="token"
|
26
|
+
user.secret.should=="token_secret"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create request token" do
|
30
|
+
request_token=mock("access_token")
|
31
|
+
@client.consumer.should_receive(:get_request_token).and_return(request_token)
|
32
|
+
token=@client.get_request_token
|
33
|
+
token.should==request_token
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create request token" do
|
37
|
+
request_token=mock("request_token")
|
38
|
+
access_token=mock("access_token")
|
39
|
+
access_token.stub!(:token).and_return('token')
|
40
|
+
access_token.stub!(:secret).and_return('token_secret')
|
41
|
+
request_token.should_receive(:get_access_token).and_return(access_token)
|
42
|
+
user=@client.user_from_request_token(request_token)
|
43
|
+
user.client.should==@client
|
44
|
+
user.access_token.consumer.should==@client.consumer
|
45
|
+
user.token.should=="token"
|
46
|
+
user.secret.should=="token_secret"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
{
|
2
|
+
"permalink": "hello",
|
3
|
+
"valid_to": "2009/08/12 22:04:51 +0000",
|
4
|
+
"updated_at": "2008/08/12 22:04:51 +0000",
|
5
|
+
"activated_at": "2008/08/12 22:04:51 +0000",
|
6
|
+
"parties": [
|
7
|
+
{
|
8
|
+
"updated_at": "2008/08/12 22:04:51 +0000",
|
9
|
+
"invited_by_id": null,
|
10
|
+
"account_id": null,
|
11
|
+
"role": "client",
|
12
|
+
"organization_name": null,
|
13
|
+
"invited_at": null,
|
14
|
+
"id": 1102,
|
15
|
+
"agreement_id": 757,
|
16
|
+
"user_id": null,
|
17
|
+
"first_name": "Bob",
|
18
|
+
"accept_code": "d373b3dc17b7177aa0626e6ce7f449fcc3ca7c9c",
|
19
|
+
"last_name": "Wildcat",
|
20
|
+
"email": "bob@gmail.inv",
|
21
|
+
"created_at": "2008/08/12 22:04:51 +0000"},
|
22
|
+
{
|
23
|
+
"updated_at": "2008/08/12 22:04:51 +0000",
|
24
|
+
"invited_by_id": null,
|
25
|
+
"account_id": 1,
|
26
|
+
"role": "provider",
|
27
|
+
"organization_name": null,
|
28
|
+
"invited_at": null,
|
29
|
+
"id": 1103,
|
30
|
+
"agreement_id": 757,
|
31
|
+
"user_id": 1,
|
32
|
+
"first_name": "Pelle",
|
33
|
+
"accept_code": "39e6c8c02e8ee9efb7a3606a45b3e297ce616b55",
|
34
|
+
"last_name": "Braendgaard",
|
35
|
+
"email": "pelle@stakeventures.com",
|
36
|
+
"created_at": "2008/08/12 22:04:51 +0000"}
|
37
|
+
],
|
38
|
+
"title": "Agreement to pay [currency=USD] [amount=100] to [recipient]",
|
39
|
+
"active_version": 1,
|
40
|
+
"smart_fields": {
|
41
|
+
"amount": "100",
|
42
|
+
"currency": "USD"
|
43
|
+
},
|
44
|
+
"terminated_at": "2008/08/12 22:04:51 +0000",
|
45
|
+
"digest": "70b2d46022ae44ea8041c7573e856a14b2186273",
|
46
|
+
"finalized_at": "2008/08/12 22:04:51 +0000",
|
47
|
+
"version": 1,
|
48
|
+
"description": "An agreement",
|
49
|
+
"state": "final",
|
50
|
+
"created_at": "2008/08/12 22:04:51 +0000"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"updated_at": "2008/08/12 22:04:51 +0000",
|
3
|
+
"invited_by_id": null,
|
4
|
+
"account_id": null,
|
5
|
+
"role": "client",
|
6
|
+
"organization_name": null,
|
7
|
+
"invited_at": null,
|
8
|
+
"id": 1102,
|
9
|
+
"agreement_id": 757,
|
10
|
+
"user_id": null,
|
11
|
+
"first_name": "Bob",
|
12
|
+
"last_name": "Wildcat",
|
13
|
+
"email": "bob@gmail.inv",
|
14
|
+
"created_at": "2008/08/12 22:04:51 +0000"
|
15
|
+
}
|