ledger_sync 1.0.10 → 1.1.1
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +36 -20
- data/README.md +105 -66
- data/ledger_sync.gemspec +1 -0
- data/lib/ledger_sync.rb +23 -4
- data/lib/ledger_sync/adaptors/operation.rb +28 -28
- data/lib/ledger_sync/adaptors/quickbooks_online/account/mapping.rb +325 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/create.rb +54 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/find.rb +38 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/update.rb +61 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/account/searcher.rb +67 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/adaptor.rb +18 -16
- data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/create.rb +65 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/find.rb +37 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/update.rb +69 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/bill/searcher.rb +28 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/create.rb +6 -6
- data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/find.rb +1 -3
- data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/update.rb +6 -9
- data/lib/ledger_sync/adaptors/quickbooks_online/customer/searcher.rb +2 -38
- data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/create.rb +61 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/find.rb +36 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/update.rb +65 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/deposit/searcher.rb +28 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/expense/mapping.rb +15 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/create.rb +68 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/find.rb +39 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/update.rb +72 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/expense/searcher.rb +28 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/mapping.rb +14 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/create.rb +56 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/find.rb +34 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/update.rb +60 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/searcher.rb +28 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/operation.rb +30 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/create.rb +8 -22
- data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/find.rb +0 -2
- data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/update.rb +6 -22
- data/lib/ledger_sync/adaptors/quickbooks_online/searcher.rb +45 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/create.rb +52 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/find.rb +36 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/update.rb +57 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/create.rb +46 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/find.rb +36 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/update.rb +51 -0
- data/lib/ledger_sync/adaptors/quickbooks_online/vendor/searcher.rb +64 -0
- data/lib/ledger_sync/adaptors/searcher.rb +3 -1
- data/lib/ledger_sync/adaptors/test/account/operations/create.rb +53 -0
- data/lib/ledger_sync/adaptors/test/account/operations/find.rb +38 -0
- data/lib/ledger_sync/adaptors/test/account/operations/invalid.rb +25 -0
- data/lib/ledger_sync/adaptors/test/account/operations/update.rb +50 -0
- data/lib/ledger_sync/adaptors/test/account/operations/valid.rb +31 -0
- data/lib/ledger_sync/adaptors/test/account/searcher.rb +40 -0
- data/lib/ledger_sync/adaptors/test/adaptor.rb +4 -4
- data/lib/ledger_sync/adaptors/test/customer/operations/create.rb +4 -6
- data/lib/ledger_sync/adaptors/test/customer/operations/find.rb +0 -2
- data/lib/ledger_sync/adaptors/test/customer/operations/update.rb +4 -6
- data/lib/ledger_sync/adaptors/test/customer/searcher.rb +2 -2
- data/lib/ledger_sync/adaptors/test/expense/operations/create.rb +54 -0
- data/lib/ledger_sync/adaptors/test/expense/operations/find.rb +39 -0
- data/lib/ledger_sync/adaptors/test/expense/operations/update.rb +57 -0
- data/lib/ledger_sync/adaptors/test/payment/operations/create.rb +4 -20
- data/lib/ledger_sync/adaptors/test/payment/operations/find.rb +0 -2
- data/lib/ledger_sync/adaptors/test/payment/operations/update.rb +4 -20
- data/lib/ledger_sync/adaptors/test/transfer/operations/create.rb +45 -0
- data/lib/ledger_sync/adaptors/test/transfer/operations/find.rb +36 -0
- data/lib/ledger_sync/adaptors/test/transfer/operations/update.rb +48 -0
- data/lib/ledger_sync/adaptors/test/vendor/operations/create.rb +47 -0
- data/lib/ledger_sync/adaptors/test/vendor/operations/find.rb +34 -0
- data/lib/ledger_sync/adaptors/test/vendor/operations/invalid.rb +21 -0
- data/lib/ledger_sync/adaptors/test/vendor/operations/update.rb +44 -0
- data/lib/ledger_sync/adaptors/test/vendor/operations/valid.rb +27 -0
- data/lib/ledger_sync/adaptors/test/vendor/searcher.rb +41 -0
- data/lib/ledger_sync/error/resource_errors.rb +24 -0
- data/lib/ledger_sync/resource.rb +24 -64
- data/lib/ledger_sync/resource_attribute.rb +50 -0
- data/lib/ledger_sync/resource_attribute/dirty_mixin.rb +49 -0
- data/lib/ledger_sync/resource_attribute/mixin.rb +90 -0
- data/lib/ledger_sync/resource_attribute/reference.rb +9 -0
- data/lib/ledger_sync/resource_attribute/reference/many.rb +34 -0
- data/lib/ledger_sync/resource_attribute/reference/one.rb +33 -0
- data/lib/ledger_sync/resource_attribute_set.rb +58 -0
- data/lib/ledger_sync/resources/account.rb +14 -0
- data/lib/ledger_sync/resources/bill.rb +17 -0
- data/lib/ledger_sync/resources/bill_line_item.rb +11 -0
- data/lib/ledger_sync/resources/customer.rb +5 -4
- data/lib/ledger_sync/resources/deposit.rb +16 -0
- data/lib/ledger_sync/resources/deposit_line_item.rb +11 -0
- data/lib/ledger_sync/resources/expense.rb +19 -0
- data/lib/ledger_sync/resources/expense_line_item.rb +11 -0
- data/lib/ledger_sync/resources/journal_entry.rb +13 -0
- data/lib/ledger_sync/resources/journal_entry_line_item.rb +12 -0
- data/lib/ledger_sync/resources/payment.rb +5 -3
- data/lib/ledger_sync/resources/transfer.rb +15 -0
- data/lib/ledger_sync/resources/vendor.rb +12 -0
- data/lib/ledger_sync/result.rb +0 -24
- data/lib/ledger_sync/type/boolean.rb +17 -0
- data/lib/ledger_sync/type/date.rb +17 -0
- data/lib/ledger_sync/type/float.rb +17 -0
- data/lib/ledger_sync/type/integer.rb +17 -0
- data/lib/ledger_sync/type/reference_many.rb +27 -0
- data/lib/ledger_sync/type/reference_one.rb +26 -0
- data/lib/ledger_sync/type/string.rb +17 -0
- data/lib/ledger_sync/type/value.rb +12 -0
- data/lib/ledger_sync/type/value_mixin.rb +19 -0
- data/lib/ledger_sync/util/hash_helpers.rb +16 -1
- data/lib/ledger_sync/util/resources_builder.rb +36 -9
- data/lib/ledger_sync/version.rb +1 -1
- metadata +92 -7
- data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/upsert.rb +0 -42
- data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/upsert.rb +0 -53
- data/lib/ledger_sync/adaptors/test/customer/operations/upsert.rb +0 -42
- data/lib/ledger_sync/adaptors/test/payment/operations/upsert.rb +0 -53
- data/lib/ledger_sync/sync.rb +0 -108
- data/lib/ledger_sync/util/coordinator.rb +0 -72
@@ -0,0 +1,38 @@
|
|
1
|
+
module LedgerSync
|
2
|
+
module Adaptors
|
3
|
+
module QuickBooksOnline
|
4
|
+
module Account
|
5
|
+
module Operations
|
6
|
+
class Find < Operation::Find
|
7
|
+
class Contract < LedgerSync::Adaptors::Contract
|
8
|
+
params do
|
9
|
+
required(:ledger_id).filled(:string)
|
10
|
+
required(:name).maybe(:string)
|
11
|
+
required(:classification).maybe(:string)
|
12
|
+
required(:account_type).maybe(:string)
|
13
|
+
required(:account_sub_type).maybe(:string)
|
14
|
+
required(:number).maybe(:integer)
|
15
|
+
required(:currency).maybe(:string)
|
16
|
+
required(:description).maybe(:string)
|
17
|
+
required(:active).maybe(:bool)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def operate
|
24
|
+
return failure(nil) if resource.ledger_id.nil?
|
25
|
+
|
26
|
+
response = adaptor.find(
|
27
|
+
resource: 'account',
|
28
|
+
id: resource.ledger_id
|
29
|
+
)
|
30
|
+
|
31
|
+
success(response: response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ledger_sync/adaptors/quickbooks_online/account/mapping'
|
4
|
+
|
5
|
+
module LedgerSync
|
6
|
+
module Adaptors
|
7
|
+
module QuickBooksOnline
|
8
|
+
module Account
|
9
|
+
module Operations
|
10
|
+
class Update < Operation::Update
|
11
|
+
class Contract < LedgerSync::Adaptors::Contract
|
12
|
+
params do
|
13
|
+
required(:ledger_id).filled(:string)
|
14
|
+
required(:name).filled(:string)
|
15
|
+
required(:classification).filled(:string)
|
16
|
+
required(:account_type).filled(:string)
|
17
|
+
required(:account_sub_type).filled(:string)
|
18
|
+
required(:number).maybe(:integer)
|
19
|
+
required(:currency).maybe(:string)
|
20
|
+
required(:description).maybe(:string)
|
21
|
+
required(:active).maybe(:bool)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def operate
|
28
|
+
ledger_resource_data = adaptor.find(
|
29
|
+
resource: 'account',
|
30
|
+
id: resource.ledger_id
|
31
|
+
)
|
32
|
+
|
33
|
+
response = adaptor.post(
|
34
|
+
resource: 'account',
|
35
|
+
payload: merge_into(from: local_resource_data, to: ledger_resource_data)
|
36
|
+
)
|
37
|
+
|
38
|
+
resource.ledger_id = response.dig('Id')
|
39
|
+
success(response: response)
|
40
|
+
end
|
41
|
+
|
42
|
+
def local_resource_data
|
43
|
+
{
|
44
|
+
'Name' => resource.name,
|
45
|
+
'Classification' => Mapping::ACCOUNT_CLASSIFICATIONS[resource.classification],
|
46
|
+
'AccountType' => Mapping::ACCOUNT_TYPES[resource.account_type],
|
47
|
+
'AccountSubType' => Mapping::ACCOUNT_SUB_TYPES[resource.account_sub_type],
|
48
|
+
'AcctNum' => resource.number,
|
49
|
+
'CurrencyRef' => {
|
50
|
+
'value' => resource.currency,
|
51
|
+
},
|
52
|
+
'Description' => resource.description,
|
53
|
+
'Active' => resource.active
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'ledger_sync/adaptors/quickbooks_online/account/mapping'
|
2
|
+
|
3
|
+
module LedgerSync
|
4
|
+
module Adaptors
|
5
|
+
module QuickBooksOnline
|
6
|
+
module Account
|
7
|
+
class Searcher < LedgerSync::Adaptors::Searcher
|
8
|
+
def next_searcher
|
9
|
+
paginate(limit: limit, offset: offset + limit)
|
10
|
+
end
|
11
|
+
|
12
|
+
def previous_searcher
|
13
|
+
return nil if offset <= 1
|
14
|
+
|
15
|
+
paginate(limit: limit, offset: offset - limit)
|
16
|
+
end
|
17
|
+
|
18
|
+
def resources
|
19
|
+
@resources ||= begin
|
20
|
+
adaptor
|
21
|
+
.query(
|
22
|
+
resource: 'account',
|
23
|
+
query: "Name LIKE '%#{query}%'",
|
24
|
+
limit: limit,
|
25
|
+
offset: offset
|
26
|
+
)
|
27
|
+
.map do |c|
|
28
|
+
LedgerSync::Account.new(
|
29
|
+
ledger_id: c.fetch('Id'),
|
30
|
+
name: c.fetch('Name'),
|
31
|
+
classification: Mapping::ACCOUNT_CLASSIFICATIONS.invert[c.fetch('Classification')] || c.fetch('Classification'),
|
32
|
+
account_type: Mapping::ACCOUNT_TYPES.invert[c.fetch('AccountType')] || c.fetch('AccountType'),
|
33
|
+
account_sub_type: Mapping::ACCOUNT_SUB_TYPES.invert[c.fetch('AccountSubType')] || c.fetch('AccountSubType')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def search
|
40
|
+
super
|
41
|
+
rescue OAuth2::Error => e
|
42
|
+
@response = e # TODO: Better catch/raise errors as LedgerSync::Error
|
43
|
+
failure
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
# Pagination uses notation of limit and offset
|
48
|
+
# limit: number of results per page
|
49
|
+
#
|
50
|
+
# offset: position of first result in a list.
|
51
|
+
# starts from 1, not 0
|
52
|
+
#
|
53
|
+
# More here:
|
54
|
+
# https://developer.intuit.com/app/developer/qbo/docs/develop/explore-the-quickbooks-online-api/data-queries#pagination
|
55
|
+
|
56
|
+
def limit
|
57
|
+
pagination.fetch(:limit, 10).to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
def offset
|
61
|
+
pagination.fetch(:offset, 1).to_i
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -19,6 +19,7 @@ module LedgerSync
|
|
19
19
|
:previous_refresh_tokens,
|
20
20
|
:realm_id,
|
21
21
|
:refresh_token,
|
22
|
+
:refresh_token_expires_at,
|
22
23
|
:root_uri,
|
23
24
|
:test
|
24
25
|
|
@@ -43,10 +44,10 @@ module LedgerSync
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def find(resource:, id:)
|
46
|
-
url = "#{oauth_base_uri}/#{
|
47
|
+
url = "#{oauth_base_uri}/#{resourcify(resource)}/#{id}"
|
47
48
|
|
48
49
|
response = request(:get, url, headers: OAUTH_HEADERS.dup)
|
49
|
-
JSON.parse(response.body).dig(resource.
|
50
|
+
JSON.parse(response.body).dig(resource.classify)
|
50
51
|
end
|
51
52
|
|
52
53
|
def parse_operation_error(error:, operation:)
|
@@ -58,12 +59,19 @@ module LedgerSync
|
|
58
59
|
).parse
|
59
60
|
end
|
60
61
|
|
62
|
+
def post(resource:, payload:)
|
63
|
+
url = "#{oauth_base_uri}/#{resourcify(resource)}"
|
64
|
+
|
65
|
+
response = request(:post, url, headers: OAUTH_HEADERS.dup, body: payload.to_json)
|
66
|
+
JSON.parse(response.body).dig(resource.classify)
|
67
|
+
end
|
68
|
+
|
61
69
|
def query(resource:, query:, limit: 10, offset: 1)
|
62
|
-
full_query = "SELECT * FROM #{resource.
|
70
|
+
full_query = "SELECT * FROM #{resource.classify} WHERE #{query} STARTPOSITION #{offset} MAXRESULTS #{limit}"
|
63
71
|
url = "#{oauth_base_uri}/query?query=#{CGI.escape(full_query)}"
|
64
72
|
|
65
73
|
response = request(:get, url, headers: OAUTH_HEADERS.dup)
|
66
|
-
JSON.parse(response.body).dig('QueryResponse', resource.
|
74
|
+
JSON.parse(response.body).dig('QueryResponse', resource.classify) || []
|
67
75
|
end
|
68
76
|
|
69
77
|
def refresh!
|
@@ -73,6 +81,7 @@ module LedgerSync
|
|
73
81
|
@access_token = refreshed.token
|
74
82
|
|
75
83
|
@expires_at = Time&.at(refreshed.expires_at.to_i)&.to_datetime
|
84
|
+
@refresh_token_expires_at = Time&.at(Time.now.to_i + refreshed.params['x_refresh_token_expires_in'])&.to_datetime unless refreshed.params['x_refresh_token_expires_in'].nil?
|
76
85
|
|
77
86
|
@previous_refresh_tokens << refresh_token
|
78
87
|
@refresh_token = refreshed.refresh_token
|
@@ -84,15 +93,8 @@ module LedgerSync
|
|
84
93
|
raise parse_error(error: e)
|
85
94
|
end
|
86
95
|
|
87
|
-
def upsert(resource:, payload:)
|
88
|
-
url = "#{oauth_base_uri}/#{underscore(resource)}"
|
89
|
-
|
90
|
-
response = request(:post, url, headers: OAUTH_HEADERS.dup, body: payload.to_json)
|
91
|
-
JSON.parse(response.body).dig(resource.capitalize)
|
92
|
-
end
|
93
|
-
|
94
96
|
def self.ledger_attributes_to_save
|
95
|
-
%i[access_token expires_at refresh_token]
|
97
|
+
%i[access_token expires_at refresh_token refresh_token_expires_at]
|
96
98
|
end
|
97
99
|
|
98
100
|
# def self.url_for(resource:)
|
@@ -108,10 +110,6 @@ module LedgerSync
|
|
108
110
|
@oauth_base_uri ||= "#{root_uri}/v3/company/#{realm_id}"
|
109
111
|
end
|
110
112
|
|
111
|
-
def underscore(str)
|
112
|
-
LedgerSync::Util::StringHelpers.underscore(str)
|
113
|
-
end
|
114
|
-
|
115
113
|
def oauth(force: false)
|
116
114
|
if @oauth.nil? || force
|
117
115
|
@oauth = OAuth2::AccessToken.new(
|
@@ -154,6 +152,10 @@ module LedgerSync
|
|
154
152
|
adaptor: self
|
155
153
|
).parse
|
156
154
|
end
|
155
|
+
|
156
|
+
def resourcify(str)
|
157
|
+
str.tr('_', '')
|
158
|
+
end
|
157
159
|
end
|
158
160
|
end
|
159
161
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module LedgerSync
|
2
|
+
module Adaptors
|
3
|
+
module QuickBooksOnline
|
4
|
+
module Bill
|
5
|
+
module Operations
|
6
|
+
class Create < Operation::Create
|
7
|
+
class Contract < LedgerSync::Adaptors::Contract
|
8
|
+
params do
|
9
|
+
required(:ledger_id).value(:nil)
|
10
|
+
required(:vendor).hash(Types::Reference)
|
11
|
+
required(:account).hash(Types::Reference)
|
12
|
+
required(:currency).filled(:string)
|
13
|
+
required(:memo).maybe(:string)
|
14
|
+
required(:transaction_date).maybe(:date?)
|
15
|
+
required(:due_date).maybe(:date?)
|
16
|
+
required(:line_items).array(Types::Reference)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def operate
|
23
|
+
response = adaptor.post(
|
24
|
+
resource: 'bill',
|
25
|
+
payload: local_resource_data
|
26
|
+
)
|
27
|
+
|
28
|
+
resource.ledger_id = response.dig('Id')
|
29
|
+
success(response: response)
|
30
|
+
end
|
31
|
+
|
32
|
+
def local_resource_data
|
33
|
+
{
|
34
|
+
'CurrencyRef' => {
|
35
|
+
'value' => resource.currency,
|
36
|
+
},
|
37
|
+
'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
|
38
|
+
'DueDate' => resource.due_date.to_s, # Format: YYYY-MM-DD
|
39
|
+
'PrivateNote' => resource.memo,
|
40
|
+
'VendorRef' => {
|
41
|
+
'value' => resource.vendor.ledger_id,
|
42
|
+
},
|
43
|
+
'APAccountRef' => {
|
44
|
+
'value' => resource.account.ledger_id
|
45
|
+
},
|
46
|
+
'Line' => resource.line_items.map do |line_item|
|
47
|
+
{
|
48
|
+
'DetailType' => 'AccountBasedExpenseLineDetail',
|
49
|
+
'AccountBasedExpenseLineDetail' => {
|
50
|
+
'AccountRef' => {
|
51
|
+
'value' => line_item.account&.ledger_id
|
52
|
+
}
|
53
|
+
},
|
54
|
+
'Amount' => line_item.amount / 100.0,
|
55
|
+
'Description' => line_item.description
|
56
|
+
}
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module LedgerSync
|
2
|
+
module Adaptors
|
3
|
+
module QuickBooksOnline
|
4
|
+
module Bill
|
5
|
+
module Operations
|
6
|
+
class Find < Operation::Find
|
7
|
+
class Contract < LedgerSync::Adaptors::Contract
|
8
|
+
schema do
|
9
|
+
required(:ledger_id).filled(:string)
|
10
|
+
required(:vendor).hash(Types::Reference)
|
11
|
+
required(:account).hash(Types::Reference)
|
12
|
+
required(:currency).maybe(:string)
|
13
|
+
required(:memo).maybe(:string)
|
14
|
+
required(:transaction_date).maybe(:date?)
|
15
|
+
required(:due_date).maybe(:date?)
|
16
|
+
required(:line_items).array(Types::Reference)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def operate
|
23
|
+
return failure(nil) if resource.ledger_id.nil?
|
24
|
+
|
25
|
+
response = adaptor.find(
|
26
|
+
resource: 'bill',
|
27
|
+
id: resource.ledger_id
|
28
|
+
)
|
29
|
+
|
30
|
+
success(response: response)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module LedgerSync
|
2
|
+
module Adaptors
|
3
|
+
module QuickBooksOnline
|
4
|
+
module Bill
|
5
|
+
module Operations
|
6
|
+
class Update < Operation::Update
|
7
|
+
class Contract < LedgerSync::Adaptors::Contract
|
8
|
+
schema do
|
9
|
+
required(:ledger_id).filled(:string)
|
10
|
+
required(:vendor).hash(Types::Reference)
|
11
|
+
required(:account).hash(Types::Reference)
|
12
|
+
required(:currency).filled(:string)
|
13
|
+
required(:memo).maybe(:string)
|
14
|
+
required(:transaction_date).maybe(:date?)
|
15
|
+
required(:due_date).maybe(:date?)
|
16
|
+
required(:line_items).array(Types::Reference)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def operate
|
23
|
+
ledger_resource_data = adaptor.find(
|
24
|
+
resource: 'bill',
|
25
|
+
id: resource.ledger_id
|
26
|
+
)
|
27
|
+
response = adaptor.post(
|
28
|
+
resource: 'bill',
|
29
|
+
payload: merge_into(from: local_resource_data, to: ledger_resource_data)
|
30
|
+
)
|
31
|
+
|
32
|
+
resource.ledger_id = response.dig('Id')
|
33
|
+
success(response: response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def local_resource_data
|
37
|
+
{
|
38
|
+
'CurrencyRef' => {
|
39
|
+
'value' => resource.currency,
|
40
|
+
},
|
41
|
+
'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
|
42
|
+
'DueDate' => resource.due_date.to_s, # Format: YYYY-MM-DD
|
43
|
+
'PrivateNote' => resource.memo,
|
44
|
+
'VendorRef' => {
|
45
|
+
'value' => resource.vendor.ledger_id,
|
46
|
+
},
|
47
|
+
'APAccountRef' => {
|
48
|
+
'value' => resource.account.ledger_id
|
49
|
+
},
|
50
|
+
'Line' => resource.line_items.map do |line_item|
|
51
|
+
{
|
52
|
+
'DetailType' => 'AccountBasedExpenseLineDetail',
|
53
|
+
'AccountBasedExpenseLineDetail' => {
|
54
|
+
'AccountRef' => {
|
55
|
+
'value' => line_item.account&.ledger_id
|
56
|
+
}
|
57
|
+
},
|
58
|
+
'Amount' => line_item.amount / 100.0,
|
59
|
+
'Description' => line_item.description
|
60
|
+
}
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../searcher'
|
3
|
+
|
4
|
+
module LedgerSync
|
5
|
+
module Adaptors
|
6
|
+
module QuickBooksOnline
|
7
|
+
module Bill
|
8
|
+
class Searcher < QuickBooksOnline::Searcher
|
9
|
+
def resources
|
10
|
+
@resources ||= begin
|
11
|
+
adaptor
|
12
|
+
.query(
|
13
|
+
resource: 'bill',
|
14
|
+
limit: limit,
|
15
|
+
offset: offset
|
16
|
+
)
|
17
|
+
.map do |c|
|
18
|
+
LedgerSync::Bill.new(
|
19
|
+
ledger_id: c.fetch('Id')
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|