ledger_sync 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +4 -0
  7. data/.rubocop_todo.yml +25 -0
  8. data/.travis.yml +1 -1
  9. data/Dockerfile +8 -0
  10. data/Gemfile +3 -1
  11. data/Gemfile.lock +137 -8
  12. data/README.md +184 -9
  13. data/Rakefile +3 -3
  14. data/bin/console +3 -3
  15. data/docker-compose.yml +4 -0
  16. data/ledger_sync.gemspec +32 -11
  17. data/lib/ledger_sync.rb +115 -3
  18. data/lib/ledger_sync/adaptor_configuration.rb +55 -0
  19. data/lib/ledger_sync/adaptor_configuration_store.rb +52 -0
  20. data/lib/ledger_sync/adaptors/adaptor.rb +66 -0
  21. data/lib/ledger_sync/adaptors/contract.rb +16 -0
  22. data/lib/ledger_sync/adaptors/operation.rb +213 -0
  23. data/lib/ledger_sync/adaptors/quickbooks_online/adaptor.rb +161 -0
  24. data/lib/ledger_sync/adaptors/quickbooks_online/config.rb +7 -0
  25. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/create.rb +44 -0
  26. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/find.rb +35 -0
  27. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/update.rb +53 -0
  28. data/lib/ledger_sync/adaptors/quickbooks_online/customer/operations/upsert.rb +42 -0
  29. data/lib/ledger_sync/adaptors/quickbooks_online/customer/searcher.rb +63 -0
  30. data/lib/ledger_sync/adaptors/quickbooks_online/invoice/operations/create.rb +63 -0
  31. data/lib/ledger_sync/adaptors/quickbooks_online/invoice/operations/find.rb +36 -0
  32. data/lib/ledger_sync/adaptors/quickbooks_online/invoice/operations/update.rb +67 -0
  33. data/lib/ledger_sync/adaptors/quickbooks_online/invoice/operations/upsert.rb +44 -0
  34. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/create.rb +64 -0
  35. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/find.rb +35 -0
  36. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/update.rb +64 -0
  37. data/lib/ledger_sync/adaptors/quickbooks_online/payment/operations/upsert.rb +53 -0
  38. data/lib/ledger_sync/adaptors/quickbooks_online/product/operations/create.rb +46 -0
  39. data/lib/ledger_sync/adaptors/quickbooks_online/product/operations/find.rb +34 -0
  40. data/lib/ledger_sync/adaptors/quickbooks_online/product/operations/update.rb +50 -0
  41. data/lib/ledger_sync/adaptors/quickbooks_online/product/operations/upsert.rb +43 -0
  42. data/lib/ledger_sync/adaptors/quickbooks_online/util/adaptor_error_parser.rb +102 -0
  43. data/lib/ledger_sync/adaptors/quickbooks_online/util/error_matcher.rb +54 -0
  44. data/lib/ledger_sync/adaptors/quickbooks_online/util/error_parser.rb +27 -0
  45. data/lib/ledger_sync/adaptors/quickbooks_online/util/operation_error_parser.rb +96 -0
  46. data/lib/ledger_sync/adaptors/searcher.rb +64 -0
  47. data/lib/ledger_sync/adaptors/test/adaptor.rb +47 -0
  48. data/lib/ledger_sync/adaptors/test/config.rb +7 -0
  49. data/lib/ledger_sync/adaptors/test/customer/operations/create.rb +49 -0
  50. data/lib/ledger_sync/adaptors/test/customer/operations/find.rb +35 -0
  51. data/lib/ledger_sync/adaptors/test/customer/operations/invalid.rb +20 -0
  52. data/lib/ledger_sync/adaptors/test/customer/operations/update.rb +46 -0
  53. data/lib/ledger_sync/adaptors/test/customer/operations/upsert.rb +42 -0
  54. data/lib/ledger_sync/adaptors/test/customer/operations/valid.rb +26 -0
  55. data/lib/ledger_sync/adaptors/test/customer/searcher.rb +40 -0
  56. data/lib/ledger_sync/adaptors/test/error/adaptor_error/operations/throttle_error.rb +28 -0
  57. data/lib/ledger_sync/adaptors/test/payment/operations/create.rb +56 -0
  58. data/lib/ledger_sync/adaptors/test/payment/operations/find.rb +35 -0
  59. data/lib/ledger_sync/adaptors/test/payment/operations/update.rb +62 -0
  60. data/lib/ledger_sync/adaptors/test/payment/operations/upsert.rb +53 -0
  61. data/lib/ledger_sync/concerns/validatable.rb +19 -0
  62. data/lib/ledger_sync/core_ext/resonad.rb +16 -0
  63. data/lib/ledger_sync/error.rb +10 -0
  64. data/lib/ledger_sync/error/adaptor_errors.rb +47 -0
  65. data/lib/ledger_sync/error/operation_errors.rb +41 -0
  66. data/lib/ledger_sync/error/resource_errors.rb +20 -0
  67. data/lib/ledger_sync/resource.rb +92 -0
  68. data/lib/ledger_sync/resources/customer.rb +8 -0
  69. data/lib/ledger_sync/resources/invoice.rb +12 -0
  70. data/lib/ledger_sync/resources/payment.rb +11 -0
  71. data/lib/ledger_sync/resources/product.rb +6 -0
  72. data/lib/ledger_sync/resources/vendor.rb +6 -0
  73. data/lib/ledger_sync/result.rb +140 -0
  74. data/lib/ledger_sync/sync.rb +107 -0
  75. data/lib/ledger_sync/util/coordinator.rb +72 -0
  76. data/lib/ledger_sync/util/debug.rb +16 -0
  77. data/lib/ledger_sync/util/hash_helpers.rb +13 -0
  78. data/lib/ledger_sync/util/performer.rb +29 -0
  79. data/lib/ledger_sync/util/resources_builder.rb +68 -0
  80. data/lib/ledger_sync/util/string_helpers.rb +37 -0
  81. data/lib/ledger_sync/util/validator.rb +49 -0
  82. data/lib/ledger_sync/version.rb +1 -1
  83. data/release.sh +8 -0
  84. metadata +334 -11
  85. data/.rspec +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3da74afb88bc320a1a36c19cb72346d4c5fdd4055de62a4a8393879e3f70fcb5
4
- data.tar.gz: 6602d10e2339ee87831fc33b11fcd4d305a79a733aa4a67225ae1c6d30977fdd
3
+ metadata.gz: e777a594ee4da7c59da77df28dbb9d39dae0988cbcc8a0b8af5e82371e29ab11
4
+ data.tar.gz: 9df2f22c0b7001e077b8d03e934145ffdc58b91051ab32e2a581a86c16b40ce9
5
5
  SHA512:
6
- metadata.gz: bc29df605f6f79baa17f5a9e798c82c70c602bca83aac6b4e5427b7f46ac8f8990d893fc5b9015678a5bb658ac35bbc7663e24a71aff922e4c06d77da76382c4
7
- data.tar.gz: e6f250ee6a0821ee8691766c5f4eaa016889ec90173442c1c68b6481395a65f81f24817ebbc0fc04747de4902951472c3a6e4200280e7db12cd3ffdcaa351813
6
+ metadata.gz: 48b90e5bf88b16b92bb6d365070d1f8ea4011f50db62e82bf9a8dd19cc2a03106bfe56ba117a2a0a8806fb02866e1a6ccfcb3b75332c0b2fc4969920098b2821
7
+ data.tar.gz: b274ef24289ae0de509fc3ce6222e481a5ec43bffcfd7c2066c1baf1bac00edb63552206c3e35c180ba5fe1f77b58fe5f8b602f3940538e97edffff14b278cb9
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+ A clear and concise description of what the bug is.
12
+
13
+ **To Reproduce**
14
+ Steps to reproduce the behavior:
15
+ 1. Go to '...'
16
+ 2. Click on '....'
17
+ 3. Scroll down to '....'
18
+ 4. See error
19
+
20
+ **Expected behavior**
21
+ A clear and concise description of what you expected to happen.
22
+
23
+ **Screenshots**
24
+ If applicable, add screenshots to help explain your problem.
25
+
26
+ **Desktop (please complete the following information):**
27
+ - OS: [e.g. iOS]
28
+ - Browser [e.g. chrome, safari]
29
+ - Version [e.g. 22]
30
+
31
+ **Smartphone (please complete the following information):**
32
+ - Device: [e.g. iPhone6]
33
+ - OS: [e.g. iOS8.1]
34
+ - Browser [e.g. stock browser, safari]
35
+ - Version [e.g. 22]
36
+
37
+ **Additional context**
38
+ Add any other context about the problem here.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Additional context**
20
+ Add any other context or screenshots about the feature request here.
data/.gitignore CHANGED
@@ -9,3 +9,7 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ .byebug_history
14
+
15
+ .DS_Store
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.6
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,25 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2019-03-29 13:21:38 +0100 using RuboCop version 0.66.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ Metrics/AbcSize:
10
+ Enabled: False
11
+
12
+ Metrics/BlockLength:
13
+ Enabled: False
14
+
15
+ Style/Documentation:
16
+ Enabled: False
17
+
18
+ Metrics/LineLength:
19
+ Enabled: False
20
+
21
+ Metrics/MethodLength:
22
+ Enabled: False
23
+
24
+ Metrics/ParameterLists:
25
+ Enabled: False
data/.travis.yml CHANGED
@@ -3,5 +3,5 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.6.2
6
+ - 2.5.1
7
7
  before_install: gem install bundler -v 2.0.1
data/Dockerfile ADDED
@@ -0,0 +1,8 @@
1
+ FROM ruby:2.5.1
2
+
3
+ WORKDIR /lib
4
+
5
+ COPY . .
6
+ RUN bundle install
7
+
8
+ CMD ["bundle", "exec", "rspec"]
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
2
4
 
3
5
  # Specify your gem's dependencies in ledger_sync.gemspec
4
6
  gemspec
data/Gemfile.lock CHANGED
@@ -1,35 +1,164 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ledger_sync (0.1.0)
4
+ ledger_sync (1.0.0)
5
+ colorize
6
+ coveralls
7
+ dry-schema
8
+ dry-validation
9
+ faraday
10
+ faraday-detailed_logger
11
+ faraday_middleware
12
+ fingerprintable (>= 1.2.1)
13
+ nokogiri
14
+ oauth2
15
+ resonad
16
+ simply_serializable (>= 1.3.0)
5
17
 
6
18
  GEM
7
19
  remote: https://rubygems.org/
8
20
  specs:
21
+ addressable (2.6.0)
22
+ public_suffix (>= 2.0.2, < 4.0)
23
+ ast (2.4.0)
24
+ awesome_print (1.8.0)
25
+ bump (0.8.0)
26
+ byebug (11.0.1)
27
+ colorize (0.8.1)
28
+ concurrent-ruby (1.1.5)
29
+ coveralls (0.8.23)
30
+ json (>= 1.8, < 3)
31
+ simplecov (~> 0.16.1)
32
+ term-ansicolor (~> 1.3)
33
+ thor (>= 0.19.4, < 2.0)
34
+ tins (~> 1.6)
35
+ crack (0.4.3)
36
+ safe_yaml (~> 1.0.0)
9
37
  diff-lcs (1.3)
38
+ docile (1.3.2)
39
+ dry-configurable (0.8.3)
40
+ concurrent-ruby (~> 1.0)
41
+ dry-core (~> 0.4, >= 0.4.7)
42
+ dry-container (0.7.2)
43
+ concurrent-ruby (~> 1.0)
44
+ dry-configurable (~> 0.1, >= 0.1.3)
45
+ dry-core (0.4.8)
46
+ concurrent-ruby (~> 1.0)
47
+ dry-equalizer (0.2.2)
48
+ dry-inflector (0.1.2)
49
+ dry-initializer (3.0.1)
50
+ dry-logic (1.0.2)
51
+ concurrent-ruby (~> 1.0)
52
+ dry-core (~> 0.2)
53
+ dry-equalizer (~> 0.2)
54
+ dry-schema (1.3.1)
55
+ concurrent-ruby (~> 1.0)
56
+ dry-configurable (~> 0.8, >= 0.8.3)
57
+ dry-core (~> 0.4)
58
+ dry-equalizer (~> 0.2)
59
+ dry-initializer (~> 3.0)
60
+ dry-logic (~> 1.0)
61
+ dry-types (~> 1.0)
62
+ dry-types (1.1.0)
63
+ concurrent-ruby (~> 1.0)
64
+ dry-container (~> 0.3)
65
+ dry-core (~> 0.4, >= 0.4.4)
66
+ dry-equalizer (~> 0.2, >= 0.2.2)
67
+ dry-inflector (~> 0.1, >= 0.1.2)
68
+ dry-logic (~> 1.0, >= 1.0.2)
69
+ dry-validation (1.2.0)
70
+ concurrent-ruby (~> 1.0)
71
+ dry-container (~> 0.7, >= 0.7.1)
72
+ dry-core (~> 0.4)
73
+ dry-equalizer (~> 0.2)
74
+ dry-initializer (~> 3.0)
75
+ dry-schema (~> 1.0, >= 1.3.1)
76
+ faraday (0.15.4)
77
+ multipart-post (>= 1.2, < 3)
78
+ faraday-detailed_logger (2.1.3)
79
+ faraday (~> 0.8)
80
+ faraday_middleware (0.13.1)
81
+ faraday (>= 0.7.4, < 1.0)
82
+ fingerprintable (1.2.1)
83
+ colorize
84
+ hashdiff (0.4.0)
85
+ jaro_winkler (1.5.2)
86
+ json (2.2.0)
87
+ jwt (2.2.1)
88
+ mini_portile2 (2.4.0)
89
+ multi_json (1.13.1)
90
+ multi_xml (0.6.0)
91
+ multipart-post (2.1.1)
92
+ nokogiri (1.10.3)
93
+ mini_portile2 (~> 2.4.0)
94
+ oauth2 (1.4.1)
95
+ faraday (>= 0.8, < 0.16.0)
96
+ jwt (>= 1.0, < 3.0)
97
+ multi_json (~> 1.3)
98
+ multi_xml (~> 0.5)
99
+ rack (>= 1.2, < 3)
100
+ parallel (1.17.0)
101
+ parser (2.6.3.0)
102
+ ast (~> 2.4.0)
103
+ public_suffix (3.1.0)
104
+ rack (2.0.7)
105
+ rainbow (3.0.0)
10
106
  rake (10.5.0)
107
+ resonad (1.2.0)
11
108
  rspec (3.8.0)
12
109
  rspec-core (~> 3.8.0)
13
110
  rspec-expectations (~> 3.8.0)
14
111
  rspec-mocks (~> 3.8.0)
15
- rspec-core (3.8.0)
112
+ rspec-core (3.8.2)
16
113
  rspec-support (~> 3.8.0)
17
- rspec-expectations (3.8.3)
114
+ rspec-expectations (3.8.4)
18
115
  diff-lcs (>= 1.2.0, < 2.0)
19
116
  rspec-support (~> 3.8.0)
20
- rspec-mocks (3.8.0)
117
+ rspec-mocks (3.8.1)
21
118
  diff-lcs (>= 1.2.0, < 2.0)
22
119
  rspec-support (~> 3.8.0)
23
- rspec-support (3.8.0)
120
+ rspec-support (3.8.2)
121
+ rubocop (0.71.0)
122
+ jaro_winkler (~> 1.5.1)
123
+ parallel (~> 1.10)
124
+ parser (>= 2.6)
125
+ rainbow (>= 2.2.2, < 4.0)
126
+ ruby-progressbar (~> 1.7)
127
+ unicode-display_width (>= 1.4.0, < 1.7)
128
+ ruby-progressbar (1.10.1)
129
+ safe_yaml (1.0.5)
130
+ simplecov (0.16.1)
131
+ docile (~> 1.1)
132
+ json (>= 1.8, < 3)
133
+ simplecov-html (~> 0.10.0)
134
+ simplecov-html (0.10.2)
135
+ simply_serializable (1.3.0)
136
+ fingerprintable (>= 1.2.1)
137
+ term-ansicolor (1.7.1)
138
+ tins (~> 1.0)
139
+ thor (0.20.3)
140
+ tins (1.21.0)
141
+ unicode-display_width (1.6.0)
142
+ vcr (5.0.0)
143
+ webmock (3.6.0)
144
+ addressable (>= 2.3.6)
145
+ crack (>= 0.3.2)
146
+ hashdiff (>= 0.4.0, < 2.0.0)
24
147
 
25
148
  PLATFORMS
26
149
  ruby
27
150
 
28
151
  DEPENDENCIES
29
- bundler (~> 2.0)
152
+ awesome_print
153
+ bump
154
+ bundler (~> 1.16)
155
+ byebug
30
156
  ledger_sync!
31
157
  rake (~> 10.0)
32
- rspec (~> 3.0)
158
+ rspec (~> 3.2)
159
+ rubocop
160
+ vcr
161
+ webmock
33
162
 
34
163
  BUNDLED WITH
35
- 2.0.1
164
+ 1.17.2
data/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # LedgerSync
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ledger_sync`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Build Status](https://travis-ci.org/LedgerSync/ledger_sync.svg?branch=master)](https://travis-ci.org/LedgerSync/ledger_sync) [![Coverage Status](https://coveralls.io/repos/github/LedgerSync/ledger_sync/badge.svg?branch=master)](https://coveralls.io/github/LedgerSync/ledger_sync?branch=master)
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
6
-
7
- ## Installation
5
+ # Installation
8
6
 
9
7
  Add this line to your application's Gemfile:
10
8
 
@@ -20,19 +18,196 @@ Or install it yourself as:
20
18
 
21
19
  $ gem install ledger_sync
22
20
 
23
- ## Usage
21
+ # Usage
22
+
23
+ The easiest entry point into the library is the `Sync` class, which will handle building, validating, and performing all the necessary operations to sync an object. You can of course build and manage these primitives yourself if you require more control. Here is an example of a sync:
24
+
25
+ ```ruby
26
+ sync = LedgerSync::Sync.new(
27
+ adaptor: adaptor, # The adaptor for the ledger you want to use (see below)
28
+ method: :upsert,
29
+ resources_data: resources_data, # The structured hash of resource data (see below)
30
+ resource_external_id: resource_external_id, # The root object ID on which the operation is to be performed
31
+ resource_type: resource_type # The root object type on which the operation is to be performed
32
+ )
33
+
34
+ sync.operations # Returns the ordered list of operations to be performed
35
+
36
+ sync.perform # Returns a SyncResult (either ::Success or ::Failure)
37
+ ```
38
+
39
+ **NOTE: Even when not performing the sync (`sync.perform`) and just retrieving the operations (`sync.operations`), the library will make API requests to the ledger in order to determine if a `create` or `update` is necessary for each object involved.**
40
+
41
+ # How it Works
42
+
43
+ ## The Library Structure
44
+
45
+ This library consists of two important layers:
46
+
47
+ 1. Resources
48
+ 2. Adaptors
49
+
50
+ ### Resources
51
+
52
+ Resources are named ruby objects (e.g. `Customer`, `Payment`, etc.) with strict attributes (e.g. `name`, `amount`, etc.). They are a layer between your application and an adaptor. They can be validated using an adaptor. You can create and use the resources, and an adaptor will update resources as needed based on the intention and outcome of that operation.
53
+
54
+ You can find supported resources by calling `LedgerSync.resources`.
55
+
56
+ Resources have defined attributes. Attributes are explicitly defined. An error is thrown if an unknown attribute is passed to it. You can retrieve the attributes of a resource by calling `LedgerSync::Customer.attributes`.
57
+
58
+ A subset of these `attributes` may be a `reference`, which is simply a special type of attribute that references another resource. You can retrieve the references of a resource by calling `LedgerSync::Customer.references`.
59
+
60
+ ## Adaptors
61
+
62
+ Adaptors are ledger-specific ruby objects that contain all the logic to authenticate to a ledger, perform ledger-specific operations, and validate resources based on the requirements of the ledger. Adaptors contain a number of useful objects:
63
+
64
+ - adaptor
65
+ - operations
66
+ - searchers
67
+
68
+ ### Adaptor
69
+
70
+ The adaptor handles authentication and requests to the ledger. Each adaptors initializer will vary based on the needs of that ledger.
71
+
72
+ ### Operation
73
+
74
+ Each adaptor defines operations that can be performed on specific resources (e.g. `Customer::Update`, `Payment::Create`). The operation defines three key things:
75
+
76
+ - a `Contract` class which is used to validate the resource using the `dry-validation` gem
77
+ - a `build` instance method, which handles any pre-processing to be done before the operation is performed (e.g. converting an `Upsert` into a `Create` or `Update`)
78
+ - a `perform` instance method, which handles the actual API requests and response/error handling.
79
+
80
+ Note: Adaptors may support different operations for each resource type.
81
+
82
+ ### Searcher
83
+
84
+ Searchers are a classes that make it easy to search objects in the ledger. A searcher takes an `adaptor`, `query` string and optional `pagination` hash.
85
+
86
+ # Tips and More!
24
87
 
25
- TODO: Write usage instructions here
88
+ ## Keywords
26
89
 
27
- ## Development
90
+ LedgerSync heavily uses ruby keywords so as to make it clear what values are being passed and which attributes are required. When this README says something like "the `fun_function` function takes the argument `foo`" that translates to `fun_function(foo: :some_value)`.
91
+
92
+ ## Fingerprints
93
+
94
+ Most objects in LedgerSync can be fingerprinted by calling the instance method `fingerprint`. For example:
95
+
96
+ ```ruby
97
+ puts LedgerSync::Customer.new.fingerprint # "b3eab7ec00431a4ae0468fee72e5ba8f"
98
+
99
+ puts LedgerSync::Customer.new.fingerprint == LedgerSync::Customer.new.fingerprint # true
100
+ puts LedgerSync::Customer.new.fingerprint == LedgerSync::Customer.new(name: :foo).fingerprint # false
101
+ puts LedgerSync::Customer.new.fingerprint == LedgerSync::Payment.new.fingerprint # false
102
+ ```
103
+
104
+ Fingerprints are used to compare objects. This method is used in de-duping objects, as it only considers the data inside and not the instance itself (as shown above).
105
+
106
+ ## Serialization
107
+
108
+ Most objects in LedgerSync can be serialized by calling the instance method `serialize`. For example:
109
+
110
+ ```ruby
111
+ puts LedgerSync::Payment.new(
112
+ customer: LedgerSync::Customer.new
113
+ )
114
+
115
+ {
116
+ root: "LedgerSync::Payment/8eed81c0177801a001f2544f0c85e21d",
117
+ objects: {
118
+ "LedgerSync::Payment/8eed81c0177801a001f2544f0c85e21d": {
119
+ id: "LedgerSync::Payment/8eed81c0177801a001f2544f0c85e21d",
120
+ object: "LedgerSync::Payment",
121
+ fingeprint: "8eed81c0177801a001f2544f0c85e21d",
122
+ data: {
123
+ currency: nil,
124
+ amount: nil,
125
+ customer: {
126
+ object: "reference",
127
+ id: "LedgerSync::Customer/b3eab7ec00431a4ae0468fee72e5ba8f"
128
+ },
129
+ external_id: "",
130
+ ledger_id: nil,
131
+ sync_token: nil
132
+ }
133
+ },
134
+ "LedgerSync::Customer/b3eab7ec00431a4ae0468fee72e5ba8f": {
135
+ id: "LedgerSync::Customer/b3eab7ec00431a4ae0468fee72e5ba8f",
136
+ object: "LedgerSync::Customer",
137
+ fingeprint: "b3eab7ec00431a4ae0468fee72e5ba8f",
138
+ data: {
139
+ name: nil,
140
+ email: nil,
141
+ phone_number: nil,
142
+ external_id: "",
143
+ ledger_id: nil,
144
+ sync_token: nil
145
+ }
146
+ }
147
+ }
148
+ }
149
+ ```
150
+
151
+ The serialization of any object follows the same struction. There is a `:root` key that holds the ID of the root object. There is also an `:objects` hash that contains all of the objects for this serialization. As you can see, unique nested objects listed in the `:objects` hash and referenced using a "reference object", in this case:
152
+
153
+ ```ruby
154
+ {
155
+ object: "reference",
156
+ id: "LedgerSync::Customer/b3eab7ec00431a4ae0468fee72e5ba8f"
157
+ }
158
+ ```
159
+
160
+ # Testing
161
+
162
+ LedgerSync offers a test adaptor `LedgerSync::Adaptors::Test` that you can easily use and stub without requiring API requests. For example:
163
+
164
+ ```ruby
165
+ resources_data = {
166
+ {
167
+ customer: {
168
+ 'cus_1': {
169
+ name: 'Jane Doe'
170
+ }
171
+ }
172
+ }
173
+ }
174
+ sync = LedgerSync::Sync.new(
175
+ adaptor: LedgerSync::Adaptors::Test.new,
176
+ method: :upsert,
177
+ resources_data: resources_data,
178
+ resource_external_id: 'cus_1',
179
+ resource_type: :customer
180
+ )
181
+
182
+ expect(sync.perform).to be_a(LedgerSync::SyncResult::Success)
183
+ ```
184
+
185
+ # Development
28
186
 
29
187
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
188
 
31
189
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
190
 
191
+ Run `bundle console` to start and interactive console with the library already loaded.
192
+
193
+ ### Adding an Adaptor
194
+
195
+ ## Errors
196
+
197
+ https://developer.intuit.com/app/developer/qbo/docs/develop/troubleshooting/error-codes
198
+
199
+ #### Directory Structure
200
+
201
+ /quickbooks_online/
202
+ adaptor.rb
203
+ operations/
204
+ customer/
205
+ operation.rb
206
+
207
+
33
208
  ## Contributing
34
209
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ledger_sync. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
210
+ Bug reports and pull requests are welcome on GitHub at https://github.com/LedgerSync/ledger_sync. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
211
 
37
212
  ## License
38
213
 
@@ -40,4 +215,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
215
 
41
216
  ## Code of Conduct
42
217
 
43
- Everyone interacting in the LedgerSync project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ledger_sync/blob/master/CODE_OF_CONDUCT.md).
218
+ Everyone interacting in the LedgerSync project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/LedgerSync/ledger_sync/blob/master/CODE_OF_CONDUCT.md).