shopify-gold 2.0.0.pre

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 (86) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +144 -0
  3. data/Rakefile +32 -0
  4. data/app/assets/config/gold_manifest.js +0 -0
  5. data/app/assets/images/gold/app-logo.svg +17 -0
  6. data/app/assets/images/gold/aside-bg.svg +54 -0
  7. data/app/assets/javascripts/gold/billing.js +30 -0
  8. data/app/assets/stylesheets/gold/billing.sass +64 -0
  9. data/app/assets/stylesheets/shopify/polaris.css +1 -0
  10. data/app/controllers/gold/admin/billing_controller.rb +190 -0
  11. data/app/controllers/gold/application_controller.rb +17 -0
  12. data/app/controllers/gold/authenticated_controller.rb +15 -0
  13. data/app/controllers/gold/billing_controller.rb +185 -0
  14. data/app/controllers/gold/concerns/merchant_facing.rb +85 -0
  15. data/app/jobs/app_uninstalled_job.rb +2 -0
  16. data/app/jobs/gold/after_authenticate_job.rb +36 -0
  17. data/app/jobs/gold/app_uninstalled_job.rb +10 -0
  18. data/app/jobs/gold/application_job.rb +20 -0
  19. data/app/mailers/gold/application_mailer.rb +7 -0
  20. data/app/mailers/gold/billing_mailer.rb +36 -0
  21. data/app/models/gold/billing.rb +157 -0
  22. data/app/models/gold/concerns/gilded.rb +22 -0
  23. data/app/models/gold/machine.rb +301 -0
  24. data/app/models/gold/shopify_plan.rb +70 -0
  25. data/app/models/gold/tier.rb +97 -0
  26. data/app/models/gold/transition.rb +26 -0
  27. data/app/operations/gold/accept_or_decline_charge_op.rb +119 -0
  28. data/app/operations/gold/accept_or_decline_terms_op.rb +26 -0
  29. data/app/operations/gold/apply_discount_op.rb +32 -0
  30. data/app/operations/gold/apply_tier_op.rb +51 -0
  31. data/app/operations/gold/charge_op.rb +99 -0
  32. data/app/operations/gold/check_charge_op.rb +50 -0
  33. data/app/operations/gold/cleanup_op.rb +20 -0
  34. data/app/operations/gold/convert_affiliate_to_paid_op.rb +32 -0
  35. data/app/operations/gold/freeze_op.rb +15 -0
  36. data/app/operations/gold/install_op.rb +30 -0
  37. data/app/operations/gold/issue_credit_op.rb +55 -0
  38. data/app/operations/gold/mark_as_delinquent_op.rb +21 -0
  39. data/app/operations/gold/resolve_outstanding_charge_op.rb +90 -0
  40. data/app/operations/gold/select_tier_op.rb +58 -0
  41. data/app/operations/gold/suspend_op.rb +21 -0
  42. data/app/operations/gold/uninstall_op.rb +20 -0
  43. data/app/operations/gold/unsuspend_op.rb +20 -0
  44. data/app/views/gold/admin/billing/_active_charge.erb +29 -0
  45. data/app/views/gold/admin/billing/_credit.erb +46 -0
  46. data/app/views/gold/admin/billing/_discount.erb +23 -0
  47. data/app/views/gold/admin/billing/_history.erb +65 -0
  48. data/app/views/gold/admin/billing/_overview.erb +14 -0
  49. data/app/views/gold/admin/billing/_shopify_plan.erb +21 -0
  50. data/app/views/gold/admin/billing/_state.erb +26 -0
  51. data/app/views/gold/admin/billing/_status.erb +25 -0
  52. data/app/views/gold/admin/billing/_tier.erb +155 -0
  53. data/app/views/gold/admin/billing/_trial_days.erb +42 -0
  54. data/app/views/gold/billing/_inner_head.html.erb +1 -0
  55. data/app/views/gold/billing/declined_charge.html.erb +20 -0
  56. data/app/views/gold/billing/expired_charge.html.erb +14 -0
  57. data/app/views/gold/billing/missing_charge.html.erb +22 -0
  58. data/app/views/gold/billing/outstanding_charge.html.erb +12 -0
  59. data/app/views/gold/billing/suspended.html.erb +8 -0
  60. data/app/views/gold/billing/terms.html.erb +22 -0
  61. data/app/views/gold/billing/tier.html.erb +29 -0
  62. data/app/views/gold/billing/transition_error.html.erb +9 -0
  63. data/app/views/gold/billing/unavailable.erb +8 -0
  64. data/app/views/gold/billing/uninstalled.html.erb +13 -0
  65. data/app/views/gold/billing_mailer/affiliate_to_paid.erb +23 -0
  66. data/app/views/gold/billing_mailer/delinquent.html.erb +21 -0
  67. data/app/views/gold/billing_mailer/suspension.html.erb +19 -0
  68. data/app/views/layouts/gold/billing.html.erb +22 -0
  69. data/app/views/layouts/gold/mailer.html.erb +13 -0
  70. data/app/views/layouts/gold/mailer.text.erb +1 -0
  71. data/config/routes.rb +33 -0
  72. data/db/migrate/01_create_gold_billing.rb +11 -0
  73. data/db/migrate/02_create_gold_transitions.rb +29 -0
  74. data/db/migrate/03_add_foreign_key_to_billing.rb +8 -0
  75. data/lib/gold/admin_engine.rb +8 -0
  76. data/lib/gold/billing_migrator.rb +107 -0
  77. data/lib/gold/coverage.rb +89 -0
  78. data/lib/gold/diagram.rb +40 -0
  79. data/lib/gold/engine.rb +16 -0
  80. data/lib/gold/exceptions/metadata_missing.rb +5 -0
  81. data/lib/gold/outcomes.rb +77 -0
  82. data/lib/gold/retries.rb +31 -0
  83. data/lib/gold/version.rb +3 -0
  84. data/lib/gold.rb +102 -0
  85. data/lib/tasks/gold_tasks.rake +94 -0
  86. metadata +298 -0
@@ -0,0 +1,58 @@
1
+ module Gold
2
+ module Outcomes
3
+ CannotSelectTier = Class.new(Failure)
4
+ SameTier = Class.new(Success)
5
+ end
6
+
7
+ # Allows a merchant to select their initial tier or change their tier.
8
+ class SelectTierOp
9
+ include Outcomes
10
+
11
+ def initialize(billing, tier, enforce_locking = true)
12
+ @billing = billing
13
+ @tier = tier
14
+ @enforce_locking = enforce_locking
15
+ end
16
+
17
+ def call
18
+ @billing.transaction do
19
+ return CannotSelectTier.new(:nil) unless @tier
20
+ return CannotSelectTier.new(:locked) if @enforce_locking && @tier.locked?
21
+
22
+ unless @billing.qualifies_for_tier?(@tier)
23
+ return CannotSelectTier.new(:disqualified)
24
+ end
25
+
26
+ # Mark the tier as selected
27
+ if @billing.transition_to(:select_tier, tier_id: @tier.id)
28
+ elsif @billing.transition_to(:change_tier, tier_id: @tier.id)
29
+ else
30
+ message = "Cannot transition from '#{@billing.current_state}' " \
31
+ "to 'select_tier' or 'change_tier'"
32
+ raise Statesman::TransitionFailedError, message
33
+ end
34
+
35
+ # Mark the beginning of the trial if it hasn't been set already
36
+ @billing.update(trial_starts_at: Time.current) unless @billing.trial_starts_at
37
+
38
+ # Process the tier selection, creating charges if necessary
39
+ if @billing.shopify_plan.affiliate?
40
+ @billing.tier = @tier
41
+ @billing.save!
42
+ @billing.transition_to!(:affiliate)
43
+ return TierApplied.new
44
+ elsif @billing.shopify_plan.staff?
45
+ @billing.tier = @tier
46
+ @billing.save!
47
+ @billing.transition_to!(:staff)
48
+ return TierApplied.new
49
+ elsif @tier.free?
50
+ return ApplyTierOp.new(@billing).call
51
+ else
52
+ # A valid charge is necessary before applying the new tier
53
+ return ChargeNeeded.new
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ module Gold
2
+ # Invoked when Helium suspends a merchant for violating ToS.
3
+ class SuspendOp
4
+ include Outcomes
5
+
6
+ def initialize(billing)
7
+ @billing = billing
8
+ end
9
+
10
+ def call
11
+ @billing.transition_to_or_stay_in!(:marked_as_suspended)
12
+
13
+ # Communicate suspension to the merchant.
14
+ BillingMailer.suspension(@billing).deliver_now
15
+
16
+ @billing.transition_to!(:suspended)
17
+
18
+ Success.new
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module Gold
2
+ # Invoked when a shop has uninstalled this app.
3
+ class UninstallOp
4
+ include Outcomes
5
+
6
+ def initialize(billing)
7
+ @billing = billing
8
+ end
9
+
10
+ def call
11
+ return Success.new if @billing.current_state == :uninstalled
12
+
13
+ @billing.transition_to_or_stay_in!(:marked_as_uninstalled)
14
+ @billing.transition_to!(:uninstalled)
15
+ Gold.configuration.on_uninstall&.call(@billing)
16
+
17
+ Success.new
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Gold
2
+ # Invoked when Helium unsuspends a shop.
3
+ class UnsuspendOp
4
+ include Outcomes
5
+
6
+ def initialize(billing)
7
+ @billing = billing
8
+ end
9
+
10
+ def call
11
+ if @billing.can_transition_to?(:affiliate)
12
+ @billing.transition_to!(:affiliate)
13
+ else
14
+ @billing.transition_to!(:check_charge)
15
+ end
16
+
17
+ Success.new
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header">
3
+ <strong>Active charge</strong>
4
+ </div>
5
+ <div class="card-body">
6
+ <% billing.shop.with_shopify_session do %>
7
+ <% charge = @active_charge %>
8
+ <% if charge %>
9
+ <% if charge.test %>
10
+ <span class="badge badge-warning">test charge</span>
11
+ <hr>
12
+ <% end %>
13
+ <p>Name<br> <strong><%= charge.name %></strong></p>
14
+ <p>ID<br> <strong><%= charge.id %></strong></p>
15
+ <p>Monthly<br> <strong>$<%= charge.price %></strong></p>
16
+ <p>Trial days<br> <strong><%= charge.trial_days %></strong></p>
17
+ <p>Created at<br> <strong><%= DateTime.parse(charge.created_at).strftime("%Y-%m-%e %H:%M") %></strong></p>
18
+ <p>Trial ends on<br> <strong><%= charge.trial_ends_on %></strong></p>
19
+ <p>Next billing<br> <strong><%= charge.billing_on %></strong></p>
20
+
21
+ <%= form_tag(gold_admin_engine.cancel_charge_path(id: billing.id, charge_id: charge.id), method: :delete) do %>
22
+ <%= submit_tag 'Cancel charge', class: "btn btn-danger", data: {confirm: "Are you really sure you want to cancel this charge?"} %>
23
+ <% end %>
24
+ <% else %>
25
+ No charge from Shopify
26
+ <% end %>
27
+ <% end %>
28
+ </div>
29
+ </div>
@@ -0,0 +1,46 @@
1
+ <% billing.shop.with_shopify_session do %>
2
+ <% credits = @credits %>
3
+ <div class="card mb-3">
4
+ <div class="card-header">
5
+ <strong>Credit</strong>
6
+ </div>
7
+ <div class="card-body">
8
+ <h6>Credits</h6>
9
+ <% if credits.any? %>
10
+ <table class="table celled">
11
+ <thead>
12
+ <tr>
13
+ <th>Reason</th>
14
+ <th>Amount</th>
15
+ </tr>
16
+ </thead>
17
+ <tbody>
18
+ <% billing.shop.with_shopify_session do %>
19
+ <% ShopifyAPI::ApplicationCredit.all.each do |credit| %>
20
+ <tr>
21
+ <%= credit.description %>
22
+ <% if credit.test %>
23
+ <strong>(test)</strong>
24
+ <% end %>
25
+ </tr>
26
+ <tr><%= credit.amount %></tr>
27
+ <% end %>
28
+ <% end %>
29
+ </tbody>
30
+ </table>
31
+ <% else %>
32
+ <p>No active credits</p>
33
+ <% end %>
34
+ <hr>
35
+ <%= form_tag(gold_admin_engine.issue_credit_path(id: billing.id), method: :post) do %>
36
+ <p>Give the merchant a credit for next month (in dollars)</p>
37
+ <%= number_field_tag 'amount', 0, size: 3 %>
38
+ <%= text_field_tag 'reason', '', placeholder: 'Reason to merchant' %>
39
+ <div>
40
+ <hr>
41
+ <%= submit_tag 'Issue Credit', class: "btn btn-primary" %>
42
+ </div>
43
+ <% end %>
44
+ </div>
45
+ </div>
46
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header">
3
+ <strong>Discount</strong>
4
+ </div>
5
+ <div class="card-body">
6
+ <%= form_tag(gold_admin_engine.apply_discount_path(id: billing.id), method: :put) do %>
7
+ <input
8
+ type="number"
9
+ name="percentage"
10
+ min="0"
11
+ max="100"
12
+ value="<%= billing.discount_percentage %>">%
13
+ <div>
14
+ <hr>
15
+ <% if billing.can_transition_to?(:apply_discount) %>
16
+ <%= submit_tag 'Apply discount', class: "btn btn-primary", data: {confirm: "Are you really sure you want to apply this discount?"} %>
17
+ <% else %>
18
+ <p>Discount cannot be applied in the current state</p>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+ </div>
23
+ </div>
@@ -0,0 +1,65 @@
1
+
2
+ <div class="card">
3
+ <div class="card-header">
4
+ <strong>History</strong>
5
+ </div>
6
+ <div class="card-body">
7
+ <p>These are all the billing-related events that have happened.
8
+ Only forcefully transition to a state as a last resort.</p>
9
+
10
+ <div class="mb-4">
11
+ <%= form_tag(gold_admin_engine.transition_path, method: :put) do %>
12
+ <input type="hidden" name="id" value="<%= billing.id %>">
13
+ <div>
14
+ Transition from <mark><%= billing.current_state %></mark>
15
+ &rarr;
16
+ <select name="to" class="mr-2">
17
+ <option value="">Select a state...</option>
18
+ <% Gold::Machine.successors.with_indifferent_access[billing.current_state].each do |transition| %>
19
+ <option><%= transition %></option>
20
+ <% end %>
21
+ </select>
22
+ </div>
23
+ <div class="mb-2 mt-2">
24
+ Metadata:
25
+ <input type="text" name="metadata[key]" placeholder="key">
26
+ <input type="text" name="metadata[value]" placeholder="value">
27
+ </div>
28
+ <%= submit_tag 'Transition', class: "btn btn-primary" %>
29
+ <% end %>
30
+ </div>
31
+ <div style="max-height: 500px; overflow: auto;">
32
+ <table class="table table-sm table-dark">
33
+ <thead>
34
+ <tr>
35
+ <th>Date</th>
36
+ <th>State</th>
37
+ <th>Metadata</th>
38
+ </tr>
39
+ </thead>
40
+ <tbody>
41
+ <% last_transition = nil %>
42
+ <% billing.state_machine.history.where.not(to_state: "check_charge").reverse.each do |transition| %>
43
+ <%# This hides all the check_charges and back to billing %>
44
+ <% if transition.to_state == "billing" %>
45
+ <% unless last_transition&.to_state == "billing" %>
46
+ <tr>
47
+ <td><%= transition.created_at.localtime.strftime("%Y-%m-%e %H:%M") %></td>
48
+ <td><%= transition.to_state %></td>
49
+ <td><%= transition.metadata %></td>
50
+ </tr>
51
+ <% end %>
52
+ <% else %>
53
+ <tr>
54
+ <td><%= transition.created_at.localtime.strftime("%Y-%m-%e %H:%M") %></td>
55
+ <td><%= transition.to_state %></td>
56
+ <td><%= transition.metadata %></td>
57
+ </tr>
58
+ <% end %>
59
+ <% last_transition = transition %>
60
+ <% end %>
61
+ </tbody>
62
+ </table>
63
+ </div>
64
+ </div>
65
+ </div>
@@ -0,0 +1,14 @@
1
+ <%= render "gold/admin/billing/state", billing: billing %>
2
+ <% tier = billing.tier %>
3
+ <% if tier %>
4
+ <%= render "gold/admin/billing/tier", billing: billing, tier: tier %>
5
+ <% end %>
6
+ <%= render "gold/admin/billing/active_charge", billing: billing %>
7
+ <%= render "gold/admin/billing/status", billing: billing %>
8
+ <%= render "gold/admin/billing/discount", billing: billing %>
9
+ <% if tier %>
10
+ <%= render "gold/admin/billing/trial_days", billing: billing %>
11
+ <% end %>
12
+ <%= render "gold/admin/billing/credit", billing: billing %>
13
+ <%= render "gold/admin/billing/shopify_plan", billing: billing %>
14
+ <%= render "gold/admin/billing/history", billing: billing %>
@@ -0,0 +1,21 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header">
3
+ <strong>Shopify Plan Override</strong>
4
+ </div>
5
+ <div class="card-body">
6
+ <%= form_tag(gold_admin_engine.override_shopify_plan_path(id: billing.id), method: :put) do %>
7
+ <p>
8
+ Actual Shopify plan:
9
+ <span class="badge badge-info"><%= billing.shop.shopify_plan_name %></span>
10
+ </p>
11
+ <input
12
+ type="text"
13
+ name="plan"
14
+ value="<%= billing.shopify_plan_override %>">
15
+ <div>
16
+ <hr>
17
+ <%= submit_tag 'Override', class: "btn btn-primary", data: {confirm: "Are you really sure you want to override plan?"} %>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ </div>
@@ -0,0 +1,26 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header"><strong>Status</strong></div>
3
+ <div class="card-body">
4
+ <h3 class="badge
5
+ <% if billing.state_machine.accepted? %>
6
+ badge-success
7
+ <% else %>
8
+ badge-warning
9
+ <% end %>">
10
+ <%= billing.current_state %>
11
+ <% metadata = billing.transitions.last&.metadata %>
12
+ <% if metadata&.keys&.any? %>
13
+ &rarr;
14
+ <%= metadata.to_a.join(": ") %>
15
+ <% end %>
16
+ </h3>
17
+
18
+ <% if billing.can_transition_to?(:optional_charge_declined) %>
19
+ <%= form_tag(gold_admin_engine.transition_path(id: billing.id), method: :put) do %>
20
+ <input type="hidden" name="to[]" value="optional_charge_declined">
21
+ <input type="hidden" name="to[]" value="billing">
22
+ <%= submit_tag 'Decline', class: "btn btn-danger btn-sm", data: { confirm: "Are you sure you want to decline this charge?" } %>
23
+ <% end %>
24
+ <% end %>
25
+ </div>
26
+ </div>
@@ -0,0 +1,25 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header">
3
+ <strong>Account status</strong>
4
+ </div>
5
+ <div class="card-body">
6
+ <% if billing.current_state.to_s.include?("suspended") %>
7
+ <p>This account is currently <strong>suspended</strong></p>
8
+ <%= form_tag(gold_admin_engine.unsuspend_path(id: billing.id), method: :put) do %>
9
+ <%= submit_tag 'Unsuspend', data: {confirm: "Are you really sure you want to UNSUSPEND this account?"} %>
10
+ <% end %>
11
+ <% else %>
12
+ <p>This account is currently <strong>allowed</strong></p>
13
+ <% if billing.can_transition_to? :marked_as_suspended %>
14
+ <%= form_tag(gold_admin_engine.suspend_path(id: billing.id), method: :put) do %>
15
+ <div>
16
+ <label>
17
+ <input type="checkbox" name="confirm_suspend"> Yes I want to suspend this account
18
+ </label>
19
+ </div>
20
+ <%= submit_tag 'Confirm suspend', class:"btn btn-secondary btn-danger", data: {confirm: "Are you really sure you want to SUSPEND this account?"} %>
21
+ <% end %>
22
+ <% end %>
23
+ <% end %>
24
+ </div>
25
+ </div>
@@ -0,0 +1,155 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header"><strong>Tier</strong></div>
3
+ <div class="card-body">
4
+ <table class="table">
5
+ <tr>
6
+ <td><h6>Plan</h6></td>
7
+ <td><h6>Plan ID</h6></td>
8
+ <td><h6>Monthly price</h6></td>
9
+ <td><h6>Plan trial days</h6></td>
10
+ <td><h6>Trial days left</h6></td>
11
+ <td><h6>Features</h6></td>
12
+ </tr>
13
+ <% next_tier = billing.last_selected_tier %>
14
+ <% if tier.id != next_tier.id %>
15
+ <tr>
16
+ <td><%= next_tier.name %> <span class="badge badge-warning">pending</span></td>
17
+ <td>
18
+ <span class="badge badge-info"><%= next_tier.id %></span>
19
+ </td>
20
+ <td>
21
+ <% next_tier_price = next_tier.monthly_price %>
22
+ <% next_tier_calc_price = billing.calculate_price(next_tier) %>
23
+
24
+ <% if next_tier_price != next_tier_calc_price %>
25
+ <s><%= number_to_currency(next_tier_price) %></s>
26
+ <% end %>
27
+
28
+ <%= number_to_currency(next_tier_calc_price) %>
29
+ </td>
30
+ <td><%= next_tier.trial_days %></td>
31
+ <td><%= billing.calculate_trial_days(next_tier) %></td>
32
+ <td>
33
+ <% next_tier.features.each do |feature| %>
34
+ <div>
35
+ <span class="badge badge-success"><%= feature.join(": ") %></span>
36
+ </div>
37
+ <% end %>
38
+ </td>
39
+ </tr>
40
+ <% end %>
41
+
42
+ <% if tier %>
43
+ <tr>
44
+ <td><%= tier.name %> <span class="badge badge-success">active</span></td>
45
+ <td>
46
+ <span class="badge badge-info"><%= tier.id %></span>
47
+ </td>
48
+ <td>
49
+ <% tier_price = tier.monthly_price %>
50
+ <% tier_calc_price = billing.calculate_price(tier) %>
51
+
52
+ <% if tier_price != tier_calc_price %>
53
+ <s><%= number_to_currency(tier_price) %></s>
54
+ <% end %>
55
+
56
+ <%= number_to_currency(tier_calc_price) %>
57
+ </td>
58
+ <td><%= tier.trial_days %></td>
59
+ <td><%= billing.calculate_trial_days(tier) %></td>
60
+ <td>
61
+ <% tier.features.each do |feature| %>
62
+ <div>
63
+ <span class="badge badge-success"><%= feature.join(": ") %></span>
64
+ </div>
65
+ <% end %>
66
+ </td>
67
+ </tr>
68
+ <% end %>
69
+ </table>
70
+ <hr>
71
+ <% if billing.can_transition_to?(:change_tier) %>
72
+ <%= form_tag(gold_admin_engine.change_tier_path(id: billing.id), method: :put) do %>
73
+ Change tier &rarr;
74
+ <select name="tier" class="mr-2">
75
+ <option value="">Select a tier...</option>
76
+ <%= Gold::Tier.all.each do |_tier| %>
77
+ <% price_difference = _tier.monthly_price - tier.monthly_price %>
78
+ <option value="<%= _tier.id %>" <% if _tier.locked? %>disabled<% end %>>
79
+ <%= _tier.name %>
80
+ <% if _tier.free? %>
81
+ (free)
82
+ <% elsif price_difference > 0 %>
83
+ (+<%= number_to_currency(price_difference) %>)
84
+ <% elsif price_difference < 0 %>
85
+ (-<%= number_to_currency(price_difference.abs) %>)
86
+ <% end %>
87
+
88
+ <% if _tier.locked? %>(locked)<% end %>
89
+ </option>
90
+ <% end %>
91
+ </select>
92
+ <%= submit_tag 'Apply', class: "btn btn-primary btn-sm" %>
93
+ <% end %>
94
+ <% else %>
95
+ <p>Can't change tiers, because the current state doesn't allow it</p>
96
+ <% end %>
97
+ <br />
98
+ <a data-toggle="collapse" href="#collapsePlans" role="button" aria-expanded="false" aria-controls="collapsePlans">
99
+ See all plans
100
+ </a>
101
+
102
+ <table id="collapsePlans" class="table celled collapse">
103
+ <thead>
104
+ <tr>
105
+ <th>ID</th>
106
+ <th>Name</th>
107
+ <th>Monthly price</th>
108
+ <th>Trial days</th>
109
+ <th>Features</th>
110
+ <th>Qualifications</th>
111
+ </tr>
112
+ </thead>
113
+ <tbody>
114
+ <% Gold::Tier.all.each do |tier| %>
115
+ <tr>
116
+ <td><%= tier.id %></td>
117
+ <td>
118
+ <%= tier.name %>
119
+
120
+ <div>
121
+ <% if tier.locked? %>
122
+ <span class="badge badge-warning">locked</span>
123
+ <% end %>
124
+
125
+ <% if tier.free? %>
126
+ <span class="badge badge-info">free</span>
127
+ <% end %>
128
+
129
+ <% unless tier.visible? %>
130
+ <span class="badge badge-secondary">hidden</span>
131
+ <% end %>
132
+ </div>
133
+ </td>
134
+ <td><%= number_to_currency(tier.monthly_price) %></td>
135
+ <td><%= tier.trial_days %></td>
136
+ <td>
137
+ <% tier.features.each do |feature| %>
138
+ <div>
139
+ <span class="badge badge-success"><%= feature.join(": ") %></span>
140
+ </div>
141
+ <% end %>
142
+ </td>
143
+ <td>
144
+ <% tier.qualifications.each do |qual| %>
145
+ <div>
146
+ <span class="badge badge-danger"><%= qual.join(": ") %></span>
147
+ </div>
148
+ <% end %>
149
+ </td>
150
+ </tr>
151
+ <% end %>
152
+ </tbody>
153
+ </table>
154
+ </div>
155
+ </div>
@@ -0,0 +1,42 @@
1
+ <div class="card mb-3">
2
+ <div class="card-header">
3
+ <strong>Trial Days</strong>
4
+ </div>
5
+ <div class="card-body">
6
+ <% if billing.trial_starts_at %>
7
+ <p>
8
+ Trial started at:
9
+ <strong><%= billing.trial_starts_at.localtime.strftime("%Y-%m-%e %H:%M") %></strong>
10
+ </p>
11
+
12
+ <p>
13
+ Trial days left:
14
+ <strong><%= billing.trial_days_left %></strong>
15
+ </p>
16
+
17
+ <hr>
18
+
19
+ <%= form_tag(gold_admin_engine.reset_trial_days_path(id: billing.id), method: :put) do %>
20
+ <input type="hidden" name="trial_action" value="reset">
21
+ <p>
22
+ Start the trial over starting today. The merchant won't be forced to update charge.
23
+ </p>
24
+ <%= submit_tag 'Reset trial', class: "btn btn-primary", data: {confirm: "You sure?"} %>
25
+ <% end %>
26
+
27
+ <hr>
28
+
29
+ <%= form_tag(gold_admin_engine.reset_trial_days_path(id: billing.id), method: :put) do %>
30
+ <input type="hidden" name="trial_action" value="clear">
31
+ <p>
32
+ Clear the trial and only start again once they choose a plan. The merchant will be
33
+ prompted to accept a new charge if they already have one.
34
+ </p>
35
+ <%= submit_tag 'Clear trial', class: "btn btn-secondary", data: {confirm: "You sure?"} %>
36
+ <% end %>
37
+
38
+ <% else %>
39
+ <p>Trial not started yet</p>
40
+ <% end %>
41
+ </div>
42
+ </div>
@@ -0,0 +1 @@
1
+ <%# Override this in your app %>
@@ -0,0 +1,20 @@
1
+ <p class="Polaris-DisplayText Polaris-DisplayText--sizeLarge">
2
+ Charge declined
3
+ </p>
4
+ <p>
5
+ We couldn't process your payment because you declined the charge from Shopify.
6
+ </p>
7
+ <div style="height: 25px;"></div>
8
+
9
+ <%= form_tag(retry_charge_path, method: :post) do %>
10
+ <a class="Polaris-Button" href="<%= tier_path %>">Choose a plan</a>
11
+ <span style="padding: 0 10px;">or</span>
12
+ <button
13
+ type="submit"
14
+ class="Polaris-Button Polaris-Button--primary">
15
+ <span class="Polaris-Button__Content">
16
+ <span class="Polaris-Button__Text">Try again</span>
17
+ </span>
18
+ </button>
19
+ </p>
20
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <p class="Polaris-DisplayText Polaris-DisplayText--sizeLarge">
2
+ Your app charge has expired
3
+ </p>
4
+ <p>Please accept a new charge before continuing.</p>
5
+ <div style="height: 25px;"></div>
6
+ <%= form_tag(retry_charge_path, method: :post) do %>
7
+ <button
8
+ type="submit"
9
+ class="Polaris-Button Polaris-Button--primary">
10
+ <span class="Polaris-Button__Content">
11
+ <span class="Polaris-Button__Text">Try again</span>
12
+ </span>
13
+ </button>
14
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <p class="Polaris-DisplayText Polaris-DisplayText--sizeLarge">
2
+ Missing app charge
3
+ </p>
4
+
5
+ <p>
6
+ We have checked our records and Shopify's and we cannot find your recurring
7
+ charge for <%= Gold.configuration.app_name %>. The following might prompt you to approve a new charge with
8
+ Shopify. Don't worry, this will replace any existing charge so you won't be
9
+ double-charged.
10
+ </p>
11
+
12
+ <div style="height: 25px;"></div>
13
+
14
+ <%= form_tag(retry_charge_path, method: :post) do %>
15
+ <button
16
+ type="submit"
17
+ class="Polaris-Button Polaris-Button--primary">
18
+ <span class="Polaris-Button__Content">
19
+ <span class="Polaris-Button__Text">Continue</span>
20
+ </span>
21
+ </button>
22
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <p class="Polaris-DisplayText Polaris-DisplayText--sizeLarge">
2
+ Outstanding app charge
3
+ </p>
4
+
5
+ <p>
6
+ Please approve this charge before continuing. You will be redirected to Shopify's billing
7
+ to accept this charge.
8
+ </p>
9
+
10
+ <div style="height: 25px;"></div>
11
+
12
+ <a class="Polaris-Button Polaris-Button--primary" href="<%= @confirmation_url %>">View charges</a>
@@ -0,0 +1,8 @@
1
+ <p class="Polaris-DisplayText Polaris-DisplayText--sizeLarge">
2
+ Your store is currently suspended
3
+ </p>
4
+
5
+ <p>
6
+ We have sent you an email about this. Please reach out to support so
7
+ that we can resolve this.
8
+ </p>