Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added invoice payment support

  • Loading branch information...
commit 2563bda8d9001279e7f2253dfa7bbb08ee5c67e8 1 parent 9f809e8
@awd awd authored prsimp committed
View
31 lib/harvest/api/invoice_payments.rb
@@ -0,0 +1,31 @@
+module Harvest
+ module API
+ class InvoicePayments < Base
+ api_model Harvest::InvoicePayment
+ include Harvest::Behavior::Crud
+
+ def all(invoice)
+ response = request(:get, credentials, "/invoices/#{invoice.to_i}/payments")
+ api_model.parse(response.parsed_response)
+ end
+
+ def find(invoice, payment)
+ response = request(:get, credentials, "/invoices/#{invoice.to_i}/payments/#{payment.to_i}")
+ api_model.parse(response.parsed_response).first
+ end
+
+ def create(payment)
+ payment = api_model.wrap(payment)
+ response = request(:post, credentials, "/invoices/#{payment.invoice_id}/payments", :body => payment.to_json)
+ id = response.headers["location"].match(/\/.*\/(\d+)\/.*\/(\d+)/)[2]
+ find(payment.invoice_id, id)
+ end
+
+ def delete(payment)
+ request(:delete, credentials, "/invoices/#{payment.invoice_id}/payments/#{payment.to_i}")
+ payment.id
+ end
+
+ end
+ end
+end
View
134 lib/harvest/base.rb
@@ -1,7 +1,7 @@
module Harvest
class Base
attr_reader :request, :credentials
-
+
# @see Harvest.client
# @see Harvest.hardy_client
def initialize(subdomain, username, password, options = {})
@@ -9,7 +9,7 @@ def initialize(subdomain, username, password, options = {})
@credentials = Credentials.new(subdomain, username, password, options[:ssl])
raise InvalidCredentials unless credentials.valid?
end
-
+
# All API actions surrounding accounts
#
# == Examples
@@ -19,76 +19,76 @@ def initialize(subdomain, username, password, options = {})
def account
@account ||= Harvest::API::Account.new(credentials)
end
-
+
# All API Actions surrounding Clients
- #
+ #
# == Examples
# harvest.clients.all() # Returns all clients in the system
- #
+ #
# harvest.clients.find(100) # Returns the client with id = 100
- #
+ #
# client = Harvest::Client.new(:name => 'SuprCorp')
# saved_client = harvest.clients.create(client) # returns a saved version of Harvest::Client
- #
+ #
# client = harvest.clients.find(205)
# client.name = 'SuprCorp LTD.'
# updated_client = harvest.clients.update(client) # returns an updated version of Harvest::Client
- #
+ #
# client = harvest.clients.find(205)
# harvest.clients.delete(client) # returns 205
- #
+ #
# client = harvest.clients.find(301)
# deactivated_client = harvest.clients.deactivate(client) # returns an updated deactivated client
# activated_client = harvest.clients.activate(client) # returns an updated activated client
- #
+ #
# @see Harvest::Behavior::Crud
# @see Harvest::Behavior::Activatable
# @return [Harvest::API::Clients]
def clients
@clients ||= Harvest::API::Clients.new(credentials)
end
-
+
# All API Actions surrounding Client Contacts
- #
+ #
# == Examples
# harvest.contacts.all() # Returns all contacts in the system
# harvest.contacts.all(10) # Returns all contacts for the client id=10 in the system
- #
+ #
# harvest.contacts.find(100) # Returns the contact with id = 100
- #
+ #
# contact = Harvest::Contact.new(:first_name => 'Jane', :last_name => 'Doe', :client_id => 10)
# saved_contact = harvest.contacts.create(contact) # returns a saved version of Harvest::Contact
- #
+ #
# contact = harvest.contacts.find(205)
# contact.first_name = 'Jilly'
# updated_contact = harvest.contacts.update(contact) # returns an updated version of Harvest::Contact
- #
+ #
# contact = harvest.contacts.find(205)
# harvest.contacts.delete(contact) # returns 205
- #
+ #
# @see Harvest::Behavior::Crud
# @return [Harvest::API::Contacts]
def contacts
@contacts ||= Harvest::API::Contacts.new(credentials)
end
-
+
# All API Actions surrounding Projects
- #
+ #
# == Examples
# harvest.projects.all() # Returns all projects in the system
- #
+ #
# harvest.projects.find(100) # Returns the project with id = 100
- #
+ #
# project = Harvest::Project.new(:name => 'SuprGlu' :client_id => 10)
# saved_project = harvest.projects.create(project) # returns a saved version of Harvest::Project
- #
+ #
# project = harvest.projects.find(205)
# project.name = 'SuprSticky'
# updated_project = harvest.projects.update(project) # returns an updated version of Harvest::Project
- #
+ #
# project = harvest.project.find(205)
# harvest.projects.delete(project) # returns 205
- #
+ #
# project = harvest.projects.find(301)
# deactivated_project = harvest.projects.deactivate(project) # returns an updated deactivated project
# activated_project = harvest.projects.activate(project) # returns an updated activated project
@@ -102,67 +102,67 @@ def contacts
def projects
@projects ||= Harvest::API::Projects.new(credentials)
end
-
+
# All API Actions surrounding Tasks
- #
+ #
# == Examples
# harvest.tasks.all() # Returns all tasks in the system
- #
+ #
# harvest.tasks.find(100) # Returns the task with id = 100
- #
+ #
# task = Harvest::Task.new(:name => 'Server Administration' :default => true)
# saved_task = harvest.tasks.create(task) # returns a saved version of Harvest::Task
- #
+ #
# task = harvest.tasks.find(205)
# task.name = 'Server Administration'
# updated_task = harvest.tasks.update(task) # returns an updated version of Harvest::Task
- #
+ #
# task = harvest.task.find(205)
# harvest.tasks.delete(task) # returns 205
- #
+ #
# @see Harvest::Behavior::Crud
# @return [Harvest::API::Tasks]
def tasks
@tasks ||= Harvest::API::Tasks.new(credentials)
end
-
+
# All API Actions surrounding Users
- #
+ #
# == Examples
# harvest.users.all() # Returns all users in the system
- #
+ #
# harvest.users.find(100) # Returns the user with id = 100
- #
+ #
# user = Harvest::User.new(:first_name => 'Edgar', :last_name => 'Ruth', :email => 'edgar@ruth.com', :password => 'mypassword', :timezone => :cst, :admin => false, :telephone => '444-4444')
# saved_user = harvest.users.create(user) # returns a saved version of Harvest::User
- #
+ #
# user = harvest.users.find(205)
# user.email = 'edgar@ruth.com'
# updated_user = harvest.users.update(user) # returns an updated version of Harvest::User
- #
+ #
# user = harvest.users.find(205)
# harvest.users.delete(user) # returns 205
- #
+ #
# user = harvest.users.find(301)
# deactivated_user = harvest.users.deactivate(user) # returns an updated deactivated user
# activated_user = harvest.users.activate(user) # returns an updated activated user
- #
+ #
# user = harvest.users.find(401)
# harvest.users.reset_password(user) # will trigger the reset password feature of harvest and shoot the user an email
- #
+ #
# @see Harvest::Behavior::Crud
# @see Harvest::Behavior::Activatable
# @return [Harvest::API::Users]
def users
@users ||= Harvest::API::Users.new(credentials)
end
-
+
# All API Actions surrounding assigning tasks to projects
- #
+ #
# == Examples
# project = harvest.projects.find(101)
# harvest.task_assignments.all(project) # returns all tasks assigned to the project (as Harvest::TaskAssignment)
- #
+ #
# project = harvest.projects.find(201)
# harvest.task_assignments.find(project, 5) # returns the task assignment with ID 5 that is assigned to the project
#
@@ -184,13 +184,13 @@ def users
def task_assignments
@task_assignments ||= Harvest::API::TaskAssignments.new(credentials)
end
-
+
# All API Actions surrounding assigning users to projects
- #
+ #
# == Examples
# project = harvest.projects.find(101)
# harvest.user_assignments.all(project) # returns all users assigned to the project (as Harvest::UserAssignment)
- #
+ #
# project = harvest.projects.find(201)
# harvest.user_assignments.find(project, 5) # returns the user assignment with ID 5 that is assigned to the project
#
@@ -212,21 +212,21 @@ def task_assignments
def user_assignments
@user_assignments ||= Harvest::API::UserAssignments.new(credentials)
end
-
+
# All API Actions surrounding managing expense categories
#
# == Examples
# harvest.expense_categories.all() # Returns all expense categories in the system
- #
+ #
# harvest.expense_categories.find(100) # Returns the expense category with id = 100
- #
+ #
# category = Harvest::ExpenseCategory.new(:name => 'Mileage', :unit_price => 0.485)
# saved_category = harvest.expense_categories.create(category) # returns a saved version of Harvest::ExpenseCategory
- #
+ #
# category = harvest.clients.find(205)
# category.name = 'Travel'
# updated_category = harvest.expense_categories.update(category) # returns an updated version of Harvest::ExpenseCategory
- #
+ #
# category = harvest.expense_categories.find(205)
# harvest.expense_categories.delete(category) # returns 205
#
@@ -235,22 +235,22 @@ def user_assignments
def expense_categories
@expense_categories ||= Harvest::API::ExpenseCategories.new(credentials)
end
-
+
# All API Actions surrounding expenses
#
# == Examples
# harvest.expenses.all() # Returns all expenses for the current week
# harvest.expenses.all(Time.parse('11/12/2009')) # returns all expenses for the week of 11/12/2009
- #
+ #
# harvest.expenses.find(100) # Returns the expense with id = 100
def expenses
@expenses ||= Harvest::API::Expenses.new(credentials)
end
-
+
def time
@time ||= Harvest::API::Time.new(credentials)
end
-
+
def reports
@reports ||= Harvest::API::Reports.new(credentials)
end
@@ -262,5 +262,27 @@ def invoice_categories
def invoices
@invoices ||= Harvest::API::Invoices.new(credentials)
end
+
+ # All API Actions surrounding invoice payments
+ #
+ # == Examples
+ # invoice = harvest.invoices.find(100)
+ # harvest.invoice_payments.all(invoice) # returns all payments for the invoice (as Harvest::InvoicePayment)
+ #
+ # invoice = harvest.invoices.find(100)
+ # harvest.invoice_payments.find(invoice, 5) # returns the payment with ID 5 that is assigned to the invoice
+ #
+ # invoice = harvest.invoices.find(100)
+ # payment = Harvest::InvoicePayment.new(:invoice_id => invoice.id)
+ # saved_payment = harvest.invoice_payments.create(payment) # returns a saved version of the payment
+ #
+ # invoice = harvest.invoices.find(100)
+ # payment = harvest.invoice_payments.find(invoice, 5)
+ # harvest.invoice_payments.delete(payment) # returns 5
+ #
+ # @return [Harvest::API::InvoicePayments]
+ def invoice_payments
+ @invoice_payments ||= Harvest::API::InvoicePayments.new(credentials)
+ end
end
-end
+end
View
8 lib/harvest/invoice_payment.rb
@@ -0,0 +1,8 @@
+module Harvest
+ class InvoicePayment < Hashie::Mash
+ include Harvest::Model
+
+ api_path '/payments'
+ def self.json_root; 'payment'; end
+ end
+end
View
12 lib/harvested.rb
@@ -19,14 +19,14 @@
require 'harvest/base'
%w(crud activatable).each {|a| require "harvest/behavior/#{a}"}
-%w(model client contact project task user rate_limit_status task_assignment user_assignment expense_category expense time_entry invoice_category line_item invoice).each {|a| require "harvest/#{a}"}
-%w(base account clients contacts projects tasks users task_assignments user_assignments expense_categories expenses time reports invoice_categories invoices).each {|a| require "harvest/api/#{a}"}
+%w(model client contact project task user rate_limit_status task_assignment user_assignment expense_category expense time_entry invoice_category line_item invoice invoice_payment).each {|a| require "harvest/#{a}"}
+%w(base account clients contacts projects tasks users task_assignments user_assignments expense_categories expenses time reports invoice_categories invoices invoice_payments).each {|a| require "harvest/api/#{a}"}
module Harvest
VERSION = File.read(File.expand_path(File.join(File.dirname(__FILE__), '..', 'VERSION'))).strip
-
+
class << self
-
+
# Creates a standard client that will raise all errors it encounters
#
# == Options
@@ -38,7 +38,7 @@ class << self
def client(subdomain, username, password, options = {})
Harvest::Base.new(subdomain, username, password, options)
end
-
+
# Creates a hardy client that will retry common HTTP errors it encounters and sleep() if it determines it is over your rate limit
#
# == Options
@@ -66,4 +66,4 @@ def hardy_client(subdomain, username, password, options = {})
Harvest::HardyClient.new(client(subdomain, username, password, options), (retries || 5))
end
end
-end
+end
View
13 spec/factories.rb
@@ -7,6 +7,10 @@
"Item #{n}"
end
+ sequence :project_name do |n|
+ "Joe's Steam Cleaning Project #{n}"
+ end
+
factory :client, class: Harvest::Client do
name
details "Steam Cleaning across the country"
@@ -14,12 +18,13 @@
factory :invoice, class: Harvest::Invoice do
subject "Invoice for Joe's Stream Cleaning"
+ client_id nil
issued_at "2011-03-31"
due_at "2011-03-31"
due_at_human_format "upon receipt"
currency "United States Dollars - USD"
- number "1000"
+ sequence(:number)
notes "Some notes go here"
period_end "2011-03-31"
period_start "2011-02-26"
@@ -40,8 +45,10 @@
unit_price "12.00"
end
- sequence :project_name do |n|
- "Joe's Steam Cleaning Project #{n}"
+ factory :invoice_payment, class: Harvest::InvoicePayment do
+ paid_at Time.now
+ amount "0.00"
+ notes "Payment received"
end
factory :project, class: Harvest::Project do
View
44 spec/functional/invoice_payments_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe 'harvest invoice payments' do
+ it 'allows retrieving existing invoice payments' do
+ cassette('invoice_payment1') do
+ client = harvest.clients.create(FactoryGirl.attributes_for(:client))
+ invoice = harvest.invoices.create(FactoryGirl.attributes_for(:invoice, :client_id => client.id))
+
+ payment = Harvest::InvoicePayment.new(FactoryGirl.attributes_for(:invoice_payment, :invoice_id => invoice.id, :amount => invoice.amount))
+ payment_saved = harvest.invoice_payments.create(payment)
+
+ payment_found = harvest.invoice_payments.find(invoice, payment_saved)
+
+ payment_found.should == payment_saved
+ end
+ end
+
+ it 'allows adding, and removing invoice payments' do
+ cassette('invoice_payment2') do
+ client = harvest.clients.create(FactoryGirl.attributes_for(:client))
+ invoice = harvest.invoices.create(FactoryGirl.attributes_for(:invoice, :client_id => client.id))
+
+ half_amount = (invoice.amount.to_f / 2)
+
+ payment1 = Harvest::InvoicePayment.new(FactoryGirl.attributes_for(:invoice_payment, :invoice_id => invoice.id, :amount => half_amount))
+ payment1 = harvest.invoice_payments.create(payment1)
+
+ invoice = harvest.invoices.find(invoice.id)
+ invoice.state.should == 'partial'
+
+ payment2 = Harvest::InvoicePayment.new(FactoryGirl.attributes_for(:invoice_payment, :invoice_id => invoice.id, :amount => half_amount))
+ payment2 = harvest.invoice_payments.create(payment2)
+
+ invoice = harvest.invoices.find(invoice.id)
+ invoice.state.should == 'paid'
+
+ harvest.invoice_payments.all(invoice).each { |ip| harvest.invoice_payments.delete(ip) }
+ harvest.invoice_payments.all(invoice).should be_empty
+
+ invoice = harvest.invoices.find(invoice.id)
+ invoice.state.should == 'open'
+ end
+ end
+end
View
5 spec/harvest/invoice_payment_spec.rb
@@ -0,0 +1,5 @@
+require 'spec_helper'
+
+describe Harvest::InvoicePayment do
+ it_behaves_like 'a json sanitizer', %w(cache_version)
+end
Please sign in to comment.
Something went wrong with that request. Please try again.