workarea-gift_cards 3.4.10 → 4.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 (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