ledger_sync 1.1.1 → 1.1.2

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +2 -3
  5. data/lib/ledger_sync.rb +12 -6
  6. data/lib/ledger_sync/adaptors/ledger_serializer.rb +124 -0
  7. data/lib/ledger_sync/adaptors/ledger_serializer_attribute.rb +148 -0
  8. data/lib/ledger_sync/adaptors/ledger_serializer_attribute_set.rb +51 -0
  9. data/lib/ledger_sync/adaptors/ledger_serializer_type/mapping_type.rb +41 -0
  10. data/lib/ledger_sync/adaptors/ledger_serializer_type/references_many_type.rb +24 -0
  11. data/lib/ledger_sync/adaptors/ledger_serializer_type/value_type.rb +17 -0
  12. data/lib/ledger_sync/adaptors/operation.rb +15 -9
  13. data/lib/ledger_sync/adaptors/quickbooks_online/account/ledger_serializer.rb +21 -0
  14. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/create.rb +8 -36
  15. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/find.rb +1 -13
  16. data/lib/ledger_sync/adaptors/quickbooks_online/account/operations/update.rb +4 -35
  17. data/lib/ledger_sync/adaptors/quickbooks_online/account/searcher.rb +3 -44
  18. data/lib/ledger_sync/adaptors/quickbooks_online/adaptor.rb +75 -28
  19. data/lib/ledger_sync/adaptors/quickbooks_online/bill/ledger_serializer.rb +40 -0
  20. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/create.rb +9 -48
  21. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/find.rb +10 -21
  22. data/lib/ledger_sync/adaptors/quickbooks_online/bill/operations/update.rb +9 -52
  23. data/lib/ledger_sync/adaptors/quickbooks_online/bill_line_item/ledger_serializer.rb +27 -0
  24. data/lib/ledger_sync/adaptors/quickbooks_online/customer/ledger_serializer.rb +23 -0
  25. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/create.rb +2 -25
  26. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/find.rb +2 -14
  27. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/update.rb +3 -30
  28. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/ledger_serializer.rb +35 -0
  29. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/create.rb +2 -39
  30. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/find.rb +2 -14
  31. data/lib/ledger_sync/adaptors/quickbooks_online/deposit/operations/update.rb +4 -43
  32. data/lib/ledger_sync/adaptors/quickbooks_online/deposit_line_item/ledger_serializer.rb +27 -0
  33. data/lib/ledger_sync/adaptors/quickbooks_online/expense/ledger_serializer.rb +48 -0
  34. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/create.rb +10 -51
  35. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/find.rb +10 -22
  36. data/lib/ledger_sync/adaptors/quickbooks_online/expense/operations/update.rb +10 -55
  37. data/lib/ledger_sync/adaptors/quickbooks_online/expense_line_item/ledger_serializer.rb +27 -0
  38. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/ledger_serializer.rb +32 -0
  39. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/create.rb +4 -37
  40. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/find.rb +4 -15
  41. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/operations/update.rb +5 -42
  42. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry_line_item/ledger_serializer.rb +31 -0
  43. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer.rb +103 -0
  44. data/lib/ledger_sync/adaptors/quickbooks_online/{account/mapping.rb → ledger_serializer_type/account_sub_type.rb} +128 -148
  45. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/account_type.rb +51 -0
  46. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/amount_type.rb +23 -0
  47. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/classification_type.rb +23 -0
  48. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/date_type.rb +23 -0
  49. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/journal_entry_line_item_type.rb +20 -0
  50. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/payment_type.rb +21 -0
  51. data/lib/ledger_sync/adaptors/quickbooks_online/operation.rb +2 -7
  52. data/lib/ledger_sync/adaptors/quickbooks_online/operation/create.rb +29 -0
  53. data/lib/ledger_sync/adaptors/quickbooks_online/operation/find.rb +31 -0
  54. data/lib/ledger_sync/adaptors/quickbooks_online/operation/full_update.rb +43 -0
  55. data/lib/ledger_sync/adaptors/quickbooks_online/operation/sparse_update.rb +29 -0
  56. data/lib/ledger_sync/adaptors/quickbooks_online/payment/ledger_serializer.rb +23 -0
  57. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/create.rb +1 -24
  58. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/find.rb +1 -13
  59. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/update.rb +2 -29
  60. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/ledger_serializer.rb +33 -0
  61. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/create.rb +1 -29
  62. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/find.rb +1 -13
  63. data/lib/ledger_sync/adaptors/quickbooks_online/transfer/operations/update.rb +4 -35
  64. data/lib/ledger_sync/adaptors/quickbooks_online/util/adaptor_error_parser.rb +2 -1
  65. data/lib/ledger_sync/adaptors/quickbooks_online/util/operation_error_parser.rb +2 -1
  66. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/ledger_serializer.rb +25 -0
  67. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/create.rb +1 -23
  68. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/find.rb +1 -13
  69. data/lib/ledger_sync/adaptors/quickbooks_online/vendor/operations/update.rb +2 -29
  70. data/lib/ledger_sync/adaptors/test/account/operations/create.rb +5 -1
  71. data/lib/ledger_sync/adaptors/test/account/operations/find.rb +5 -1
  72. data/lib/ledger_sync/adaptors/test/account/operations/invalid.rb +1 -0
  73. data/lib/ledger_sync/adaptors/test/account/operations/update.rb +8 -2
  74. data/lib/ledger_sync/adaptors/test/account/operations/valid.rb +1 -0
  75. data/lib/ledger_sync/adaptors/test/customer/operations/create.rb +5 -1
  76. data/lib/ledger_sync/adaptors/test/customer/operations/find.rb +5 -1
  77. data/lib/ledger_sync/adaptors/test/customer/operations/invalid.rb +1 -0
  78. data/lib/ledger_sync/adaptors/test/customer/operations/update.rb +1 -24
  79. data/lib/ledger_sync/adaptors/test/customer/operations/valid.rb +3 -6
  80. data/lib/ledger_sync/adaptors/test/expense/operations/create.rb +8 -3
  81. data/lib/ledger_sync/adaptors/test/expense/operations/find.rb +4 -14
  82. data/lib/ledger_sync/adaptors/test/expense/operations/update.rb +2 -32
  83. data/lib/ledger_sync/adaptors/test/ledger_serializer.rb +64 -0
  84. data/lib/ledger_sync/adaptors/test/operation/create.rb +27 -0
  85. data/lib/ledger_sync/adaptors/test/operation/find.rb +29 -0
  86. data/lib/ledger_sync/adaptors/test/operation/update.rb +34 -0
  87. data/lib/ledger_sync/adaptors/test/payment/operations/create.rb +5 -1
  88. data/lib/ledger_sync/adaptors/test/payment/operations/find.rb +5 -1
  89. data/lib/ledger_sync/adaptors/test/payment/operations/update.rb +1 -23
  90. data/lib/ledger_sync/adaptors/test/transfer/operations/create.rb +1 -22
  91. data/lib/ledger_sync/adaptors/test/transfer/operations/find.rb +1 -13
  92. data/lib/ledger_sync/adaptors/test/transfer/operations/update.rb +1 -25
  93. data/lib/ledger_sync/adaptors/test/vendor/operations/create.rb +5 -1
  94. data/lib/ledger_sync/adaptors/test/vendor/operations/find.rb +7 -1
  95. data/lib/ledger_sync/adaptors/test/vendor/operations/invalid.rb +1 -0
  96. data/lib/ledger_sync/adaptors/test/vendor/operations/update.rb +1 -23
  97. data/lib/ledger_sync/adaptors/test/vendor/operations/valid.rb +1 -0
  98. data/lib/ledger_sync/error/adaptor_errors.rb +17 -5
  99. data/lib/ledger_sync/error/operation_errors.rb +12 -5
  100. data/lib/ledger_sync/error/resource_errors.rb +5 -1
  101. data/lib/ledger_sync/resource.rb +33 -6
  102. data/lib/ledger_sync/resource_attribute.rb +4 -0
  103. data/lib/ledger_sync/resource_attribute/dirty_mixin.rb +16 -0
  104. data/lib/ledger_sync/resource_attribute/mixin.rb +19 -7
  105. data/lib/ledger_sync/resource_attribute/reference/many.rb +55 -1
  106. data/lib/ledger_sync/resource_attribute_set.rb +6 -7
  107. data/lib/ledger_sync/resources/account.rb +1 -1
  108. data/lib/ledger_sync/resources/bill.rb +1 -0
  109. data/lib/ledger_sync/resources/bill_line_item.rb +2 -0
  110. data/lib/ledger_sync/resources/expense.rb +5 -1
  111. data/lib/ledger_sync/resources/expense_line_item.rb +2 -0
  112. data/lib/ledger_sync/resources/journal_entry.rb +1 -0
  113. data/lib/ledger_sync/result.rb +4 -3
  114. data/lib/ledger_sync/type/id.rb +34 -0
  115. data/lib/ledger_sync/type/reference_many.rb +8 -2
  116. data/lib/ledger_sync/type/reference_one.rb +5 -0
  117. data/lib/ledger_sync/type/value_mixin.rb +12 -0
  118. data/lib/ledger_sync/util/hash_helpers.rb +16 -0
  119. data/lib/ledger_sync/version.rb +1 -1
  120. data/qa.rb +142 -0
  121. metadata +38 -5
  122. data/lib/ledger_sync/adaptors/quickbooks_online/expense/mapping.rb +0 -15
  123. data/lib/ledger_sync/adaptors/quickbooks_online/journal_entry/mapping.rb +0 -14
  124. data/lib/ledger_sync/error/sync_errors.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bf08ab386468485d8e81f3e40d43ca41664d69e4a09d1e70f658e047f82295d
4
- data.tar.gz: 69a554102281aae008333eeea328691bcc242417152e3fe6e2ddfca726a7cb7c
3
+ metadata.gz: 53419559e8cc29609542a442a100a9ecf8fe4dff040f4233631f4e13c688c893
4
+ data.tar.gz: 707b1bc26a777fb442cce8052a8facff59ce715ddaf5a09c8c626b5e7867d0c7
5
5
  SHA512:
6
- metadata.gz: ac04c1f2fc9fc9fb06443ad61a3f28e3ca102f1bd70d0c8c693549f2a9e75d83b4ad4fc10e5ed476b31038cd0190b6a077f9b3fefa02d629a15746a23e4e6647
7
- data.tar.gz: 7b282b14b77360effae62f6b3f4c36c3f067a0d29f5bd721686c80460784943304a42c01cae1336aaf0dd6fc7803f39e63868ea38fce900150385f3b43ff969c
6
+ metadata.gz: edf14189d54667014a36ab9959ae0ba60a980c80131ea1cf36507358da50151a7e0428cc785d72aba91d6dd7a4b81836f40d743fedf93efbb0c90b3b2f3eecc8
7
+ data.tar.gz: a8eb0c9a2d75b5a2177f480f3fe2dbe4410201fa59cab4d5abca51586612012271081242e5190f894caa9b218f5ee3e899c1fb42e171512bae949fd40c01a978
data/.gitignore CHANGED
@@ -11,5 +11,6 @@
11
11
  .rspec_status
12
12
 
13
13
  .byebug_history
14
+ .qa_config.yml
14
15
 
15
16
  .DS_Store
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ledger_sync (1.1.1)
4
+ ledger_sync (1.1.2)
5
5
  activemodel
6
6
  colorize
7
7
  coveralls
data/README.md CHANGED
@@ -189,7 +189,7 @@ puts LedgerSync::Payment.new(
189
189
  },
190
190
  external_id: "",
191
191
  ledger_id: nil,
192
- sync_token: nil
192
+
193
193
  }
194
194
  },
195
195
  "LedgerSync::Customer/b3eab7ec00431a4ae0468fee72e5ba8f": {
@@ -201,8 +201,7 @@ puts LedgerSync::Payment.new(
201
201
  email: nil,
202
202
  phone_number: nil,
203
203
  external_id: "",
204
- ledger_id: nil,
205
- sync_token: nil
204
+ ledger_id: nil
206
205
  }
207
206
  }
208
207
  }
@@ -85,9 +85,20 @@ module LedgerSync
85
85
  end
86
86
 
87
87
  def self.register_adaptor(adaptor_key)
88
+ adaptor_root_path = "ledger_sync/adaptors/#{adaptor_key}"
89
+ require "#{adaptor_root_path}/adaptor"
88
90
  self.adaptors ||= LedgerSync::AdaptorConfigurationStore.new
89
91
  self.adaptors.register_adaptor(adaptor_key)
92
+
90
93
  yield(adaptors.send(adaptor_key))
94
+
95
+ adaptor_files = Gem.find_files("#{adaptor_root_path}/**/*.rb")
96
+ # Sort the files to include BFS-style as most dependencies are in parent folders
97
+ adaptor_files.sort { |a, b| a.count('/') <=> b.count('/') }.each do |path|
98
+ next if path.include?('config.rb')
99
+
100
+ require path
101
+ end
91
102
  end
92
103
 
93
104
  def self.register_resource(resource:)
@@ -105,12 +116,7 @@ end
105
116
  # Adaptors
106
117
  require 'ledger_sync/adaptors/adaptor'
107
118
  require 'ledger_sync/adaptors/searcher'
108
- Gem.find_files('ledger_sync/adaptors/**/*.rb').each do |path|
109
- next if path.include?('config.rb')
110
-
111
- require path
112
- end
113
-
119
+ require 'ledger_sync/adaptors/ledger_serializer'
114
120
  Gem.find_files('ledger_sync/adaptors/**/config.rb').each { |path| require path }
115
121
 
116
122
  # Register Resources
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ledger_serializer_type/value_type'
4
+ require_relative 'ledger_serializer_attribute'
5
+ require_relative 'ledger_serializer_attribute_set'
6
+ Gem.find_files('ledger_sync/adaptors/ledger_serializer_type/**/*.rb').each { |path| require path }
7
+
8
+ module LedgerSync
9
+ module Adaptors
10
+ class LedgerSerializer
11
+ attr_reader :resource
12
+
13
+ def initialize(resource:)
14
+ @resource = resource
15
+ ensure_inferred_resource_class!
16
+ end
17
+
18
+ def attribute_value_from_ledger(hash:, ledger_serializer_attribute:, resource:)
19
+ ledger_serializer_attribute.value_from_ledger(
20
+ hash: hash,
21
+ resource: resource
22
+ )
23
+ end
24
+
25
+ def deserialize(hash:)
26
+ deserialize_into = resource.dup # Do not overwrite values in the resource
27
+ hash = Util::HashHelpers.deep_stringify_keys(hash)
28
+
29
+ self.class.attributes.each do |ledger_serializer_attribute|
30
+ next unless ledger_serializer_attribute.resource_attribute?
31
+
32
+ value = attribute_value_from_ledger(
33
+ hash: hash,
34
+ ledger_serializer_attribute: ledger_serializer_attribute,
35
+ resource: deserialize_into
36
+ )
37
+
38
+ deserialize_into.assign_attribute(
39
+ ledger_serializer_attribute.resource_attribute_dot_parts.first,
40
+ value
41
+ )
42
+ end
43
+
44
+ deserialize_into
45
+ end
46
+
47
+ def to_ledger_hash(only_changes: false)
48
+ ret = {}
49
+
50
+ self.class.attributes.each do |ledger_serializer_attribute|
51
+ next if only_changes && !resource.attribute_changed?(ledger_serializer_attribute.resource_attribute)
52
+
53
+ ret = Util::HashHelpers.deep_merge(
54
+ hash_to_merge_into: ret,
55
+ other_hash: ledger_serializer_attribute.ledger_attribute_hash_for(resource: resource)
56
+ )
57
+ end
58
+
59
+ ret
60
+ end
61
+
62
+ def self.attribute(ledger_attribute:, resource_attribute: nil, type: LedgerSerializerType::ValueType, &block)
63
+ _attribute(
64
+ block: (block if block_given?),
65
+ ledger_attribute: ledger_attribute,
66
+ resource_attribute: resource_attribute,
67
+ type: type
68
+ )
69
+ end
70
+
71
+ def self.attributes
72
+ @attributes ||= LedgerSerializerAttributeSet.new(serializer_class: self)
73
+ end
74
+
75
+ def self.references_many(ledger_attribute:, resource_attribute:, serializer:)
76
+ _attribute(
77
+ ledger_attribute: ledger_attribute,
78
+ resource_attribute: resource_attribute,
79
+ serializer: serializer,
80
+ type: LedgerSerializerType::ReferencesManyType
81
+ )
82
+ end
83
+
84
+ def self.id(ledger_attribute:, resource_attribute:, &block)
85
+ @id ||= _attribute(
86
+ block: (block if block_given?),
87
+ id: true,
88
+ ledger_attribute: ledger_attribute,
89
+ resource_attribute: resource_attribute
90
+ )
91
+ end
92
+
93
+ def self._inferred_resource_class
94
+ parts = name.split('::')
95
+ LedgerSync.const_get(parts[parts.index('Adaptors') + 2])
96
+ end
97
+
98
+ private_class_method def self._attribute(**keywords)
99
+ attributes.add(
100
+ _build_attribute(**keywords)
101
+ )
102
+ end
103
+
104
+ private_class_method def self._build_attribute(block: nil, id: false, ledger_attribute:, resource_attribute: nil, resource_class: nil, serializer: nil, type: LedgerSerializerType::ValueType)
105
+ LedgerSerializerAttribute.new(
106
+ id: id,
107
+ block: block,
108
+ ledger_attribute: ledger_attribute,
109
+ resource_attribute: resource_attribute,
110
+ resource_class: resource_class,
111
+ serializer: serializer,
112
+ type: type
113
+ )
114
+ end
115
+
116
+ private
117
+
118
+ def ensure_inferred_resource_class!
119
+ inferred_resource_class = self.class._inferred_resource_class
120
+ raise "Resource must be a #{inferred_resource_class.name}. Given #{resource.class}" unless resource.is_a?(inferred_resource_class)
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ledger_serializer_type/value_type'
4
+ Gem.find_files('ledger_sync/adaptors/ledger_serializer_type/**/*.rb').each { |path| require path }
5
+
6
+ module LedgerSync
7
+ module Adaptors
8
+ class LedgerSerializerAttribute
9
+ attr_reader :block,
10
+ :id,
11
+ :ledger_attribute,
12
+ :resource_attribute,
13
+ :resource_class,
14
+ :serializer,
15
+ :type
16
+
17
+ def initialize(block: nil, id: false, ledger_attribute:, resource_attribute: nil, resource_class: nil, serializer: nil, type: LedgerSerializerType::ValueType)
18
+ raise 'block and resource_attribute cannot both be present' unless block.nil? || resource_attribute.nil?
19
+
20
+ @block = block
21
+ @id = id
22
+ @ledger_attribute = ledger_attribute.to_s
23
+ @resource_attribute = resource_attribute.to_s
24
+ @resource_class = resource_class
25
+ @serializer = serializer
26
+ @type = type.new
27
+ end
28
+
29
+ def block_value_for(resource:)
30
+ block.call(resource)
31
+ end
32
+
33
+ # Make nested/dot calls (e.g. `vendor.ledger_id`)
34
+ def dot_value_for(resource:)
35
+ resource_attribute_dot_parts.inject(resource) { |r, dot_method| r&.send(dot_method) }
36
+ end
37
+
38
+ def ledger_attribute_dot_parts
39
+ @ledger_attribute_dot_parts ||= ledger_attribute.split('.')
40
+ end
41
+
42
+ def ledger_attribute_hash_for(resource:)
43
+ ledger_attribute_hash_with(value: value_from_local(resource: resource))
44
+ end
45
+
46
+ # Create nested hash for ledger
47
+ #
48
+ # when ledger_attribute = 'Foo.Bar.Baz',
49
+ # ledger_attribute_hash_with(value: 123)
50
+ # Result:
51
+ # {
52
+ # 'Foo' => {
53
+ # 'Bar' => {
54
+ # 'Baz' => 123
55
+ # }
56
+ # }
57
+ # }
58
+ def ledger_attribute_hash_with(value:)
59
+ ledger_attribute_dot_parts.reverse.inject(value) { |a, n| { n => a } }
60
+ end
61
+
62
+ def references_many?
63
+ type.is_a?(LedgerSerializerType::ReferencesManyType)
64
+ end
65
+
66
+ def resource_attribute?
67
+ resource_attribute.present?
68
+ end
69
+
70
+ def resource_attribute_dot_parts
71
+ @resource_attribute_dot_parts ||= resource_attribute.split('.')
72
+ end
73
+
74
+ def value_from_local(resource:)
75
+ value = if block.nil?
76
+ dot_value_for(resource: resource)
77
+ else
78
+ block_value_for(resource: resource)
79
+ end
80
+
81
+ if references_many?
82
+ type.convert_from_local(
83
+ serializer: serializer,
84
+ value: value
85
+ )
86
+ else
87
+ type.convert_from_local(
88
+ value: value
89
+ )
90
+ end
91
+ end
92
+
93
+ def value_from_ledger(hash:, resource:)
94
+ value = hash.dig(*ledger_attribute_dot_parts)
95
+
96
+ value = if references_many?
97
+ type.convert_from_ledger(
98
+ resource_class: resource_class,
99
+ serializer: serializer,
100
+ value: value
101
+ )
102
+ else
103
+ type.convert_from_ledger(
104
+ value: value
105
+ )
106
+ end
107
+
108
+ return value if resource_attribute_dot_parts.count <= 1
109
+
110
+ nested_resource = resource.send(resource_attribute_dot_parts.first)
111
+ nested_resource ||= resource_attribute_class(resource: resource).new
112
+
113
+ build_resource_value_from_nested_attributes(
114
+ nested_resource,
115
+ value,
116
+ resource_attribute_dot_parts[1..-1]
117
+ )
118
+ end
119
+
120
+ private
121
+
122
+ def build_resource_value_from_nested_attributes(resource, value, attribute_parts)
123
+ resource = resource.dup
124
+ first_attribute, *remaining_attributes = attribute_parts
125
+
126
+ if remaining_attributes.count.zero?
127
+ resource.public_send("#{first_attribute}=", value)
128
+ else
129
+ resource.public_send(
130
+ "#{first_attribute}=",
131
+ build_resource_value_from_nested_attributes(
132
+ resource.public_send(first_attribute) || resource.class.resource_attributes[first_attribute.to_sym].type.resource_class.new,
133
+ value,
134
+ remaining_attributes
135
+ )
136
+ )
137
+ end
138
+
139
+ resource
140
+ end
141
+
142
+ def resource_attribute_class(resource:)
143
+ @resource_attribute_type ||= {}
144
+ @resource_attribute_type[resource] ||= resource.class.resource_attributes[resource_attribute_dot_parts.first.to_sym].type.resource_class
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ class LedgerSerializerAttributeSet
6
+ attr_reader :attributes,
7
+ :id_attribute,
8
+ :ledger_attribute_keyed_hash,
9
+ :resource_attribute_keyed_hash,
10
+ :serializer_class
11
+
12
+ delegate :[],
13
+ :each,
14
+ :include?,
15
+ :map,
16
+ to: :attributes
17
+
18
+ def initialize(serializer_class:)
19
+ @attributes = []
20
+ @ledger_attribute_keyed_hash = {}
21
+ @resource_attribute_keyed_hash = {}
22
+ @serializer_class = serializer_class
23
+ end
24
+
25
+ def add(attribute)
26
+ @attributes << attribute
27
+ @id_attribute = attribute if attribute.id
28
+ if attribute.ledger_attribute.present?
29
+ raise "ledger_attribute already defined for #{serializer_class.name}: #{attribute.ledger_attribute}" if ledger_attribute_keyed_hash.key?(attribute.ledger_attribute.to_s)
30
+
31
+ ledger_attribute_keyed_hash[attribute.ledger_attribute.to_s] = attribute
32
+ end
33
+
34
+ if attribute.resource_attribute.present?
35
+ raise "resource_attribute already defined for #{serializer_class.name}: #{attribute.resource_attribute}" if resource_attribute_keyed_hash.key?(attribute.resource_attribute.to_s)
36
+
37
+ resource_attribute_keyed_hash[attribute.resource_attribute.to_s] = attribute
38
+ end
39
+
40
+ # TODO: Can make this validate something like `expense.vendor.id`
41
+ # raise "#{resource_attribute} is not an attribute of the resource #{_inferred_resource_class}" if !resource_attribute.nil? && !_inferred_resource_class.serialize_attribute?(resource_attribute)
42
+
43
+ attribute
44
+ end
45
+
46
+ def ledger_attribute?(key)
47
+ ledger_attribute_keyed_hash.include?(key.to_s)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module LedgerSerializerType
6
+ class MappingType < ValueType
7
+ attr_reader :source, :value
8
+
9
+ def self.mapping
10
+ @mapping ||= begin
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+
15
+ def convert_from_ledger(value:)
16
+ return if value.nil?
17
+ raise "Ledger to local mapping not found: #{value}" unless reverse_mapping_hash.key?(value)
18
+
19
+ reverse_mapping_hash[value]
20
+ end
21
+
22
+ def convert_from_local(value:)
23
+ return if value.nil?
24
+ raise "Local to ledger mapping not found: #{value}" unless mapping_hash.key?(value)
25
+
26
+ mapping_hash[value]
27
+ end
28
+
29
+ private
30
+
31
+ def mapping_hash
32
+ @mapping_hash ||= self.class.mapping
33
+ end
34
+
35
+ def reverse_mapping_hash
36
+ @reverse_mapping_hash ||= mapping_hash.to_a.map(&:reverse).to_h
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end