ledger_sync 1.1.2 → 1.1.3

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