ledger_sync 1.3.4 → 1.3.5

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +14 -1
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +3 -2
  5. data/Dockerfile +2 -2
  6. data/Gemfile.lock +11 -11
  7. data/LICENSE.txt +97 -21
  8. data/README.md +28 -11
  9. data/bin/quickbooks_online_oauth_server.rb +101 -0
  10. data/lib/ledger_sync.rb +8 -0
  11. data/lib/ledger_sync/adaptor_configuration.rb +4 -4
  12. data/lib/ledger_sync/adaptor_configuration_store.rb +4 -4
  13. data/lib/ledger_sync/adaptors/adaptor.rb +4 -6
  14. data/lib/ledger_sync/adaptors/dashboard_url_helper.rb +23 -0
  15. data/lib/ledger_sync/adaptors/ledger_serializer_attribute_set.rb +3 -5
  16. data/lib/ledger_sync/adaptors/mixins/infer_ledger_serializer_mixin.rb +16 -0
  17. data/lib/ledger_sync/adaptors/netsuite/account/searcher_ledger_deserializer.rb +30 -0
  18. data/lib/ledger_sync/adaptors/netsuite/adaptor.rb +11 -3
  19. data/lib/ledger_sync/adaptors/netsuite/customer/searcher.rb +12 -0
  20. data/lib/ledger_sync/adaptors/netsuite/customer/searcher_ledger_deserializer.rb +23 -0
  21. data/lib/ledger_sync/adaptors/netsuite/dashboard_url_helper.rb +24 -0
  22. data/lib/ledger_sync/adaptors/netsuite/department/searcher_ledger_deserializer.rb +21 -0
  23. data/lib/ledger_sync/adaptors/netsuite/ledger_serializer_type/active_type.rb +26 -0
  24. data/lib/ledger_sync/adaptors/netsuite/location/ledger_serializer.rb +18 -0
  25. data/lib/ledger_sync/adaptors/netsuite/location/operations/create.rb +21 -0
  26. data/lib/ledger_sync/adaptors/netsuite/location/operations/delete.rb +21 -0
  27. data/lib/ledger_sync/adaptors/netsuite/location/operations/find.rb +21 -0
  28. data/lib/ledger_sync/adaptors/netsuite/location/operations/update.rb +21 -0
  29. data/lib/ledger_sync/adaptors/netsuite/location/searcher.rb +12 -0
  30. data/lib/ledger_sync/adaptors/netsuite/record/http_method.rb +1 -1
  31. data/lib/ledger_sync/adaptors/netsuite/record/metadata.rb +11 -7
  32. data/lib/ledger_sync/adaptors/netsuite/searcher.rb +30 -8
  33. data/lib/ledger_sync/adaptors/netsuite/vendor/searcher.rb +12 -0
  34. data/lib/ledger_sync/adaptors/netsuite/vendor/searcher_ledger_deserializer.rb +23 -0
  35. data/lib/ledger_sync/adaptors/operation.rb +7 -3
  36. data/lib/ledger_sync/adaptors/quickbooks_online/adaptor.rb +7 -2
  37. data/lib/ledger_sync/adaptors/quickbooks_online/dashboard_url_helper.rb +1 -26
  38. data/lib/ledger_sync/adaptors/quickbooks_online/department/ledger_serializer.rb +6 -3
  39. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer.rb +1 -1
  40. data/lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/department_reference_type.rb +26 -0
  41. data/lib/ledger_sync/adaptors/quickbooks_online/operation/full_update.rb +0 -1
  42. data/lib/ledger_sync/adaptors/quickbooks_online/util/adaptor_error_parser.rb +5 -5
  43. data/lib/ledger_sync/adaptors/quickbooks_online/util/error_matcher.rb +1 -1
  44. data/lib/ledger_sync/adaptors/quickbooks_online/util/error_parser.rb +1 -1
  45. data/lib/ledger_sync/adaptors/quickbooks_online/util/operation_error_parser.rb +5 -5
  46. data/lib/ledger_sync/adaptors/stripe/adaptor.rb +4 -12
  47. data/lib/ledger_sync/adaptors/stripe/dashboard_url_helper.rb +21 -0
  48. data/lib/ledger_sync/deserializer.rb +59 -0
  49. data/lib/ledger_sync/error/adaptor_errors.rb +2 -2
  50. data/lib/ledger_sync/error/resource_errors.rb +18 -19
  51. data/lib/ledger_sync/resource.rb +9 -8
  52. data/lib/ledger_sync/resource_attribute.rb +30 -7
  53. data/lib/ledger_sync/resource_attribute/mixin.rb +13 -23
  54. data/lib/ledger_sync/resource_attribute/reference/many.rb +11 -5
  55. data/lib/ledger_sync/resource_attribute/reference/one.rb +10 -4
  56. data/lib/ledger_sync/resource_attribute_set.rb +3 -7
  57. data/lib/ledger_sync/resources/location.rb +7 -0
  58. data/lib/ledger_sync/serialization/attribute.rb +47 -0
  59. data/lib/ledger_sync/serialization/attribute_set_mixin.rb +27 -0
  60. data/lib/ledger_sync/serialization/deserializer_attribute.rb +60 -0
  61. data/lib/ledger_sync/serialization/deserializer_attribute_set.rb +22 -0
  62. data/lib/ledger_sync/serialization/deserializer_delegator.rb +17 -0
  63. data/lib/ledger_sync/serialization/mixin.rb +72 -0
  64. data/lib/ledger_sync/serialization/serializer_attribute.rb +51 -0
  65. data/lib/ledger_sync/serialization/serializer_attribute_set.rb +22 -0
  66. data/lib/ledger_sync/serialization/serializer_delegator.rb +17 -0
  67. data/lib/ledger_sync/serialization/type/references_many_type.rb +19 -0
  68. data/lib/ledger_sync/serialization/type/references_one_type.rb +12 -0
  69. data/lib/ledger_sync/serialization/type/serializer_type.rb +23 -0
  70. data/lib/ledger_sync/serialization/type/value_type.rb +15 -0
  71. data/lib/ledger_sync/serializer.rb +46 -0
  72. data/lib/ledger_sync/type/date.rb +2 -0
  73. data/lib/ledger_sync/type/id.rb +2 -0
  74. data/lib/ledger_sync/type/reference_one.rb +8 -4
  75. data/lib/ledger_sync/type/value_mixin.rb +2 -2
  76. data/lib/ledger_sync/util/mixins/delegate_iterable_methods_mixin.rb +42 -0
  77. data/lib/ledger_sync/util/mixins/dupable_mixin.rb +13 -0
  78. data/lib/ledger_sync/version.rb +1 -1
  79. metadata +39 -3
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module Stripe
6
+ class DashboardURLHelper < LedgerSync::Adaptors::DashboardURLHelper
7
+ def resource_path
8
+ @resource_path = case resource
9
+ when LedgerSync::Customer
10
+ "/customers/#{resource.ledger_id}"
11
+ else
12
+ raise Error::AdaptorError::UnknownURLFormat.new(
13
+ adaptor: self,
14
+ resource: resource
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'serialization/mixin'
4
+ require_relative 'serialization/deserializer_attribute_set'
5
+ require_relative 'serialization/deserializer_attribute'
6
+
7
+ module LedgerSync
8
+ class Deserializer
9
+ include Serialization::Mixin
10
+
11
+ def attribute_value_from_ledger(hash:, ledger_serializer_attribute:, resource:)
12
+ ledger_serializer_attribute.value_from_hash(
13
+ hash: hash,
14
+ resource: resource
15
+ )
16
+ end
17
+
18
+ def deserialize(args = {})
19
+ hash = args.fetch(:hash)
20
+ resource = args.fetch(:resource)
21
+
22
+ deserialize_into = resource.dup # Do not overwrite values in the resource
23
+ hash = Util::HashHelpers.deep_stringify_keys(hash)
24
+
25
+ self.class.attributes.each_value do |ledger_serializer_attribute|
26
+ value = attribute_value_from_ledger(
27
+ hash: hash,
28
+ ledger_serializer_attribute: ledger_serializer_attribute,
29
+ resource: deserialize_into
30
+ )
31
+
32
+ deserialize_into.assign_attribute(
33
+ ledger_serializer_attribute.resource_attribute_dot_parts.first,
34
+ value
35
+ )
36
+ end
37
+
38
+ deserialize_into
39
+ end
40
+
41
+ def self.attribute(resource_attribute, args = {}, &block)
42
+ _attribute(
43
+ args.merge(
44
+ block: (block if block_given?),
45
+ resource_attribute: resource_attribute
46
+ )
47
+ )
48
+ end
49
+
50
+ def self.attribute_class
51
+ Serialization::DeserializerAttribute
52
+ end
53
+
54
+ def self.attributes
55
+ @attributes ||= Serialization::DeserializerAttributeSet.new(serializer_class: self)
56
+ end
57
+ end
58
+ end
59
+
@@ -43,8 +43,8 @@ module LedgerSync
43
43
 
44
44
  def initialize(adaptor:, message: nil, response: nil)
45
45
  message ||= 'Your request has been throttled.'
46
- @rate_limiting_wait_in_seconds = LedgerSync.adaptors.config_from_klass(
47
- klass: adaptor.class
46
+ @rate_limiting_wait_in_seconds = LedgerSync.adaptors.config_from_class(
47
+ adaptor_class: adaptor.class
48
48
  ).rate_limiting_wait_in_seconds
49
49
 
50
50
  super(
@@ -1,4 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LedgerSync
4
+ class ResourceAttributeError < Error
5
+ class TypeError < self
6
+ attr_reader :attribute, :resource_class, :value
7
+
8
+ def initialize(args = {})
9
+ @attribute = args.fetch(:attribute)
10
+ @resource_class = args.fetch(:resource_class)
11
+ @value = args.fetch(:value)
12
+
13
+ message = attribute.type.error_message(args)
14
+
15
+ super(message: message)
16
+ end
17
+ end
18
+ end
19
+
2
20
  class ResourceError < Error
3
21
  attr_reader :resource
4
22
 
@@ -6,25 +24,6 @@ module LedgerSync
6
24
  @resource = resource
7
25
  super(message: message)
8
26
  end
9
- class AttributeTypeError < self
10
- attr_reader :attribute, :resource, :value
11
-
12
- def initialize(attribute:, resource:, value:)
13
- @attribute = attribute
14
- @resource = resource
15
- @value = value
16
-
17
- resource_class = resource.class
18
-
19
- message = attribute.type.error_message(
20
- attribute: attribute,
21
- resource: resource,
22
- value: value
23
- )
24
-
25
- super(message: message, resource: nil)
26
- end
27
- end
28
27
 
29
28
  class ReferenceAssignmentError < self
30
29
  def initialize(attribute:, resource:, value:)
@@ -12,6 +12,7 @@ module LedgerSync
12
12
  include ResourceAttribute::Mixin
13
13
  include ResourceAttribute::Reference::One::Mixin
14
14
  include ResourceAttribute::Reference::Many::Mixin
15
+ include Util::Mixins::DupableMixin
15
16
 
16
17
  PRIMITIVES = [
17
18
  ActiveModel::Type,
@@ -28,6 +29,9 @@ module LedgerSync
28
29
 
29
30
  serialize except: %i[resource_attributes references]
30
31
 
32
+ attribute :external_id, type: Type::ID
33
+ attribute :ledger_id, type: Type::ID
34
+
31
35
  def assign_attribute(name, value)
32
36
  public_send("#{name}=", value)
33
37
  self
@@ -46,11 +50,7 @@ module LedgerSync
46
50
  super.merge(Hash[resource_attributes.references_many.map { |ref| [ref.name, ref.changes['value']] if ref.changed? }.compact])
47
51
  end
48
52
 
49
- def dup
50
- Marshal.load(Marshal.dump(self))
51
- end
52
-
53
- def klass_from_resource_type(obj)
53
+ def class_from_resource_type(obj)
54
54
  LedgerSync.const_get(LedgerSync::Util::StringHelpers.camelcase(obj))
55
55
  end
56
56
 
@@ -59,8 +59,9 @@ module LedgerSync
59
59
  end
60
60
 
61
61
  def self.inherited(subclass)
62
- subclass.attribute :external_id, type: Type::ID
63
- subclass.attribute :ledger_id, type: Type::ID
62
+ resource_attributes.each do |_name, resource_attribute|
63
+ subclass._add_resource_attribute(resource_attribute)
64
+ end
64
65
  end
65
66
 
66
67
  def self.resource_module_str
@@ -79,7 +80,7 @@ module LedgerSync
79
80
  end
80
81
 
81
82
  def ==(other)
82
- other.fingerprint == fingerprint
83
+ other&.fingerprint == fingerprint
83
84
  end
84
85
  end
85
86
  end
@@ -14,22 +14,35 @@ module LedgerSync
14
14
  class ResourceAttribute
15
15
  include Fingerprintable::Mixin
16
16
  include SimplySerializable::Mixin
17
+ include Util::Mixins::DupableMixin
17
18
 
18
- attr_accessor :value
19
19
  attr_reader :name,
20
20
  :reference,
21
- :type
21
+ :resource_class,
22
+ :type,
23
+ :value
22
24
 
23
- def initialize(name:, type:, value: nil)
24
- @name = name.to_sym
25
+ def initialize(args = {})
26
+ @name = args.fetch(:name).to_sym
27
+ @resource_class = args.fetch(:resource_class)
28
+ @type = args.fetch(:type)
29
+ @value = args.fetch(:value, nil)
25
30
 
26
- type = type.new if type.respond_to?(:new) && !type.is_a?(Type::Value)
31
+ @type = type.new if type.respond_to?(:new) && !type.is_a?(Type::Value)
27
32
 
28
33
  raise "Invalid Type: #{type}" unless type.is_a?(ActiveModel::Type::Value)
34
+ end
35
+
36
+ def assert_valid(args = {})
37
+ value = args.fetch(:value)
29
38
 
30
- @type = type
39
+ return if valid_with?(value: value)
31
40
 
32
- @value = value
41
+ raise ResourceAttributeError::TypeError.new(
42
+ attribute: self,
43
+ resource_class: resource_class,
44
+ value: value
45
+ )
33
46
  end
34
47
 
35
48
  def cast(value)
@@ -50,5 +63,15 @@ module LedgerSync
50
63
  def valid_with?(value:)
51
64
  type.valid_without_casting?(value: value)
52
65
  end
66
+
67
+ def value=(val)
68
+ assert_valid(value: val)
69
+ @value = type.cast(val)
70
+ end
71
+
72
+ def will_change?(val)
73
+ assert_valid(value: val)
74
+ value != type.cast(val)
75
+ end
53
76
  end
54
77
  end
@@ -13,6 +13,15 @@ module LedgerSync
13
13
  end
14
14
 
15
15
  module ClassMethods
16
+ def _add_resource_attribute(resource_attribute)
17
+ _define_attribute_methods(resource_attribute.name)
18
+
19
+ resource_attributes.add(resource_attribute)
20
+ references_many_resource_attributes << resource_attribute if resource_attribute.type.is_a?(Reference::Many)
21
+
22
+ resource_attribute
23
+ end
24
+
16
25
  def _define_attribute_methods(name)
17
26
  class_eval do
18
27
  define_attribute_methods name
@@ -21,22 +30,10 @@ module LedgerSync
21
30
  resource_attributes[name].value
22
31
  end
23
32
 
24
- define_method "_#{name}_valid_with_value?" do |val|
25
- unless resource_attributes[name].valid_with?(value: val)
26
- raise ResourceError::AttributeTypeError.new(
27
- attribute: resource_attributes[name],
28
- resource: self,
29
- value: val
30
- )
31
- end
32
- end
33
-
34
33
  define_method "#{name}=" do |val|
35
- attribute = resource_attributes[name]
36
- public_send("_#{name}_valid_with_value?", val)
37
- val = attribute.type.cast(val) if attribute.type.cast?
38
- public_send("#{name}_will_change!") unless val == resource_attributes[name] # For Dirty
39
- attribute.value = val
34
+ resource_attribute = resource_attributes[name]
35
+ public_send("#{name}_will_change!") if resource_attribute.will_change?(val) # For Dirty
36
+ resource_attribute.value = val
40
37
  end
41
38
 
42
39
  serialize attributes: [name]
@@ -44,14 +41,7 @@ module LedgerSync
44
41
  end
45
42
 
46
43
  def attribute(name, type:)
47
- resource_attribute = ResourceAttribute.new(name: name, type: type)
48
-
49
- _define_attribute_methods(name)
50
-
51
- resource_attributes.add(resource_attribute)
52
- references_many_resource_attributes << resource_attribute if resource_attribute.type.is_a?(Reference::Many)
53
-
54
- resource_attribute
44
+ _add_resource_attribute(ResourceAttribute.new(name: name, resource_class: self, type: type))
55
45
  end
56
46
 
57
47
  def references_many_resource_attributes
@@ -56,18 +56,24 @@ module LedgerSync
56
56
 
57
57
  module ClassMethods
58
58
  def references_many(name, to:)
59
- resource_attribute = ResourceAttribute::Reference::Many.new(name: name, to: to)
59
+ resource_attribute = ResourceAttribute::Reference::Many.new(
60
+ name: name,
61
+ resource_class: self,
62
+ to: to
63
+ )
60
64
  resource_attributes.add resource_attribute
61
65
  _define_attribute_methods(name)
62
66
  end
63
67
  end
64
68
  end
65
69
 
66
- def initialize(name:, to:)
70
+ def initialize(args = {})
71
+ to = args.fetch(:to)
67
72
  super(
68
- name: name,
69
- type: Type::ReferenceMany.new(resource_class: to),
70
- value: ManyArray.new
73
+ args.except(:to).merge(
74
+ type: Type::ReferenceMany.new(resource_class: to),
75
+ value: ManyArray.new
76
+ )
71
77
  )
72
78
  end
73
79
 
@@ -14,17 +14,23 @@ module LedgerSync
14
14
 
15
15
  module ClassMethods
16
16
  def references_one(name, to:)
17
- resource_attribute = ResourceAttribute::Reference::One.new(name: name, to: to)
17
+ resource_attribute = ResourceAttribute::Reference::One.new(
18
+ name: name,
19
+ resource_class: self,
20
+ to: to
21
+ )
18
22
  resource_attributes.add resource_attribute
19
23
  _define_attribute_methods(name)
20
24
  end
21
25
  end
22
26
  end
23
27
 
24
- def initialize(name:, to:)
28
+ def initialize(args = {})
29
+ to = args.fetch(:to)
25
30
  super(
26
- name: name,
27
- type: Type::ReferenceOne.new(resource_class: to)
31
+ args.except(:to).merge(
32
+ type: Type::ReferenceOne.new(resource_class: to)
33
+ )
28
34
  )
29
35
  end
30
36
  end
@@ -2,19 +2,15 @@
2
2
 
3
3
  module LedgerSync
4
4
  class ResourceAttributeSet
5
+ include Util::Mixins::DelegateIterableMethodsMixin
6
+
5
7
  attr_reader :attributes,
6
8
  :references,
7
9
  :references_one,
8
10
  :references_many,
9
11
  :resource
10
12
 
11
- delegate :[],
12
- :each,
13
- :include?,
14
- :key?,
15
- :keys,
16
- :map,
17
- to: :attributes
13
+ delegate_hash_methods_to :attributes
18
14
 
19
15
  alias names keys
20
16
 
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ class Location < LedgerSync::Resource
5
+ attribute :name, type: Type::String
6
+ end
7
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem.find_files('ledger_sync/serialization/type/**/*.rb').each { |path| require path }
4
+
5
+ module LedgerSync
6
+ class Serialization
7
+ class Attribute
8
+ attr_reader :block,
9
+ :hash_attribute,
10
+ :resource_attribute,
11
+ :resource_class,
12
+ :type
13
+
14
+ def initialize(args = {})
15
+ @block = args.fetch(:block, nil)
16
+ @hash_attribute = args.fetch(:hash_attribute, nil).try(:to_s)
17
+ @resource_attribute = args.fetch(:resource_attribute, nil).try(:to_s)
18
+ @resource_class = args.fetch(:resource_class, nil)
19
+ @type = args.fetch(:type, nil) || Type::ValueType.new
20
+ end
21
+
22
+ def block_value_for(args = {})
23
+ block.call(args.merge(attribute: self))
24
+ end
25
+
26
+ def hash_attribute_dot_parts
27
+ @hash_attribute_dot_parts ||= hash_attribute.split('.')
28
+ end
29
+
30
+ def reference?
31
+ references_many? || references_one?
32
+ end
33
+
34
+ def references_many?
35
+ type.is_a?(Type::ReferencesManyType)
36
+ end
37
+
38
+ def references_one?
39
+ type.is_a?(Type::ReferencesOneType)
40
+ end
41
+
42
+ def resource_attribute_dot_parts
43
+ @resource_attribute_dot_parts ||= resource_attribute.split('.')
44
+ end
45
+ end
46
+ end
47
+ end