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,72 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module Expense
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(:account).hash(Types::Reference)
11
+ required(:vendor).hash(Types::Reference)
12
+ required(:amount).filled(:integer)
13
+ required(:currency).filled(:string)
14
+ required(:memo).filled(:string)
15
+ required(:payment_type).filled(:string)
16
+ required(:transaction_date).filled(:date?)
17
+ required(:exchange_rate).maybe(:float)
18
+ required(:line_items).array(Types::Reference)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def operate
25
+ ledger_resource_data = adaptor.find(
26
+ resource: 'purchase',
27
+ id: resource.ledger_id
28
+ )
29
+ response = adaptor.post(
30
+ resource: 'purchase',
31
+ payload: merge_into(from: local_resource_data, to: ledger_resource_data)
32
+ )
33
+
34
+ resource.ledger_id = response.dig('Id')
35
+ success(response: response)
36
+ end
37
+
38
+ def local_resource_data
39
+ {
40
+ 'CurrencyRef' => {
41
+ 'value' => resource.currency,
42
+ },
43
+ 'PaymentType' => Mapping::PAYMENT_TYPES[resource.payment_type],
44
+ 'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
45
+ 'PrivateNote' => resource.memo,
46
+ 'ExchangeRate' => resource.exchange_rate,
47
+ 'EntityRef' => {
48
+ 'value' => resource.vendor.ledger_id,
49
+ },
50
+ 'AccountRef' => {
51
+ 'value' => resource.account.ledger_id
52
+ },
53
+ 'Line' => resource.line_items.map do |line_item|
54
+ {
55
+ 'DetailType' => 'AccountBasedExpenseLineDetail',
56
+ 'AccountBasedExpenseLineDetail' => {
57
+ 'AccountRef' => {
58
+ 'value' => line_item.account&.ledger_id
59
+ }
60
+ },
61
+ 'Amount' => line_item.amount / 100.0,
62
+ 'Description' => line_item.description
63
+ }
64
+ end
65
+ }
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ 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 Expense
8
+ class Searcher < QuickBooksOnline::Searcher
9
+ def resources
10
+ @resources ||= begin
11
+ adaptor
12
+ .query(
13
+ resource: 'purchase',
14
+ limit: limit,
15
+ offset: offset
16
+ )
17
+ .map do |c|
18
+ LedgerSync::Expense.new(
19
+ ledger_id: c.fetch('Id')
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module JournalEntry
5
+ module Mapping
6
+ LINE_ITEM_TYPES = {
7
+ 'debit' => 'Debit',
8
+ 'credit' => 'Credit',
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module JournalEntry
5
+ module Operations
6
+ class Create < Operation::Create
7
+ class Contract < LedgerSync::Adaptors::Contract
8
+ params do
9
+ required(:ledger_id).value(:nil)
10
+ optional(:currency).filled(:string)
11
+ optional(:memo).filled(:string)
12
+ optional(:transaction_date).filled(:date?)
13
+ optional(:line_items).array(Types::Reference)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def operate
20
+ response = adaptor.post(
21
+ resource: 'journal_entry',
22
+ payload: local_resource_data
23
+ )
24
+
25
+ resource.ledger_id = response.dig('Id')
26
+ success(response: response)
27
+ end
28
+
29
+ def local_resource_data
30
+ {
31
+ 'CurrencyRef' => {
32
+ 'value' => resource.currency,
33
+ },
34
+ 'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
35
+ 'PrivateNote' => resource.memo,
36
+ 'Line' => resource.line_items.map do |line_item|
37
+ {
38
+ 'DetailType' => 'JournalEntryLineDetail',
39
+ 'JournalEntryLineDetail' => {
40
+ 'PostingType': Mapping::LINE_ITEM_TYPES[line_item.entry_type],
41
+ 'AccountRef' => {
42
+ 'value' => line_item.account&.ledger_id
43
+ }
44
+ },
45
+ 'Amount' => line_item.amount / 100.0,
46
+ 'Description' => line_item.description
47
+ }
48
+ end
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module JournalEntry
5
+ module Operations
6
+ class Find < Operation::Find
7
+ class Contract < LedgerSync::Adaptors::Contract
8
+ schema do
9
+ required(:ledger_id).filled(:string)
10
+ optional(:currency).maybe(:string)
11
+ optional(:memo).maybe(:string)
12
+ optional(:transaction_date).filled(:date?)
13
+ optional(:line_items).array(Types::Reference)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def operate
20
+ return failure(nil) if resource.ledger_id.nil?
21
+
22
+ response = adaptor.find(
23
+ resource: 'journal_entry',
24
+ id: resource.ledger_id
25
+ )
26
+
27
+ success(response: response)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ module LedgerSync
2
+ module Adaptors
3
+ module QuickBooksOnline
4
+ module JournalEntry
5
+ module Operations
6
+ class Update < Operation::Update
7
+ class Contract < LedgerSync::Adaptors::Contract
8
+ schema do
9
+ required(:ledger_id).filled(:string)
10
+ optional(:currency).filled(:string)
11
+ optional(:memo).filled(:string)
12
+ optional(:transaction_date).filled(:date?)
13
+ optional(:line_items).array(Types::Reference)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def operate
20
+ ledger_resource_data = adaptor.find(
21
+ resource: 'journal_entry',
22
+ id: resource.ledger_id
23
+ )
24
+ response = adaptor.post(
25
+ resource: 'journal_entry',
26
+ payload: merge_into(from: local_resource_data, to: ledger_resource_data)
27
+ )
28
+
29
+ resource.ledger_id = response.dig('Id')
30
+ success(response: response)
31
+ end
32
+
33
+ def local_resource_data
34
+ {
35
+ 'CurrencyRef' => {
36
+ 'value' => resource.currency,
37
+ },
38
+ 'TxnDate' => resource.transaction_date.to_s, # Format: YYYY-MM-DD
39
+ 'PrivateNote' => resource.memo,
40
+ 'Line' => resource.line_items.map do |line_item|
41
+ {
42
+ 'DetailType' => 'JournalEntryLineDetail',
43
+ 'JournalEntryLineDetail' => {
44
+ 'PostingType': Mapping::LINE_ITEM_TYPES[line_item.entry_type],
45
+ 'AccountRef' => {
46
+ 'value' => line_item.account&.ledger_id
47
+ }
48
+ },
49
+ 'Amount' => line_item.amount / 100.0,
50
+ 'Description' => line_item.description
51
+ }
52
+ end
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ 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 JournalEntry
8
+ class Searcher < QuickBooksOnline::Searcher
9
+ def resources
10
+ @resources ||= begin
11
+ adaptor
12
+ .query(
13
+ resource: 'journal_entry',
14
+ limit: limit,
15
+ offset: offset
16
+ )
17
+ .map do |c|
18
+ LedgerSync::JournalEntry.new(
19
+ ledger_id: c.fetch('Id')
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ module Operation
7
+ TYPES = %i[create find update].freeze
8
+
9
+ module Mixin
10
+ def self.included(base)
11
+ base.include Adaptors::Operation::Mixin
12
+ end
13
+
14
+ def perform
15
+ super
16
+ rescue OAuth2::Error => e
17
+ failure(e)
18
+ end
19
+ end
20
+
21
+ TYPES.each do |type|
22
+ klass = Class.new do
23
+ include QuickBooksOnline::Operation::Mixin
24
+ end
25
+ Operation.const_set(LedgerSync::Util::StringHelpers.camelcase(type.to_s), klass)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LedgerSync
2
4
  module Adaptors
3
5
  module QuickBooksOnline
@@ -19,40 +21,24 @@ module LedgerSync
19
21
 
20
22
  private
21
23
 
22
- def build
23
- build_customer_operation
24
- add_root_operation(self)
25
- end
26
-
27
24
  def operate
28
- response = adaptor.upsert(
25
+ response = adaptor.post(
29
26
  resource: 'payment',
30
27
  payload: local_resource_data
31
28
  )
32
29
 
33
30
  resource.ledger_id = response.dig('Id')
34
31
  success(response: response)
35
- rescue OAuth2::Error => e
36
- failure(e)
37
- end
38
-
39
- def build_customer_operation
40
- customer = Customer::Operations::Upsert.new(
41
- adaptor: adaptor,
42
- resource: resource.customer
43
- )
44
-
45
- add_before_operation(customer)
46
32
  end
47
33
 
48
34
  def local_resource_data
49
35
  {
50
- 'TotalAmt': resource.amount,
51
- 'CurrencyRef': {
52
- 'value': resource.currency,
36
+ 'TotalAmt' => resource.amount / 100.0,
37
+ 'CurrencyRef' => {
38
+ 'value' => resource.currency
53
39
  },
54
- 'CustomerRef': {
55
- 'value': resource.customer.ledger_id,
40
+ 'CustomerRef' => {
41
+ 'value' => resource.customer.ledger_id
56
42
  }
57
43
  }
58
44
  end
@@ -24,8 +24,6 @@ module LedgerSync
24
24
  )
25
25
 
26
26
  success(response: response)
27
- rescue OAuth2::Error => e
28
- failure(e)
29
27
  end
30
28
  end
31
29
  end
@@ -15,44 +15,28 @@ module LedgerSync
15
15
 
16
16
  private
17
17
 
18
- def build
19
- build_customer_operation
20
- add_root_operation(self)
21
- end
22
-
23
18
  def operate
24
19
  ledger_resource_data = adaptor.find(
25
20
  resource: 'payment',
26
21
  id: resource.ledger_id
27
22
  )
28
- response = adaptor.upsert(
23
+ response = adaptor.post(
29
24
  resource: 'payment',
30
25
  payload: merge_into(from: local_resource_data, to: ledger_resource_data)
31
26
  )
32
27
 
33
28
  resource.ledger_id = response.dig('Id')
34
29
  success(response: response)
35
- rescue OAuth2::Error => e
36
- failure(e)
37
- end
38
-
39
- def build_customer_operation
40
- customer = Customer::Operations::Upsert.new(
41
- adaptor: adaptor,
42
- resource: resource.customer
43
- )
44
-
45
- add_before_operation(customer)
46
30
  end
47
31
 
48
32
  def local_resource_data
49
33
  {
50
- 'TotalAmt': resource.amount,
51
- 'CurrencyRef': {
52
- 'value': resource.currency,
34
+ 'TotalAmt' => resource.amount / 100.0,
35
+ 'CurrencyRef' => {
36
+ 'value' => resource.currency,
53
37
  },
54
- 'CustomerRef': {
55
- 'value': resource.customer.ledger_id,
38
+ 'CustomerRef' => {
39
+ 'value' => resource.customer.ledger_id,
56
40
  }
57
41
  }
58
42
  end