-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
netsuite_endpoint.rb
252 lines (207 loc) · 7.62 KB
/
netsuite_endpoint.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
require "sinatra"
require "endpoint_base"
require File.expand_path(File.dirname(__FILE__) + '/lib/netsuite_integration')
class NetsuiteEndpoint < EndpointBase::Sinatra::Base
endpoint_key ENV["ENDPOINT_KEY"]
Honeybadger.configure do |config|
config.api_key = ENV['HONEYBADGER_KEY']
config.environment_name = ENV['RACK_ENV']
end if ENV['HONEYBADGER_KEY'].present?
set :logging, true
# Make sure sinatra error handlers run
set :show_exceptions, :after_handler
error Errno::ENOENT do
result 500, env['sinatra.error'].message
end
error Savon::SOAPFault do
result 500, env['sinatra.error'].to_s
end
before do
if config = @config
@netsuite_client ||= NetSuite.configure do
reset!
if config['netsuite_wsdl_url'].present?
wsdl config['netsuite_wsdl_url']
end
if config['netsuite_api_version'].present?
api_version config['netsuite_api_version']
else
api_version "2013_2"
end
if config['netsuite_role'].present?
role config['netsuite_role']
else
role 3
end
sandbox config.fetch('netsuite_sandbox', false)
email config.fetch('netsuite_email')
password config.fetch('netsuite_password')
account config.fetch('netsuite_account')
read_timeout 175
log_level :info
end
end
end
post '/get_products' do
products = NetsuiteIntegration::Product.new(@config)
if products.collection.any?
products.messages.each do |message|
add_object "product", message
end
add_parameter 'netsuite_last_updated_after', products.last_modified_date
count = products.messages.count
@summary = "#{count} #{"item".pluralize count} found in NetSuite"
end
result 200, @summary
end
post '/add_order' do
begin
create_or_update_order
rescue NetSuite::RecordNotFound => e
result 500, e.message
rescue NetsuiteIntegration::CreationFailCustomerException => e
result 500, "Could not save customer #{@payload[:order][:email]}: #{e.message}"
rescue NetsuiteIntegration::NonInventoryItemException => e
result 500, e.message
rescue => e
log_exception(e)
result 500, e.message
end
end
post '/update_order' do
begin
create_or_update_order
rescue NetSuite::RecordNotFound => e
result 500, e.message
rescue NetsuiteIntegration::CreationFailCustomerException => e
result 500, "Could not save customer with id #{@payload[:order][:email]}"
rescue NetsuiteIntegration::NonInventoryItemException => e
result 500, e.message
rescue => e
log_exception(e)
result 500, e.message
end
end
post '/cancel_order' do
if order = sales_order_service.find_by_external_id(@payload[:order][:number] || @payload[:order][:id])
if customer_record_exists?
refund = NetsuiteIntegration::Refund.new(@config, @payload, order)
if refund.process!
summary = "Customer Refund created and NetSuite Sales Order #{@payload[:order][:number]} was closed"
result 200, summary
else
summary = "Failed to create a Customer Refund and close the NetSuite Sales Order #{@payload[:order][:number]}"
result 500, summary
end
else
sales_order_service.close!(order)
result 200, "NetSuite Sales Order #{@payload[:order][:number]} was closed"
end
else
result 500, "NetSuite Sales Order not found for order #{@payload[:order][:number] || @payload[:order][:id]}"
end
end
post '/get_inventory' do
begin
stock = NetsuiteIntegration::InventoryStock.new(@config, @payload)
if stock.collection? && stock.inventory_units.present?
stock.inventory_units.each { |unit| add_object :inventory, unit }
count = stock.inventory_units.count
summary = "#{count} #{"inventory units".pluralize count} fetched from NetSuite"
add_parameter 'netsuite_poll_stock_timestamp', stock.last_modified_date
elsif stock.sku.present?
add_object :inventory, { id: stock.sku, sku: stock.sku, quantity: stock.quantity_available }
count = stock.quantity_available
summary = "#{count} #{"unit".pluralize count} available of #{stock.sku} according to NetSuite"
end
result 200, summary
rescue NetSuite::RecordNotFound
result 200
rescue => e
log_exception(e)
result 500, e.message
end
end
post '/get_shipments' do
begin
shipment = NetsuiteIntegration::Shipment.new(@config, @payload)
if !shipment.latest_fulfillments.empty?
count = shipment.latest_fulfillments.count
summary = "#{count} #{"shipment".pluralize count} found in NetSuite"
add_parameter 'netsuite_poll_fulfillment_timestamp', shipment.last_modified_date
shipment.messages.each { |s| add_object :shipment, s }
result 200, summary
else
result 200
end
rescue NetSuite::RecordNotFound => e
result 500, e.message
rescue => e
log_exception(e)
result 500, e.message
end
end
post '/add_shipment' do
begin
order = NetsuiteIntegration::Shipment.new(@config, @payload).import
result 200, "Order #{order.external_id} fulfilled in NetSuite # #{order.tran_id}"
end
end
private
def create_or_update_order
order = NetsuiteIntegration::Order.new(@config, @payload)
error_notification = ""
summary = ""
if order.imported?
if order.update
summary << "Order #{order.existing_sales_order.external_id} updated on NetSuite # #{order.existing_sales_order.tran_id}"
else
error_notification << "Failed to update order #{order.sales_order.external_id} into Netsuite: #{order.errors}"
end
else
if order.create
summary << "Order #{order.sales_order.external_id} sent to NetSuite # #{order.sales_order.tran_id}"
else
error_notification << "Failed to import order #{order.sales_order.external_id} into Netsuite: #{order.errors}"
end
end
if order.paid? && !error_notification.present?
customer_deposit = NetsuiteIntegration::Services::CustomerDeposit.new(@config, @payload)
records = customer_deposit.create_records order.sales_order
errors = records.map(&:errors).compact.flatten
errors = errors.map(&:message).flatten
if errors.any?
error_notification << " Failed to set up Customer Deposit for #{(order.existing_sales_order || order.sales_order).external_id}: #{errors.join(", ")}"
end
if customer_deposit.persisted
summary << ". Customer Deposit set up for Sales Order #{(order.existing_sales_order || order.sales_order).tran_id}"
end
end
if any_payments_void? && !error_notification.present?
refund = NetsuiteIntegration::Refund.new(@config, @payload, order.existing_sales_order, "void")
unless refund.service.find_by_external_id(refund.deposits)
if refund.create
summary << ". Customer Refund created for #{@payload[:order][:number]}"
else
error_notification << "Failed to create a Customer Refund for order #{@payload[:order][:number]}"
end
end
end
if error_notification.present?
result 500, error_notification
else
result 200, summary
end
end
def customer_record_exists?
@payload[:order][:payments] && @payload[:order][:payments].any?
end
def sales_order_service
@sales_order_service ||= NetsuiteIntegration::Services::SalesOrder.new(@config)
end
def any_payments_void?
@payload[:order][:payments].any? do |p|
p[:status] == "void"
end
end
end