ledger_sync 1.1.1 → 1.1.2

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