workarea-paypal 2.0.8
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.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.eslintignore +2 -0
- data/.eslintrc +24 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.scss-lint.yml +188 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +314 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +6 -0
- data/LICENSE +52 -0
- data/README.md +47 -0
- data/Rakefile +54 -0
- data/app/assets/images/workarea/admin/payment_icons/paypal.svg +1 -0
- data/app/assets/images/workarea/storefront/payment_icons/paypal.svg +1 -0
- data/app/assets/javascripts/workarea/storefront/paypal/modules/update_checkout_submit_text.js +60 -0
- data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +13 -0
- data/app/controllers/workarea/storefront/paypal_controller.rb +51 -0
- data/app/models/workarea/payment.decorator +27 -0
- data/app/models/workarea/payment/authorize/paypal.rb +31 -0
- data/app/models/workarea/payment/capture/paypal.rb +35 -0
- data/app/models/workarea/payment/purchase/paypal.rb +31 -0
- data/app/models/workarea/payment/refund/paypal.rb +26 -0
- data/app/models/workarea/payment/tender/paypal.rb +11 -0
- data/app/models/workarea/search/order_text.decorator +8 -0
- data/app/services/workarea/paypal/setup.rb +114 -0
- data/app/services/workarea/paypal/update.rb +69 -0
- data/app/view_models/workarea/admin/paypal_view_model.rb +6 -0
- data/app/view_models/workarea/store_front/checkout/payment_view_model.decorator +18 -0
- data/app/view_models/workarea/store_front/credit_card_view_model.decorator +7 -0
- data/app/view_models/workarea/store_front/paypal_view_model.rb +6 -0
- data/app/views/workarea/admin/orders/tenders/_paypal.html.haml +2 -0
- data/app/views/workarea/api/orders/tenders/_paypal.json.jbuilder +3 -0
- data/app/views/workarea/storefront/carts/_paypal_checkout.html.haml +1 -0
- data/app/views/workarea/storefront/checkouts/_paypal_error.html.haml +6 -0
- data/app/views/workarea/storefront/checkouts/_paypal_payment.html.haml +12 -0
- data/app/views/workarea/storefront/order_mailer/tenders/_paypal.html.haml +3 -0
- data/app/views/workarea/storefront/order_mailer/tenders/_paypal.text.haml +2 -0
- data/app/views/workarea/storefront/orders/tenders/_paypal.html.haml +2 -0
- data/bin/rails +17 -0
- data/config/initializers/append_points.rb +19 -0
- data/config/initializers/workarea.rb +7 -0
- data/config/locales/en.yml +19 -0
- data/config/routes.rb +4 -0
- data/lib/workarea/paypal.rb +34 -0
- data/lib/workarea/paypal/engine.rb +8 -0
- data/lib/workarea/paypal/version.rb +5 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +34 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/config/application.rb +24 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +9 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +54 -0
- data/test/dummy/config/environments/production.rb +86 -0
- data/test/dummy/config/environments/test.rb +43 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/puma.rb +47 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/db/seeds.rb +2 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/workarea/storefront/paypal_integration_test.rb +345 -0
- data/test/integration/workarea/storefront/place_order_integration_test.decorator +11 -0
- data/test/models/workarea/payment/authorize/paypal_test.rb +94 -0
- data/test/models/workarea/payment/capture/paypal_test.rb +69 -0
- data/test/models/workarea/payment/purchase/paypal_test.rb +94 -0
- data/test/models/workarea/payment/refund/paypal_test.rb +69 -0
- data/test/models/workarea/payment_test.decorator +34 -0
- data/test/models/workarea/search/admin/order_test.decorator +32 -0
- data/test/services/workarea/paypal/setup_test.rb +120 -0
- data/test/services/workarea/paypal/update_test.rb +221 -0
- data/test/system/workarea/storefront/cart_system_test.decorator +14 -0
- data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +9 -0
- data/test/test_helper.rb +10 -0
- data/workarea-paypal.gemspec +21 -0
- metadata +170 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module Workarea
|
|
2
|
+
module Paypal
|
|
3
|
+
class Setup
|
|
4
|
+
attr_reader :order, :user, :shipping, :context
|
|
5
|
+
delegate :request, to: :context
|
|
6
|
+
delegate :gateway, to: Workarea::Paypal
|
|
7
|
+
|
|
8
|
+
def initialize(order, user, shipping, context)
|
|
9
|
+
@order = order
|
|
10
|
+
@user = user
|
|
11
|
+
@shipping = shipping
|
|
12
|
+
@context = context
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def paypal_response
|
|
16
|
+
@paypal_response ||= gateway.setup_authorization(
|
|
17
|
+
order.total_price.cents,
|
|
18
|
+
ip: request.remote_ip,
|
|
19
|
+
return_url: context.complete_paypal_url(order.id),
|
|
20
|
+
cancel_return_url: context.cart_url,
|
|
21
|
+
currency: order.total_price.currency,
|
|
22
|
+
subtotal: subtotal,
|
|
23
|
+
shipping: order.shipping_total.cents,
|
|
24
|
+
handling: 0,
|
|
25
|
+
tax: order.tax_total.cents,
|
|
26
|
+
items: items,
|
|
27
|
+
shipping_address: shipping_address,
|
|
28
|
+
order_id: order.id
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def items
|
|
33
|
+
order_items + item_level_discounts + order_level_discounts
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def subtotal
|
|
37
|
+
order.subtotal_price.cents +
|
|
38
|
+
order.price_adjustments.adjusting('order').discounts.sum.cents
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def shipping_address
|
|
42
|
+
serialize_address(shipping.try(:address) || user.try(:default_shipping_address))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def token
|
|
46
|
+
paypal_response.token
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def redirect_url
|
|
50
|
+
gateway.redirect_url_for(token)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def serialize_address(address)
|
|
56
|
+
return {} unless address
|
|
57
|
+
|
|
58
|
+
name = "#{address.first_name} #{address.last_name}"
|
|
59
|
+
phone = [address.phone_number, address.phone_extension].reject(&:blank?).join(' x')
|
|
60
|
+
|
|
61
|
+
{ name: name,
|
|
62
|
+
address1: address.street,
|
|
63
|
+
address2: address.street_2,
|
|
64
|
+
city: address.city,
|
|
65
|
+
state: address.region,
|
|
66
|
+
country: address.country,
|
|
67
|
+
zip: address.postal_code,
|
|
68
|
+
phone: phone }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def order_items
|
|
72
|
+
order.items.map do |item|
|
|
73
|
+
item_discount_total = item.price_adjustments.discounts.sum.cents
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
name: item.product_attributes.with_indifferent_access[:name],
|
|
77
|
+
quantity: item.quantity,
|
|
78
|
+
amount: (item.total_price.cents - item_discount_total) / item.quantity
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def item_level_discounts
|
|
84
|
+
order_items_with_discounts = order.items.select do |item|
|
|
85
|
+
item.price_adjustments.discounts.present?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
order_items_with_discounts.flat_map do |item|
|
|
89
|
+
item.price_adjustments.discounts.map do |discount|
|
|
90
|
+
{
|
|
91
|
+
name: discount.description.titleize,
|
|
92
|
+
quantity: 1,
|
|
93
|
+
amount: discount.amount.cents
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def order_level_discounts
|
|
100
|
+
order
|
|
101
|
+
.price_adjustments
|
|
102
|
+
.adjusting('order')
|
|
103
|
+
.discounts
|
|
104
|
+
.map do |discount|
|
|
105
|
+
{
|
|
106
|
+
name: discount.description.titleize,
|
|
107
|
+
quantity: 1,
|
|
108
|
+
amount: discount.amount.cents
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Workarea
|
|
2
|
+
module Paypal
|
|
3
|
+
class Update
|
|
4
|
+
attr_reader :order, :payment, :shipping, :token
|
|
5
|
+
|
|
6
|
+
def initialize(order, payment, shipping, token)
|
|
7
|
+
@order = order
|
|
8
|
+
@payment = payment
|
|
9
|
+
@shipping = shipping
|
|
10
|
+
@token = token
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def details
|
|
14
|
+
@details ||= Workarea::Paypal.gateway.details_for(token)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def apply
|
|
18
|
+
order.email ||= details.email
|
|
19
|
+
set_shipping_address(details.params)
|
|
20
|
+
set_shipping_service
|
|
21
|
+
set_billing_address(details.params)
|
|
22
|
+
|
|
23
|
+
payment.clear_credit_card
|
|
24
|
+
payment.set_paypal(
|
|
25
|
+
token: details.token,
|
|
26
|
+
payer_id: details.payer_id,
|
|
27
|
+
details: details.params
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
Pricing.perform(order, shipping)
|
|
31
|
+
payment.adjust_tender_amounts(order.total_price)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def set_shipping_address(params)
|
|
37
|
+
shipping.set_address(
|
|
38
|
+
first_name: params['first_name'],
|
|
39
|
+
last_name: params['last_name'],
|
|
40
|
+
street: params['PaymentDetails']['ShipToAddress']['Street1'],
|
|
41
|
+
street_2: params['PaymentDetails']['ShipToAddress']['Street2'],
|
|
42
|
+
city: params['PaymentDetails']['ShipToAddress']['CityName'],
|
|
43
|
+
region: params['PaymentDetails']['ShipToAddress']['StateOrProvince'],
|
|
44
|
+
postal_code: params['PaymentDetails']['ShipToAddress']['PostalCode'],
|
|
45
|
+
country: params['PaymentDetails']['ShipToAddress']['Country'],
|
|
46
|
+
phone_number: params['PaymentDetails']['ShipToAddress']['Phone']
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def set_billing_address(params)
|
|
51
|
+
payment.set_address(
|
|
52
|
+
first_name: params['PayerInfo']['PayerName']['FirstName'],
|
|
53
|
+
last_name: params['PayerInfo']['PayerName']['LastName'],
|
|
54
|
+
street: params['PayerInfo']['Address']['Street1'],
|
|
55
|
+
street_2: params['PayerInfo']['Address']['Street2'],
|
|
56
|
+
city: params['PayerInfo']['Address']['CityName'],
|
|
57
|
+
region: params['PayerInfo']['Address']['StateOrProvince'],
|
|
58
|
+
postal_code: params['PayerInfo']['Address']['PostalCode'],
|
|
59
|
+
country: params['PayerInfo']['Address']['Country'],
|
|
60
|
+
phone_number: params['PayerInfo']['Address']['Phone']
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def set_shipping_service
|
|
65
|
+
Checkout::Steps::Shipping.new(self).update({})
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Workarea
|
|
2
|
+
decorate Storefront::Checkout::PaymentViewModel, with: :paypal do
|
|
3
|
+
def paypal?
|
|
4
|
+
payment.paypal?
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def using_new_card?
|
|
8
|
+
super && !paypal?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def credit_cards
|
|
12
|
+
super.map do |card|
|
|
13
|
+
card.options[:paypal] = paypal?
|
|
14
|
+
card
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
%p.cart__checkout-action.cart__checkout-action--paypal= link_to(image_tag('https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif'), start_paypal_path, alt: t('workarea.storefront.paypal.check_out'))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
.checkout-payment__primary-method{ class: ('checkout-payment__primary-method--selected' if @step.paypal?) }
|
|
2
|
+
.button-property
|
|
3
|
+
= hidden_field_tag 'from_checkout', 'from_checkout'
|
|
4
|
+
.value= radio_button_tag 'payment', 'paypal', step.paypal?, data: { update_checkout_submit_text: { prevent: step.paypal?, text: t('workarea.storefront.paypal.checkout_submit_text') }.to_json }
|
|
5
|
+
= label_tag 'payment[paypal]', nil, class: 'button-property__name' do
|
|
6
|
+
%span.button-property__text= t('workarea.storefront.paypal.paypal')
|
|
7
|
+
%p.checkout-payment__primary-method-description
|
|
8
|
+
= inline_svg('workarea/admin/payment_icons/paypal.svg', class: 'payment-icon', title: 'PayPal')
|
|
9
|
+
- if @step.paypal?
|
|
10
|
+
%span= t('workarea.storefront.paypal.payment_recieved')
|
|
11
|
+
- else
|
|
12
|
+
%span= t('workarea.storefront.paypal.on_continue')
|
data/bin/rails
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
|
|
3
|
+
|
|
4
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
|
5
|
+
ENGINE_PATH = File.expand_path('../../lib/workarea/paypal/engine', __FILE__)
|
|
6
|
+
|
|
7
|
+
# Set up gems listed in the Gemfile.
|
|
8
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
|
9
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
|
10
|
+
|
|
11
|
+
require 'action_controller/railtie'
|
|
12
|
+
require 'action_view/railtie'
|
|
13
|
+
require 'action_mailer/railtie'
|
|
14
|
+
require 'rails/test_unit/railtie'
|
|
15
|
+
require 'sprockets/railtie'
|
|
16
|
+
|
|
17
|
+
require 'rails/engine/commands'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Workarea::Plugin.append_partials(
|
|
2
|
+
'storefront.cart_checkout_actions',
|
|
3
|
+
'workarea/storefront/carts/paypal_checkout'
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
Workarea::Plugin.append_partials(
|
|
7
|
+
'storefront.payment_error',
|
|
8
|
+
'workarea/storefront/checkouts/paypal_error'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
Workarea::Plugin.append_partials(
|
|
12
|
+
'storefront.payment_method',
|
|
13
|
+
'workarea/storefront/checkouts/paypal_payment'
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Workarea::Plugin.append_javascripts(
|
|
17
|
+
'storefront.modules',
|
|
18
|
+
'workarea/storefront/paypal/modules/update_checkout_submit_text'
|
|
19
|
+
)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Workarea.config.tender_types << :paypal
|
|
2
|
+
|
|
3
|
+
# Gateway application_id is sent as PayPal BN code for revenue sharing
|
|
4
|
+
# 'WebLinc_SP' should be used for all WebLinc installations
|
|
5
|
+
ActiveMerchant::Billing::PaypalGateway.application_id = 'WebLinc_SP'
|
|
6
|
+
|
|
7
|
+
Workarea::Paypal.auto_configure_gateway
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
en:
|
|
3
|
+
workarea:
|
|
4
|
+
admin:
|
|
5
|
+
orders:
|
|
6
|
+
tenders:
|
|
7
|
+
paypal:
|
|
8
|
+
title: PayPal
|
|
9
|
+
storefront:
|
|
10
|
+
paypal:
|
|
11
|
+
address_error: We can not ship to this address. Please enter a new address.
|
|
12
|
+
check_out: Check Out with PayPal
|
|
13
|
+
checkout_submit_text: Continue to PayPal
|
|
14
|
+
on_continue: When you continue, you will be taken to the PayPal website.
|
|
15
|
+
paid_with_paypal: Paid with PayPal
|
|
16
|
+
payment_recieved: Thank You! We have received your information back from PayPal.
|
|
17
|
+
Please confirm that the shipping address and shipping method are correct,
|
|
18
|
+
then click on 'Place Order'.
|
|
19
|
+
paypal: PayPal
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'workarea'
|
|
2
|
+
require 'workarea/storefront'
|
|
3
|
+
require 'workarea/admin'
|
|
4
|
+
|
|
5
|
+
module Workarea
|
|
6
|
+
module Paypal
|
|
7
|
+
def self.gateway
|
|
8
|
+
Workarea.config.gateways.paypal
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.gateway=(gateway)
|
|
12
|
+
Workarea.config.gateways.paypal = gateway
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.auto_configure_gateway
|
|
16
|
+
if Rails.application.secrets.paypal.present?
|
|
17
|
+
self.gateway = ActiveMerchant::Billing::PaypalExpressGateway.new(
|
|
18
|
+
Rails.application.secrets.paypal.deep_symbolize_keys
|
|
19
|
+
)
|
|
20
|
+
elsif gateway.blank?
|
|
21
|
+
self.gateway = ActiveMerchant::Billing::BogusGateway.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if ENV['HTTP_PROXY'].present? && gateway.present?
|
|
25
|
+
parsed = URI.parse(ENV['HTTP_PROXY'])
|
|
26
|
+
gateway.proxy_address = parsed.host
|
|
27
|
+
gateway.proxy_port = parsed.port
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
require 'workarea/paypal/version'
|
|
34
|
+
require 'workarea/paypal/engine'
|
data/test/dummy/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
2
|
+
// listed below.
|
|
3
|
+
//
|
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
|
6
|
+
//
|
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
|
9
|
+
//
|
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
|
11
|
+
// about supported directives.
|
|
12
|
+
//
|
|
13
|
+
//= require_tree .
|