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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +36 -20
  3. data/README.md +105 -66
  4. data/ledger_sync.gemspec +1 -0
  5. data/lib/ledger_sync.rb +23 -4
  6. data/lib/ledger_sync/adaptors/operation.rb +28 -28
  7. data/lib/ledger_sync/adaptors/quickbooks_online/account/mapping.rb +325 -0
  8. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/create.rb +54 -0
  9. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/find.rb +38 -0
  10. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/update.rb +61 -0
  11. data/lib/ledger_sync/adaptors/quickbooks_online/account/searcher.rb +67 -0
  12. data/lib/ledger_sync/adaptors/quickbooks_online/adaptor.rb +18 -16
  13. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/create.rb +65 -0
  14. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/find.rb +37 -0
  15. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/update.rb +69 -0
  16. data/lib/ledger_sync/adaptors/quickbooks_online/bill/searcher.rb +28 -0
  17. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/create.rb +6 -6
  18. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/find.rb +1 -3
  19. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/update.rb +6 -9
  20. data/lib/ledger_sync/adaptors/quickbooks_online/customer/searcher.rb +2 -38
  21. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/create.rb +61 -0
  22. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/find.rb +36 -0
  23. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/update.rb +65 -0
  24. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/searcher.rb +28 -0
  25. data/lib/ledger_sync/adaptors/quickbooks_online/expense/mapping.rb +15 -0
  26. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/create.rb +68 -0
  27. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/find.rb +39 -0
  28. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/update.rb +72 -0
  29. data/lib/ledger_sync/adaptors/quickbooks_online/expense/searcher.rb +28 -0
  30. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/mapping.rb +14 -0
  31. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/create.rb +56 -0
  32. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/find.rb +34 -0
  33. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/update.rb +60 -0
  34. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/searcher.rb +28 -0
  35. data/lib/ledger_sync/adaptors/quickbooks_online/operation.rb +30 -0
  36. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/create.rb +8 -22
  37. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/find.rb +0 -2
  38. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/update.rb +6 -22
  39. data/lib/ledger_sync/adaptors/quickbooks_online/searcher.rb +45 -0
  40. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/create.rb +52 -0
  41. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/find.rb +36 -0
  42. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/update.rb +57 -0
  43. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/create.rb +46 -0
  44. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/find.rb +36 -0
  45. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/update.rb +51 -0
  46. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/searcher.rb +64 -0
  47. data/lib/ledger_sync/adaptors/searcher.rb +3 -1
  48. data/lib/ledger_sync/adaptors/test/account/operations/create.rb +53 -0
  49. data/lib/ledger_sync/adaptors/test/account/operations/find.rb +38 -0
  50. data/lib/ledger_sync/adaptors/test/account/operations/invalid.rb +25 -0
  51. data/lib/ledger_sync/adaptors/test/account/operations/update.rb +50 -0
  52. data/lib/ledger_sync/adaptors/test/account/operations/valid.rb +31 -0
  53. data/lib/ledger_sync/adaptors/test/account/searcher.rb +40 -0
  54. data/lib/ledger_sync/adaptors/test/adaptor.rb +4 -4
  55. data/lib/ledger_sync/adaptors/test/customer/operations/create.rb +4 -6
  56. data/lib/ledger_sync/adaptors/test/customer/operations/find.rb +0 -2
  57. data/lib/ledger_sync/adaptors/test/customer/operations/update.rb +4 -6
  58. data/lib/ledger_sync/adaptors/test/customer/searcher.rb +2 -2
  59. data/lib/ledger_sync/adaptors/test/expense/operations/create.rb +54 -0
  60. data/lib/ledger_sync/adaptors/test/expense/operations/find.rb +39 -0
  61. data/lib/ledger_sync/adaptors/test/expense/operations/update.rb +57 -0
  62. data/lib/ledger_sync/adaptors/test/payment/operations/create.rb +4 -20
  63. data/lib/ledger_sync/adaptors/test/payment/operations/find.rb +0 -2
  64. data/lib/ledger_sync/adaptors/test/payment/operations/update.rb +4 -20
  65. data/lib/ledger_sync/adaptors/test/transfer/operations/create.rb +45 -0
  66. data/lib/ledger_sync/adaptors/test/transfer/operations/find.rb +36 -0
  67. data/lib/ledger_sync/adaptors/test/transfer/operations/update.rb +48 -0
  68. data/lib/ledger_sync/adaptors/test/vendor/operations/create.rb +47 -0
  69. data/lib/ledger_sync/adaptors/test/vendor/operations/find.rb +34 -0
  70. data/lib/ledger_sync/adaptors/test/vendor/operations/invalid.rb +21 -0
  71. data/lib/ledger_sync/adaptors/test/vendor/operations/update.rb +44 -0
  72. data/lib/ledger_sync/adaptors/test/vendor/operations/valid.rb +27 -0
  73. data/lib/ledger_sync/adaptors/test/vendor/searcher.rb +41 -0
  74. data/lib/ledger_sync/error/resource_errors.rb +24 -0
  75. data/lib/ledger_sync/resource.rb +24 -64
  76. data/lib/ledger_sync/resource_attribute.rb +50 -0
  77. data/lib/ledger_sync/resource_attribute/dirty_mixin.rb +49 -0
  78. data/lib/ledger_sync/resource_attribute/mixin.rb +90 -0
  79. data/lib/ledger_sync/resource_attribute/reference.rb +9 -0
  80. data/lib/ledger_sync/resource_attribute/reference/many.rb +34 -0
  81. data/lib/ledger_sync/resource_attribute/reference/one.rb +33 -0
  82. data/lib/ledger_sync/resource_attribute_set.rb +58 -0
  83. data/lib/ledger_sync/resources/account.rb +14 -0
  84. data/lib/ledger_sync/resources/bill.rb +17 -0
  85. data/lib/ledger_sync/resources/bill_line_item.rb +11 -0
  86. data/lib/ledger_sync/resources/customer.rb +5 -4
  87. data/lib/ledger_sync/resources/deposit.rb +16 -0
  88. data/lib/ledger_sync/resources/deposit_line_item.rb +11 -0
  89. data/lib/ledger_sync/resources/expense.rb +19 -0
  90. data/lib/ledger_sync/resources/expense_line_item.rb +11 -0
  91. data/lib/ledger_sync/resources/journal_entry.rb +13 -0
  92. data/lib/ledger_sync/resources/journal_entry_line_item.rb +12 -0
  93. data/lib/ledger_sync/resources/payment.rb +5 -3
  94. data/lib/ledger_sync/resources/transfer.rb +15 -0
  95. data/lib/ledger_sync/resources/vendor.rb +12 -0
  96. data/lib/ledger_sync/result.rb +0 -24
  97. data/lib/ledger_sync/type/boolean.rb +17 -0
  98. data/lib/ledger_sync/type/date.rb +17 -0
  99. data/lib/ledger_sync/type/float.rb +17 -0
  100. data/lib/ledger_sync/type/integer.rb +17 -0
  101. data/lib/ledger_sync/type/reference_many.rb +27 -0
  102. data/lib/ledger_sync/type/reference_one.rb +26 -0
  103. data/lib/ledger_sync/type/string.rb +17 -0
  104. data/lib/ledger_sync/type/value.rb +12 -0
  105. data/lib/ledger_sync/type/value_mixin.rb +19 -0
  106. data/lib/ledger_sync/util/hash_helpers.rb +16 -1
  107. data/lib/ledger_sync/util/resources_builder.rb +36 -9
  108. data/lib/ledger_sync/version.rb +1 -1
  109. metadata +92 -7
  110. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/upsert.rb +0 -42
  111. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/upsert.rb +0 -53
  112. data/lib/ledger_sync/adaptors/test/customer/operations/upsert.rb +0 -42
  113. data/lib/ledger_sync/adaptors/test/payment/operations/upsert.rb +0 -53
  114. data/lib/ledger_sync/sync.rb +0 -108
  115. data/lib/ledger_sync/util/coordinator.rb +0 -72
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ class Searcher < Adaptors::Searcher
7
+ def next_searcher
8
+ paginate(limit: limit, offset: offset + limit)
9
+ end
10
+
11
+ def previous_searcher
12
+ return nil if offset <= 1
13
+
14
+ paginate(limit: limit, offset: offset - limit)
15
+ end
16
+
17
+ def search
18
+ super
19
+ rescue OAuth2::Error => e
20
+ @response = e # TODO: Better catch/raise errors as LedgerSync::Error
21
+ failure
22
+ end
23
+
24
+ private
25
+
26
+ # Pagination uses notation of limit and offset
27
+ # limit: number of results per page
28
+ #
29
+ # offset: position of first result in a list.
30
+ # starts from 1, not 0
31
+ #
32
+ # More here:
33
+ # https://developer.intuit.com/app/developer/qbo/docs/develop/explore-the-quickbooks-online-api/data-queries#pagination
34
+
35
+ def limit
36
+ pagination.fetch(:limit, 10).to_i
37
+ end
38
+
39
+ def offset
40
+ pagination.fetch(:offset, 1).to_i
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,52 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module Transfer
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(:from_account).hash(Types::Reference)
11
+ required(:to_account).hash(Types::Reference)
12
+ required(:amount).filled(:integer)
13
+ required(:currency).filled(:string)
14
+ required(:memo).filled(:string)
15
+ required(:transaction_date).filled(:date?)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ response = adaptor.post(
23
+ resource: 'transfer',
24
+ payload: local_resource_data
25
+ )
26
+
27
+ resource.ledger_id = response.dig('Id')
28
+ success(response: response)
29
+ end
30
+
31
+ def local_resource_data
32
+ {
33
+ 'CurrencyRef' => {
34
+ 'value' => resource.currency,
35
+ },
36
+ 'Amount' => resource.amount,
37
+ 'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
38
+ 'PrivateNote' => resource.memo,
39
+ 'FromAccountRef' => {
40
+ 'value' => resource.from_account.ledger_id
41
+ },
42
+ 'ToAccountRef' => {
43
+ 'value' => resource.to_account.ledger_id
44
+ }
45
+ }
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,36 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module Transfer
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(:from_account).hash(Types::Reference)
11
+ required(:to_account).hash(Types::Reference)
12
+ required(:amount).maybe(:integer)
13
+ required(:currency).maybe(:string)
14
+ required(:memo).maybe(:string)
15
+ required(:transaction_date).maybe(:date?)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ return failure(nil) if resource.ledger_id.nil?
23
+
24
+ response = adaptor.find(
25
+ resource: 'transfer',
26
+ id: resource.ledger_id
27
+ )
28
+
29
+ success(response: response)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,57 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module Transfer
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(:from_account).hash(Types::Reference)
11
+ required(:to_account).hash(Types::Reference)
12
+ required(:amount).filled(:integer)
13
+ required(:currency).filled(:string)
14
+ required(:memo).filled(:string)
15
+ required(:transaction_date).filled(:date?)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ ledger_resource_data = adaptor.find(
23
+ resource: 'transfer',
24
+ id: resource.ledger_id
25
+ )
26
+ response = adaptor.post(
27
+ resource: 'transfer',
28
+ payload: merge_into(from: local_resource_data, to: ledger_resource_data)
29
+ )
30
+
31
+ resource.ledger_id = response.dig('Id')
32
+ success(response: response)
33
+ end
34
+
35
+ def local_resource_data
36
+ {
37
+ 'CurrencyRef' => {
38
+ 'value' => resource.currency,
39
+ },
40
+ 'Amount' => resource.amount,
41
+ 'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
42
+ 'PrivateNote' => resource.memo,
43
+ 'FromAccountRef' => {
44
+ 'value' => resource.from_account.ledger_id
45
+ },
46
+ 'ToAccountRef' => {
47
+ 'value' => resource.to_account.ledger_id
48
+ }
49
+ }
50
+
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ module Vendor
7
+ module Operations
8
+ class Create < Operation::Create
9
+ class Contract < LedgerSync::Adaptors::Contract
10
+ params do
11
+ required(:ledger_id).value(:nil)
12
+ optional(:display_name).maybe(:string)
13
+ optional(:first_name).maybe(:string)
14
+ optional(:last_name).maybe(:string)
15
+ optional(:email).maybe(:string)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ response = adaptor.post(
23
+ resource: 'vendor',
24
+ payload: local_resource_data
25
+ )
26
+
27
+ resource.ledger_id = response.dig('Id')
28
+ success(response: response)
29
+ end
30
+
31
+ def local_resource_data
32
+ {
33
+ 'DisplayName' => resource.display_name,
34
+ 'GivenName' => resource.first_name,
35
+ 'FamilyName' => resource.last_name,
36
+ 'PrimaryEmailAddr' => {
37
+ 'Address' => resource.email
38
+ }
39
+ }
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ module Vendor
7
+ module Operations
8
+ class Find < Operation::Find
9
+ class Contract < LedgerSync::Adaptors::Contract
10
+ params do
11
+ required(:ledger_id).filled(:string)
12
+ required(:display_name).maybe(:string)
13
+ required(:first_name).maybe(:string)
14
+ required(:last_name).maybe(:string)
15
+ optional(:email).maybe(:string)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ return failure(nil) if resource.ledger_id.nil?
23
+
24
+ response = adaptor.find(
25
+ resource: 'vendor',
26
+ id: resource.ledger_id
27
+ )
28
+
29
+ success(response: response)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ module Vendor
7
+ module Operations
8
+ class Update < Operation::Update
9
+ class Contract < LedgerSync::Adaptors::Contract
10
+ params do
11
+ required(:ledger_id).filled(:string)
12
+ optional(:display_name).maybe(:string)
13
+ optional(:first_name).maybe(:string)
14
+ optional(:last_name).maybe(:string)
15
+ optional(:email).maybe(:string)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def operate
22
+ ledger_resource_data = adaptor.find(
23
+ resource: 'vendor',
24
+ id: resource.ledger_id
25
+ )
26
+
27
+ response = adaptor.post(
28
+ resource: 'vendor',
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
+ 'DisplayName' => resource.display_name,
39
+ 'GivenName' => resource.first_name,
40
+ 'FamilyName' => resource.last_name,
41
+ 'PrimaryEmailAddr' => {
42
+ 'Address' => resource.email
43
+ }
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,64 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module Vendor
5
+ class Searcher < LedgerSync::Adaptors::Searcher
6
+ def next_searcher
7
+ paginate(limit: limit, offset: offset + limit)
8
+ end
9
+
10
+ def previous_searcher
11
+ return nil if offset <= 1
12
+
13
+ paginate(limit: limit, offset: offset - limit)
14
+ end
15
+
16
+ def resources
17
+ @resources ||= begin
18
+ adaptor
19
+ .query(
20
+ resource: 'vendor',
21
+ query: "DisplayName LIKE '%#{query}%'",
22
+ limit: limit,
23
+ offset: offset
24
+ )
25
+ .map do |c|
26
+ LedgerSync::Vendor.new(
27
+ ledger_id: c.fetch('Id'),
28
+ display_name: c.fetch('DisplayName'),
29
+ first_name: c.dig('GivenName'),
30
+ last_name: c.dig('FamilyName')
31
+ )
32
+ end
33
+ end
34
+ end
35
+
36
+ def search
37
+ super
38
+ rescue OAuth2::Error => e
39
+ @response = e # TODO: Better catch/raise errors as LedgerSync::Error
40
+ failure
41
+ end
42
+
43
+ private
44
+ # Pagination uses notation of limit and offset
45
+ # limit: number of results per page
46
+ #
47
+ # offset: position of first result in a list.
48
+ # starts from 1, not 0
49
+ #
50
+ # More here:
51
+ # https://developer.intuit.com/app/developer/qbo/docs/develop/explore-the-quickbooks-online-api/data-queries#pagination
52
+
53
+ def limit
54
+ pagination.fetch(:limit, 10).to_i
55
+ end
56
+
57
+ def offset
58
+ pagination.fetch(:offset, 1).to_i
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LedgerSync
2
4
  module Adaptors
3
5
  class Searcher
@@ -61,4 +63,4 @@ module LedgerSync
61
63
  end
62
64
  end
63
65
  end
64
- end
66
+ end
@@ -0,0 +1,53 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module Test
4
+ module Account
5
+ module Operations
6
+ class Create < Operation::Create
7
+ class Contract < LedgerSync::Adaptors::Contract
8
+ schema do
9
+ required(:ledger_id).value(:nil)
10
+ required(:name).filled(:string)
11
+ required(:classification).filled(:string)
12
+ required(:account_type).filled(:string)
13
+ required(:account_sub_type).filled(: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 id
24
+ SecureRandom.uuid
25
+ end
26
+
27
+ def local_resource_data
28
+ {
29
+ 'name' => resource.name,
30
+ 'classification' => resource.classification,
31
+ 'account_type' => resource.account_type,
32
+ 'account_sub_type' => resource.account_sub_type
33
+ }
34
+ end
35
+
36
+ def operate
37
+ response = adaptor.post(
38
+ resource: 'account',
39
+ payload: local_resource_data.merge(
40
+ 'id' => id
41
+ )
42
+ )
43
+
44
+ resource.ledger_id = response.dig('id')
45
+
46
+ success(response: response)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end