Add resource definitions for all 22 API tags, wire client accessors and require tree
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "fiken/version"
|
||||||
|
require_relative "fiken/error"
|
||||||
|
require_relative "fiken/object"
|
||||||
|
require_relative "fiken/connection"
|
||||||
|
require_relative "fiken/collection"
|
||||||
|
require_relative "fiken/resource"
|
||||||
|
|
||||||
|
# Shared sub-resources used by the resource definitions below.
|
||||||
|
require_relative "fiken/resources/concerns/attachments"
|
||||||
|
require_relative "fiken/resources/concerns/payments"
|
||||||
|
require_relative "fiken/resources/concerns/drafts"
|
||||||
|
|
||||||
|
# Resource definitions (one file per API tag).
|
||||||
|
require_relative "fiken/resources/companies"
|
||||||
|
require_relative "fiken/resources/accounts"
|
||||||
|
require_relative "fiken/resources/bank_accounts"
|
||||||
|
require_relative "fiken/resources/contacts"
|
||||||
|
require_relative "fiken/resources/groups"
|
||||||
|
require_relative "fiken/resources/products"
|
||||||
|
require_relative "fiken/resources/journal_entries"
|
||||||
|
require_relative "fiken/resources/transactions"
|
||||||
|
require_relative "fiken/resources/invoices"
|
||||||
|
require_relative "fiken/resources/credit_notes"
|
||||||
|
require_relative "fiken/resources/offers"
|
||||||
|
require_relative "fiken/resources/order_confirmations"
|
||||||
|
require_relative "fiken/resources/sales"
|
||||||
|
require_relative "fiken/resources/purchases"
|
||||||
|
require_relative "fiken/resources/inbox"
|
||||||
|
require_relative "fiken/resources/projects"
|
||||||
|
require_relative "fiken/resources/activities"
|
||||||
|
require_relative "fiken/resources/time_entries"
|
||||||
|
require_relative "fiken/resources/time_users"
|
||||||
|
|
||||||
|
require_relative "fiken/oauth"
|
||||||
|
require_relative "fiken/client"
|
||||||
|
|
||||||
|
# Ruby client for the Fiken API v2 (https://api.fiken.no/api/v2/docs).
|
||||||
|
module Fiken
|
||||||
|
class << self
|
||||||
|
# Convenience constructor: Fiken.client(token: "...")
|
||||||
|
def client(**options)
|
||||||
|
Client.new(**options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
# The entry point. Holds the connection and exposes the resource accessors.
|
||||||
|
#
|
||||||
|
# client = Fiken::Client.new(token: ENV["FIKEN_TOKEN"])
|
||||||
|
# client.user
|
||||||
|
# client.companies.list
|
||||||
|
# client.contacts("my-company-slug").find(123)
|
||||||
|
# client.invoices("my-company-slug").drafts.create(invoice_attrs)
|
||||||
|
class Client
|
||||||
|
attr_reader :connection
|
||||||
|
|
||||||
|
def initialize(token: nil, access_token: nil, **options)
|
||||||
|
bearer = token || access_token
|
||||||
|
raise ArgumentError, "provide :token or :access_token" if bearer.nil? || bearer.empty?
|
||||||
|
|
||||||
|
@connection = Connection.new(token: bearer, **options)
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /user
|
||||||
|
def user
|
||||||
|
Object.new(connection.get("/user").body)
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /companies, GET /companies/{slug}
|
||||||
|
def companies
|
||||||
|
Resources::Companies.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Convenience: fetch a single company by slug.
|
||||||
|
def company(slug)
|
||||||
|
companies.find(slug)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Company-scoped resources. Each takes the company slug.
|
||||||
|
def accounts(slug) = Resources::Accounts.new(self, slug)
|
||||||
|
def account_balances(slug) = Resources::AccountBalances.new(self, slug)
|
||||||
|
def activities(slug) = Resources::Activities.new(self, slug)
|
||||||
|
def bank_accounts(slug) = Resources::BankAccounts.new(self, slug)
|
||||||
|
def bank_balances(slug) = Resources::BankBalances.new(self, slug)
|
||||||
|
def contacts(slug) = Resources::Contacts.new(self, slug)
|
||||||
|
def credit_notes(slug) = Resources::CreditNotes.new(self, slug)
|
||||||
|
def groups(slug) = Resources::Groups.new(self, slug)
|
||||||
|
def inbox(slug) = Resources::Inbox.new(self, slug)
|
||||||
|
def invoices(slug) = Resources::Invoices.new(self, slug)
|
||||||
|
def journal_entries(slug) = Resources::JournalEntries.new(self, slug)
|
||||||
|
def offers(slug) = Resources::Offers.new(self, slug)
|
||||||
|
def order_confirmations(slug) = Resources::OrderConfirmations.new(self, slug)
|
||||||
|
def products(slug) = Resources::Products.new(self, slug)
|
||||||
|
def projects(slug) = Resources::Projects.new(self, slug)
|
||||||
|
def purchases(slug) = Resources::Purchases.new(self, slug)
|
||||||
|
def sales(slug) = Resources::Sales.new(self, slug)
|
||||||
|
def time_entries(slug) = Resources::TimeEntries.new(self, slug)
|
||||||
|
def time_users(slug) = Resources::TimeUsers.new(self, slug)
|
||||||
|
def transactions(slug) = Resources::Transactions.new(self, slug)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/accounts — find by account code (e.g. "1500:10001").
|
||||||
|
class Accounts < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"accounts"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# /companies/{slug}/accountBalances
|
||||||
|
class AccountBalances < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"accountBalances"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/activities (time-tracking activities)
|
||||||
|
class Activities < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::PatchUpdatable
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"activities"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/bankAccounts
|
||||||
|
class BankAccounts < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"bankAccounts"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# /companies/{slug}/bankBalances
|
||||||
|
class BankBalances < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"bankBalances"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# GET /companies and GET /companies/{companySlug}
|
||||||
|
class Companies < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"companies"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/contacts and nested contact persons.
|
||||||
|
class Contacts < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::Updatable # PUT
|
||||||
|
include Resource::Deletable
|
||||||
|
include Resource::Attachable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"contacts"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Contacts only support uploading attachments, not listing them.
|
||||||
|
def attachments_listable?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def contact_persons(contact_id)
|
||||||
|
ContactPersons.new(client, company_slug, "#{base_path}/#{contact_id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# /companies/{slug}/contacts/{id}/contactPerson
|
||||||
|
class ContactPersons < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::Updatable # PUT
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def initialize(client, company_slug, parent_path)
|
||||||
|
super(client, company_slug)
|
||||||
|
@parent_path = parent_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def base_path
|
||||||
|
"#{@parent_path}/contactPerson"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/creditNotes
|
||||||
|
class CreditNotes < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Sendable
|
||||||
|
include Resource::HasCounter
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"creditNotes"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createCreditNote"
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /creditNotes/full — credit a whole invoice.
|
||||||
|
def create_full(attributes)
|
||||||
|
post_create("#{base_path}/full", attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /creditNotes/partial — credit selected lines/amounts.
|
||||||
|
def create_partial(attributes)
|
||||||
|
post_create("#{base_path}/partial", attributes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/groups (contact groups)
|
||||||
|
class Groups < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"groups"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/inbox — documents awaiting bookkeeping.
|
||||||
|
class Inbox < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"inbox"
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /inbox — multipart upload of an inbox document.
|
||||||
|
def create(path: nil, io: nil, filename: nil, content_type: "application/octet-stream", **fields)
|
||||||
|
parts = { "file" => build_file_part(path, io, filename, content_type) }
|
||||||
|
fields.each { |key, value| parts[key.to_s] = value.to_s unless value.nil? }
|
||||||
|
build_created(connection.post_multipart(base_path, parts))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/invoices
|
||||||
|
class Invoices < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::PatchUpdatable # finalized invoices update via PATCH
|
||||||
|
include Resource::Attachable
|
||||||
|
include Resource::Sendable
|
||||||
|
include Resource::HasCounter
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"invoices"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createInvoice"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/journalEntries
|
||||||
|
class JournalEntries < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Attachable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"journalEntries"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creation posts to a sibling path: POST /generalJournalEntries
|
||||||
|
def create_general(attributes)
|
||||||
|
post_create("/companies/#{company_slug}/generalJournalEntries", attributes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/offers
|
||||||
|
class Offers < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Sendable
|
||||||
|
include Resource::HasCounter
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"offers"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createOffer"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/orderConfirmations
|
||||||
|
class OrderConfirmations < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::HasCounter
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"orderConfirmations"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createOrderConfirmation"
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /{id}/createInvoiceDraft — turn a confirmation into an invoice draft.
|
||||||
|
def create_invoice_draft(confirmation_id)
|
||||||
|
post_create("#{base_path}/#{confirmation_id}/createInvoiceDraft", nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/products
|
||||||
|
class Products < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::Updatable # PUT
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"products"
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /products/salesReport — returns an array of per-product report rows.
|
||||||
|
def sales_report(attributes)
|
||||||
|
body = connection.post("#{base_path}/salesReport", attributes).body
|
||||||
|
Array(body).map { |row| wrap(row) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/projects
|
||||||
|
class Projects < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::PatchUpdatable
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"projects"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/purchases
|
||||||
|
class Purchases < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::Attachable
|
||||||
|
include Resource::Payable
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"purchases"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createPurchase"
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH /{id}/delete — delete a purchase (with a reason).
|
||||||
|
def delete(id, attributes = nil)
|
||||||
|
connection.patch("#{base_path}/#{id}/delete", attributes)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/sales
|
||||||
|
class Sales < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::Attachable
|
||||||
|
include Resource::Payable
|
||||||
|
include Resource::Draftable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"sales"
|
||||||
|
end
|
||||||
|
|
||||||
|
def draft_create_action
|
||||||
|
"createSale"
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH /{id}/settled — mark a sale as settled.
|
||||||
|
def settle(id, attributes = nil)
|
||||||
|
patch_one("#{base_path}/#{id}/settled", attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH /{id}/writeOff — write off a sale as a loss.
|
||||||
|
def write_off(id, attributes = nil)
|
||||||
|
patch_one("#{base_path}/#{id}/writeOff", attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH /{id}/delete — delete a sale (with a reason).
|
||||||
|
def delete(id, attributes = nil)
|
||||||
|
connection.patch("#{base_path}/#{id}/delete", attributes)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/timeEntries
|
||||||
|
class TimeEntries < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
include Resource::Creatable
|
||||||
|
include Resource::PatchUpdatable
|
||||||
|
include Resource::Deletable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"timeEntries"
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /timeEntries/createInvoiceDraft — invoice selected time entries.
|
||||||
|
def create_invoice_draft(attributes)
|
||||||
|
post_create("#{base_path}/createInvoiceDraft", attributes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/timeUsers
|
||||||
|
class TimeUsers < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"timeUsers"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Fiken
|
||||||
|
module Resources
|
||||||
|
# /companies/{slug}/transactions
|
||||||
|
class Transactions < Resource::Base
|
||||||
|
include Resource::Listable
|
||||||
|
include Resource::Findable
|
||||||
|
|
||||||
|
def resource_path
|
||||||
|
"transactions"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deletion is a PATCH to /{id}/delete (optionally with a description).
|
||||||
|
def delete(id, attributes = nil)
|
||||||
|
connection.patch("#{base_path}/#{id}/delete", attributes)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user