Created
October 20, 2016 23:01
Star
You must be signed in to star a gist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Michael Bianco <mike@suitesync.io> | |
# Description: Boilerplate implementing linking Stripe Charges to NetSuite Invoices | |
# Documentation: Reach out to SuiteSync for additional documentation! | |
# requires the following environment variables: | |
# | |
# STRIPE_KEY | |
# NETSUITE_EMAIL | |
# NETSUITE_PASSWORD | |
# NETSUITE_ACCOUNT | |
require 'stripe' | |
require 'netsuite' | |
# Replace this test mode key and run this example on your account | |
Stripe.api_key = ENV['STRIPE_TEST_KEY'] | |
NetSuite.configure do | |
reset! | |
# NOTE that API versions > 2015_1 require a more complicated authentication setup | |
api_version '2015_1' | |
read_timeout 60 * 3 | |
silent ENV['NETSUITE_SILENT'].nil? || ENV['NETSUITE_SILENT'] == 'true' | |
email ENV['NETSUITE_EMAIL'] | |
password ENV['NETSUITE_PASSWORD'] | |
account ENV['NETSUITE_ACCOUNT'] | |
soap_header({ | |
'platformMsgs:preferences' => { | |
'platformMsgs:ignoreReadOnlyFields' => true, | |
} | |
}) | |
end | |
# Fake order class to generate a Stripe customer, charge, and NS items | |
class Order | |
class << self | |
def find(*) | |
customer = create_stripe_customer | |
create_stripe_token_with_customer(customer) | |
charge = Stripe::Charge.create( | |
amount: 10_00, | |
currency: "usd", | |
customer: customer.id, | |
# this is optional. The `description` is passed through to the CustomerPayment memo field | |
description: "A Stripe shirt and NetSuite shoes", | |
metadata: { | |
# more info on this feature: https://dashboard.suitesync.io/docs/field-customization#controlling-when-records-are-created-in-netsuite | |
netsuite_block_translation: true | |
} | |
) | |
OpenStruct.new( | |
stripe_charge_id: charge.id, | |
# NOTE this is just an example ID of a customer in NetSuite to faciliate creating a SalesOrder! | |
# https://system.na1.netsuite.com/app/common/entity/custjoblist.nl | |
netsuite_customer_id: 235724, | |
items: [ | |
OpenStruct.new( | |
netsuite_id: create_netsuite_item.internal_id, | |
quantity: 1, | |
price: 10.0 | |
) | |
], | |
number: "T#{Time.now.to_i}" | |
) | |
end | |
private | |
def create_netsuite_item | |
ns_inventory_item = NetSuite::Records::InventoryItem.new( | |
item_id: "suitesync_test_item", | |
display_name: "SuiteSync Test Item", | |
external_id: "suitesync_test_item", | |
) | |
# in order to fulfill this item in a testing environment, you'll need to adjust the inventory | |
# https://system.na1.netsuite.com/app/accounting/transactions/invadjst.nl | |
NetSuite::Utilities.backoff { ns_inventory_item.upsert } | |
if NetSuite::Utilities.request_failed?(ns_inventory_item) | |
fail("failed to upsert item. #{ns_inventory_item.errors}") | |
end | |
ns_inventory_item | |
end | |
def create_stripe_customer | |
Stripe::Customer.create(description: "Customer") | |
end | |
def create_stripe_token_with_customer(stripe_customer) | |
# Create a card token to be associated with a customer. This is normally done | |
# on your payment frontend using Stripe.js https://stripe.com/docs/custom-form | |
card_token = Stripe::Token.create( | |
:card => { | |
:number => '4242424242424242', | |
:exp_month => 8, | |
:exp_year => (Date.today>>24).year, | |
:cvc => "314", | |
} | |
) | |
stripe_customer.sources.create(card: card_token.id) | |
end | |
end | |
end | |
class NetSuiteWorker | |
def perform(type) | |
order = Order.find | |
netsuite_class = if type == :sales_order | |
NetSuite::Records::SalesOrder | |
elsif type == :invoice | |
NetSuite::Records::Invoice | |
end | |
ns_order = netsuite_class.new( | |
# It is highly recommended to use the order unique identifier as the external ID | |
external_id: order.number, | |
entity: { internal_id: order.netsuite_customer_id }, | |
item_list: build_item_list(order), | |
) | |
# This custom field must be created in NetSuite | |
ns_order.custom_field_list.custbody_suitesync_authorization_code = order.stripe_charge_id | |
NetSuite::Utilities.backoff { ns_order.upsert } | |
if NetSuite::Utilities.request_failed?(ns_order) | |
fail("failed to upsert order. #{ns_order.errors}") | |
end | |
ns_order | |
end | |
protected | |
def build_item_list(order) | |
items = order.items.map do |line_item| | |
{ | |
item: { internal_id: line_item.netsuite_id }, | |
quantity: line_item.quantity, | |
rate: line_item.price | |
} | |
end | |
{ item: items } | |
end | |
end | |
ns_invoice = NetSuiteWorker.new.perform(:invoice) | |
# A SalesOrder must be billed to create an Invoice | |
# once an invoice is created, SuiteSync will create a CustomerPayment and apply it to the invoice | |
ns_order = NetSuiteWorker.new.perform(:sales_order) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment