diff --git a/lib/freeagent/base.rb b/lib/freeagent/base.rb
deleted file mode 100644
index 56718fc..0000000
--- a/lib/freeagent/base.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-module Freeagent
-
- class Base
-
- def initialize(attributes={})
- attributes.each do |key, value|
- raise "no attr_accessor set for #{key} on #{self.class}" if !respond_to?("#{key}=")
- self.send("#{key}=", value)
- end
- end
-
- def self.get(path)
- @@resp = APICache.get(path) do
- http = Net::HTTP.new(Freeagent.domain, 443)
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
- http.start do |http|
- request = Net::HTTP::Get.new(path, {'Content-Type' => 'application/xml', 'Accept' => 'application/xml'})
- request.basic_auth(Freeagent.username, Freeagent.password)
- response = http.request(request)
- case response
- when Net::HTTPSuccess
- @@resp = response.body
- else
- response.error!
- raise APICache::InvalidResponse
- end
- end
- end
- end
-
- def self.parse(path, options)
- response = []
- Nokogiri::XML(@@resp).xpath(path).each do |ts|
- res = {}
- options.each do |key|
- res[key.underscore.to_sym] = ts.xpath(key).text
- end
- response << self.new(res)
- end
- return response
- end
-
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/contact.rb b/lib/freeagent/contact.rb
deleted file mode 100644
index ce89c39..0000000
--- a/lib/freeagent/contact.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module Freeagent
-
- class Contact < Base
- @elements = ['id', 'organisation-name', 'first-name', 'last-name', 'address1', 'address2', 'address3', 'town', 'region', 'country', 'postcode', 'phone-number', 'email', 'contact-name-on-invoices', 'sales-tax-registration_number', 'uses-contact-invoice-sequence']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find_all
- get '/contacts'
- contacts = parse('contacts/contact', @elements)
- return contacts
- end
-
- def self.find(contact_id)
- get '/contacts/'+contact_id
- contacts = parse('contact', @elements)
- return contacts[0]
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/invoice.rb b/lib/freeagent/invoice.rb
deleted file mode 100644
index 26c2801..0000000
--- a/lib/freeagent/invoice.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-module Freeagent
-
- class Invoice < Base
- @elements = ['id', 'contact-id', 'project-id', 'dated-on', 'due-on', 'reference', 'net-value', 'sales-tax-value', 'status', 'comments', 'discount-percent', 'omit-header', 'payment-terms', 'written-off-date', 'invoice-items']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find_all(project_id = false)
- if project_id
- get '/projects/'+project_id+'/invoices'
- else
- get '/invoices'
- end
- invoices = parse('invoices/invoice', @elements)
- return invoices.reverse
- end
-
- def self.find(invoice_id)
- get '/invoices/'+invoice_id
- invoices = parse('invoice', @elements)
- invoices.each do |i|
- i.invoice_items = InvoiceItem.find_all(invoice_id)
- end
- return invoices[0]
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/invoice_item.rb b/lib/freeagent/invoice_item.rb
deleted file mode 100644
index be65220..0000000
--- a/lib/freeagent/invoice_item.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module Freeagent
-
- class InvoiceItem < Invoice
- @elements = ['id', 'invoice-id', 'project-id', 'item-type', 'price', 'quantity', 'description', 'sales-tax-rate']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find_all(invoice_id)
- items = parse('invoice/invoice-items/invoice-item', @elements)
- return items
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/project.rb b/lib/freeagent/project.rb
deleted file mode 100644
index 4b70aac..0000000
--- a/lib/freeagent/project.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-module Freeagent
-
- class Project < Base
- @elements = ['id', 'contact-id', 'name', 'billing-basis', 'budget', 'budget-units', 'invoicing-reference', 'is-ir35', 'normal-billing-rate', 'payment-terms-in-days', 'starts-on', 'ends-on', 'status', 'uses-project-invoice-sequence']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find_all
- get '/projects'
- projects = parse('projects/project', @elements)
- return projects
- end
-
- def self.find(project_id)
- get '/projects/'+project_id
- projects = parse('project', @elements)
- return projects[0]
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/task.rb b/lib/freeagent/task.rb
deleted file mode 100644
index 2cda2fd..0000000
--- a/lib/freeagent/task.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-module Freeagent
-
- class Task < Base
- @elements = ['id', 'project-id', 'name']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find(project_id, task_id)
- get '/projects/'+project_id+'/tasks/'+task_id
- tasks = parse('task', @elements)
- return tasks[0]
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent/timeslip.rb b/lib/freeagent/timeslip.rb
deleted file mode 100644
index d3e196c..0000000
--- a/lib/freeagent/timeslip.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-module Freeagent
-
- class Timeslip < Base
- @elements = ['id', 'dated-on', 'project-id', 'task-id', 'task', 'user-id', 'hours', 'comment']
- @elements.each {|t| attr_accessor t.underscore.to_sym}
-
- def self.find_all(project_id = false)
- if project_id
- get '/projects/'+project_id+'/timeslips'
- else
- get '/timeslips'
- end
- timeslips = parse('timeslips/timeslip', @elements)
- timeslips.each do |t|
- t.task = Task.find(project_id, t.task_id)
- end
- return timeslips.reverse
- end
-
- def self.find(timeslip_id)
- get '/timeslips'+timeslip_id
- timeslips = parse('timeslip', @elements)
- return timeslips[0]
- end
- end
-
-end
\ No newline at end of file
diff --git a/lib/freeagent_api.rb b/lib/freeagent_api.rb
index b36536f..50aae0d 100644
--- a/lib/freeagent_api.rb
+++ b/lib/freeagent_api.rb
@@ -1,29 +1,190 @@
require 'rubygems'
-require 'nokogiri'
-require 'net/https'
-require 'api_cache'
-require 'activesupport'
require 'activeresource'
-# Require Freeagent library files
-Dir[File.join(File.dirname(__FILE__), "freeagent/*.rb")].each { |f| require f }
-
module Freeagent
class << self
attr_accessor :domain, :username, :password
+ end
+
+ class Error < StandardError; end
- def self.domain=(domain)
- @domain = domain
+ class Base < ActiveResource::Base
+ def self.authenticate
+ self.site = "https://#{Freeagent.domain}"
+ self.user = Freeagent.username
+ self.password = Freeagent.password
end
+ end
+
+ # Find contacts
+ #
+ # Contact.find :all # find all contacts
+ # Contact.find contact_id # find specific contact by ID
+ #
+ # Create contact
+ #
+ # Required attributes
+ # :first_name
+ # :last_name
+ #
+ # contact = Contact.new :first_name => 'Joe', :last_name => 'Bloggs'
+ # contact.save
+ #
+ # Update contact
+ #
+ # contact = Contact.find contact_id
+ # contact.first_name = 'Joe'
+ # contact.last_name = 'Bloggs'
+ # contact.save
+ #
+ # Delete contact
+ #
+ # Contact.delete contact_id
+ # contact.destroy
+ #
+
+ class Contact < Base
+ end
+
+ # Find projects
+ #
+ # Project.find :all # find all projects
+ # Project.find project_id # find specific project by ID
+ #
+ # Create project
+ #
+ # Required attributes
+ # :contact_id
+ # :name
+ # :payment_term_in_days
+ # :billing_basis # must be 1, 7, 7.5, or 8
+ # :budget_units # must be Hours, Days, or Monetary
+ # :status # must be Active or Completed
+ #
+ # Project = Project.new params
+ # contact.save
+ #
+ # Update project
+ #
+ # project = Project.find project_id
+ # project.name = 'Website redesign and build'
+ # project.save
+ #
+ # Delete project
+ #
+ # Project.delete project_id
+ # project.destroy
+ #
+
+ class Project < Base
- def self.username=(username)
- @username = username
+ def invoices
+ Invoice.find :all, :params => {:project_id => id}
+ end
+
+ def tasks
+ Task.find :all, :params => {:project_id => id}
+ end
+
+ def timeslips
+ Timeslip.find :all, :params => {:project_id => id}
end
- def self.password=(password)
- @password = password
+ end
+
+ # Find invoices
+ #
+ # Invoice.find :all
+ # Invoice.find :all, :params => {:project_id => project_id}
+ # Invoice.find task_id
+ #
+ #TODO Create invoice
+ #
+ #TODO Update invoice
+ #
+ #TODO Delete project
+ #
+ ##TODO add Change status methods
+ # /invoices/invoice_id/mark_as_draft
+ # /invoices/invoice_id/mark_as_sent
+ # /invoices/invoice_id/mark_as_cancelled
+
+
+ class Invoice < Base
+
+ def self.find(*args)
+ opts = args.slice!(1) || {}
+ self.prefix = "/projects/#{opts[:params][:project_id]}/" if opts[:params] && opts[:params][:project_id]
+ super
+ end
+
+ end
+
+ # Find invoice items
+ #
+ # InvoiceItem.find :all, :params => {:invoice_id => invoice_id}
+ # InvoiceItem.find invoice_item_id, :params => {:invoice_id => invoice_id}
+ #
+ #TODO Create invoice item
+ #
+
+ class InvoiceItem < Base
+ self.prefix = '/invoices/:invoice_id/'
+ end
+
+ # Find tasks
+ #
+ # Task.find :all
+ # Task.find :all, :params => {:project_id => project_id}
+ # Task.find task_id
+ #
+ #TODO Create task
+ #
+ #TODO Update task
+ #
+ #TODO Delete project
+ #
+
+ class Task < Base
+
+ self.prefix = '/projects/:project_id/'
+
+# def self.find(*args)
+# opts = args.slice!(1) || {}
+# self.prefix = "/projects/#{opts[:params][:project_id]}/" if opts[:params] && opts[:params][:project_id]
+# super
+# end
+
+ end
+
+ # Find timeslips
+ #
+ # Timeslip.find :all, :params => {:view => '2009-01-01_2009-10-01'}
+ # Timeslip.find :all, :params => {:project_id => project_id}
+ # Timeslip.find :timeslip_id
+
+
+ class Timeslip < Base
+
+ def self.find(*args)
+ opts = args.slice!(1) || {}
+ self.prefix = "/projects/#{opts[:params][:project_id]}/" if opts[:params] && opts[:params][:project_id]
+ super
end
+
end
+# class ActiveResource::Connection
+# def http
+# http = Net::HTTP.new(@site.host, @site.port)
+# http.use_ssl = @site.is_a?(URI::HTTPS)
+# http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
+# http.read_timeout = @timeout if @timeout
+# #Here's the addition that allows you to see the output
+# http.set_debug_output $stderr
+# return http
+# end
+# end
+
end
\ No newline at end of file
diff --git a/test/freeagent_api_test.rb b/test/freeagent_api_test.rb
index 8e741bf..8934d77 100644
--- a/test/freeagent_api_test.rb
+++ b/test/freeagent_api_test.rb
@@ -1,31 +1,12 @@
require 'test_helper'
-require 'yaml'
class FreeagentApiTest < Test::Unit::TestCase
- include Freeagent
-
- context "Before we do anything, we" do
- setup do
- @config ||= YAML.load_file 'test/user_credentials.yaml'
- end
- should "set the domain" do
- assert Freeagent.domain = @config['domain']
- end
- should "set the username" do
- assert Freeagent.username = @config['username']
- end
- should "set the password" do
- assert Freeagent.password = @config['password']
- end
- end
-
- context "Many projects" do
- setup do
- @projects = Project.find_all
- end
- should "be in an array" do
- assert @projects.is_a? Array
+ context "Authentication details" do
+ should "match what was set" do
+ assert_equal Base.site, URI.parse('https://testuser.freeagentcentral.com')
+ assert_equal Base.user, 'testuser'
+ assert_equal Base.password, 'testpass'
end
end
diff --git a/test/project_test.rb b/test/project_test.rb
new file mode 100644
index 0000000..1c73b00
--- /dev/null
+++ b/test/project_test.rb
@@ -0,0 +1,37 @@
+require 'test_helper'
+
+class ProjectTest < Test::Unit::TestCase
+
+ def setup
+ fake_it_all
+ @projects = Project.find :all
+ @project = Project.find 17820
+ end
+
+ context "Project class" do
+ should "have correct collection path" do
+ assert_equal Project.collection_path, '/projects.xml'
+ end
+ should "have correct element path" do
+ assert_equal Project.element_path(:first), '/projects/first.xml'
+ assert_equal Project.element_path(1), '/projects/1.xml'
+ end
+ end
+
+ context "Projects" do
+ should "return an array" do
+ assert @projects.is_a? Array
+ end
+ should "return projects" do
+ assert_equal 5, @projects.size
+ assert @projects.first.is_a? Project
+ end
+ end
+
+ context "Project" do
+ should "return a Project" do
+ assert @project.is_a? Project
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/test/stubs/projects/get b/test/stubs/projects/get
new file mode 100644
index 0000000..6e72675
--- /dev/null
+++ b/test/stubs/projects/get
@@ -0,0 +1,92 @@
+HTTP/1.1 200 OK
+Status: 200
+Content-Type: application/xml; charset=utf-8
+
+
+
+
+ 7.5
+ 0
+ Hours
+ 27314
+
+ 2009-08-26T17:11:22Z
+
+ 17820
+ false
+ Ecommerce web development
+ 200.0
+
+ Active
+ 2009-08-26T17:11:22Z
+ false
+
+
+ 1.0
+ 8
+ Hours
+ 27317
+
+ 2009-10-09T09:53:29Z
+ 2009-12-01T00:00:00Z
+ 20601
+ false
+ Website multi-lingual support
+ 35.0
+ 2009-11-30T00:00:00Z
+ Active
+ 2009-10-09T10:53:21Z
+ false
+
+
+ 1.0
+ 0
+ Hours
+ 27318
+
+ 2009-10-20T08:47:31Z
+
+ 21356
+ false
+ Ongoing design and maintenance work
+ 30.0
+
+ Active
+ 2009-10-20T08:47:31Z
+ false
+
+
+ 1.0
+ 61
+ Hours
+ 30530
+
+ 2009-10-09T10:00:52Z
+ 2009-12-01T00:00:00Z
+ 20602
+ false
+ Website redesign and redevelopment
+ 35.0
+ 2009-10-26T00:00:00Z
+ Active
+ 2009-10-09T10:39:08Z
+ false
+
+
+ 1.0
+ 34
+ Hours
+ 30530
+
+ 2009-10-09T10:15:26Z
+ 2010-01-12T00:00:00Z
+ 20603
+ false
+ Single page product mini sites
+ 35.0
+ 2009-12-08T00:00:00Z
+ Active
+ 2009-10-09T10:59:29Z
+ false
+
+
\ No newline at end of file
diff --git a/test/stubs/projects/get_17820 b/test/stubs/projects/get_17820
new file mode 100644
index 0000000..ff7cc27
--- /dev/null
+++ b/test/stubs/projects/get_17820
@@ -0,0 +1,22 @@
+HTTP/1.1 200 OK
+Status: 200
+Content-Type: application/xml; charset=utf-8
+
+
+
+ 7.5
+ 0
+ Hours
+ 27314
+
+ 2009-08-26T17:11:22Z
+
+ 17820
+ false
+ Ecommerce web development
+ 200.0
+
+ Active
+ 2009-08-26T17:11:22Z
+ false
+
\ No newline at end of file
diff --git a/test/task_test.rb b/test/task_test.rb
new file mode 100644
index 0000000..a68fa79
--- /dev/null
+++ b/test/task_test.rb
@@ -0,0 +1,16 @@
+require 'test_helper'
+
+
+class TaskTest < Test::Unit::TestCase
+
+ context "Task class" do
+ should "have correct collection path" do
+ assert Task.collection_path(:project_id => 1000) === '/projects/1000/tasks.xml'
+ end
+ should "have correct element path" do
+ assert Task.element_path(:first, :project_id => 1000) === '/projects/1000/tasks/first.xml'
+ assert Task.element_path(1000, :project_id => 1000) === '/projects/1000/tasks/1000.xml'
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/test/test_helper.rb b/test/test_helper.rb
index c31b765..4cf045a 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,10 +1,37 @@
require 'rubygems'
require 'test/unit'
require 'shoulda'
+require 'fakeweb'
+require 'pp'
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
+
require 'freeagent_api'
+include Freeagent
+
+Freeagent.domain = 'testuser.freeagentcentral.com'
+Freeagent.username = 'testuser'
+Freeagent.password = 'testpass'
+
+Base.authenticate
+
+FakeWeb.allow_net_connect = false
+
+def stub_file(path)
+ File.join(File.dirname(__FILE__), 'stubs', path)
+end
+
+def fake_it_all
+ FakeWeb.clean_registry
+ fakes = {
+ "/projects.xml" => File.join('projects', 'get'),
+ "/projects/17820.xml" => File.join('projects', 'get_17820')
+ }
+ fakes.each do |path, stub|
+ FakeWeb.register_uri(:get, 'https://testuser:testpass@testuser.freeagentcentral.com'+path, :response => stub_file(stub))
+ end
+end
class Test::Unit::TestCase
end