ledger_sync 1.0.10 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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