papierkram_api_client 0.1.3 → 0.2.0

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile.lock +3 -3
  5. data/README.md +155 -55
  6. data/lib/papierkram_api/client.rb +92 -0
  7. data/lib/papierkram_api/v1/business_intelligence/base.rb +23 -0
  8. data/lib/papierkram_api/v1/business_intelligence/expenses_by_category.rb +98 -0
  9. data/lib/papierkram_api/v1/business_intelligence/smart_queries/expense_vouchers_for_month_in_year.rb +58 -0
  10. data/lib/papierkram_api/v1/endpoints/banking/bank_connections.rb +30 -0
  11. data/lib/papierkram_api/v1/endpoints/banking/transactions.rb +20 -0
  12. data/lib/papierkram_api/v1/endpoints/base.rb +77 -0
  13. data/lib/papierkram_api/v1/endpoints/contact/companies.rb +30 -0
  14. data/lib/papierkram_api/v1/endpoints/contact/companies_persons.rb +28 -0
  15. data/lib/papierkram_api/v1/endpoints/expense/vouchers.rb +45 -0
  16. data/lib/papierkram_api/v1/endpoints/income/estimates.rb +46 -0
  17. data/lib/papierkram_api/v1/endpoints/income/invoices.rb +46 -0
  18. data/lib/papierkram_api/v1/endpoints/income/propositions.rb +20 -0
  19. data/lib/papierkram_api/v1/endpoints/info.rb +14 -0
  20. data/lib/papierkram_api/v1/endpoints/projects.rb +26 -0
  21. data/lib/papierkram_api/v1/endpoints/tracker/tasks.rb +33 -0
  22. data/lib/papierkram_api/v1/endpoints/tracker/time_entries.rb +62 -0
  23. data/lib/papierkram_api/v1/helper/date_helper.rb +14 -0
  24. data/lib/{api → papierkram_api}/v1/helper/pdf_from_response.rb +1 -1
  25. data/lib/papierkram_api/v1/validators/expense_voucher.rb +105 -0
  26. data/lib/papierkram_api_client/version.rb +1 -1
  27. data/lib/papierkram_api_client.rb +21 -102
  28. metadata +22 -16
  29. data/lib/api/v1/banking/bank_connections.rb +0 -28
  30. data/lib/api/v1/banking/transactions.rb +0 -18
  31. data/lib/api/v1/base.rb +0 -75
  32. data/lib/api/v1/contact/companies.rb +0 -28
  33. data/lib/api/v1/contact/companies_persons.rb +0 -26
  34. data/lib/api/v1/expense/vouchers.rb +0 -43
  35. data/lib/api/v1/income/estimates.rb +0 -44
  36. data/lib/api/v1/income/invoices.rb +0 -44
  37. data/lib/api/v1/income/propositions.rb +0 -18
  38. data/lib/api/v1/info.rb +0 -12
  39. data/lib/api/v1/projects.rb +0 -24
  40. data/lib/api/v1/tracker/tasks.rb +0 -31
  41. data/lib/api/v1/tracker/time_entries.rb +0 -59
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module BusinessIntelligence
6
+ # Business Intelligence for Expenses
7
+ class ExpensesByCategory
8
+ #
9
+ # Calculate the expenses by category
10
+ #
11
+ # @param [Array<Hash>] expense_vouchers represents a list of expense vouchers in the format:
12
+ #
13
+ # @param [<Type>] &block <description>
14
+ #
15
+ # @return [<Type>] <description>
16
+ #
17
+ def call(expense_vouchers:, &block)
18
+ return {} if expense_vouchers.is_a?(Array) && expense_vouchers.empty?
19
+
20
+ validate_expense_vouchers!(expense_vouchers)
21
+ if block_given?
22
+ results(expense_vouchers, &block)
23
+ else
24
+ results(expense_vouchers)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def results(expense_vouchers)
31
+ coll = prepare_voucher_data(expense_vouchers)
32
+ coll = yield(coll) if block_given?
33
+ line_items_grouped_by_category = coll.group_by { |v| v['category'] }
34
+ sum_categories!(line_items_grouped_by_category)
35
+ end
36
+
37
+ def sum_categories!(line_items_grouped_by_category)
38
+ lookup_table = {}
39
+ line_items_grouped_by_category.each do |category_name, line_items|
40
+ line_items_by_creditor_lot = {}
41
+ line_items_by_creditor = line_items.group_by { |v| v['creditor'] }
42
+ sum_up_creditor!(line_items_by_creditor, line_items_by_creditor_lot)
43
+ build_result_lookup_table!(lookup_table, category_name, line_items, line_items_by_creditor_lot)
44
+ end
45
+ lookup_table
46
+ end
47
+
48
+ def sum_up_creditor!(line_items_by_creditor, line_items_by_creditor_lot)
49
+ line_items_by_creditor.each do |category_name, line_items|
50
+ line_items_by_creditor_lot[category_name] = line_items.reduce(0) do |sum, creditor|
51
+ sum + creditor['amount']
52
+ end
53
+ end
54
+ line_items_by_creditor_lot
55
+ end
56
+
57
+ def build_result_lookup_table!(lookup_table, category_name, line_items, line_items_by_creditor_lot)
58
+ lookup_table[category_name] = {
59
+ 'amount' => line_items.reduce(0) { |sum, line_item| sum + line_item['amount'] },
60
+ 'amount_by_creditor' => line_items_by_creditor_lot,
61
+ 'line_items' => line_items
62
+ }
63
+ end
64
+
65
+ def prepare_voucher_data(vouchers)
66
+ coll = []
67
+ vouchers.flat_map do |voucher|
68
+ voucher['line_items'].each do |line_item|
69
+ res = line_item.merge(
70
+ { 'voucher_name' => voucher['name'] },
71
+ { 'voucher_id' => voucher['id'] },
72
+ 'creditor' => voucher['creditor']
73
+ )
74
+ coll.push(res)
75
+ end
76
+ end
77
+ coll
78
+ end
79
+
80
+ # TODO: move to a validator class forPapierkramApi::V1::Validators::ExpenseVouchers
81
+ def validate_expense_vouchers!(expense_vouchers)
82
+ raise ArgumentError, 'expense_vouchers must be an Array' unless expense_vouchers.is_a?(Array)
83
+ raise ArgumentError, 'expense_vouchers must not be empty' if expense_vouchers.empty?
84
+ raise ArgumentError, 'expense_vouchers must contain Hashes' unless expense_vouchers.all?(Hash)
85
+
86
+ validator = PapierkramApi::V1::Validators::ExpenseVoucher.new
87
+ expense_vouchers.all? do |voucher|
88
+ validate_expense_voucher!(validator, voucher)
89
+ end
90
+ end
91
+
92
+ def validate_expense_voucher!(validator, expense_voucher)
93
+ validator.validate!(expense_voucher)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module BusinessIntelligence
6
+ module SmartQueries
7
+ # This class is responsible for all the API calls related to expense vouchers.
8
+ class ExpenseVouchersForMonthInYear
9
+ include PapierkramApi::V1::Helper::DateHelper
10
+
11
+ def initialize(expense_voucher_api)
12
+ @expense_voucher_api = expense_voucher_api
13
+ end
14
+
15
+ def for_month_in_year(year:, month:)
16
+ @year = year
17
+ @month = month
18
+ @start_date = Date.new(@year, @month, 1)
19
+ @end_date = Date.new(@year, @month + 1, 1) - 1
20
+ collect_expense_vouchers
21
+ end
22
+
23
+ private
24
+
25
+ def collect_expense_vouchers
26
+ all_expense_vouchers_in_date_range.map do |voucher|
27
+ @expense_voucher_api.by(id: voucher['id']).body
28
+ end
29
+ end
30
+
31
+ def all_expense_vouchers_in_date_range
32
+ page = 1
33
+ vouchers = []
34
+ res = expense_vouchers(page: page)
35
+ res.body['entries'].each { |v| vouchers << v }
36
+ while res.body['page'] != res.body['total_pages']
37
+ res = expense_vouchers(page: page)
38
+ res.body['entries'].each { |v| vouchers << v }
39
+ end
40
+ vouchers
41
+ end
42
+
43
+ def expense_vouchers(page: 1)
44
+ @expense_voucher_api.all(
45
+ page: page,
46
+ document_date_range_start: build_date_string_for_api(@start_date),
47
+ document_date_range_end: build_date_string_for_api(@end_date)
48
+ )
49
+ end
50
+
51
+ def expense_voucher(id)
52
+ @expense_voucher_api.by(id: id)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Banking
7
+ # This class is responsible for all the API calls related to banking bank connections.
8
+ class BankConnections < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:)
10
+ get("#{@url_api_path}/banking/bank_connections/#{id}")
11
+ end
12
+
13
+ def all(page: 1,
14
+ page_size: 100,
15
+ order_by: nil,
16
+ order_direction: nil)
17
+ query = {
18
+ page: page,
19
+ page_size: page_size
20
+ }
21
+ query[:order_by] = order_by if order_by
22
+ query[:order_direction] = order_direction if order_direction
23
+
24
+ get("#{@url_api_path}/banking/bank_connections", query)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Banking
7
+ # This class is responsible for all the API calls related to banking transactions.
8
+ class Transactions
9
+ def by(id:)
10
+ # wip
11
+ end
12
+
13
+ def all
14
+ # wip
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ # This class is the base class for all the API calls.
7
+ class Base
8
+ attr_reader :client, :url_api_path
9
+
10
+ def initialize(client)
11
+ @client = client
12
+ @url_api_path = '/api/v1'
13
+ end
14
+
15
+ def remaining_quota(response)
16
+ return response.headers['x-remaining-quota'].to_i if response.is_a?(Faraday::Response)
17
+ raise ArgumentError, 'Invalid response object' unless response.is_a?(Hash)
18
+
19
+ quota = response.dig('headers', 'x-remaining-quota') || response['x-remaining-quota']
20
+ return Integer(quota) if quota
21
+
22
+ raise ArgumentError, "No remaining quota found in response: #{response}"
23
+ end
24
+
25
+ def get(url, params = {}, headers = {})
26
+ validate_get!(params)
27
+ call_wrapper!(:get, url, params, headers)
28
+ end
29
+
30
+ def post(url, params = {}, headers = {})
31
+ call_wrapper!(:post, url, params, headers)
32
+ end
33
+
34
+ def put(url, params = {}, headers = {})
35
+ call_wrapper!(:put, url, params, headers)
36
+ end
37
+
38
+ def patch(url, params = {}, headers = {})
39
+ call_wrapper!(:patch, url, params, headers)
40
+ end
41
+
42
+ def delete(url, params = {}, headers = {})
43
+ call_wrapper!(:delete, url, params, headers)
44
+ end
45
+
46
+ private
47
+
48
+ def call_wrapper!(method, url, params = {}, headers = {})
49
+ @client.send(method, url, params, headers)
50
+ end
51
+
52
+ def validate_order_direction!(order_direction)
53
+ return if order_direction.nil?
54
+
55
+ raise ArgumentError, 'Invalid order direction' unless %w[asc desc].include?(order_direction)
56
+ end
57
+
58
+ def validate_billing_state!(billing_state)
59
+ return if billing_state.nil?
60
+
61
+ raise ArgumentError, 'Invalid billing state' unless %w[billed
62
+ unbilled
63
+ billable
64
+ unbillable
65
+ archived].include?(billing_state)
66
+ end
67
+
68
+ def validate_get!(params)
69
+ return unless params
70
+
71
+ validate_order_direction!(params[:order_direction])
72
+ validate_billing_state!(params[:billing_state])
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Contact
7
+ # This class is responsible for all the API calls related to banking bank connections.
8
+ class Companies < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:)
10
+ get("#{@url_api_path}/contact/companies/#{id}")
11
+ end
12
+
13
+ def all(page: 1,
14
+ page_size: 100,
15
+ order_by: nil,
16
+ order_direction: nil)
17
+ query = {
18
+ page: page,
19
+ page_size: page_size
20
+ }
21
+ query[:order_by] = order_by if order_by
22
+ query[:order_direction] = order_direction if order_direction
23
+
24
+ get("#{@url_api_path}/contact/companies", query)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Contact
7
+ # This class is responsible for all the API calls related to companies' persons connections.
8
+ class CompaniesPersons < PapierkramApi::V1::Endpoints::Base
9
+ def by(company_id:, id:)
10
+ get("#{@url_api_path}/contact/companies/#{company_id}/persons/#{id}")
11
+ end
12
+
13
+ def all(company_id:, page: 1, page_size: 100, order_by: nil, order_direction: nil)
14
+ query = {
15
+ company_id: company_id,
16
+ page: page,
17
+ page_size: page_size
18
+ }
19
+ query[:order_by] = order_by if order_by
20
+ query[:order_direction] = order_direction if order_direction
21
+
22
+ get("#{@url_api_path}/contact/companies/#{company_id}/persons", query)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Expense
7
+ # This class is responsible for all the API calls related to expense vouchers.
8
+ class Vouchers < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:, pdf: false)
10
+ if pdf == true
11
+ return get("#{@url_api_path}/expense/vouchers/#{id}/pdf", nil,
12
+ { headers: { 'Content-Type' => 'application/pdf' } })
13
+ end
14
+ get("#{@url_api_path}/expense/vouchers/#{id}")
15
+ end
16
+
17
+ def all(page: 1, # rubocop:disable Metrics/CyclomaticComplexity
18
+ page_size: 100,
19
+ order_by: nil,
20
+ order_direction: nil,
21
+ creditor_id: nil,
22
+ project_id: nil,
23
+ document_date_range_start: nil,
24
+ document_date_range_end: nil)
25
+ query = {
26
+ page: page,
27
+ page_size: page_size
28
+ }
29
+ query[:order_by] = order_by if order_by
30
+ query[:order_direction] = order_direction if order_direction
31
+ query[:creditor_id] = creditor_id if creditor_id
32
+ query[:project_id] = project_id if project_id
33
+ query[:document_date_range_start] = document_date_range_start if document_date_range_start
34
+ if document_date_range_end && document_date_range_start
35
+ query[:document_date_range_end] =
36
+ document_date_range_end
37
+ end
38
+
39
+ get("#{@url_api_path}/expense/vouchers", query)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Income
7
+ # This class is responsible for all the API calls related to income estimates.
8
+ class Estimates < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:, pdf: false)
10
+ if pdf == true
11
+ return get("#{@url_api_path}/income/estimates/#{id}/pdf", nil,
12
+ { headers: { 'Content-Type' => 'application/pdf' } })
13
+ end
14
+
15
+ get("#{@url_api_path}/income/estimates/#{id}")
16
+ end
17
+
18
+ def all(page: 1, # rubocop:disable Metrics/CyclomaticComplexity
19
+ page_size: 100,
20
+ order_by: nil,
21
+ order_direction: nil,
22
+ creditor_id: nil,
23
+ project_id: nil,
24
+ document_date_range_start: nil,
25
+ document_date_range_end: nil)
26
+ query = {
27
+ page: page,
28
+ page_size: page_size
29
+ }
30
+ query[:order_by] = order_by if order_by
31
+ query[:order_direction] = order_direction if order_direction
32
+ query[:creditor_id] = creditor_id if creditor_id
33
+ query[:project_id] = project_id if project_id
34
+ query[:document_date_range_start] = document_date_range_start if document_date_range_start
35
+ if document_date_range_end && document_date_range_start
36
+ query[:document_date_range_end] =
37
+ document_date_range_end
38
+ end
39
+
40
+ get("#{@url_api_path}/income/estimates", query)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Income
7
+ # This class is responsible for all the API calls related to income invoices.
8
+ class Invoices < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:, pdf: false)
10
+ if pdf == true
11
+ return get("#{@url_api_path}/income/invoices/#{id}/pdf", nil,
12
+ { headers: { 'Content-Type' => 'application/pdf' } })
13
+ end
14
+
15
+ get("#{@url_api_path}/income/invoices/#{id}")
16
+ end
17
+
18
+ def all(page: 1, # rubocop:disable Metrics/CyclomaticComplexity
19
+ page_size: 100,
20
+ order_by: nil,
21
+ order_direction: nil,
22
+ creditor_id: nil,
23
+ project_id: nil,
24
+ document_date_range_start: nil,
25
+ document_date_range_end: nil)
26
+ query = {
27
+ page: page,
28
+ page_size: page_size
29
+ }
30
+ query[:order_by] = order_by if order_by
31
+ query[:order_direction] = order_direction if order_direction
32
+ query[:creditor_id] = creditor_id if creditor_id
33
+ query[:project_id] = project_id if project_id
34
+ query[:document_date_range_start] = document_date_range_start if document_date_range_start
35
+ if document_date_range_end && document_date_range_start
36
+ query[:document_date_range_end] =
37
+ document_date_range_end
38
+ end
39
+
40
+ get("#{@url_api_path}/income/invoices", query)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Income
7
+ # This class is responsible for all the API calls related to income propositions.
8
+ class Propositions < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:)
10
+ get("#{@url_api_path}/income/propositions/#{id}")
11
+ end
12
+
13
+ def all
14
+ get("#{@url_api_path}/income/propositions")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ # This class is responsible for all the API calls related to info connections.
7
+ class Info < PapierkramApi::V1::Endpoints::Base
8
+ def details
9
+ get("#{@url_api_path}/info")
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ # This class is responsible for all the API calls related to projects connections.
7
+ class Projects < PapierkramApi::V1::Endpoints::Base
8
+ def by(id:)
9
+ get("#{@url_api_path}/projects/#{id}")
10
+ end
11
+
12
+ def all(page: 1, per_page: 100, order_by: nil, order_direction: nil, company_id: nil)
13
+ query = {
14
+ page: page,
15
+ per_page: per_page
16
+ }
17
+ query[:order_by] = order_by if order_by
18
+ query[:order_direction] = order_direction if order_direction
19
+ query[:company_id] = company_id if company_id
20
+
21
+ get("#{@url_api_path}/projects", query)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Tracker
7
+ # This class is responsible for all the API calls related to tracker tasks connections.
8
+ class Tasks < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:)
10
+ get("#{@url_api_path}/tracker/tasks/#{id}")
11
+ end
12
+
13
+ def all(page: 1,
14
+ page_size: 100,
15
+ order_by: nil,
16
+ order_direction: nil,
17
+ project_id: nil,
18
+ proposition_id: nil)
19
+ query = {
20
+ page: page,
21
+ page_size: page_size
22
+ }
23
+ query[:order_by] = order_by if order_by
24
+ query[:order_direction] = order_direction if order_direction
25
+ query[:project_id] = project_id if project_id
26
+ query[:proposition_id] = proposition_id if proposition_id
27
+ get("#{@url_api_path}/tracker/tasks", query)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Endpoints
6
+ module Tracker
7
+ # This class is responsible for all the API calls related to tracker time entries connections.
8
+ class TimeEntries < PapierkramApi::V1::Endpoints::Base
9
+ def by(id:)
10
+ get("#{@url_api_path}/tracker/time_entries/#{id}")
11
+ end
12
+
13
+ def all(page: 1, # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/ParameterLists
14
+ page_size: 100,
15
+ order_by: nil,
16
+ order_direction: nil,
17
+ project_id: nil,
18
+ task_id: nil,
19
+ invoice_id: nil,
20
+ user_id: nil,
21
+ billing_state: nil,
22
+ start_time_range_start: nil,
23
+ start_time_range_end: nil)
24
+ validate!(billing_state: billing_state,
25
+ start_time_range_start: start_time_range_start,
26
+ start_time_range_end: start_time_range_end)
27
+
28
+ query = {
29
+ page: page,
30
+ page_size: page_size
31
+ }
32
+ query[:order_by] = order_by if order_by
33
+ query[:order_direction] = order_direction if order_direction
34
+ query[:project_id] = project_id if project_id
35
+ query[:task_id] = task_id if task_id
36
+ query[:invoice_id] = invoice_id if invoice_id
37
+ query[:user_id] = user_id if user_id
38
+ query[:billing_state] = billing_state if billing_state
39
+ query[:start_time_range_start] = start_time_range_start if start_time_range_start
40
+ query[:start_time_range_end] = start_time_range_end if start_time_range_end
41
+ get("#{@url_api_path}/tracker/time_entries", query)
42
+ end
43
+
44
+ private
45
+
46
+ def validate!(billing_state:, start_time_range_start:, start_time_range_end:)
47
+ if billing_state && !%w[billed unbilled billable unbillable archived].include?(billing_state)
48
+ raise ArgumentError,
49
+ 'billing_state must be one of: "billed" "unbilled"" billable" "unbillable" "archived"'
50
+ end
51
+ if start_time_range_start && !start_time_range_start.is_a?(Time)
52
+ raise ArgumentError, 'start_time_range_start must be a Time object'
53
+ end
54
+ return unless start_time_range_end && !start_time_range_end.is_a?(Time)
55
+
56
+ raise ArgumentError, 'start_time_range_end must be a Time object'
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PapierkramApi
4
+ module V1
5
+ module Helper
6
+ # Helper module for date related methods
7
+ module DateHelper
8
+ def build_date_string_for_api(date)
9
+ date.strftime('%Y-%m-%d')
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Api
3
+ module PapierkramApi
4
4
  module V1
5
5
  module Helper
6
6
  # This class is responsible to convert a response to a pdf file.