Skip to content

Commit 6154418

Browse files
committed
Initial commit
0 parents  commit 6154418

29 files changed

+604
-0
lines changed

.gitignore

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
\#*
2+
*~
3+
.#*
4+
.DS_Store
5+
.idea
6+
.project
7+
.sass-cache
8+
coverage
9+
Gemfile.lock
10+
tmp
11+
nbproject
12+
pkg
13+
*.swp
14+
spec/dummy
15+
.bundle
16+
.rvmrc
17+
.ruby-version
18+
.ruby-gemset

.rspec

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--color

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source 'https://rubygems.org'
2+
3+
gemspec

LICENSE

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Copyright (c) 2016 [name of plugin creator]
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without modification,
5+
are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright notice,
8+
this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above copyright notice,
10+
this list of conditions and the following disclaimer in the documentation
11+
and/or other materials provided with the distribution.
12+
* Neither the name Spree nor the names of its contributors may be used to
13+
endorse or promote products derived from this software without specific
14+
prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
Spree Shapco
2+
================
3+
4+
Integrates a Spree store with the [Shapco fulfillment service](http://3plcentral.com).
5+
6+
## Installation
7+
8+
1. Add this extension to your Gemfile with this line:
9+
```ruby
10+
gem 'spree_shapco', github: 'cehdeti/spree_shapco', branch: 'master'
11+
```
12+
13+
2. Install the gem using Bundler:
14+
```ruby
15+
bundle install
16+
```
17+
18+
3. Copy & run migrations
19+
```ruby
20+
bundle exec rails g spree_shapco:install
21+
```
22+
23+
4. Restart your server
24+
25+
If your server was running, restart it so that it can find the assets properly.
26+
27+
## Testing
28+
29+
First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.
30+
31+
```shell
32+
bundle
33+
bundle exec rake
34+
```
35+
36+
When testing your applications integration with this extension you may use it's factories.
37+
Simply add this require statement to your spec_helper:
38+
39+
```ruby
40+
require 'spree_shapco/factories'
41+
```
42+
43+
44+
## Contributing
45+
46+
If you'd like to contribute, please take a look at the
47+
[instructions](CONTRIBUTING.md) for installing dependencies and crafting a good
48+
pull request.
49+
50+
Copyright (c) 2016 [name of extension creator], released under the New BSD License

Rakefile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
require 'bundler'
2+
Bundler::GemHelper.install_tasks
3+
4+
require 'rspec/core/rake_task'
5+
require 'spree/testing_support/extension_rake'
6+
7+
RSpec::Core::RakeTask.new
8+
9+
task :default do
10+
if Dir["spec/dummy"].empty?
11+
Rake::Task[:test_app].invoke
12+
Dir.chdir("../../")
13+
end
14+
Rake::Task[:spec].invoke
15+
end
16+
17+
desc 'Generates a dummy app for testing'
18+
task :test_app do
19+
ENV['LIB_NAME'] = 'spree_shapco'
20+
Rake::Task['extension:test_app'].invoke
21+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module Spree
2+
module Admin
3+
class ShapcoSettingsController < Spree::Admin::BaseController
4+
CREDENTIAL_FIELDS = [
5+
:shapco_username,
6+
:shapco_password,
7+
:shapco_subscriber_id
8+
].freeze
9+
10+
before_action :set_fields, :set_shipping_categories
11+
12+
def edit
13+
end
14+
15+
def update
16+
params.slice(*@fields).each do |name, value|
17+
Spree::Config[name] = value if Spree::Config.has_preference? name
18+
end
19+
20+
@error = SpreeShapco.test
21+
22+
if @error
23+
render :edit
24+
else
25+
flash[:success] = Spree.t(:successfully_updated, resource: Spree.t(:shapco_settings))
26+
redirect_to edit_admin_shapco_settings_path
27+
end
28+
end
29+
30+
private
31+
32+
def set_fields
33+
@credential_fields = CREDENTIAL_FIELDS
34+
@fields = @credential_fields.freeze
35+
@savon = ThreePLCentral.savon_config
36+
end
37+
38+
def set_shipping_categories
39+
@shipping_categories = Spree::ShippingCategory.with_shapco
40+
end
41+
end
42+
end
43+
end

app/models/spree/address_decorator.rb

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Spree::Address.class_eval do
2+
def as_shapco
3+
name = "#{firstname} #{lastname}"
4+
5+
{
6+
name: name,
7+
company_name: company || name || "None",
8+
phone_number1: phone,
9+
address: {
10+
address1: address1, address2: address2, city: city, state: state.abbr,
11+
zip: zipcode, country: country.name
12+
}
13+
}
14+
end
15+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Spree::AppConfiguration.class_eval do
2+
preference :shapco_username, :string
3+
preference :shapco_password, :password
4+
preference :shapco_subscriber_id, :string
5+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module ShapcoOrderUpdater
2+
def update_payment_state
3+
initial_state = order.payment_state
4+
super.tap { create_shapco_order if initial_state != 'paid' && order.payment_state == 'paid' }
5+
end
6+
7+
private
8+
9+
def create_shapco_order
10+
order.shipments.send_to_shapco.each(&:send_to_shapco)
11+
end
12+
end
13+
14+
Spree::OrderUpdater.class_eval do
15+
prepend ShapcoOrderUpdater
16+
end
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Spree::Shipment.class_eval do
2+
SHAPCO_SUCCESS_RESPONSE = '1'.freeze
3+
4+
scope :with_shapco, -> { joins(:shipping_methods).merge(Spree::ShippingMethod.with_shapco) }
5+
scope :sent_to_shapco, -> { where(sent_to_shapco: true) }
6+
scope :not_sent_to_shapco, -> { where(sent_to_shapco: false) }
7+
scope :send_to_shapco, -> { distinct.merge(with_shapco).merge(not_sent_to_shapco) }
8+
9+
def logger
10+
rails_logger = Rails.logger
11+
model_logger = super
12+
model_logger.is_a?(rails_logger.class) ? model_logger : rails_logger
13+
end
14+
15+
def as_shapco
16+
end
17+
18+
def send_to_shapco
19+
return if sent_to_shapco
20+
logger.debug("Shapco Order ##{order.number} Shipment ##{number}")
21+
logger.info 'Creating shipment record'
22+
success = Rails.env.production? ? do_send_to_shapco : simulate_send_to_shapco
23+
update_column :sent_to_shapco, success
24+
end
25+
26+
private
27+
28+
def do_send_to_shapco
29+
serialized = as_shapco
30+
logger.info("Sending shipment: #{serialized}")
31+
response = Shapco::Order.create(serialized)
32+
(response.body[:int32] == SHAPCO_SUCCESS_RESPONSE).tap do |success|
33+
logger.error("Error creating shipment: #{response.body}") unless success
34+
end
35+
rescue => ex
36+
logger.error("Error creating shipment: #{ex.message}")
37+
false
38+
end
39+
40+
def simulate_send_to_shapco
41+
logger.debug("Not in production environment, skipping shipment creation. Would have sent: #{as_shapco}")
42+
true
43+
end
44+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Spree::ShippingCategory.class_eval do
2+
scope :with_shapco, -> { where(shapco: true) }
3+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Spree::ShippingMethod.class_eval do
2+
scope :with_shapco, -> { joins(:shipping_categories).merge(Spree::ShippingCategory.with_shapco) }
3+
4+
def as_shapco
5+
end
6+
7+
private
8+
9+
def carrier
10+
admin_name.split(' ').first
11+
end
12+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Deface::Override.new(
2+
virtual_path: "spree/admin/shared/sub_menu/_configuration",
3+
name: "add_shapco_admin_menu_link",
4+
insert_bottom: "[data-hook='admin_configurations_sidebar_menu']",
5+
text: "<%= configurations_sidebar_menu_item 'Shapco Settings', edit_admin_shapco_settings_path %>"
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Deface::Override.new(
2+
virtual_path: "spree/admin/shipping_categories/_form",
3+
name: "add_shapco_to_admin_shipping_category_edit",
4+
insert_bottom: "[data-hook='admin_shipping_category_form_fields']",
5+
partial: "spree/admin/shipping_categories/edit_shapco"
6+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<%= render 'spree/admin/shared/sub_menu/configuration' %>
2+
3+
<% content_for :page_title do %>
4+
<%= Spree.t(:shapco_settings) %>
5+
<% end %>
6+
7+
<div id="preferences" data-hook>
8+
<%- if @error %>
9+
<div class="alert alert-danger">
10+
<%= Spree.t(:shapco_api_error, message: @error.message) %>
11+
</div>
12+
<%- end %>
13+
14+
<h6>WSDL URL: <%=@savon[:wsdl] %></h6>
15+
<%= form_tag admin_shapco_settings_path, method: :put do %>
16+
<div class="row">
17+
<div class="col-md-12">
18+
<fieldset class="no-border-bottom">
19+
<legend><%= Spree.t(:shapco_api_credentials)%></legend>
20+
<%- @credential_fields.each do |key| %>
21+
<%- type = Spree::Config.preference_type(key) %>
22+
<div class="form-group">
23+
<%= label_tag(key, Spree.t(key)) + tag(:br) if type != :boolean %>
24+
<%= preference_field_tag(key, Spree::Config[key], type: type) %>
25+
<%= label_tag(key, Spree.t(key)) + tag(:br) if type == :boolean %>
26+
</div>
27+
<% end %>
28+
</fieldset>
29+
</div>
30+
</div>
31+
32+
<div class="form-buttons" data-hook="buttons">
33+
<%= button Spree.t('actions.update'), 'refresh' %>
34+
<span class="or"><%= Spree.t(:or) %></span>
35+
<%= button_link_to Spree.t('actions.cancel'), edit_admin_shapco_settings_url, icon: 'delete' %>
36+
</div>
37+
<% end %>
38+
39+
<br />
40+
<br />
41+
<div class="row">
42+
<div class="col-md-12">
43+
<%- if @shipping_categories %>
44+
Shapco sync is enabled for the following shipping categories:
45+
<ul>
46+
<%- @shipping_categories.each do |cat| %>
47+
<li><%= link_to cat.name, edit_admin_shipping_category_path(cat) %></li>
48+
<%- end %>
49+
</ul>
50+
<%- else %>
51+
Shapco sync is not enabled for any shipping categories.&nbsp;
52+
<%- end %>
53+
Enable Shapco sync on the <%=link_to 'shipping categories admin page', admin_shipping_categories_path %>.
54+
</div>
55+
</div>
56+
</div>
57+
58+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div data-hook="admin_shipping_categories_form_shapco">
2+
<div class="form-group">
3+
<%= f.label :shapco do %>
4+
<%= f.check_box :shapco %>
5+
<%= Spree.t(:shapco_create) %>
6+
<%- end %>
7+
</div>
8+
</div>

bin/rails

+7
Original file line numberDiff line numberDiff line change
@@ -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_3plcentral/engine', __FILE__)
5+
6+
require 'rails/all'
7+
require 'rails/engine/commands'

config/locales/en.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
en:
2+
spree:
3+
shapco: Shapco
4+
5+
shapco_create: Create orders in Shapco
6+
7+
shapco_api_error: "Could not connect to Shapco API. Error: %{message}"
8+
9+
shapco_settings: Shapco Settings
10+
shapco_api_credentials: API Credentials
11+
shapco_username: Username
12+
shapco_password: Password
13+
shapco_subscriber_id: Subscriber ID

config/routes.rb

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Spree::Core::Engine.routes.draw do
2+
namespace :admin do
3+
resource :shapco_settings
4+
end
5+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddShapcoToShippingCategories < ActiveRecord::Migration
2+
def change
3+
add_column :spree_shipping_categories, :shapco, :boolean, null: false, default: false
4+
end
5+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddSentToShapcoToShipments < ActiveRecord::Migration
2+
def change
3+
add_column :spree_shipments, :sent_to_shapco, :boolean, null: false, default: false
4+
end
5+
end

0 commit comments

Comments
 (0)