spree_fosdick_integration 0.0.3

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/Gemfile +21 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +76 -0
  6. data/Rakefile +15 -0
  7. data/app/controllers/spree/admin/fosdick_shipments_controller.rb +18 -0
  8. data/app/mailers/spree/fosdick_shipment_mailer.rb +13 -0
  9. data/app/models/spree/fosdick_exception.rb +15 -0
  10. data/app/models/spree/fosdick_shipment.rb +8 -0
  11. data/app/models/spree/shipment_decorator.rb +17 -0
  12. data/app/overrides/add_fosdick_panel.rb +8 -0
  13. data/app/serializers/address_serializer.rb +18 -0
  14. data/app/serializers/inventory_unit_serializer.rb +21 -0
  15. data/app/serializers/shipment_serializer.rb +104 -0
  16. data/app/services/exception_logger.rb +21 -0
  17. data/app/views/spree/admin/fosdick_shipments/_filters_bar.html.haml +36 -0
  18. data/app/views/spree/admin/fosdick_shipments/_fosdick_shipments_list.html.haml +28 -0
  19. data/app/views/spree/admin/fosdick_shipments/_fosdick_shipments_list_respond.js.erb +1 -0
  20. data/app/views/spree/admin/fosdick_shipments/_titles.html.haml +5 -0
  21. data/app/views/spree/admin/fosdick_shipments/index.html.haml +3 -0
  22. data/app/views/spree/admin/fosdick_shipments/index.js.haml +1 -0
  23. data/app/views/spree/fosdick_shipment_mailer/order_shipped.html.erb +135 -0
  24. data/config/locales/en.yml +14 -0
  25. data/config/locales/ru.yml +14 -0
  26. data/config/routes.rb +10 -0
  27. data/db/migrate/20151013153126_create_spree_fosdick_shipment.rb +17 -0
  28. data/db/migrate/20151015122038_create_fosdick_exceptions.rb +15 -0
  29. data/db/migrate/20151028105216_add_fosdick_atempt_and_state_spree_shipments.rb +6 -0
  30. data/lib/fosdick/documents/shipment.rb +89 -0
  31. data/lib/fosdick/processor.rb +64 -0
  32. data/lib/fosdick/receiver.rb +49 -0
  33. data/lib/fosdick/sender.rb +39 -0
  34. data/lib/generators/spree_fosdick_integration/install/install_generator.rb +32 -0
  35. data/lib/generators/spree_fosdick_integration/install/templates/fosdick.rb +6 -0
  36. data/lib/generators/spree_fosdick_integration/install/templates/fosdick.yml.template +18 -0
  37. data/lib/spree_fosdick_integration.rb +8 -0
  38. data/lib/spree_fosdick_integration/engine.rb +22 -0
  39. data/lib/spree_fosdick_integration/factories.rb +31 -0
  40. data/lib/spree_fosdick_integration/version.rb +3 -0
  41. data/script/rails +7 -0
  42. data/spec/controllers/admin/fosdick_shipments_controller_spec.rb +16 -0
  43. data/spec/models/spree/fosdick_exception_spec.rb +21 -0
  44. data/spec/models/spree/fosdick_shipment_spec.rb +9 -0
  45. data/spec/models/spree/shipment_spec.rb +50 -0
  46. data/spec/services/exception_logger_spec.rb +11 -0
  47. data/spec/services/fosdick/processor_spec.rb +94 -0
  48. data/spec/services/fosdick/receiver_spec.rb +43 -0
  49. data/spec/services/fosdick/sender_spec.rb +34 -0
  50. data/spec/spec_helper.rb +99 -0
  51. data/spree_fosdick_integration.gemspec +37 -0
  52. metadata +286 -0
@@ -0,0 +1,39 @@
1
+ module Fosdick
2
+ class Sender
3
+ include HTTParty
4
+ base_uri FOSDICK_CONFIG['ipost_uri']
5
+ format :xml
6
+
7
+ def self.send_doc(doc, config)
8
+ client = config['client_name']
9
+
10
+ begin
11
+ # required sleep 2 sec for Fosdick Shopping Cart iPost interface
12
+ sleep 2
13
+ res = post("/#{client}/cart/ipost.asp", body: doc)
14
+ rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError,
15
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
16
+
17
+ raise Fosdick::SendError
18
+ end
19
+ return validate_and_return(res)
20
+ end
21
+
22
+ private
23
+
24
+ def self.validate_and_return(response)
25
+ order_response = response['UnitycartOrderResponse']['OrderResponse']
26
+
27
+ if order_response['SuccessCode'] == 'True'
28
+ order_response['OrderNumber']
29
+ else
30
+ {
31
+ code: order_response['ErrorCode'],
32
+ errors: order_response['Errors']
33
+ }
34
+ end
35
+ end
36
+ end
37
+
38
+ class SendError < StandardError; end
39
+ end
@@ -0,0 +1,32 @@
1
+ module SpreeFosdickIntegration
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+
5
+ class_option :auto_run_migrations, type: :boolean, default: false
6
+
7
+ def self.source_paths
8
+ paths = self.superclass.source_paths
9
+ paths << File.expand_path('../templates', __FILE__)
10
+ paths.flatten
11
+ end
12
+
13
+ def add_migrations
14
+ run 'bundle exec rake railties:install:migrations FROM=spree_fosdick_integration'
15
+ end
16
+
17
+ def run_migrations
18
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask 'Would you like to run the migrations now? [Y/n]')
19
+ if run_migrations
20
+ run 'bundle exec rake db:migrate'
21
+ else
22
+ puts 'Skipping rake db:migrate, don\'t forget to run it!'
23
+ end
24
+ end
25
+
26
+ def copy_initializer
27
+ copy_file 'fosdick.yml.template', 'config/fosdick.yml'
28
+ copy_file 'fosdick.rb', 'config/initializers/fosdick.rb'
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ FOSDICK_CONFIG = YAML.load_file("#{Rails.root}/config/fosdick.yml")[Rails.env]
2
+ FOSDICK_STATES_EXCEPTIONS = {
3
+ 'U.S. Armed Forces – Americas' => 'AA',
4
+ 'U.S. Armed Forces – Europe' => 'AE',
5
+ 'U.S. Armed Forces – Pacific' => 'AP'
6
+ }
@@ -0,0 +1,18 @@
1
+ defaults: &defaults
2
+ test: true
3
+ ipost_uri: 'https://www.unitycart.com'
4
+ client_name: test
5
+ adcode: TEST
6
+ client_code: ad54LIADFJ2754
7
+ basic_auth:
8
+ login: CLIENTTEST
9
+ password: TESTPW22415
10
+
11
+ test:
12
+ <<: *defaults
13
+ development:
14
+ <<: *defaults
15
+ staging:
16
+ <<: *defaults
17
+ production:
18
+ <<: *defaults
@@ -0,0 +1,8 @@
1
+ require 'spree_core'
2
+ require 'spree_fosdick_integration/engine'
3
+
4
+ require 'spree_fosdick_integration/version'
5
+
6
+ module SpreeFosdickIntegration
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,22 @@
1
+ module SpreeFosdickIntegration
2
+ class Engine < Rails::Engine
3
+ require 'spree/core'
4
+ isolate_namespace Spree
5
+ engine_name 'spree_fosdick_integration'
6
+
7
+ config.autoload_paths += %W(#{config.root}/lib)
8
+
9
+ # use rspec for tests
10
+ config.generators do |g|
11
+ g.test_framework :rspec
12
+ end
13
+
14
+ def self.activate
15
+ Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
16
+ Rails.configuration.cache_classes ? require(c) : load(c)
17
+ end
18
+ end
19
+
20
+ config.to_prepare &method(:activate).to_proc
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ FactoryGirl.define do
2
+ # Example adding this to your spec_helper will load these Factories for use:
3
+ # require 'spree_fosdick_integration/factories'
4
+
5
+ factory :fosdick_shipment, class: Spree::FosdickShipment do
6
+ shipment
7
+ fosdick_order_num '5177595188'
8
+ external_order_num 'H28547338764'
9
+ tracking_number nil
10
+ state 'sent'
11
+ confirmation_sent false
12
+ ship_date nil
13
+
14
+ factory :fosdick_shipment_shipped do
15
+ fosdick_order_num '00501201556352008'
16
+ tracking_number ['9261295598944533641919']
17
+ state 'shipped'
18
+ confirmation_sent true
19
+ ship_date {Time.zone.now}
20
+ end
21
+ end
22
+
23
+ factory :fosdick_exception, class: Spree::FosdickException do
24
+ fosdick_shipment
25
+
26
+ error_code 'Error'
27
+ message 'Error - Unknown Shipping Method: 0099DEX'
28
+ state 'error'
29
+ happened_at {Time.zone.now}
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module SpreeFosdickIntegration
2
+ VERSION = '0.0.3'
3
+ end
@@ -0,0 +1,7 @@
1
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
2
+
3
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
4
+ ENGINE_PATH = File.expand_path('../../lib/spree_abandoned_cart/engine', __FILE__)
5
+
6
+ require 'rails/all'
7
+ require 'rails/engine/commands'
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Spree::Admin::FosdickShipmentsController, type: :controller do
4
+ describe '#index' do
5
+ let!(:fosdick_shipment) { create :fosdick_shipment }
6
+ let!(:admin) { create :admin_user }
7
+ before { sign_in(admin) }
8
+
9
+ it 'should have 200 response' do
10
+ get :index, { use_route: SpreeFosdickIntegration }
11
+
12
+ expect(response.status).to eq(200)
13
+ expect(assigns[:fosdick_shipments]).to eq [fosdick_shipment]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Spree::FosdickException, type: :model do
4
+ describe 'relationships with other entities' do
5
+ it { should belong_to(:fosdick_shipment).class_name('Spree::FosdickShipment')}
6
+ end
7
+
8
+ describe 'instance methods' do
9
+ let(:shipment) {create :shipment}
10
+ let(:fosdick_shipment) {create :fosdick_shipment, shipment: shipment}
11
+ let(:fosdick_exception) {create :fosdick_exception, fosdick_shipment: fosdick_shipment}
12
+
13
+ it 'should update fosdick state of a shipment after creation' do
14
+ expect(fosdick_exception.shipment.fosdick_state).to eq 'exception'
15
+ end
16
+
17
+ it 'should return shipment for current fosdick exception' do
18
+ expect(fosdick_exception.shipment).to eq shipment
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Spree::FosdickShipment, type: :model do
4
+ describe 'relationships with other entities' do
5
+ it { should belong_to(:shipment).class_name('Spree::Shipment')}
6
+ it { should have_many(:fosdick_exceptions)}
7
+ it { should serialize(:tracking_number) }
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Spree::Shipment, type: :model do
4
+ describe 'relationships with other entities' do
5
+ it { should have_one(:fosdick_shipment)}
6
+ end
7
+
8
+ describe 'class methods' do
9
+ let!(:shipment) { create :shipment, shipped_at: nil, state: 'ready', send_atempt: 0 }
10
+ let!(:result) { JSON.parse(
11
+ { 'id'=>'H58716774464',
12
+ 'order_id'=>'R547700419',
13
+ 'email'=>'georgiana@armstrong.co.uk',
14
+ 'cost'=>100.0,
15
+ 'status'=>'ready',
16
+ 'stock_location'=>'NY Warehouse',
17
+ 'shipping_method'=>nil,
18
+ 'tracking'=>'U10000',
19
+ 'placed_on'=>'',
20
+ 'shipped_at'=>nil,
21
+ 'totals'=>
22
+ { 'item'=>'$0.00',
23
+ 'adjustment'=>'$0.00',
24
+ 'tax'=>'$0.00',
25
+ 'shipping'=>'$0.00',
26
+ 'payment'=>'0.0',
27
+ 'order'=>'$0.00'},
28
+ 'updated_at'=>'2015-11-13T13:18:31Z',
29
+ 'channel'=>'spree',
30
+ 'items'=>[],
31
+ 'shipping_method_code'=>'UPS_GROUND',
32
+ 'billing_address'=>
33
+ { 'firstname'=>'John',
34
+ 'lastname'=>'Doe',
35
+ 'address1'=>'10 Lovely Street',
36
+ 'address2'=>'Northwest',
37
+ 'zipcode'=>'35005',
38
+ 'city'=>'Herndon',
39
+ 'state'=>'AL',
40
+ 'country'=>'US',
41
+ 'phone'=>'555-555-0199'},
42
+ 'shipping_address'=>nil}.to_json) }
43
+
44
+ before { allow(ActiveModel::ArraySerializer).to receive(:new).and_return([result]) }
45
+
46
+ it 'should perform shipments to fosdick' do
47
+ expect(Spree::Shipment.perform_fosdick_shipments).to eq [result]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ExceptionLogger, type: :services do
4
+ let!(:fosdick_shipment) { create :fosdick_shipment }
5
+
6
+ it 'should log exceptions' do
7
+ ExceptionLogger.new.log('Error', 'Error - Unknown Shipping Method: 0099DEX', fosdick_shipment.id)
8
+
9
+ expect(Spree::FosdickException.last.fosdick_shipment).to eq fosdick_shipment
10
+ end
11
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Fosdick::Processor, type: :services do
4
+ before { stub_const 'FOSDICK_CONFIG', {
5
+ 'test' =>true,
6
+ 'ipost_uri' =>'https://www.unitycart.com',
7
+ 'client_name' =>'test',
8
+ 'adcode' =>'TEST',
9
+ 'client_code' =>'TEST_CODE',
10
+ 'basic_auth' =>{
11
+ 'login' =>'TESTLOG',
12
+ 'password'=>'password'}
13
+ }}
14
+
15
+ let(:config) { FOSDICK_CONFIG }
16
+ let!(:order_ready_to_ship) {create :order_ready_to_ship}
17
+
18
+ describe 'sender service logic' do
19
+ let(:doc) {Fosdick::Documents::Shipment.new(Spree::Shipment.perform_fosdick_shipments.first, config).to_xml}
20
+ let(:response) { '<UnitycartOrderResponse xml:lang="en-US">
21
+ <OrderResponse ExternalID="YourID">
22
+ <SuccessCode>True</SuccessCode>
23
+ <OrderNumber>2679987865</OrderNumber>
24
+ </OrderResponse>
25
+ </UnitycartOrderResponse>'}
26
+
27
+ before {
28
+ stub_request(:post, "https://www.unitycart.com/test/cart/ipost.asp").
29
+ with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
30
+ to_return(:status => 200, :body => response, :headers => {})
31
+ }
32
+
33
+ it 'should send new shipment to fosdick' do
34
+ eligible_shipment = Spree::Shipment.perform_fosdick_shipments.last
35
+
36
+ expect{Fosdick::Processor.send_shipment(eligible_shipment, config)}.to change{Spree::FosdickShipment.count}.from(0).to(1)
37
+ expect(Spree::FosdickShipment.last.external_order_num).to eq order_ready_to_ship.shipments.first.number
38
+ expect(Spree::FosdickShipment.last.fosdick_order_num).to eq '2679987865'
39
+ expect(Spree::FosdickShipment.last.state).to eq 'sent'
40
+ expect(Spree::FosdickShipment.last.tracking_number).to eq nil
41
+ expect(Spree::FosdickShipment.last.ship_date).to eq nil
42
+
43
+ expect(Spree::Shipment.last.state).to eq 'shipped'
44
+ expect(Spree::Shipment.last.fosdick_state).to eq 'success'
45
+ end
46
+ end
47
+
48
+ describe 'receiver service logic' do
49
+ let!(:fosdick_shipment) {create :fosdick_shipment, external_order_num: 'H0011001',
50
+ spree_shipment_id: order_ready_to_ship.shipments.last.id,
51
+ tracking_number: nil}
52
+ let(:response) { '[
53
+ {
54
+ "fosdick_order_num": "00101201506460001",
55
+ "external_order_num": "H0011001",
56
+ "ship_date": "2015-02-06",
57
+ "trackings": [
58
+ {
59
+ "tracking_num": "9274899998944522337",
60
+ "carrier_code": "92",
61
+ "carrier_name": "FEDEX SMART POST"
62
+ },
63
+ {
64
+ "tracking_num": "9274899998944599999",
65
+ "carrier_code": "92",
66
+ "carrier_name": "FEDEX SMART POST"
67
+ }
68
+ ]
69
+ }]'}
70
+
71
+ before {
72
+ stub_request(:get, "https://www.customerstatus.com/fosdickapi/shipmentdetail.json?external_order_num=#{fosdick_shipment.external_order_num}").
73
+ with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
74
+ to_return(:status => 200, :body => response, :headers => {})
75
+ }
76
+
77
+ before { Spree::Shipment.last.update_column(:number, 'H0011001')}
78
+ before { ActionMailer::Base.deliveries.clear }
79
+
80
+ it 'should receive shipment details from fosdick' do
81
+ Fosdick::Processor.receive_shipment({external_order_num: 'H0011001'}, 'shipmentdetail.json' )
82
+
83
+ expect(Spree::FosdickShipment.last.tracking_number).to eq (['9274899998944522337', '9274899998944599999'])
84
+ expect(Spree::FosdickShipment.last.confirmation_sent).to eq true
85
+ expect(Spree::FosdickShipment.last.ship_date).to eq '2015-02-06 00:00:00'
86
+ expect(Spree::FosdickShipment.last.fosdick_order_num).to eq '00101201506460001'
87
+ end
88
+
89
+ it 'should notify user by email that order shipped' do
90
+
91
+ expect{Fosdick::Processor.receive_shipment({external_order_num: 'H0011001'}, 'shipmentdetail.json' )}.to change{ActionMailer::Base.deliveries.count}.from(0).to(1)
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ RSpec.describe Fosdick::Receiver, type: :services do
5
+ before { stub_const 'FOSDICK_CONFIG', {
6
+ 'test' =>true,
7
+ 'ipost_uri' =>'https://www.unitycart.com',
8
+ 'client_name' =>'test',
9
+ 'adcode' =>'TEST',
10
+ 'client_code' =>'TEST_CODE',
11
+ 'basic_auth' =>{
12
+ 'login' =>'TESTLOG',
13
+ 'password'=>'password'}
14
+ }}
15
+
16
+ let(:fosdick_shipment) {create :fosdick_shipment}
17
+ let(:config) { FOSDICK_CONFIG }
18
+ let(:response) { '[
19
+ {
20
+ "fosdick_order_num": "00101201506460001",
21
+ "external_order_num": "0011001",
22
+ "ship_date": "2015-02-06",
23
+ "trackings": [
24
+ {
25
+ "tracking_num": "9274899998944522337",
26
+ "carrier_code": "92",
27
+ "carrier_name": "FEDEX SMART POST"
28
+ },
29
+ {
30
+ "tracking_num": "9274899998944599999",
31
+ "carrier_code": "92",
32
+ "carrier_name": "FEDEX SMART POST"
33
+ }
34
+ ]
35
+ }]'}
36
+
37
+ before {
38
+ stub_request(:get, "https://www.customerstatus.com/fosdickapi/shipmentdetail.json?external_order_num=#{fosdick_shipment.external_order_num}").
39
+ with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
40
+ to_return(:status => 200, :body => response, :headers => {})
41
+ }
42
+ it {expect(Fosdick::Receiver.new('shipmentdetail.json', {external_order_num: fosdick_shipment.external_order_num}).call_api(config)).to eq JSON.parse(response)}
43
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Fosdick::Sender, type: :services do
4
+ before { stub_const 'FOSDICK_CONFIG', {
5
+ 'test' =>true,
6
+ 'ipost_uri' =>'https://www.unitycart.com',
7
+ 'client_name' =>'test',
8
+ 'adcode' =>'TEST',
9
+ 'client_code' =>'TEST_CODE',
10
+ 'basic_auth' =>{
11
+ 'login' =>'TESTLOG',
12
+ 'password'=>'password'}
13
+ }}
14
+
15
+ let!(:order_ready_to_ship) {create :order_ready_to_ship}
16
+
17
+ let(:config) { FOSDICK_CONFIG }
18
+ let(:doc) {Fosdick::Documents::Shipment.new(Spree::Shipment.perform_fosdick_shipments.first, config).to_xml}
19
+ let(:response) { '<UnitycartOrderResponse xml:lang="en-US">
20
+ <OrderResponse ExternalID="YourID">
21
+ <SuccessCode>True</SuccessCode>
22
+ <OrderNumber>2679987865</OrderNumber>
23
+ </OrderResponse>
24
+ </UnitycartOrderResponse>'}
25
+
26
+ before {
27
+ stub_request(:post, "https://www.unitycart.com/test/cart/ipost.asp").
28
+ with(:body => doc,
29
+ :headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
30
+ to_return(:status => 200, :body => response, :headers => {})
31
+ }
32
+
33
+ it {expect(Fosdick::Sender.send_doc(doc, config)).to eq '2679987865'}
34
+ end