spree_np_atobarai 1.0.0
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/.gitignore +23 -0
- data/Gemfile +3 -0
- data/LICENSE +673 -0
- data/README.md +71 -0
- data/app/controllers/spree/admin/np_orders_controller.rb +36 -0
- data/app/controllers/spree_np_atobarai/checkout_controller_decorator.rb +26 -0
- data/app/models/spree/payment_method/np_atobarai.rb +94 -0
- data/app/models/spree_np_atobarai/order_decorator.rb +114 -0
- data/app/models/spree_np_atobarai/payment_decorator.rb +23 -0
- data/app/overrides/add_invoice_sending_method_to_account_orders.rb +27 -0
- data/app/overrides/add_invoice_sending_method_to_checkout_summary.rb +13 -0
- data/app/overrides/add_invoice_sending_method_to_payment.rb +11 -0
- data/app/overrides/add_invoice_sending_method_to_purchased_items_table.rb +22 -0
- data/app/overrides/hide_preference_fields_for_payment_method_np_atobarai.rb +10 -0
- data/app/overrides/set_orders_active_for_np_orders.rb +10 -0
- data/app/services/spree_np_atobarai/order_csv_service.rb +123 -0
- data/app/views/spree/admin/np_orders/index.html.erb +29 -0
- data/app/views/spree/admin/payment_methods/custom_form_fields/_np_atobarai_form_fields.html.erb +32 -0
- data/app/views/spree/checkout/payment/_npatobarai.html.erb +12 -0
- data/app/views/spree_np_atobarai/_np_atobarai_invoice_options.html.erb +24 -0
- data/app/views/spree_np_atobarai/admin/_orders_nav_item.html.erb +4 -0
- data/app/views/spree_np_atobarai/admin/np_orders/_list.html.erb +29 -0
- data/app/views/spree_np_atobarai/admin/np_orders/_order.html.erb +31 -0
- data/bin/rails +8 -0
- data/config/initializers/admin_navigation.rb +20 -0
- data/config/locales/activerecord.en.yml +9 -0
- data/config/locales/activerecord.ja.yml +9 -0
- data/config/locales/en.yml +21 -0
- data/config/locales/ja.yml +25 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20250401033922_add_column_invoice_sending_to_payment.rb +5 -0
- data/lib/generators/spree_np_atobarai/install_generator.rb +19 -0
- data/lib/spree_np_atobarai/engine.rb +34 -0
- data/lib/spree_np_atobarai/version.rb +7 -0
- data/lib/spree_np_atobarai.rb +5 -0
- data/spree_np_atobarai.gemspec +29 -0
- metadata +151 -0
data/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# SpreeNpAtobarai
|
|
2
|
+
|
|
3
|
+
`spree_np_atobarai` is a Spree extension that integrates the [NP Atobarai](https://np-atobarai.jp/) payment service into your Spree store. It provides functionalities for managing orders using this payment method, exporting order data in CSV format, and selecting invoice sending methods.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
1. **New Payment Method Type**
|
|
8
|
+
- Adds `Spree::PaymentMethod::NpAtobarai`, allowing customers to pay using the NP Atobarai service.
|
|
9
|
+
|
|
10
|
+
2. **Order Management Screen**
|
|
11
|
+
- Provides an admin interface for managing orders that use the NP Atobarai payment method.
|
|
12
|
+
|
|
13
|
+
3. **CSV Export for NP Atobarai**
|
|
14
|
+
- Allows exporting NP orders in CSV format for upload to the NP Atobarai service.
|
|
15
|
+
|
|
16
|
+
4. **Invoice Sending Methods Selection**
|
|
17
|
+
- Allows selecting `invoice_sending_methods` when using the `NP Atobarai` payment method.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
1. Add spree_np_atobarai to your Gemfile:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
gem 'spree_np_atobarai'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Install the gem using Bundler:
|
|
28
|
+
|
|
29
|
+
```shell
|
|
30
|
+
bundle install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Copy & run migrations:
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
bundle exec rails g spree_np_atobarai:install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### Creating the Payment Method
|
|
42
|
+
|
|
43
|
+
After installing the extension, create a new NP Atobarai payment method using the Rails console:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
Spree::PaymentMethod::NpAtobarai.find_or_create_by(
|
|
47
|
+
name: "Np Atobarai 1",
|
|
48
|
+
description: "Np Atobarai payment method",
|
|
49
|
+
active: true,
|
|
50
|
+
display_on: "both",
|
|
51
|
+
auto_capture: true
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This will register the NP Atobarai payment method in your Spree store and make it available for use.
|
|
56
|
+
|
|
57
|
+
### Managing NP Orders
|
|
58
|
+
Once installed, an NP Order management screen will be available in the Spree admin panel. Here, you can view and manage all orders that use the NP Atobarai payment method.
|
|
59
|
+
|
|
60
|
+
### Exporting NP Orders to CSV
|
|
61
|
+
To generate a CSV file for NP orders, navigate to the NP Order section in the admin panel and click the Export CSV button.
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
This extension is available as open source under the terms of either:
|
|
66
|
+
* [GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later)](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
67
|
+
* [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
|
|
68
|
+
|
|
69
|
+
## Credits
|
|
70
|
+
|
|
71
|
+
[be agile Co., Ltd.](https://be-agile.jp/)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Admin
|
|
3
|
+
class NpOrdersController < Spree::Admin::OrdersController
|
|
4
|
+
include Spree::Admin::OrderConcern
|
|
5
|
+
|
|
6
|
+
respond_to :html
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
super
|
|
10
|
+
# Spree 5.3 追従: 本家の index は空メソッドになり、@orders → @collection(controller_name 由来の
|
|
11
|
+
# @np_orders)へ移行。np_atobarai 限定は scope override で適用済みなので、ビュー(@orders/@search 前提)
|
|
12
|
+
# 向けに @collection を @orders へエイリアスする。
|
|
13
|
+
@orders = @collection
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def csv_export
|
|
17
|
+
send_data SpreeNpAtobarai::OrderCSVService.new(params[:order_ids]).to_csv,
|
|
18
|
+
filename: "orders-#{Time.current.strftime('%Y%m%d%H%M%S')}.csv",
|
|
19
|
+
type: "text/csv",
|
|
20
|
+
disposition: "attachment"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def scope
|
|
26
|
+
# Spree 5.3 追従: collection(ransack/ページネーション)の基盤 scope に np_atobarai 限定を適用する。
|
|
27
|
+
# 本家 OrdersController#scope は index 時に .complete を付けるため、それに合わせる。
|
|
28
|
+
current_store.orders.accessible_by(current_ability, :index).complete.np_atobarai_orders
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def model_class
|
|
32
|
+
Spree::Order
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module SpreeNpAtobarai
|
|
2
|
+
module CheckoutControllerDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
base.before_action :validate_invoice_method_for_np_atobarai, only: [ :update ], if: -> { params[:state] == 'payment' }
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def validate_invoice_method_for_np_atobarai
|
|
10
|
+
payments_attribute = params.dig(:order, :payments_attributes)&.last
|
|
11
|
+
return if payments_attribute.blank?
|
|
12
|
+
|
|
13
|
+
payment_method_id = payments_attribute[:payment_method_id]
|
|
14
|
+
invoice_sending = payments_attribute[:invoice_sending]
|
|
15
|
+
|
|
16
|
+
payment = Spree::Payment.new(payment_method_id: payment_method_id, invoice_sending: invoice_sending)
|
|
17
|
+
payment.valid?
|
|
18
|
+
return if payment.errors[:invoice_sending].blank?
|
|
19
|
+
|
|
20
|
+
flash[:error] = Spree.t('please_select_invoice_sending_method')
|
|
21
|
+
redirect_to(checkout_state_path(@order.token, @order.state))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Spree::CheckoutController.prepend SpreeNpAtobarai::CheckoutControllerDecorator
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
class Spree::PaymentMethod::NpAtobarai < Spree::PaymentMethod
|
|
2
|
+
INVOICE_SENDING_OPTIONS = [ :postal, :email ]
|
|
3
|
+
|
|
4
|
+
preference :np_atobarai_fee, :float, default: 330
|
|
5
|
+
preference :np_atobarai_no_fee_same_month, :boolean, default: true
|
|
6
|
+
preference :tax_category_id, :integer
|
|
7
|
+
|
|
8
|
+
def actions
|
|
9
|
+
%w[capture void]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Indicates whether its possible to capture the payment
|
|
13
|
+
def can_capture?(payment)
|
|
14
|
+
[ 'checkout', 'pending' ].include?(payment.state)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Indicates whether its possible to void the payment.
|
|
18
|
+
def can_void?(payment)
|
|
19
|
+
payment.state != 'void'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def custom_form_fields_partial_name
|
|
23
|
+
'np_atobarai_form_fields'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def capture(*)
|
|
27
|
+
ActiveMerchant::Billing::Response.new(true, "", {}, {})
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def cancel(*)
|
|
31
|
+
ActiveMerchant::Billing::Response.new(true, "", {}, {})
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def void(*)
|
|
35
|
+
ActiveMerchant::Billing::Response.new(true, "", {}, {})
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def source_required?
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def np_atobarai_fee_adjustment_applicable?(order, payment)
|
|
43
|
+
return false if preferred_np_atobarai_fee.blank? || order.blank? || payment&.invoice_sending_email?
|
|
44
|
+
|
|
45
|
+
return true if preferred_np_atobarai_no_fee_same_month.blank?
|
|
46
|
+
|
|
47
|
+
!has_np_atobarai_orders_this_month?(order.billing_address&.phone)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def create_np_atobarai_fee_adjustment!(order)
|
|
51
|
+
adjustment = order.adjustments.new
|
|
52
|
+
adjustment.source = self
|
|
53
|
+
adjustment.order = order
|
|
54
|
+
adjustment.amount = preferred_np_atobarai_fee
|
|
55
|
+
adjustment.label = np_atobarai_fee_label
|
|
56
|
+
adjustment.save!
|
|
57
|
+
adjustment
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class << self
|
|
61
|
+
def destroy_np_atobarai_adjustments(order)
|
|
62
|
+
order.adjustments.where(label: np_atobarai_fee_label).destroy_all
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def np_atobarai_fee_label
|
|
66
|
+
Spree.t('np_atobarai_fee_adjustment')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def invoice_sending_options
|
|
70
|
+
Spree::Payment.invoice_sendings.slice(*INVOICE_SENDING_OPTIONS)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
delegate :np_atobarai_fee_label, to: :class
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def has_np_atobarai_orders_this_month?(phone_number)
|
|
79
|
+
return false if phone_number.blank?
|
|
80
|
+
|
|
81
|
+
start_of_month = Time.current.beginning_of_month
|
|
82
|
+
end_of_month = Time.current.end_of_month
|
|
83
|
+
payment_method_ids = Spree::PaymentMethod::NpAtobarai.ids
|
|
84
|
+
return false if payment_method_ids.blank?
|
|
85
|
+
|
|
86
|
+
Spree::Order.complete
|
|
87
|
+
.where(state: 'complete')
|
|
88
|
+
.completed_between(start_of_month, end_of_month)
|
|
89
|
+
.joins(:bill_address, :payments)
|
|
90
|
+
.where("REPLACE(spree_addresses.phone, '-', '') = ?", phone_number.delete('-'))
|
|
91
|
+
.where(spree_payments: { payment_method_id: payment_method_ids, invoice_sending: Spree::Payment.invoice_sendings[:postal] })
|
|
92
|
+
.merge(Spree::Payment.valid).exists?
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module SpreeNpAtobarai
|
|
2
|
+
module OrderDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
base.set_callback :updating_from_params, :before, :adjust_np_atobarai_fee, prepend: true
|
|
5
|
+
base.set_callback :updating_from_params, :after, :update_np_atobarai_invoice_sending, prepend: true
|
|
6
|
+
|
|
7
|
+
base.scope :np_atobarai_orders, -> {
|
|
8
|
+
joins(:payments)
|
|
9
|
+
.where(spree_payments: { payment_method_id: Spree::PaymentMethod::NpAtobarai.ids })
|
|
10
|
+
.merge(Spree::Payment.unscoped.valid).distinct
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def human_invoice_sending_name
|
|
15
|
+
payments.last&.human_invoice_sending_name
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def np_atobarai_order?
|
|
19
|
+
Spree::Order.np_atobarai_orders.exists?(id: id)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def adjust_np_atobarai_fee
|
|
25
|
+
return if payments_attributes.blank?
|
|
26
|
+
|
|
27
|
+
destroy_np_atobarai_adjustments
|
|
28
|
+
payment_method = find_np_atobarai_payment_method
|
|
29
|
+
create_np_atobarai_fee_adjustment!(payment_method)
|
|
30
|
+
updater.update
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def find_np_atobarai_payment_method
|
|
34
|
+
payment_method_ids = payments_attributes.pluck('payment_method_id')
|
|
35
|
+
# Spree 5.3 で Order#available_payment_methods は deprecated になり、かつ gem 内部で
|
|
36
|
+
# collect_payment_methods(store) を arity 0 のメソッドへ 1 引数で呼ぶ不整合があるため
|
|
37
|
+
# ArgumentError (wrong number of arguments given 1 expected 0) で必ず落ちる。
|
|
38
|
+
# 5.3 推奨の collect_frontend_payment_methods(配列を返す)へ置き換える。
|
|
39
|
+
available_method_ids = collect_frontend_payment_methods.map(&:id)
|
|
40
|
+
|
|
41
|
+
Spree::PaymentMethod
|
|
42
|
+
.where(id: payment_method_ids)
|
|
43
|
+
.where(id: available_method_ids)
|
|
44
|
+
.find_by(type: 'Spree::PaymentMethod::NpAtobarai')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def destroy_np_atobarai_adjustments
|
|
48
|
+
Spree::PaymentMethod::NpAtobarai.destroy_np_atobarai_adjustments(self)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def create_np_atobarai_fee_adjustment!(payment_method)
|
|
52
|
+
return if payment_method.blank?
|
|
53
|
+
|
|
54
|
+
# payments_attributesからinvoice_sendingを取得
|
|
55
|
+
invoice_sending = payments_attributes.dig(0, 'invoice_sending')
|
|
56
|
+
|
|
57
|
+
# メール送付の場合は手数料なし
|
|
58
|
+
return if invoice_sending == 'email'
|
|
59
|
+
|
|
60
|
+
# 郵送の場合、または未指定の場合に手数料を追加
|
|
61
|
+
# 同月内の既存注文チェックは、np_atobarai_fee_adjustment_applicableで行われる
|
|
62
|
+
return if preferred_np_atobarai_no_fee_same_month && has_np_atobarai_orders_this_month?(billing_address&.phone)
|
|
63
|
+
|
|
64
|
+
payment_method.create_np_atobarai_fee_adjustment!(self)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def has_np_atobarai_orders_this_month?(phone_number)
|
|
68
|
+
return false if phone_number.blank?
|
|
69
|
+
|
|
70
|
+
start_of_month = Time.current.beginning_of_month
|
|
71
|
+
end_of_month = Time.current.end_of_month
|
|
72
|
+
payment_method_ids = Spree::PaymentMethod::NpAtobarai.ids
|
|
73
|
+
return false if payment_method_ids.blank?
|
|
74
|
+
|
|
75
|
+
Spree::Order.complete
|
|
76
|
+
.where(state: 'complete')
|
|
77
|
+
.completed_between(start_of_month, end_of_month)
|
|
78
|
+
.joins(:bill_address, :payments)
|
|
79
|
+
.where("REPLACE(spree_addresses.phone, '-', '') = ?", phone_number.delete('-'))
|
|
80
|
+
.where(spree_payments: { payment_method_id: payment_method_ids, invoice_sending: Spree::Payment.invoice_sendings[:postal] })
|
|
81
|
+
.merge(Spree::Payment.valid).exists?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def preferred_np_atobarai_no_fee_same_month
|
|
85
|
+
payment_method = find_np_atobarai_payment_method
|
|
86
|
+
payment_method&.preferred_np_atobarai_no_fee_same_month
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def update_np_atobarai_invoice_sending
|
|
90
|
+
return if payments_attributes.blank?
|
|
91
|
+
|
|
92
|
+
payment_method = find_np_atobarai_payment_method
|
|
93
|
+
return if payment_method.blank?
|
|
94
|
+
|
|
95
|
+
invoice_sending = payments_attributes.dig(0, 'invoice_sending')
|
|
96
|
+
return if invoice_sending.blank?
|
|
97
|
+
|
|
98
|
+
payment = payments.where(payment_method_id: payment_method.id).where.not(state: Spree::Payment::INVALID_STATES).last
|
|
99
|
+
return if payment.blank?
|
|
100
|
+
|
|
101
|
+
payment.update_columns(invoice_sending: invoice_sending) if payment.invoice_sending != invoice_sending
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# ba_spree_cash_on_delivery の同名 private メソッドと実装が同一。engine ごとにモジュールを
|
|
105
|
+
# 分離した結果、両方が Spree::Order の ancestors に載り外側だけが呼ばれるが、実装が同じなので
|
|
106
|
+
# どちらが外側でも挙動は変わらない。
|
|
107
|
+
# @see https://github.com/be-agile/giga-repeat/issues/1307
|
|
108
|
+
def payments_attributes
|
|
109
|
+
@updating_params&.dig('order', 'payments_attributes') || []
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
Spree::Order.prepend SpreeNpAtobarai::OrderDecorator
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module SpreeNpAtobarai
|
|
2
|
+
module PaymentDecorator
|
|
3
|
+
def self.prepended(base)
|
|
4
|
+
base.attribute :invoice_sending, :string
|
|
5
|
+
base.enum :invoice_sending, { postal: 'postal', email: 'email' }, prefix: :invoice_sending
|
|
6
|
+
|
|
7
|
+
base.validates :invoice_sending, presence: true,
|
|
8
|
+
if: ->(payment) { payment.payment_method.is_a?(Spree::PaymentMethod::NpAtobarai) }
|
|
9
|
+
|
|
10
|
+
base.define_singleton_method(:human_invoice_sending_name) do |invoice_sending_type|
|
|
11
|
+
return if invoice_sending_type.blank?
|
|
12
|
+
|
|
13
|
+
I18n.t("activerecord.attributes.spree/payment.invoice_sendings.#{invoice_sending_type}")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def human_invoice_sending_name
|
|
18
|
+
self.class.human_invoice_sending_name(invoice_sending)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Spree::Payment.prepend(SpreeNpAtobarai::PaymentDecorator) unless Spree::Payment.included_modules.include?(SpreeNpAtobarai::PaymentDecorator)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# This Deface override adds a new column for "Invoice Sending Method"
|
|
2
|
+
# to the orders table on the `account/orders` page.
|
|
3
|
+
Deface::Override.new(
|
|
4
|
+
virtual_path: 'spree/account/_orders',
|
|
5
|
+
name: 'add_invoice_sending_method_to_account_orders',
|
|
6
|
+
insert_after: 'table tr > th:nth-of-type(2)',
|
|
7
|
+
text: <<-ERB
|
|
8
|
+
<% if @orders.np_atobarai_orders.any? %>
|
|
9
|
+
<th class="font-normal px-4">
|
|
10
|
+
<%= Spree::Payment.human_attribute_name :invoice_sending %>
|
|
11
|
+
</th>
|
|
12
|
+
<% end %>
|
|
13
|
+
ERB
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Deface::Override.new(
|
|
17
|
+
virtual_path: 'spree/account/_order',
|
|
18
|
+
name: 'add_invoice_sending_method_to_account_orders_rows',
|
|
19
|
+
insert_after: 'tr > td:nth-of-type(2)',
|
|
20
|
+
text: <<-ERB
|
|
21
|
+
<% if @orders.np_atobarai_orders.any? %>
|
|
22
|
+
<td class="md:w-auto pr-2 md:px-4 md:border-y border-accent">
|
|
23
|
+
<%= order.human_invoice_sending_name %>
|
|
24
|
+
</td>
|
|
25
|
+
<% end %>
|
|
26
|
+
ERB
|
|
27
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Deface::Override.new(
|
|
2
|
+
virtual_path: 'spree/checkout/_summary',
|
|
3
|
+
name: 'add_invoice_sending_method_to_checkout_summary',
|
|
4
|
+
insert_top: "div[data-hook='order_summary']",
|
|
5
|
+
text: <<-ERB
|
|
6
|
+
<% if (order.confirm? || order.complete?) && order.np_atobarai_order? %>
|
|
7
|
+
<div class="flex justify-between items-center mb-2">
|
|
8
|
+
<span><%= Spree::Payment.human_attribute_name :invoice_sending %>:</span>
|
|
9
|
+
<span><%= order.human_invoice_sending_name %></span>
|
|
10
|
+
</div>
|
|
11
|
+
<% end %>
|
|
12
|
+
ERB
|
|
13
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Deface::Override.new(
|
|
2
|
+
virtual_path: 'spree/admin/payments/_payment',
|
|
3
|
+
name: 'add_invoice_sending_method_to_payment',
|
|
4
|
+
insert_after: "strong:contains('payment_method_name(payment)')",
|
|
5
|
+
text: <<-HTML
|
|
6
|
+
<% if payment.payment_method.is_a?(Spree::PaymentMethod::NpAtobarai) && payment.invoice_sending.present? %>
|
|
7
|
+
<p class="mb-1 mt-2"><%= Spree::Payment.human_attribute_name :invoice_sending %>:</p>
|
|
8
|
+
<strong><%= payment.human_invoice_sending_name %></strong>
|
|
9
|
+
<% end %>
|
|
10
|
+
HTML
|
|
11
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Deface::Override.new(
|
|
2
|
+
virtual_path: 'spree/shared/_purchased_items_table',
|
|
3
|
+
name: 'add_invoice_sending_method_to_purchased_items_table',
|
|
4
|
+
insert_before: "erb[loud]:contains('spree/shared/purchased_items_table/total')",
|
|
5
|
+
text: <<-HTML
|
|
6
|
+
<% if order.np_atobarai_order? %>
|
|
7
|
+
<tr>
|
|
8
|
+
<td></td>
|
|
9
|
+
<td>
|
|
10
|
+
<p class="f-fallback purchase_total purchase_total--label">
|
|
11
|
+
<%= Spree::Payment.human_attribute_name :invoice_sending %>:
|
|
12
|
+
</p>
|
|
13
|
+
</td>
|
|
14
|
+
<td class="purchase_total-col">
|
|
15
|
+
<p class="f-fallback purchase_total">
|
|
16
|
+
<%= order.human_invoice_sending_name %>
|
|
17
|
+
</p>
|
|
18
|
+
</td>
|
|
19
|
+
</tr>
|
|
20
|
+
<% end %>
|
|
21
|
+
HTML
|
|
22
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Deface::Override.new(
|
|
2
|
+
virtual_path: 'spree/admin/payment_methods/_form',
|
|
3
|
+
name: 'hide_preference_fields_for_payment_method_np_atobarai',
|
|
4
|
+
replace: "erb[loud]:contains('preference_fields(@object, f)')",
|
|
5
|
+
text: <<-HTML
|
|
6
|
+
<% unless @object.is_a?(Spree::PaymentMethod::NpAtobarai) %>
|
|
7
|
+
<%= preference_fields(@object, f) unless preference_fields(@object, f).empty? %>
|
|
8
|
+
<% end %>
|
|
9
|
+
HTML
|
|
10
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Deface::Override.new(
|
|
2
|
+
virtual_path: 'spree/admin/shared/sidebar/_orders_nav',
|
|
3
|
+
name: 'set_orders_active_for_np_orders',
|
|
4
|
+
insert_after: "erb[silent]:contains('orders_active =')",
|
|
5
|
+
text: <<-ERB
|
|
6
|
+
<% if controller_name == 'np_orders' %>
|
|
7
|
+
<% orders_active = true %>
|
|
8
|
+
<% end %>
|
|
9
|
+
ERB
|
|
10
|
+
)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module SpreeNpAtobarai
|
|
2
|
+
class OrderCSVService
|
|
3
|
+
CSV_HEADER = [
|
|
4
|
+
"加盟店取引ID", "加盟店取引受注日", "企業名", "部署名", "担当者名", "購入企業ID",
|
|
5
|
+
"郵便番号", "住所", "電話番号1", "電話番号2",
|
|
6
|
+
"メールアドレス(To)", "メールアドレス(Cc)1", "メールアドレス(Cc)2", "メールアドレス(Cc)3", "メールアドレス(Cc)4",
|
|
7
|
+
"配送先企業名", "配送先部署名", "配送先担当者名", "配送先担当者名(カナ)",
|
|
8
|
+
"配送先郵便番号", "配送先住所", "配送先電話番号",
|
|
9
|
+
"決済方法", "FAX番号", "請求書送付方法", "コンビニ払い設定",
|
|
10
|
+
"取引金額", "明細", "元加盟店取引受注日", "単価", "数量", "金額", "NP購入企業ID", "請求書税区分"
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
def initialize(order_ids)
|
|
14
|
+
@order_ids = order_ids.map(&:to_i)
|
|
15
|
+
@orders = Spree::Order.where(id: order_ids).includes(:line_items, :adjustments, :ship_address, :bill_address, payments: :payment_method)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_csv
|
|
19
|
+
options = {
|
|
20
|
+
encoding: "Shift_JIS",
|
|
21
|
+
undef: :replace, # 未定義文字を置換
|
|
22
|
+
replace: '?', # 未定義文字の置換文字
|
|
23
|
+
invalid: :replace # 不正なバイトシーケンスを置換
|
|
24
|
+
}
|
|
25
|
+
CSV.generate do |csv|
|
|
26
|
+
csv << CSV_HEADER
|
|
27
|
+
|
|
28
|
+
@order_ids.each do |id|
|
|
29
|
+
order = @orders.find { |o| o.id == id }
|
|
30
|
+
next unless order
|
|
31
|
+
|
|
32
|
+
rows = build_order_rows(order)
|
|
33
|
+
rows.each { |row| csv << row }
|
|
34
|
+
end
|
|
35
|
+
end.encode("Shift_JIS", **options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def build_order_rows(order)
|
|
41
|
+
detail_rows = build_detail_rows(order)
|
|
42
|
+
rows = []
|
|
43
|
+
|
|
44
|
+
# Row 1: full info + first detail row
|
|
45
|
+
rows << build_main_row(order, detail_rows.shift)
|
|
46
|
+
|
|
47
|
+
# From row 2 onwards: add detail rows with nil values for the first 27 columns
|
|
48
|
+
detail_rows.each do |detail_row|
|
|
49
|
+
base = Array.new(27, nil)
|
|
50
|
+
rows << base + detail_row + [ nil, nil ]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
rows
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def build_main_row(order, detail_row)
|
|
57
|
+
bill = order.bill_address
|
|
58
|
+
ship = order.ship_address
|
|
59
|
+
same_address = bill == ship
|
|
60
|
+
|
|
61
|
+
[
|
|
62
|
+
order.number,
|
|
63
|
+
order.created_at.strftime('%Y/%m/%d'), # Format to YYYY/MM/DD
|
|
64
|
+
bill&.company.presence || "#{bill&.last_name} #{bill&.first_name}",
|
|
65
|
+
nil, nil, nil,
|
|
66
|
+
bill&.zipcode,
|
|
67
|
+
"#{bill&.state&.name}#{bill&.city}#{bill&.address1}#{bill&.address2}",
|
|
68
|
+
bill&.phone,
|
|
69
|
+
nil,
|
|
70
|
+
order.email,
|
|
71
|
+
nil, nil, nil, nil, # Cc emails
|
|
72
|
+
(!same_address ? (ship&.company.presence || "#{ship&.last_name} #{ship&.first_name}") : nil),
|
|
73
|
+
nil, nil, nil,
|
|
74
|
+
(!same_address ? ship&.zipcode : nil),
|
|
75
|
+
(!same_address ? "#{ship&.state&.name}#{ship&.city}#{ship&.address1}#{ship&.address2}" : nil),
|
|
76
|
+
(!same_address ? ship&.phone : nil),
|
|
77
|
+
2,
|
|
78
|
+
nil,
|
|
79
|
+
latest_np_payment(order)&.invoice_sending_postal? ? 1 : 2,
|
|
80
|
+
nil,
|
|
81
|
+
order.total.to_i
|
|
82
|
+
] + detail_row + [ nil, nil ]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Build detail rows for the order
|
|
86
|
+
# Each detail row contains the following columns:
|
|
87
|
+
# - 明細
|
|
88
|
+
# - 元加盟店取引受注日 : always nil
|
|
89
|
+
# - 単価
|
|
90
|
+
# - 数量
|
|
91
|
+
# - 金額
|
|
92
|
+
def build_detail_rows(order)
|
|
93
|
+
rows = []
|
|
94
|
+
set_row = lambda do |name, price, quantity|
|
|
95
|
+
rows << [ name, nil, price.to_i, quantity, price.to_i * quantity ]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
order.line_items.each do |li|
|
|
99
|
+
set_row.call(li.product.name, li.price, li.quantity)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
order.all_adjustments.eligible.where.not(source_type: [ "Spree::TaxRate" ]).each do |adj|
|
|
103
|
+
amount = adj.amount
|
|
104
|
+
next if amount == 0
|
|
105
|
+
|
|
106
|
+
set_row.call(adj.label, amount, 1)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
if order.shipment_total.to_i > 0
|
|
110
|
+
set_row.call("送料", order.shipment_total, 1)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
rows
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def latest_np_payment(order)
|
|
117
|
+
order.payments.valid
|
|
118
|
+
.joins(:payment_method)
|
|
119
|
+
.where(spree_payment_methods: { type: "Spree::PaymentMethod::NpAtobarai" })
|
|
120
|
+
.last
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<% content_for :page_title do %>
|
|
2
|
+
<% if controller_name == 'checkouts' %>
|
|
3
|
+
<%= Spree.t(:draft_orders) %>
|
|
4
|
+
<% else %>
|
|
5
|
+
<%= Spree.t(:orders) %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<% content_for :page_actions do %>
|
|
10
|
+
<%= button_to Spree.t("admin.np_atobarai.btns.btn_export"), csv_export_admin_np_orders_path,
|
|
11
|
+
method: :post,
|
|
12
|
+
params: { order_ids: @orders.map(&:id) },
|
|
13
|
+
class: "btn btn-primary",
|
|
14
|
+
data: { turbo: false } %>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<div class="card-lg np-orders-container">
|
|
18
|
+
<%= render 'spree/admin/orders/filters' %>
|
|
19
|
+
<%= render 'spree_np_atobarai/admin/np_orders/list' %>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
document.addEventListener("turbo:load", function() {
|
|
24
|
+
const form = document.querySelector(".np-orders-container form.filter-wrap")
|
|
25
|
+
if (form) {
|
|
26
|
+
form.removeAttribute("action")
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
</script>
|
data/app/views/spree/admin/payment_methods/custom_form_fields/_np_atobarai_form_fields.html.erb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<div class="form-group">
|
|
2
|
+
<%= f.label :preferred_np_atobarai_fee, Spree.t('np_atobarai.fee_label') %>
|
|
3
|
+
<%= f.text_field :preferred_np_atobarai_fee, class: 'form-control' %>
|
|
4
|
+
<span class="text-muted form-text mt-2">
|
|
5
|
+
<%= Spree.t('np_atobarai.fee_hint') %>
|
|
6
|
+
</span>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div class="form-group">
|
|
10
|
+
<div class="custom-control custom-checkbox">
|
|
11
|
+
<%= f.check_box :preferred_np_atobarai_no_fee_same_month, class: 'custom-control-input' %>
|
|
12
|
+
<%= f.label :preferred_np_atobarai_no_fee_same_month, Spree.t('np_atobarai.no_fee_same_month_label'), class: 'custom-control-label' %>
|
|
13
|
+
</div>
|
|
14
|
+
<span class="text-muted form-text mt-2">
|
|
15
|
+
<%= Spree.t('np_atobarai.no_fee_same_month_hint') %>
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="form-group">
|
|
20
|
+
<%= f.label :preferred_tax_category_id, Spree.t(:tax_category) %>
|
|
21
|
+
<%= f.collection_select(
|
|
22
|
+
:preferred_tax_category_id,
|
|
23
|
+
Spree::TaxCategory.all,
|
|
24
|
+
:id,
|
|
25
|
+
:name,
|
|
26
|
+
{ include_blank: Spree.t(:none) },
|
|
27
|
+
{ class: 'custom-select' }
|
|
28
|
+
) %>
|
|
29
|
+
<span class="text-muted form-text mt-2">
|
|
30
|
+
内税計算を適用する税カテゴリーを選択してください
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% current_payment = @order.payments.last %>
|
|
2
|
+
|
|
3
|
+
<%= render 'spree_np_atobarai/np_atobarai_invoice_options', current_payment: current_payment, payment_method: payment_method, order: @order %>
|
|
4
|
+
|
|
5
|
+
<div class="payment-NpAtobarai">
|
|
6
|
+
<p><%= Spree.t('storefront.checkout.np_atobarai.description').html_safe %></p>
|
|
7
|
+
<% if payment_method&.np_atobarai_fee_adjustment_applicable?(@order, current_payment) %>
|
|
8
|
+
<p>
|
|
9
|
+
<strong><%= Spree.t('storefront.checkout.np_atobarai.extra', extra: Spree::Money.new(payment_method.preferred_np_atobarai_fee).to_s) %></strong>
|
|
10
|
+
</p>
|
|
11
|
+
<% end %>
|
|
12
|
+
</div>
|