myob_acumatica 0.1.0 → 0.1.2

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.
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'logger'
5
+ require 'date'
6
+ require 'dotenv/load'
7
+ require 'myob_acumatica'
8
+
9
+ access_token = ENV['MYOB_ACUMATICA_ACCESS_TOKEN']
10
+ logger = Logger.new($stdout)
11
+
12
+ MyobAcumatica::Api::Invoice.get_ad_hoc_schema(
13
+ access_token: access_token,
14
+ logger: logger
15
+ )
16
+
17
+ invoice1 = MyobAcumatica::Api::Invoice.put_entity(
18
+ access_token: access_token,
19
+ entity: {
20
+ 'Customer' => { 'value' => 'JOHNGOOD1' },
21
+ 'CustomerID' => { 'value' => 'JOHNGOOD1' },
22
+ 'Date' => { 'value' => Date.today.strftime('%Y-%m-%d') },
23
+ 'DueDate' => { 'value' => (Date.today + 30).strftime('%Y-%m-%d') },
24
+ 'Terms' => { 'value' => 'NET14DAYS' },
25
+ 'Type' => { 'value' => 'Invoice' },
26
+ 'Hold' => { 'value' => false },
27
+ 'BillingAddressOverride' => { 'value' => true },
28
+ 'BillingAddress' => {
29
+ 'AddressLine1' => { 'value' => 'Fillmore Str' },
30
+ 'City' => { 'value' => 'San Francisco' },
31
+ 'State' => { 'value' => 'CA' }
32
+ },
33
+ 'custom' => {
34
+ 'Document' => {
35
+ 'DiscDate' => { 'value' => (Date.today + 10).strftime('%Y-%m-%dT00:00:00+00:00') }
36
+ }
37
+ }
38
+ },
39
+ logger: logger
40
+ )
41
+
42
+ MyobAcumatica::Api::Invoice.get_by_id(
43
+ access_token: access_token,
44
+ id: invoice1['id'],
45
+ logger: logger
46
+ )
47
+
48
+ MyobAcumatica::Api::Invoice.get_by_keys(
49
+ access_token: access_token,
50
+ keys: [invoice1['Type']['value'], invoice1['ReferenceNbr']['value']],
51
+ logger: logger
52
+ )
53
+
54
+ MyobAcumatica::Api::Invoice.get_list(
55
+ access_token: access_token,
56
+ query_params: {
57
+ # '$filter' => "Status eq 'Open' and "\
58
+ # "LastModifiedDateTime gt datetimeoffset'2020-08-18T23:59:59.999+04:00'",
59
+ # '$expand' => 'Invoices',
60
+ '$skip' => 1,
61
+ '$top' => 4
62
+ },
63
+ logger: logger
64
+ )
65
+
66
+ MyobAcumatica::Api::Invoice.put_file(
67
+ access_token: access_token,
68
+ keys: [invoice1['Type']['value'], invoice1['ReferenceNbr']['value']],
69
+ file_path: 'examples/dummy.pdf',
70
+ logger: logger
71
+ )
72
+
73
+ MyobAcumatica::Api::Invoice.invoke_action(
74
+ access_token: access_token,
75
+ action_name: 'ReleaseInvoice',
76
+ entity: { 'id' => invoice1['id'] },
77
+ logger: logger
78
+ )
79
+
80
+ # MyobAcumatica::Api::Invoice.release(
81
+ # access_token: access_token,
82
+ # entity: { 'id' => invoice1['id'] },
83
+ # logger: logger
84
+ # )
85
+
86
+ MyobAcumatica::Api::Invoice.delete_by_keys(
87
+ access_token: access_token,
88
+ keys: [invoice1['Type']['value'], invoice1['ReferenceNbr']['value']],
89
+ logger: logger
90
+ )
91
+
92
+ invoice2 = MyobAcumatica::Api::Invoice.put_entity(
93
+ access_token: access_token,
94
+ entity: {
95
+ 'Customer' => { 'value' => 'JOHNGOOD2' },
96
+ 'CustomerID' => { 'value' => 'JOHNGOOD2' },
97
+ 'Date' => { 'value' => Date.today.strftime('%Y-%m-%d') },
98
+ 'DueDate' => { 'value' => (Date.today + 30).strftime('%Y-%m-%d') },
99
+ 'Terms' => { 'value' => 'NET14DAYS' },
100
+ 'Type' => { 'value' => 'Invoice' },
101
+ 'Hold' => { 'value' => false },
102
+ 'BillingAddressOverride' => { 'value' => true },
103
+ 'BillingAddress' => {
104
+ 'AddressLine1' => { 'value' => 'Fillmore Str' },
105
+ 'City' => { 'value' => 'San Francisco' },
106
+ 'State' => { 'value' => 'CA' }
107
+ },
108
+ 'custom' => {
109
+ 'Document' => {
110
+ 'DiscDate' => { 'value' => (Date.today + 10).strftime('%Y-%m-%dT00:00:00+00:00') }
111
+ }
112
+ }
113
+ },
114
+ logger: logger
115
+ )
116
+
117
+ MyobAcumatica::Api::Invoice.delete_by_id(
118
+ access_token: access_token,
119
+ id: invoice2['id'],
120
+ logger: logger
121
+ )
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyobAcumatica
4
+ module Api
5
+ # Provides methods to interact with the Customer API endpoints.
6
+ module Customer
7
+ module_function
8
+
9
+ # Deletes a customer by ID.
10
+ # @example Delete a customer by ID
11
+ # MyobAcumatica::Api::Customer.delete_by_id(
12
+ # access_token: '...',
13
+ # id: '00000000-0000-4000-8000-000000000000',
14
+ # logger: Logger.new($stdout)
15
+ # )
16
+ # @param access_token [String] The OAuth2 access token.
17
+ # @param id [String] The unique ID of the customer.
18
+ # @param instance_name [String] The instance name.
19
+ # @param endpoint_name [String] The endpoint name.
20
+ # @param endpoint_version [String] The endpoint version.
21
+ # @param logger [Logger, nil] Optional logger for logging the request process.
22
+ # @return [nil] Always nil.
23
+ def delete_by_id(access_token:, id:,
24
+ instance_name: INSTANCE_NAME,
25
+ endpoint_name: ENDPOINT_NAME,
26
+ endpoint_version: ENDPOINT_VERSION,
27
+ logger: nil)
28
+ Http.request(
29
+ instance_name: instance_name,
30
+ access_token: access_token,
31
+ method: :delete,
32
+ endpoint_name: endpoint_name,
33
+ endpoint_version: endpoint_version,
34
+ path: "Customer/#{id}",
35
+ logger: logger
36
+ )
37
+ end
38
+
39
+ # Deletes a customer by composite keys.
40
+ # @example Delete a customer by keys
41
+ # MyobAcumatica::Api::Customer.delete_by_keys(
42
+ # access_token: '...',
43
+ # keys: ['JOHNGOOD'],
44
+ # logger: Logger.new($stdout)
45
+ # )
46
+ # @param access_token [String] The OAuth2 access token.
47
+ # @param keys [Array<String>] An array of keys that uniquely identify the customer.
48
+ # @param instance_name [String] The instance name.
49
+ # @param endpoint_name [String] The endpoint name.
50
+ # @param endpoint_version [String] The endpoint version.
51
+ # @param logger [Logger, nil] Optional logger for logging the request process.
52
+ # @return [nil] Always nil.
53
+ def delete_by_keys(access_token:, keys:,
54
+ instance_name: INSTANCE_NAME,
55
+ endpoint_name: ENDPOINT_NAME,
56
+ endpoint_version: ENDPOINT_VERSION,
57
+ logger: nil)
58
+ Http.request(
59
+ instance_name: instance_name,
60
+ access_token: access_token,
61
+ method: :delete,
62
+ endpoint_name: endpoint_name,
63
+ endpoint_version: endpoint_version,
64
+ path: "Customer/#{keys.join('/')}",
65
+ logger: logger
66
+ )
67
+ end
68
+
69
+ # Retrieves the ad-hoc schema for the customer endpoint.
70
+ # @example Retrieve the ad-hoc schema
71
+ # MyobAcumatica::Api::Customer.get_ad_hoc_schema(
72
+ # access_token: '...',
73
+ # logger: Logger.new($stdout)
74
+ # )
75
+ # @param access_token [String] The OAuth2 access token.
76
+ # @param instance_name [String] The instance name.
77
+ # @param endpoint_name [String] The endpoint name.
78
+ # @param endpoint_version [String] The endpoint version.
79
+ # @param logger [Logger, nil] Optional logger for logging the request process.
80
+ # @return [Hash] The ad hoc schema
81
+ def get_ad_hoc_schema(access_token:,
82
+ instance_name: INSTANCE_NAME,
83
+ endpoint_name: ENDPOINT_NAME,
84
+ endpoint_version: ENDPOINT_VERSION,
85
+ logger: nil)
86
+ Http.request(
87
+ instance_name: instance_name,
88
+ access_token: access_token,
89
+ method: :get,
90
+ endpoint_name: endpoint_name,
91
+ endpoint_version: endpoint_version,
92
+ path: 'Customer/$adHocSchema',
93
+ logger: logger
94
+ )
95
+ end
96
+
97
+ # Retrieves a customer by ID.
98
+ # @example Retrieve a customer by ID
99
+ # MyobAcumatica::Api::Customer.get_by_id(
100
+ # access_token: '...',
101
+ # id: '00000000-0000-4000-8000-000000000000',
102
+ # logger: Logger.new($stdout)
103
+ # )
104
+ # @param access_token [String] The OAuth2 access token.
105
+ # @param id [String] The unique ID of the customer.
106
+ # @param query_params [Hash] Additional query parameters for the request.
107
+ # @param instance_name [String] The instance name.
108
+ # @param endpoint_name [String] The endpoint name.
109
+ # @param endpoint_version [String] The endpoint version.
110
+ # @param logger [Logger, nil] Optional logger for logging the request process.
111
+ # @return [Hash] The customer
112
+ def get_by_id(access_token:, id:, query_params: {},
113
+ instance_name: INSTANCE_NAME,
114
+ endpoint_name: ENDPOINT_NAME,
115
+ endpoint_version: ENDPOINT_VERSION,
116
+ logger: nil)
117
+ Http.request(
118
+ instance_name: instance_name,
119
+ access_token: access_token,
120
+ method: :get,
121
+ endpoint_name: endpoint_name,
122
+ endpoint_version: endpoint_version,
123
+ path: "Customer/#{id}",
124
+ query_params: query_params,
125
+ logger: logger
126
+ )
127
+ end
128
+
129
+ # Retrieves a customer by keys.
130
+ # @example Retrieve a customer by keys
131
+ # MyobAcumatica::Api::Customer.get_by_keys(
132
+ # access_token: '...',
133
+ # keys: ['JOHNGOOD'],
134
+ # logger: Logger.new($stdout)
135
+ # )
136
+ # @param access_token [String] The OAuth2 access token.
137
+ # @param keys [Array<String>] An array of keys that uniquely identify the customer.
138
+ # @param query_params [Hash] Additional query parameters for the request.
139
+ # @param instance_name [String] The instance name.
140
+ # @param endpoint_name [String] The endpoint name.
141
+ # @param endpoint_version [String] The endpoint version.
142
+ # @param logger [Logger, nil] Optional logger for logging the request process.
143
+ # @return [Hash] The customer
144
+ def get_by_keys(access_token:, keys:, query_params: {},
145
+ instance_name: INSTANCE_NAME,
146
+ endpoint_name: ENDPOINT_NAME,
147
+ endpoint_version: ENDPOINT_VERSION,
148
+ logger: nil)
149
+ Http.request(
150
+ instance_name: instance_name,
151
+ access_token: access_token,
152
+ method: :get,
153
+ endpoint_name: endpoint_name,
154
+ endpoint_version: endpoint_version,
155
+ path: "Customer/#{keys.join('/')}",
156
+ query_params: query_params,
157
+ logger: logger
158
+ )
159
+ end
160
+
161
+ # Retrieves a list of customers.
162
+ # @example Retrieve a list of customers
163
+ # MyobAcumatica::Api::Customer.get_list(
164
+ # access_token: '...',
165
+ # query_params: { '$top' => 10 },
166
+ # logger: Logger.new($stdout)
167
+ # )
168
+ # @param access_token [String] The OAuth2 access token.
169
+ # @param query_params [Hash] Additional query parameters for the request.
170
+ # @param instance_name [String] The instance name.
171
+ # @param endpoint_name [String] The endpoint name.
172
+ # @param endpoint_version [String] The endpoint version.
173
+ # @param logger [Logger, nil] Optional logger for logging the request process.
174
+ # @return [Array<Hash>] A list of customers.
175
+ def get_list(access_token:, query_params: {},
176
+ instance_name: INSTANCE_NAME,
177
+ endpoint_name: ENDPOINT_NAME,
178
+ endpoint_version: ENDPOINT_VERSION,
179
+ logger: nil)
180
+ Http.request(
181
+ instance_name: instance_name,
182
+ access_token: access_token,
183
+ method: :get,
184
+ endpoint_name: endpoint_name,
185
+ endpoint_version: endpoint_version,
186
+ path: 'Customer',
187
+ query_params: query_params,
188
+ logger: logger
189
+ )
190
+ end
191
+
192
+ # Updates or creates a customer entity.
193
+ #
194
+ # @example Update or create a customer entity with detailed information
195
+ # MyobAcumatica::Api::Customer.put_entity(
196
+ # access_token: '...',
197
+ # instance_name: 'example.myobadvanced.com',
198
+ # entity: {
199
+ # 'CustomerID' => { 'value' => 'JOHNGOOD' },
200
+ # 'CustomerName' => { 'value' => 'John Good' },
201
+ # 'CustomerClass' => { 'value' => 'CUSTDFT' }
202
+ # }
203
+ # )
204
+ #
205
+ # @param access_token [String] The OAuth2 access token.
206
+ # @param entity [Hash] The customer entity.
207
+ # @param query_params [Hash] Optional query parameters.
208
+ # @param instance_name [String] The name of the instance.
209
+ # @param endpoint_name [String] The endpoint name.
210
+ # @param endpoint_version [String] The endpoint version.
211
+ # @param logger [Logger, nil] Optional logger for request debugging.
212
+ # @return [Hash] The response from the server.
213
+ def put_entity(access_token:, entity:, query_params: {},
214
+ instance_name: INSTANCE_NAME,
215
+ endpoint_name: ENDPOINT_NAME,
216
+ endpoint_version: ENDPOINT_VERSION,
217
+ logger: nil)
218
+ Http.request(
219
+ instance_name: instance_name,
220
+ access_token: access_token,
221
+ method: :put,
222
+ endpoint_name: endpoint_name,
223
+ endpoint_version: endpoint_version,
224
+ path: 'Customer',
225
+ body: entity,
226
+ query_params: query_params,
227
+ logger: logger
228
+ )
229
+ end
230
+
231
+ # Uploads a file to a specific customer record by resolving the `files:put` link.
232
+ #
233
+ # @example Upload a PDF to a customer record
234
+ # MyobAcumatica::Api::Customer.put_file(
235
+ # access_token: '...',
236
+ # instance_name: 'example.myobadvanced.com',
237
+ # keys: ['JOHNGOOD'],
238
+ # file_path: 'examples/sample.pdf'
239
+ # )
240
+ #
241
+ # @param access_token [String] The OAuth2 access token.
242
+ # @param keys [Array<String>] Key(s) identifying the customer record.
243
+ # @param file_path [String] Full path to the file to be uploaded.
244
+ # @param instance_name [String] The name of the instance.
245
+ # @param endpoint_name [String] The endpoint name.
246
+ # @param endpoint_version [String] The endpoint version.
247
+ # @param logger [Logger, nil] Optional logger for HTTP debugging.
248
+ # @return [nil] Returns nil if successful.
249
+ # @raise [MyobAcumatica::Error] If the upload fails.
250
+ def put_file(access_token:, keys:, file_path:,
251
+ instance_name: INSTANCE_NAME,
252
+ endpoint_name: ENDPOINT_NAME,
253
+ endpoint_version: ENDPOINT_VERSION,
254
+ logger: nil)
255
+ customer = get_by_keys(
256
+ access_token: access_token,
257
+ instance_name: instance_name,
258
+ keys: keys,
259
+ logger: logger
260
+ )
261
+
262
+ put_url_template = customer.dig('_links', 'files:put')
263
+ raise MyobAcumatica::Error, 'files:put link not found' unless put_url_template
264
+
265
+ filename = File.basename(file_path)
266
+ path = put_url_template.gsub('{filename}', filename)
267
+
268
+ Http.request(
269
+ instance_name: instance_name,
270
+ access_token: access_token,
271
+ method: :put,
272
+ endpoint_name: endpoint_name,
273
+ endpoint_version: endpoint_version,
274
+ path: path,
275
+ body: File.binread(file_path),
276
+ content_type: 'application/octet-stream',
277
+ logger: logger
278
+ )
279
+ end
280
+
281
+ # Invokes a custom action on the Customer entity.
282
+ #
283
+ # @example Invoke the 'CreateContactFromCustomer' action
284
+ # MyobAcumatica::Api::Customer.invoke_action(
285
+ # access_token: '...',
286
+ # action_name: 'CreateContactFromCustomer',
287
+ # entity: { 'CustomerID' => { 'value' => 'JOHNGOOD' } },
288
+ # parameters: {
289
+ # 'FirstName' => { 'value' => 'John' },
290
+ # 'LastName' => { 'value' => 'Smith' }
291
+ # },
292
+ # logger: Logger.new($stdout)
293
+ # )
294
+ #
295
+ # @param access_token [String] The OAuth2 access token.
296
+ # @param action_name [String] The name of the action to invoke (e.g., 'CreateContactFromCustomer').
297
+ # @param entity [Hash] The entity payload on which to invoke the action.
298
+ # @param parameters [Hash] Optional parameters for the action.
299
+ # @param instance_name [String] The instance name.
300
+ # @param endpoint_name [String] The endpoint name.
301
+ # @param endpoint_version [String] The endpoint version.
302
+ # @param logger [Logger, nil] Optional logger for HTTP debugging.
303
+ # @return [Hash, nil] The response from the action, if any.
304
+ def invoke_action(access_token:, action_name:, entity:, parameters: {},
305
+ instance_name: INSTANCE_NAME,
306
+ endpoint_name: ENDPOINT_NAME,
307
+ endpoint_version: ENDPOINT_VERSION,
308
+ logger: nil)
309
+ Http.request(
310
+ instance_name: instance_name,
311
+ access_token: access_token,
312
+ method: :post,
313
+ endpoint_name: endpoint_name,
314
+ endpoint_version: endpoint_version,
315
+ path: "Customer/#{action_name}",
316
+ body: { 'entity' => entity, 'parameters' => parameters },
317
+ logger: logger
318
+ )
319
+ end
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MyobAcumatica
4
+ module Api
5
+ module Http
6
+ module_function
7
+
8
+ def request(instance_name:, access_token:, method:,
9
+ endpoint_name:, endpoint_version:, path:,
10
+ accept: 'application/json', content_type: 'application/json',
11
+ query_params: {}, body: nil, logger: nil)
12
+ uri = URI.join("https://#{instance_name}/", 'entity/', "#{endpoint_name}/", "#{endpoint_version}/",
13
+ path.to_s)
14
+ uri.query = URI.encode_www_form(query_params) unless query_params.empty?
15
+
16
+ http = Net::HTTP.new(uri.host, uri.port)
17
+ http.use_ssl = uri.scheme == 'https'
18
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
+ http.set_debug_output(logger) unless logger.nil?
20
+
21
+ request_class = case method
22
+ when :get then Net::HTTP::Get
23
+ when :post then Net::HTTP::Post
24
+ when :put then Net::HTTP::Put
25
+ when :delete then Net::HTTP::Delete
26
+ end
27
+
28
+ request = request_class.new(uri)
29
+ request['Authorization'] = "Bearer #{access_token}"
30
+ request['Content-Type'] = content_type
31
+ request['Accept'] = accept
32
+ request.body = content_type == 'application/json' ? body.to_json : body
33
+
34
+ response = http.request(request)
35
+
36
+ case response
37
+ when Net::HTTPAccepted
38
+ { 'location' => response['Location'] }
39
+ when Net::HTTPNoContent
40
+ nil
41
+ when Net::HTTPSuccess
42
+ response.body.empty? ? nil : JSON.parse(response.body)
43
+ else
44
+ raise MyobAcumatica::Error, "HTTP #{response.code}: #{response.body}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end