kounta_rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ module Kounta
2
+
3
+ class PriceList < Kounta::Resource
4
+ property :parent_id
5
+ property :name
6
+ property :products
7
+ coerce_key :products, Product
8
+ end
9
+
10
+ end
@@ -0,0 +1,30 @@
1
+ module Kounta
2
+
3
+ class Product < Kounta::Resource
4
+ property :company_id
5
+ property :code
6
+ property :barcode
7
+ property :stock
8
+ property :name
9
+ property :description
10
+ property :tags
11
+ property :image
12
+ property :unit_price
13
+ property :cost_price
14
+ property :taxes
15
+ property :sites
16
+
17
+ has_many :categories, Kounta::Category, {:company_id => :company_id}, lambda { |klass| {companies: klass.company_id, products: klass.company_id, categories: nil} }
18
+ coerce_key :taxes, Kounta::Tax
19
+
20
+ def tags_include?(name)
21
+ tags.any?{ |s| s.casecmp(name) == 0 }
22
+ end
23
+
24
+ def resource_path
25
+ {companies: company_id, products: id}
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,91 @@
1
+ require 'hashie'
2
+ require_relative "rest/client"
3
+
4
+ module Kounta
5
+
6
+ class Resource < Hashie::Dash
7
+ include Hashie::Extensions::Coercion
8
+
9
+ property :id
10
+ property :created_at
11
+ property :updated_at
12
+
13
+ def self.coerce(data)
14
+ if data.kind_of? Array
15
+ data.map { |item| self.new(item) }
16
+ else
17
+ self.new(data)
18
+ end
19
+ end
20
+
21
+ def self.has_one(sym, klass, assignments, route)
22
+ define_method(sym) do |item_id=nil, *args|
23
+ if item_id
24
+ assign_into(client.object_from_response(klass, :get, route.call(self, item_id), {:params => args[0]}), self, assignments)
25
+ else
26
+ assign_into(klass.new, self, assignments)
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.has_many(sym, klass, assignments, route)
32
+ define_method(sym) do |*args|
33
+ client.objects_from_response(klass, :get, route.call(self), {:params => args[0]}).map {|returned_klass| assign_into(returned_klass, self, assignments) }
34
+ end
35
+ end
36
+
37
+ def initialize(hash={})
38
+ if hash
39
+ hash.each_pair do |k,v|
40
+ begin
41
+ self[k] = v
42
+ rescue NoMethodError => e
43
+ raise Kounta::Errors::UnknownResourceAttribute.new("Unknown attribute: #{k} on resource #{self.class}")
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def client
50
+ @@client ||= Kounta::REST::Client.new
51
+ end
52
+
53
+ def to_hash(hash={})
54
+ {}.tap do |returning|
55
+ self.class.properties.each do |property|
56
+ next if ignored_properties.include?(property)
57
+ returning[property] = self[property] if self[property]
58
+ end
59
+ end.merge(hash)
60
+ end
61
+
62
+ def save!
63
+ response = new? ? client.perform(resource_path, :post, {:body => to_hash}) : client.perform(resource_path, :put, {:body => to_hash})
64
+ if response
65
+ response.each_pair do |k,v|
66
+ self[k] = v
67
+ end
68
+ end
69
+ self
70
+ end
71
+
72
+ def new?
73
+ !id
74
+ end
75
+
76
+ def ignored_properties(array=[])
77
+ array + [:created_at, :updated_at, :id, :company_id, :site_id]
78
+ end
79
+
80
+ private
81
+
82
+ def assign_into(klass, assigner, assignments)
83
+ assignments.each_pair do |k,v|
84
+ klass[k] = assigner[v]
85
+ end
86
+ klass
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,65 @@
1
+ require 'oauth2'
2
+ require 'yell'
3
+
4
+ module Kounta
5
+ module REST
6
+ class Client
7
+
8
+ def initialize
9
+ raise Kounta::Errors::MissingOauthDetails unless has_required_oauth_details?
10
+ @logger = Yell.new STDOUT
11
+ @conn = OAuth2::AccessToken.new(client, Kounta.client_token, {:refresh_token => Kounta.client_refresh_token})
12
+
13
+ end
14
+
15
+ def client
16
+ @oauth_client ||= OAuth2::Client.new(Kounta.client_id, Kounta.client_secret, {
17
+ :site => Kounta::SITE_URI,
18
+ :authorize_url => Kounta::AUTHORIZATION_URI,
19
+ :token_url => Kounta::TOKEN_URI
20
+ })
21
+ end
22
+
23
+ def path_from_hash(url_hash)
24
+ url_hash.map{ |key, value| value ? "#{key}/#{value}" : "#{key}" }.join('/')
25
+ end
26
+
27
+ def perform(url_hash, request_method, options={})
28
+ begin
29
+ log("#{request_method}: #{Kounta::SITE_URI}#{path_from_hash(url_hash)}.#{FORMAT.to_s} (#{options})")
30
+ response = @conn.request(request_method, "#{path_from_hash(url_hash)}.#{FORMAT.to_s}", options)
31
+ rescue OAuth2::Error => ex
32
+ if ex.message.include? 'The access token provided has expired'
33
+ log('oauth2 token expired, refreshing it...')
34
+ @conn = refreshed_token
35
+ retry
36
+ end
37
+ end
38
+ response.parsed if response
39
+ end
40
+
41
+ def objects_from_response(klass, request_method, url_hash, options={})
42
+ perform(url_hash, request_method, options).map { |response| klass.new(response) }
43
+ end
44
+
45
+ def object_from_response(klass, request_method, url_hash, options={})
46
+ klass.new( perform(url_hash, request_method, options) )
47
+ end
48
+
49
+ private
50
+
51
+ def has_required_oauth_details?
52
+ Kounta.client_id && Kounta.client_secret && Kounta.client_token && Kounta.client_refresh_token
53
+ end
54
+
55
+ def log(message)
56
+ @logger.info(message) unless !Kounta.enable_logging
57
+ end
58
+
59
+ def refreshed_token
60
+ OAuth2::AccessToken.from_hash(client, :refresh_token => Kounta.client_refresh_token).refresh!
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,42 @@
1
+ module Kounta
2
+
3
+ class Site < Kounta::Resource
4
+ property :company_id
5
+ property :name
6
+ property :code
7
+ property :business_number
8
+ property :contact_person
9
+ property :shipping_address
10
+ property :postal_address
11
+ property :email
12
+ property :mobile
13
+ property :phone
14
+ property :fax
15
+ property :location
16
+ property :image
17
+ property :website
18
+ property :register_level_reconciliation
19
+ property :products
20
+ property :price_list
21
+
22
+ coerce_key :shipping_address, Kounta::Address
23
+ coerce_key :postal_address, Kounta::Address
24
+ coerce_key :price_list, Kounta::PriceList
25
+
26
+ has_one :product, Kounta::Product, {:company_id => :company_id}, lambda { |klass, item_id| {companies: klass.company_id, sites: klass.id, products: item_id} }
27
+ has_one :category, Kounta::Category, {:company_id => :company_id}, lambda { |klass, item_id| {companies: klass.company_id, sites: klass.id, categories: item_id} }
28
+ has_one :address, Kounta::Address, {:company_id => :company_id}, lambda { |klass, item_id| {companies: klass.company_id, sites: klass.id, addresses: item_id} }
29
+ has_one :order, Kounta::Order, {:company_id => :company_id}, lambda { |klass, item_id| {companies: klass.company_id, sites: klass.id, orders: item_id} }
30
+
31
+ has_many :products, Kounta::Product, {:company_id => :company_id}, lambda { |klass| {companies: klass.company_id, sites: klass.id, products: nil} }
32
+ has_many :categories, Kounta::Category, {:company_id => :company_id}, lambda { |klass| {companies: klass.company_id, sites: klass.id, categories: nil} }
33
+ has_many :addresses, Kounta::Address, {:company_id => :company_id}, lambda { |klass| {companies: klass.company_id, sites: klass.id, addresses: nil} }
34
+ has_many :orders, Kounta::Order, {:company_id => :company_id}, lambda { |klass| {companies: klass.company_id, sites: klass.id, orders: nil} }
35
+
36
+ def resource_path
37
+ {companies: company_id, sites: id}
38
+ end
39
+
40
+ end
41
+
42
+ end
data/lib/kounta/tax.rb ADDED
@@ -0,0 +1,10 @@
1
+ module Kounta
2
+
3
+ class Tax < Kounta::Resource
4
+ property :company_id
5
+ property :code
6
+ property :name
7
+ property :rate
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ module Kounta
2
+ VERSION = "0.0.1"
3
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ require 'rspec'
5
+ require 'webmock/rspec'
6
+ require 'kounta'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.include Helpers
14
+
15
+ config.before(:each) do
16
+
17
+ stub_endpoints
18
+
19
+ Kounta.configure do |config|
20
+ config.client_id = "1234"
21
+ config.client_secret = "5678"
22
+ config.client_token = "abcd"
23
+ config.client_refresh_token = "efgh"
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,11 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Address do
4
+
5
+ subject { Kounta::Company.new.customer(701892).address(198109) }
6
+
7
+ it "should have a resource path" do
8
+ subject.resource_path.should eq({people: 701892, addresses: 198109})
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Category do
4
+
5
+ subject { Kounta::Company.new.category(1) }
6
+
7
+ it "should have a resource path" do
8
+ subject.resource_path.should eq({companies: 162, categories: 1})
9
+ end
10
+
11
+ end
@@ -0,0 +1,24 @@
1
+ require "helper"
2
+ require 'oj'
3
+
4
+ describe Kounta::Company do
5
+
6
+ subject { Kounta::Company }
7
+
8
+ it "should be able to create a company from an existing hash" do
9
+ subject.new(Oj.load(File.read("#{Kounta.root}/spec/fixtures/companies_me.json")))
10
+ end
11
+
12
+ it "should be able to create a company without a hash" do
13
+ subject.new.should be_an_instance_of subject
14
+ end
15
+
16
+ it "should have a resource path" do
17
+ subject.new.resource_path.should eq({companies: 162})
18
+ end
19
+
20
+ it "should have a base price list" do
21
+ subject.new.base_price_list.should be_an_instance_of Kounta::PriceList
22
+ end
23
+
24
+ end
@@ -0,0 +1,15 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Customer do
4
+
5
+ subject { Kounta::Company.new.customer(389427) }
6
+
7
+ it "should have a name" do
8
+ subject.name.should eq("Samuel Richardson")
9
+ end
10
+
11
+ it "should have a resource path" do
12
+ subject.resource_path.should eq({companies: 162, customers: 389427})
13
+ end
14
+
15
+ end
@@ -0,0 +1,21 @@
1
+ require "helper"
2
+
3
+ describe Kounta do
4
+
5
+ subject { Kounta }
6
+
7
+ it "should be able to call a configure block" do
8
+ subject.configure do |config|
9
+ config.should be(Kounta)
10
+ end
11
+ end
12
+
13
+ it "should be able to configure loggin" do
14
+ Kounta.enable_logging.should be(false)
15
+ Kounta.enable_logging = true
16
+ Kounta.enable_logging.should be(true)
17
+ Kounta.enable_logging = false
18
+ Kounta.enable_logging.should be(false)
19
+ end
20
+
21
+ end
@@ -0,0 +1,14 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Line do
4
+
5
+ subject { Kounta::Line.new }
6
+
7
+ it "should have a resource path" do
8
+ subject.company_id = 162
9
+ subject.order_id = 6789
10
+ subject.id = 1
11
+ subject.resource_path.should eq({companies: 162, orders: 6789, lines: 1})
12
+ end
13
+
14
+ end
@@ -0,0 +1,37 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Order do
4
+
5
+ subject { Kounta::Company.new.customer(701892).order(93824701) }
6
+
7
+ it "should be able to add payments to new orders" do
8
+ new_order = Kounta::Order.new
9
+ new_order.payments << Kounta::Payment.new(:amount => 50.00)
10
+ new_order.to_hash[:payments].length.should be(1)
11
+ new_order.to_hash[:payments][0][:amount].should be(50.00)
12
+ end
13
+
14
+ it "should be able to add lines to new orders" do
15
+ new_order = Kounta::Order.new
16
+ new_order.lines << Kounta::Line.new(:quantity => 4)
17
+ new_order.to_hash[:lines].length.should be(1)
18
+ new_order.to_hash[:lines][0][:quantity].should be(4)
19
+ end
20
+
21
+ it "should be able to add and serialise payments to created orders" do
22
+ subject.payments << Kounta::Payment.new(:amount => 50.00)
23
+ subject.to_hash[:payments].length.should be(3)
24
+ subject.to_hash[:payments][2][:amount].should be(50.00)
25
+ end
26
+
27
+ it "should be able to add and serialise lines to created orders" do
28
+ subject.lines << Kounta::Line.new(:quantity => 4)
29
+ subject.to_hash[:lines].length.should be(3)
30
+ subject.to_hash[:lines][0][:quantity].should be(6)
31
+ end
32
+
33
+ it "should have a resource path" do
34
+ subject.resource_path.should eq({companies: 162, orders: 93824701})
35
+ end
36
+
37
+ end
@@ -0,0 +1,14 @@
1
+ require "helper"
2
+
3
+ describe Kounta::Payment do
4
+
5
+ subject { Kounta::Payment.new }
6
+
7
+ it "should have a resource path" do
8
+ subject.company_id = 162
9
+ subject.order_id = 6789
10
+ subject.id = 1
11
+ subject.resource_path.should eq({companies: 162, orders: 6789, payments: 1})
12
+ end
13
+
14
+ end