workarea-gift_cards 3.4.10 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/{.eslintrc → .eslintrc.json} +12 -1
  3. data/.github/workflows/ci.yml +10 -8
  4. data/.rubocop.yml +2 -197
  5. data/.stylelintrc.json +8 -0
  6. data/CHANGELOG.md +40 -20
  7. data/Gemfile +3 -5
  8. data/README.md +25 -1
  9. data/app/controllers/workarea/api/admin/gift_cards_controller.rb +309 -0
  10. data/app/controllers/workarea/api/storefront/checkouts_controller.decorator +6 -0
  11. data/app/controllers/workarea/api/storefront/gift_cards_controller.rb +2 -8
  12. data/app/controllers/workarea/storefront/checkout/gift_cards_controller.rb +32 -0
  13. data/app/controllers/workarea/storefront/gift_cards_controller.rb +15 -16
  14. data/app/models/workarea/checkout/steps/gift_card.rb +72 -0
  15. data/app/models/workarea/fulfillment/policies/create_gift_card.rb +30 -0
  16. data/app/models/workarea/payment.decorator +25 -7
  17. data/app/models/workarea/payment/authorize/gift_card.rb +7 -20
  18. data/app/models/workarea/payment/capture/gift_card.rb +5 -7
  19. data/app/models/workarea/payment/gift_card.rb +1 -1
  20. data/app/models/workarea/payment/gift_card_operation.rb +9 -0
  21. data/app/models/workarea/payment/purchase/gift_card.rb +24 -1
  22. data/app/models/workarea/payment/refund/gift_card.rb +9 -14
  23. data/app/models/workarea/payment/tender/gift_card.rb +3 -10
  24. data/app/models/workarea/search/admin/order.decorator +2 -4
  25. data/app/seeds/workarea/gift_card_seeds.rb +7 -7
  26. data/app/view_models/workarea/storefront/gift_card_order_pricing.rb +19 -20
  27. data/app/view_models/workarea/storefront/order_view_model.decorator +2 -22
  28. data/app/views/workarea/admin/payment_gift_cards/_menu.html.haml +2 -1
  29. data/app/views/workarea/storefront/checkouts/_gift_card_error.html.haml +8 -6
  30. data/app/views/workarea/storefront/checkouts/_gift_card_payment.html.haml +20 -12
  31. data/app/views/workarea/storefront/gift_card_mailer/created.html.haml +1 -1
  32. data/app/views/workarea/storefront/order_mailer/_gift_card_summary.html.haml +6 -5
  33. data/app/views/workarea/storefront/orders/_gift_card_summary.html.haml +2 -2
  34. data/app/views/workarea/storefront/products/templates/_gift_card.html.haml +5 -5
  35. data/app/workers/workarea/log_gift_card_redemption.rb +16 -9
  36. data/config/initializers/configuration.rb +7 -4
  37. data/config/initializers/fields.rb +14 -0
  38. data/config/locales/en.yml +14 -4
  39. data/config/routes.rb +9 -2
  40. data/lib/workarea/gift_cards.rb +9 -0
  41. data/lib/workarea/gift_cards/gateway.rb +128 -0
  42. data/lib/workarea/gift_cards/version.rb +1 -1
  43. data/test/documentation/workarea/api/admin/gift_cards_documentation_test.rb +24 -10
  44. data/test/documentation/workarea/api/storefront/gift_cards_documentation_test.rb +57 -50
  45. data/test/dummy/config/initializers/session_store.rb +1 -1
  46. data/test/integration/workarea/api/admin/gift_card_integration_test.rb +13 -5
  47. data/test/integration/workarea/api/storefront/checkout_gift_cards_integration_test.rb +120 -0
  48. data/test/integration/workarea/api/storefront/{balance_integration_test.rb → gift_cards_integration_test.rb} +1 -1
  49. data/test/integration/workarea/storefront/checkout_gift_cards_integration_test.rb +116 -0
  50. data/test/integration/workarea/storefront/gift_cards_integration_test.rb +48 -0
  51. data/test/integration/workarea/storefront/purchase_gift_cards_integration_test.rb +55 -0
  52. data/test/lib/workarea/gift_cards/gateway_test.rb +131 -0
  53. data/test/models/workarea/checkout/steps/gift_card_test.rb +104 -0
  54. data/test/models/workarea/fulfillment/policies/create_gift_card_test.rb +47 -0
  55. data/test/models/workarea/gift_card_payment_test.rb +15 -3
  56. data/test/models/workarea/payment/purchase/gift_card_test.rb +11 -8
  57. data/test/queries/workarea/admin_redemptions_export_test.rb +31 -35
  58. data/test/system/workarea/storefront/gift_cards_system_test.rb +8 -2
  59. data/test/view_models/workarea/storefront/gift_card_order_pricing_test.rb +113 -0
  60. data/test/workers/workarea/log_gift_card_redemption_test.rb +1 -1
  61. data/workarea-gift_cards.gemspec +4 -4
  62. metadata +32 -25
  63. data/.eslintignore +0 -2
  64. data/.scss-lint.yml +0 -188
  65. data/app/controllers/workarea/api/admin/payment_gift_cards_controller.rb +0 -49
  66. data/app/controllers/workarea/storefront/checkouts_controller.decorator +0 -24
  67. data/app/services/workarea/checkout/steps/gift_card.rb +0 -49
  68. data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +0 -32
  69. data/app/view_models/workarea/storefront/checkout/summary_view_model.decorator +0 -11
  70. data/app/workers/workarea/create_ordered_gift_cards.rb +0 -47
  71. data/config/initializers/jump_to_navigation.rb +0 -3
  72. data/test/integration/workarea/api/storefront/checkout_integration_test.rb +0 -161
  73. data/test/integration/workarea/storefront/gift_card_integration_test.rb +0 -226
  74. data/test/services/workarea/checkout/steps/gift_card_test.rb +0 -87
  75. data/test/view_models/workarea/storefront/checkout/gift_card_payment_view_model_test.rb +0 -65
  76. data/test/workers/workarea/create_ordered_gift_cards_test.rb +0 -39
@@ -5,6 +5,12 @@ module Workarea
5
5
  Checkout::Steps::GiftCard.new(current_checkout).update(params)
6
6
  render_checkout
7
7
  end
8
+
9
+ def remove_gift_card
10
+ step = Checkout::Steps::GiftCard.new(current_checkout)
11
+ step.remove(params[:gift_card_id])
12
+ render_checkout
13
+ end
8
14
  end
9
15
  end
10
16
  end
@@ -4,18 +4,12 @@ module Workarea
4
4
  module Storefront
5
5
  class GiftCardsController < Api::Storefront::ApplicationController
6
6
  def balance
7
- email = params.fetch(:email, nil)
8
- token = params.fetch(:token, nil)
9
-
10
- if email.present? && token.present?
11
- @gift_card = Payment::GiftCard.find_by_token_and_email(token, email)
12
- end
7
+ @gift_card = Workarea::GiftCards.gateway.lookup(params)
13
8
 
14
9
  if @gift_card.blank?
15
10
  raise Mongoid::Errors::DocumentNotFound.new(
16
11
  Payment::GiftCard,
17
- email: email,
18
- token: token
12
+ params.to_unsafe_h.except('controller', 'action')
19
13
  )
20
14
  end
21
15
  end
@@ -0,0 +1,32 @@
1
+ module Workarea
2
+ module Storefront
3
+ module Checkout
4
+ class GiftCardsController < CheckoutsController
5
+ def add
6
+ step = Workarea::Checkout::Steps::GiftCard.new(current_checkout)
7
+
8
+ if step.update(params)
9
+ flash[:success] = t('workarea.storefront.flash_messages.gift_card_added')
10
+ redirect_to checkout_payment_path
11
+ else
12
+ @step = Storefront::Checkout::PaymentViewModel.new(
13
+ step,
14
+ view_model_options
15
+ )
16
+
17
+ flash[:error] = t('workarea.storefront.flash_messages.gift_card_error')
18
+ render :payment
19
+ end
20
+ end
21
+
22
+ def remove
23
+ step = Workarea::Checkout::Steps::GiftCard.new(current_checkout)
24
+ step.remove(params[:gift_card_id])
25
+
26
+ flash[:success] = t('workarea.storefront.flash_messages.gift_card_removed')
27
+ redirect_to checkout_payment_path
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,24 +1,23 @@
1
1
  module Workarea
2
- class Storefront::GiftCardsController < Storefront::ApplicationController
3
- def index
4
- end
2
+ module Storefront
3
+ class GiftCardsController < ApplicationController
4
+ def index
5
+ end
5
6
 
6
- def lookup
7
- email = params.fetch(:email, nil)
8
- token = params.fetch(:token, nil)
7
+ def lookup
8
+ gift_card = Workarea::GiftCards.gateway.lookup(params)
9
9
 
10
- if email.present? && token.present?
11
- @gift_card = Workarea::Payment::GiftCard
12
- .find_by_token_and_email(token, email)
13
- end
10
+ if gift_card.present?
11
+ flash[:success] = t(
12
+ 'workarea.storefront.flash_messages.gift_card_balance',
13
+ balance: gift_card.balance.format
14
+ )
15
+ else
16
+ flash[:error] = t('workarea.storefront.flash_messages.gift_card_not_found')
17
+ end
14
18
 
15
- if @gift_card.present?
16
- flash[:success] = "Your balance is #{@gift_card.balance.format}"
17
- else
18
- flash[:error] = 'Invalid card number or email.'
19
+ redirect_to gift_cards_balance_path
19
20
  end
20
-
21
- redirect_to gift_cards_balance_path
22
21
  end
23
22
  end
24
23
  end
@@ -0,0 +1,72 @@
1
+ module Workarea
2
+ class Checkout
3
+ module Steps
4
+ class GiftCard < Base
5
+ # Add a gift card tender to the order, updates pricing and adjusts the
6
+ # tender amounts for all existing tenders.
7
+ #
8
+ # @param [Hash] params
9
+ # @option params [String] :gift_card_number a gift card number to apply
10
+ #
11
+ # @return [Boolean] whether the update succeeded (payment were saved)
12
+ #
13
+ def update(params = {})
14
+ gift_card_params = extract_gift_card_params(params)
15
+
16
+ add_gift_card(gift_card_params) if applicable_gift_card?(gift_card_params)
17
+
18
+ update_order
19
+ end
20
+
21
+ # Removes a gift card from payment, updates order pricing and readjusts
22
+ # tender amounts.
23
+ #
24
+ # @param [String] id the gift card tender id
25
+ #
26
+ # @return [Boolean] whether the update succeeded (payment was saved)
27
+ #
28
+ def remove(id)
29
+ payment.gift_cards.find(id).destroy
30
+ rescue Mongoid::Errors::DocumentNotFound
31
+ # no op
32
+ ensure
33
+ update_order
34
+ end
35
+
36
+ # Whether this step of checkout is considered complete. Requires either
37
+ # no gift cards applied, or that all gift cards are valid with a
38
+ # balance. No balance could mean a card is expired, or has been used.
39
+ #
40
+ # @return [Boolean]
41
+ #
42
+ def complete?
43
+ !payment.gift_card? ||
44
+ (
45
+ payment.gift_cards.all?(&:valid?) &&
46
+ payment.gift_cards.none? { |g| g.balance.zero? }
47
+ )
48
+ end
49
+
50
+ private
51
+
52
+ def extract_gift_card_params(params)
53
+ { number: params[:gift_card_number].to_s.gsub(/\s+/, '') }
54
+ end
55
+
56
+ def applicable_gift_card?(params)
57
+ return false unless params[:number].present?
58
+ Workarea::GiftCards.gateway.balance(params[:number]) > 0
59
+ end
60
+
61
+ def add_gift_card(params)
62
+ payment.add_gift_card(params)
63
+ end
64
+
65
+ def update_order
66
+ Pricing.perform(order, shippings)
67
+ payment.adjust_tender_amounts(order.total_price)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ module Workarea
2
+ class Fulfillment
3
+ module Policies
4
+ class CreateGiftCard < Base
5
+ def process(order_item:, fulfillment: nil)
6
+ return unless Workarea::GiftCards.uses_system_cards?
7
+ return unless order_item.gift_card?
8
+
9
+ order_item.quantity.times do
10
+ Payment::GiftCard.create!(
11
+ amount: order_item.original_unit_price,
12
+ order_id: order_item.order.id,
13
+ to: order_item.customizations['email'],
14
+ from: order_item.customizations['from'],
15
+ message: order_item.customizations['message'],
16
+ notify: true,
17
+ purchased: true
18
+ )
19
+ end
20
+
21
+ return unless fulfillment.present?
22
+ fulfillment.mark_item_shipped(
23
+ id: order_item.id.to_s,
24
+ quantity: order_item.quantity
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,19 +1,37 @@
1
1
  module Workarea
2
2
  decorate Payment, with: 'gift_cards' do
3
3
  decorated do
4
- embeds_one :gift_card, class_name: 'Workarea::Payment::Tender::GiftCard'
4
+ embeds_many :gift_cards, class_name: 'Workarea::Payment::Tender::GiftCard'
5
5
  delegate :number, to: :gift_card, allow_nil: true, prefix: true
6
+ validate :gift_card_count_limit
6
7
  end
7
8
 
8
- def set_gift_card(attrs)
9
- build_gift_card unless gift_card
10
- gift_card.number = attrs[:number]
9
+ def gift_card?
10
+ gift_cards.present?
11
+ end
12
+
13
+ def add_gift_card(attrs)
14
+ existing = gift_cards.detect do |card|
15
+ card.number.casecmp?(attrs[:number].strip)
16
+ end
17
+
18
+ if existing.present?
19
+ existing.assign_attributes(attrs)
20
+ else
21
+ gift_cards.build(attrs)
22
+ end
23
+
11
24
  save
12
25
  end
13
26
 
14
- def reset!
15
- self.gift_card = nil
16
- super
27
+ private
28
+
29
+ def gift_card_count_limit
30
+ max = Workarea.config.max_gift_cards_per_order
31
+
32
+ if gift_cards.size > max
33
+ errors.add(:base, I18n.t('workarea.gift_cards.max_applied', count: max))
34
+ end
17
35
  end
18
36
  end
19
37
  end
@@ -3,38 +3,25 @@ module Workarea
3
3
  module Authorize
4
4
  class GiftCard
5
5
  include OperationImplementation
6
+ include GiftCardOperation
6
7
 
7
8
  def complete!
8
- Payment::GiftCard.purchase(tender.number, transaction.amount.cents)
9
+ response = gateway.authorize(transaction.amount.cents, tender)
9
10
 
10
11
  transaction.response = ActiveMerchant::Billing::Response.new(
11
- true,
12
- I18n.t(
13
- 'workarea.gift_cards.debit',
14
- amount: transaction.amount,
15
- number: tender.number
16
- )
17
- )
18
-
19
- rescue Payment::InsufficientFunds
20
- transaction.response = ActiveMerchant::Billing::Response.new(
21
- false,
22
- I18n.t('workarea.gift_cards.insufficient_funds')
12
+ response.success?,
13
+ response.message
23
14
  )
24
15
  end
25
16
 
26
17
  def cancel!
27
18
  return unless transaction.success?
28
19
 
29
- Payment::GiftCard.refund(tender.number, transaction.amount.cents)
20
+ response = gateway.cancel(transaction.amount.cents, tender)
30
21
 
31
22
  transaction.cancellation = ActiveMerchant::Billing::Response.new(
32
- true,
33
- I18n.t(
34
- 'workarea.gift_cards.credit',
35
- amount: transaction.amount,
36
- number: tender.number
37
- )
23
+ response.success?,
24
+ response.message
38
25
  )
39
26
  end
40
27
  end
@@ -3,21 +3,19 @@ module Workarea
3
3
  class Capture
4
4
  class GiftCard
5
5
  include OperationImplementation
6
+ include GiftCardOperation
6
7
 
7
8
  def complete!
8
- # noop, authorization does the capture
9
+ response = gateway.capture(transaction.amount.cents, tender)
10
+
9
11
  transaction.response = ActiveMerchant::Billing::Response.new(
10
- true,
11
- I18n.t('workarea.gift_cards.capture')
12
+ response.success?,
13
+ response.message
12
14
  )
13
15
  end
14
16
 
15
17
  def cancel!
16
18
  # noop, nothing to cancel
17
- transaction.response = ActiveMerchant::Billing::Response.new(
18
- true,
19
- I18n.t('workarea.gift_cards.capture')
20
- )
21
19
  end
22
20
  end
23
21
  end
@@ -28,7 +28,7 @@ module Workarea
28
28
  index(expires_at: 1)
29
29
  index(created_at: 1)
30
30
 
31
- alias number token
31
+ alias_method :number, :token
32
32
 
33
33
  validates :token, presence: true
34
34
  validates :amount, presence: true
@@ -0,0 +1,9 @@
1
+ module Workarea
2
+ class Payment
3
+ module GiftCardOperation
4
+ def gateway
5
+ Workarea::GiftCards.gateway
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,30 @@
1
1
  module Workarea
2
2
  class Payment
3
3
  module Purchase
4
- GiftCard = Authorize::GiftCard
4
+ class GiftCard
5
+ include OperationImplementation
6
+ include GiftCardOperation
7
+
8
+ def complete!
9
+ response = gateway.purchase(transaction.amount.cents, tender)
10
+
11
+ transaction.response = ActiveMerchant::Billing::Response.new(
12
+ response.success?,
13
+ response.message
14
+ )
15
+ end
16
+
17
+ def cancel!
18
+ return unless transaction.success?
19
+
20
+ response = gateway.refund(transaction.amount.cents, tender)
21
+
22
+ transaction.cancellation = ActiveMerchant::Billing::Response.new(
23
+ response.success?,
24
+ response.message
25
+ )
26
+ end
27
+ end
5
28
  end
6
29
  end
7
30
  end
@@ -3,30 +3,25 @@ module Workarea
3
3
  class Refund
4
4
  class GiftCard
5
5
  include OperationImplementation
6
+ include GiftCardOperation
6
7
 
7
8
  def complete!
8
- Payment::GiftCard.refund(tender.number, transaction.amount.cents)
9
+ response = gateway.refund(transaction.amount.cents, tender)
10
+
9
11
  transaction.response = ActiveMerchant::Billing::Response.new(
10
- true,
11
- I18n.t(
12
- 'workarea.gift_cards.credit',
13
- amount: transaction.amount,
14
- number: tender.number
15
- )
12
+ response.success?,
13
+ response.message
16
14
  )
17
15
  end
18
16
 
19
17
  def cancel!
20
18
  return unless transaction.success?
21
19
 
22
- Payment::GiftCard.purchase(tender.number, transaction.amount.cents)
20
+ response = gateway.purchase(transaction.amount.cents, tender)
21
+
23
22
  transaction.cancellation = ActiveMerchant::Billing::Response.new(
24
- true,
25
- I18n.t(
26
- 'workarea.gift_cards.debit',
27
- amount: transaction.amount,
28
- number: tender.number
29
- )
23
+ response.success?,
24
+ response.message
30
25
  )
31
26
  end
32
27
  end
@@ -12,19 +12,12 @@ module Workarea
12
12
  end
13
13
 
14
14
  def amount=(amount)
15
- if amount.blank?
16
- super(amount)
17
- elsif balance >= amount
18
- super(amount)
19
- else
20
- super(balance)
21
- end
15
+ return super(amount) if amount.blank? || balance >= amount
16
+ super(balance)
22
17
  end
23
18
 
24
- private
25
-
26
19
  def balance
27
- @balance ||= Payment::GiftCard.find_balance(number)
20
+ @balance ||= Workarea::GiftCards.gateway.balance(number)
28
21
  end
29
22
  end
30
23
  end