ledger_sync 1.1.2 → 1.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53419559e8cc29609542a442a100a9ecf8fe4dff040f4233631f4e13c688c893
4
- data.tar.gz: 707b1bc26a777fb442cce8052a8facff59ce715ddaf5a09c8c626b5e7867d0c7
3
+ metadata.gz: 0e39d8dc0e6f3df94374cb5200d7062213327b06f470111c9d3baf4fe7407e76
4
+ data.tar.gz: 206ccec75be3d425dbaf6b3567af57536cab77851e8c815c31ee1642b81cb0ef
5
5
  SHA512:
6
- metadata.gz: edf14189d54667014a36ab9959ae0ba60a980c80131ea1cf36507358da50151a7e0428cc785d72aba91d6dd7a4b81836f40d743fedf93efbb0c90b3b2f3eecc8
7
- data.tar.gz: a8eb0c9a2d75b5a2177f480f3fe2dbe4410201fa59cab4d5abca51586612012271081242e5190f894caa9b218f5ee3e899c1fb42e171512bae949fd40c01a978
6
+ metadata.gz: 1024346df20614497f7db8e000bacd9440efb24084e2675769295ef69dc2d1d6c1770d8c5f25258ad05ba1b7bdb6d9ae23440c8d56787c3980c572e65a2af52a
7
+ data.tar.gz: b5571c6836c32ade58704aae76ac4b1577c5f457240c5ce2ef121a27b9424eb46619366fe09650c4a6953e44d6dd5b9df1eba4e42d8d313e72b17433e26075cd
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ledger_sync (1.1.2)
4
+ ledger_sync (1.1.3)
5
5
  activemodel
6
6
  colorize
7
7
  coveralls
@@ -108,7 +108,7 @@ module LedgerSync
108
108
  end
109
109
 
110
110
  def url_for(resource:)
111
- base_url = test ? 'https://app.sandbox.qbo.intuit.com/app' : 'https://app.qbo.intuit.com/app'
111
+ base_url = test ? 'https://app.sandbox.qbo.intuit.com/app' : 'https://qbo.intuit.com/app'
112
112
  resource_path = case resource
113
113
  when LedgerSync::Account
114
114
  "/register?accountId=#{resource.ledger_id}"
@@ -14,6 +14,10 @@ module LedgerSync
14
14
  attribute ledger_attribute: 'DepositLineDetail.AccountRef.value',
15
15
  resource_attribute: 'account.ledger_id'
16
16
 
17
+ attribute ledger_attribute: 'DepositLineDetail.Entity',
18
+ resource_attribute: :entity,
19
+ type: LedgerSerializerType::EntityReferenceType
20
+
17
21
  attribute ledger_attribute: 'Amount',
18
22
  resource_attribute: :amount,
19
23
  type: LedgerSerializerType::AmountType
@@ -29,8 +29,9 @@ module LedgerSync
29
29
  attribute ledger_attribute: 'ExchangeRate',
30
30
  resource_attribute: :exchange_rate
31
31
 
32
- attribute ledger_attribute: 'EntityRef.value',
33
- resource_attribute: 'vendor.ledger_id'
32
+ attribute ledger_attribute: 'EntityRef',
33
+ resource_attribute: :entity,
34
+ type: LedgerSerializerType::EntityReferenceType
34
35
 
35
36
  attribute ledger_attribute: 'DocNumber',
36
37
  resource_attribute: :reference_number
@@ -16,7 +16,7 @@ module LedgerSync
16
16
  required(:payment_type).filled(:string)
17
17
  optional(:reference_number).maybe(:string)
18
18
  optional(:transaction_date).filled(:date?)
19
- optional(:vendor).hash(Types::Reference)
19
+ optional(:entity).hash(Types::Reference)
20
20
  end
21
21
  end
22
22
  end
@@ -16,7 +16,7 @@ module LedgerSync
16
16
  optional(:payment_type).maybe(:string)
17
17
  optional(:reference_number).maybe(:string)
18
18
  optional(:transaction_date).filled(:date?)
19
- optional(:vendor).hash(Types::Reference)
19
+ optional(:entity).hash(Types::Reference)
20
20
  end
21
21
  end
22
22
  end
@@ -16,7 +16,7 @@ module LedgerSync
16
16
  required(:payment_type).filled(:string)
17
17
  optional(:reference_number).maybe(:string)
18
18
  optional(:transaction_date).filled(:date?)
19
- optional(:vendor).hash(Types::Reference)
19
+ optional(:entity).hash(Types::Reference)
20
20
  end
21
21
  end
22
22
  end
@@ -12,9 +12,7 @@ module LedgerSync
12
12
  deserialized_resource = super(hash: hash)
13
13
 
14
14
  # Ref: https://github.com/LedgerSync/ledger_sync/issues/86
15
- if deserialized_resource.is_a?(LedgerSync::Account) && deserialized_resource.account_type
16
- deserialized_resource.classification ||= LedgerSerializerType::AccountType::TYPE_TO_CLASSIFICATION_MAPPING.fetch(deserialized_resource.account_type, nil)
17
- end
15
+ deserialized_resource.classification ||= LedgerSerializerType::AccountType::TYPE_TO_CLASSIFICATION_MAPPING.fetch(deserialized_resource.account_type, nil) if deserialized_resource.is_a?(LedgerSync::Account) && deserialized_resource.account_type
18
16
 
19
17
  return deserialized_resource unless merge_for_full_update
20
18
 
@@ -59,10 +57,6 @@ module LedgerSync
59
57
  merged_resource
60
58
  end
61
59
 
62
- def self.id(**keywords)
63
- super({ ledger_attribute: 'Id', resource_attribute: :ledger_id }.merge(keywords))
64
- end
65
-
66
60
  def to_ledger_hash(deep_merge_unmapped_values: {}, only_changes: false)
67
61
  ret = super(only_changes: only_changes)
68
62
  return ret unless deep_merge_unmapped_values.any?
@@ -73,8 +67,36 @@ module LedgerSync
73
67
  )
74
68
  end
75
69
 
70
+ class << self
71
+ attr_reader :quickbooks_online_resource_types_hash
72
+ end
73
+
74
+ def self.id(**keywords)
75
+ super({ ledger_attribute: 'Id', resource_attribute: :ledger_id }.merge(keywords))
76
+ end
77
+
78
+ def self.ledger_serializer_for(resource_class:)
79
+ QuickBooksOnline.const_get("#{resource_class.name.split('LedgerSync::')[1..-1].join('LedgerSync::')}::LedgerSerializer")
80
+ end
81
+
76
82
  def self.quickbooks_online_resource_type(type = nil)
77
- @quickbooks_online_resource_type ||= (type || _inferred_resource_class.resource_type).to_s
83
+ @quickbooks_online_resource_type ||= begin
84
+ inferred_resource_class = _inferred_resource_class
85
+ qbo_type = (type || inferred_resource_class.resource_type).to_s
86
+ type_hash = QuickBooksOnline::LedgerSerializer.quickbooks_online_resource_types_hash.try(:fetch, qbo_type, nil)
87
+ raise "Cannot define type in #{name}. Type already exists: #{qbo_type}. Defined previously by #{quickbooks_online_resource_types_hash[qbo_type][:serializer_class].name}" if type_hash.present? && (type_hash[:serializer_class] != serializer_class || type_hash[:resource_class] != inferred_resource_class) if type_hash.present?
88
+
89
+ QuickBooksOnline::LedgerSerializer.class_eval do
90
+ @quickbooks_online_resource_types_hash ||= {}
91
+ end
92
+
93
+ QuickBooksOnline::LedgerSerializer.quickbooks_online_resource_types_hash[qbo_type] = {
94
+ resource_class: inferred_resource_class,
95
+ serializer_class: self
96
+ }
97
+
98
+ qbo_type
99
+ end
78
100
  end
79
101
 
80
102
  private
@@ -101,3 +123,6 @@ module LedgerSync
101
123
  end
102
124
  end
103
125
  end
126
+
127
+ # Load other serializers to populate `QuickBooksOnline::LedgerSerializer.quickbooks_online_resource_types_hash`
128
+ Gem.find_files('ledger_sync/adaptors/quickbooks_online/**/ledger_serializer.rb').each { |path| require path }
@@ -4,7 +4,7 @@ module LedgerSync
4
4
  module Adaptors
5
5
  module QuickBooksOnline
6
6
  module LedgerSerializerType
7
- class AmountType < Adaptors::LedgerSerializerType::MappingType
7
+ class AmountType < Adaptors::LedgerSerializerType::ValueType
8
8
  def convert_from_ledger(value:)
9
9
  return if value.nil?
10
10
 
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LedgerSync
4
+ module Adaptors
5
+ module QuickBooksOnline
6
+ module LedgerSerializerType
7
+ class EntityReferenceType < Adaptors::LedgerSerializerType::ValueType
8
+ def convert_from_ledger(value:)
9
+ return if value.nil?
10
+
11
+ raise "Unknown value type. Hash expected. Given: #{value.class.name}" unless value.is_a?(Hash)
12
+ return if value.empty?
13
+
14
+ value = LedgerSync::Util::HashHelpers.deep_stringify_keys(value)
15
+ resource_class = begin
16
+ quickbooks_online_type_hash = QuickBooksOnline::LedgerSerializer.quickbooks_online_resource_types_hash.fetch(value['type'].downcase, nil)
17
+ if quickbooks_online_type_hash.present?
18
+ quickbooks_online_type_hash.try(:fetch, :resource_class, nil)
19
+ else
20
+ LedgerSync.resources[value['type'].downcase.to_sym]
21
+ end
22
+ end
23
+
24
+ raise "Unknown QuickBooks Online resource type: #{value['type']}" if resource_class.blank?
25
+
26
+ ret = resource_class.new(
27
+ ledger_id: value['value']
28
+ )
29
+
30
+ ret.display_name = value['name'] if ret.respond_to?(:display_name)
31
+ ret
32
+ end
33
+
34
+ def convert_from_local(value:)
35
+ return if value.nil?
36
+ raise "Resource expected. Given: #{value.class.name}" unless value.is_a?(LedgerSync::Resource)
37
+
38
+ ret = {
39
+ 'value' => value.ledger_id
40
+ }
41
+ ret['name'] = value.display_name if value.respond_to?(:display_name)
42
+ ret['type'] = string_helpers.camelcase(
43
+ QuickBooksOnline::LedgerSerializer.ledger_serializer_for(
44
+ resource_class: value.class
45
+ ).quickbooks_online_resource_type
46
+ )
47
+ ret
48
+ end
49
+
50
+ private
51
+
52
+ def string_helpers
53
+ @string_helpers ||= LedgerSync::Util::StringHelpers
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -11,7 +11,7 @@ module LedgerSync
11
11
  required(:external_id).maybe(:string)
12
12
  required(:ledger_id).value(:nil)
13
13
  required(:account).hash(Types::Reference)
14
- required(:vendor).hash(Types::Reference)
14
+ required(:entity).hash(Types::Reference)
15
15
  required(:currency).filled(:string)
16
16
  required(:memo).filled(:string)
17
17
  required(:payment_type).filled(:string)
@@ -21,36 +21,6 @@ module LedgerSync
21
21
  required(:reference_number).filled(:string)
22
22
  end
23
23
  end
24
-
25
- private
26
-
27
- def operate
28
- response = adaptor.post(
29
- resource: 'purchase',
30
- payload: local_resource_data
31
- )
32
-
33
- resource.ledger_id = response.dig('id')
34
- success(
35
- resource: Test::LedgerSerializer.new(resource: resource).deserialize(hash: response),
36
- response: response
37
- )
38
- end
39
-
40
- def local_resource_data
41
- {
42
- 'currency' => resource.currency,
43
- 'account_id' => resource.account.ledger_id,
44
- 'vendor_id' => resource.vendor.ledger_id,
45
- 'line_items' => resource.line_items.map do |line_item|
46
- {
47
- 'account_id' => line_item.account&.ledger_id,
48
- 'Amount' => line_item.amount / 100.0,
49
- 'description' => line_item.description
50
- }
51
- end
52
- }
53
- end
54
24
  end
55
25
  end
56
26
  end
@@ -11,7 +11,7 @@ module LedgerSync
11
11
  required(:external_id).maybe(:string)
12
12
  required(:ledger_id).filled(:string)
13
13
  required(:account).hash(Types::Reference)
14
- required(:vendor).hash(Types::Reference)
14
+ required(:entity).hash(Types::Reference)
15
15
  required(:currency).maybe(:string)
16
16
  required(:memo).maybe(:string)
17
17
  required(:payment_type).maybe(:string)
@@ -9,7 +9,7 @@ module LedgerSync
9
9
  required(:external_id).maybe(:string)
10
10
  required(:ledger_id).filled(:string)
11
11
  required(:account).hash(Types::Reference)
12
- required(:vendor).hash(Types::Reference)
12
+ required(:entity).hash(Types::Reference)
13
13
  required(:currency).filled(:string)
14
14
  required(:memo).filled(:string)
15
15
  required(:payment_type).filled(:string)
@@ -4,6 +4,8 @@ module LedgerSync
4
4
  attribute :amount, type: Type::Integer
5
5
  attribute :description, type: Type::String
6
6
 
7
+ references_one :entity, to: [Customer, Vendor]
8
+
7
9
  def name
8
10
  description
9
11
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LedgerSync
2
4
  class Expense < LedgerSync::Resource
3
5
  attribute :currency, type: Type::String
@@ -7,7 +9,7 @@ module LedgerSync
7
9
  attribute :exchange_rate, type: Type::Float
8
10
  attribute :reference_number, type: Type::String
9
11
 
10
- references_one :vendor, to: Vendor
12
+ references_one :entity, to: [Customer, Vendor]
11
13
  references_one :account, to: Account
12
14
 
13
15
  references_many :line_items, to: ExpenseLineItem
@@ -13,7 +13,11 @@ module LedgerSync
13
13
  end
14
14
 
15
15
  def error_message(attribute:, resource:, value:)
16
- "Attribute #{attribute.name} for #{resource.class.name} should be a #{resource_class.name}. Given #{value.class.name}"
16
+ if resource_class.is_a?(Array)
17
+ "Attribute #{attribute.name} for #{resource.class.name} should be one of the following: #{resource_class.map(&:name).join(', ')}. Given #{value.class.name}"
18
+ else
19
+ "Attribute #{attribute.name} for #{resource.class.name} should be a #{resource_class.first.name}. Given #{value.class.name}"
20
+ end
17
21
  end
18
22
 
19
23
  def type
@@ -22,10 +26,20 @@ module LedgerSync
22
26
 
23
27
  def valid_without_casting?(value:)
24
28
  return true if value.nil?
25
- return true if value.is_a?(resource_class)
29
+ return true if resource_classes.select { |e| value.is_a?(e) }.any?
26
30
 
27
31
  false
28
32
  end
33
+
34
+ private
35
+
36
+ def resource_classes
37
+ @resource_classes ||= if resource_class.is_a?(Array)
38
+ resource_class
39
+ else
40
+ [resource_class]
41
+ end
42
+ end
29
43
  end
30
44
  end
31
45
  end
@@ -53,9 +53,10 @@ module LedgerSync
53
53
  raise "Unrecognized attribute for #{resource_class.name}: #{k}" if attribute.nil? && !ignore_unrecognized_attributes
54
54
 
55
55
  v = if attribute.is_a?(ResourceAttribute::Reference::One)
56
+ resource_type = resource_type_by(external_id: current_data[k])
56
57
  resource_or_build(
57
58
  external_id: current_data[k],
58
- type: attribute.type.resource_class.resource_type
59
+ type: resource_type
59
60
  )
60
61
  elsif attribute.is_a?(ResourceAttribute::Reference::Many)
61
62
  current_data[k].map do |many_reference|
@@ -81,6 +82,19 @@ module LedgerSync
81
82
  )
82
83
  end
83
84
 
85
+ # This will break if multiple objects of different types have the same external_id
86
+ def external_id_to_type_hash
87
+ @external_id_to_type_hash ||= begin
88
+ ret = {}
89
+ data.each do |type, type_resources|
90
+ type_resources.keys.each do |external_id|
91
+ ret[external_id] = type
92
+ end
93
+ end
94
+ ret
95
+ end
96
+ end
97
+
84
98
  def resource_key(external_id:, type:)
85
99
  "#{type}/#{external_id}"
86
100
  end
@@ -91,6 +105,10 @@ module LedgerSync
91
105
  build_resource(**external_id_and_type)
92
106
  )
93
107
  end
108
+
109
+ def resource_type_by(external_id:)
110
+ external_id_to_type_hash[external_id.to_sym]
111
+ end
94
112
  end
95
113
  end
96
114
  end
@@ -1,3 +1,3 @@
1
1
  module LedgerSync
2
- VERSION = '1.1.2'.freeze
2
+ VERSION = '1.1.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ledger_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Jackson
@@ -398,6 +398,7 @@ files:
398
398
  - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/amount_type.rb
399
399
  - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/classification_type.rb
400
400
  - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/date_type.rb
401
+ - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/entity_reference_type.rb
401
402
  - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/journal_entry_line_item_type.rb
402
403
  - lib/ledger_sync/adaptors/quickbooks_online/ledger_serializer_type/payment_type.rb
403
404
  - lib/ledger_sync/adaptors/quickbooks_online/operation.rb
@@ -524,7 +525,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
524
525
  - !ruby/object:Gem::Version
525
526
  version: '0'
526
527
  requirements: []
527
- rubygems_version: 3.0.4
528
+ rubyforge_project:
529
+ rubygems_version: 2.7.6
528
530
  signing_key:
529
531
  specification_version: 4
530
532
  summary: Sync common objects to accounting software.