diff --git a/admin/.rakeTasks b/admin/.rakeTasks
deleted file mode 100644
index 78308c2e6..000000000
--- a/admin/.rakeTasks
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/admin/Gemfile b/admin/Gemfile
index 91f5e0643..b9099a250 100644
--- a/admin/Gemfile
+++ b/admin/Gemfile
@@ -72,6 +72,7 @@ gem 'jquery-ui-rails'# , '5.0.5' #, '4.2.1'
gem 'jquery-rails'# , '4.1.1' # both this and jquery-ui-rails are pinned; if you unpin, jquery/autocomplete is missing during precomplie
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete
gem 'activeadmin' #, '1.0.0.pre4'# github: 'activeadmin', branch: 'master'
+gem 'activeadmin-searchable_select'
gem 'mime-types', '1.25'
#gem 'meta_search'
gem 'fog'
diff --git a/admin/Gemfile.lock b/admin/Gemfile.lock
index 141ff9ea3..8abef39c6 100644
--- a/admin/Gemfile.lock
+++ b/admin/Gemfile.lock
@@ -47,6 +47,10 @@ GEM
ransack (>= 1.8.7)
sass (~> 3.1)
sprockets (< 4.1)
+ activeadmin-searchable_select (1.4.0)
+ activeadmin (>= 1.x, < 3)
+ jquery-rails (>= 3.0, < 5)
+ select2-rails (~> 4.0)
activeadmin_addons (1.7.1)
active_material
railties
@@ -695,6 +699,7 @@ PLATFORMS
DEPENDENCIES
aasm
activeadmin
+ activeadmin-searchable_select
activeadmin_addons
amqp (= 0.9.8)
auto_strip_attributes (= 2.6.0)
@@ -788,7 +793,7 @@ DEPENDENCIES
zip-codes
RUBY VERSION
- ruby 2.3.1p112
+ ruby 2.4.1p111
BUNDLED WITH
1.17.3
diff --git a/admin/app/admin/affiliate_cohorts.rb b/admin/app/admin/affiliate_cohorts.rb
new file mode 100644
index 000000000..d1f4d5a6c
--- /dev/null
+++ b/admin/app/admin/affiliate_cohorts.rb
@@ -0,0 +1,108 @@
+class AffiliateCohortsHelper
+ def self.percentage(opTop, opBottom)
+ "#{(opTop/opBottom * 100).round(1)}%"
+ end
+
+ def self.quarter(date)
+ case date.month
+ when 1, 2, 3 then 0
+ when 4, 5, 6 then 1
+ when 7, 8, 9 then 2
+ when 10, 11, 12 then 3
+ end
+ end
+
+ def self.payments_for_months(affiliate_partner, year, start_month, end_month)
+ JamRuby::AffiliateMonthlyPayment.where(
+ "affiliate_partner_id = ? AND month >= ? AND month <= ? AND year = ?",
+ affiliate_partner.id,
+ start_month,
+ end_month,
+ year
+ ).order('month DESC')
+ end
+
+ def self.payments_for_quarter(affiliate_partner, year, quarter)
+ JamRuby::AffiliateQuarterlyPayment.where(
+ "affiliate_partner_id = ? AND quarter = ? AND year = ?",
+ affiliate_partner.id,
+ quarter,
+ year
+ ).order('quarter DESC')
+ end
+
+ def self.all_time_payments(affiliate_partner)
+ JamRuby::AffiliateQuarterlyPayment.where(
+ "affiliate_partner_id = ?", affiliate_partner.id
+ )
+ end
+
+ def self.current_quarter_payments(affiliate_partner)
+ AffiliateCohortsHelper.payments_for_quarter(affiliate_partner,
+ Date.today.year,
+ AffiliateCohortsHelper.quarter(Date.today)
+ )
+ end
+
+ def self.current_quarter_monthly_payments(affiliate_partner)
+ AffiliateCohortsHelper.payments_for_months(affiliate_partner,
+ Date.today.beginning_of_quarter.year,
+ Date.today.beginning_of_quarter.month,
+ Date.today.end_of_quarter.month
+ )
+ end
+
+ def self.prior_quarter_payments(affiliate_partner)
+ prev_quarter_start = (Date.today.beginning_of_quarter - 1.day).beginning_of_quarter
+ prev_quarter = AffiliateCohortsHelper.quarter(prev_quarter_start)
+ AffiliateCohortsHelper.payments_for_quarter(affiliate_partner,
+ prev_quarter_start.year,
+ prev_quarter
+ )
+ end
+
+ def self.prior_quarter_payable_amount(affiliate_partner)
+ total = AffiliateCohortsHelper.prior_quarter_payments(affiliate_partner).inject(0.0){ | sum, payment |
+ sum += payment.due_amount_in_cents }
+ paid = AffiliateCohortsHelper.prior_quarter_payments(affiliate_partner).where(paid: false).inject(0.0){ | sum, payment |
+ sum += payment.due_amount_in_cents }
+ (total - paid) / 100.0
+ end
+end
+
+ActiveAdmin.register_page "Affiliate Cohorts" do
+ menu parent: 'Reports'
+
+ content :title => "Affiliate Cohorts" do
+ table_for AffiliatePartner.includes(:partner_user).all do
+ column 'Affiliate Name' do |partner|
+ link_to partner.partner_name, admin_affiliate_path(partner)
+ end
+ column 'Affiliate ID', :id
+ column 'Affiliate Email', Proc.new{ | partner | partner.partner_user.email}
+ column 'Affiliate Paypal', Proc.new{| partner | partner&.paypal_id }
+ column 'All Time Users', :referral_user_count
+ column 'All Time Subscribers', Proc.new{ | partner | partner.subscribed_user_referrals.size }
+ column 'All Time Subscriber Conversion Rate', Proc.new{ | partner |
+ AffiliateCohortsHelper.percentage(partner.subscribed_user_referrals.size.to_f, partner.referral_user_count.to_f) }
+ column 'All Time Revenues', Proc.new{ | partner |
+ number_to_currency(AffiliateCohortsHelper.all_time_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0)
+ }
+ column 'Current Quarter Revenues', Proc.new{ | partner |
+ number_to_currency(AffiliateCohortsHelper.current_quarter_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0 )
+ }
+ column 'Current Quarter Revenues by Month', Proc.new{ | partner |
+ AffiliateCohortsHelper.current_quarter_monthly_payments(partner).each do |monthly_payment|
+ li "#{Date::MONTHNAMES[monthly_payment.month]} #{monthly_payment.year} - #{number_to_currency(monthly_payment.due_amount_in_cents.to_f / 100.0)}"
+ end
+ ''.html_safe
+ }
+ column 'Prior Quarter Revenues', Proc.new{ | partner |
+ number_to_currency(AffiliateCohortsHelper.prior_quarter_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0)
+ }
+ column 'Prior Quarter Payable', Proc.new{ | partner |
+ number_to_currency(AffiliateCohortsHelper.prior_quarter_payable_amount(partner))
+ }
+ end
+ end
+end
\ No newline at end of file
diff --git a/admin/app/admin/affiliate_links.rb b/admin/app/admin/affiliate_links.rb
new file mode 100644
index 000000000..2080553b2
--- /dev/null
+++ b/admin/app/admin/affiliate_links.rb
@@ -0,0 +1,33 @@
+ActiveAdmin.register JamRuby::AffiliateLink, :as => 'Affiliate Links' do
+
+ menu :label => 'Links', :parent => 'Affiliates'
+
+ config.sort_order = 'created_at ASC'
+ config.batch_actions = false
+ # config.clear_action_items!
+ config.filters = false
+ config.per_page = 50
+ config.paginate = true
+
+ #form :partial => 'form'
+
+
+ form do |f|
+ f.inputs 'Fields' do
+ f.input(:name, :input_html => { :maxlength => 255 })
+ f.input(:link, :input_html => { :maxlength => 255 })
+ end
+ f.actions
+ end
+
+ index do
+
+ column 'Name' do |oo|
+ oo.name
+ end
+ column 'Link' do |oo|
+ oo.link
+ end
+ actions
+ end
+end
diff --git a/admin/app/admin/affiliates.rb b/admin/app/admin/affiliates.rb
index 2ff8813e3..dc99718c4 100644
--- a/admin/app/admin/affiliates.rb
+++ b/admin/app/admin/affiliates.rb
@@ -9,22 +9,51 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
config.per_page = 50
config.paginate = true
- form :partial => 'form'
+ #form :partial => 'form'
scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
scope("Unpaid") { |partner| partner.unpaid }
+ controller do
+ helper 'active_admin/subscription'
+ end
+
+ form do |f|
+ f.inputs 'Fields' do
+ f.input(:partner_name, :input_html => { :maxlength => 128 })
+ f.input(:partner_user, as: :searchable_select, hint: 'This person is the owner of the affiliate. Has access to reporting info in account section of www.jamkazam.com')
+ f.input(:entity_type, :as => :select, :collection => AffiliatePartner::ENTITY_TYPES)
+ f.input(:rate)
+ f.input(:paypal_id)
+ end
+ f.actions
+ end
+
index do
# actions # use this for all view/edit/delete links
- column 'User' do |oo| link_to(oo.partner_user.name, admin_user_path(oo.partner_user.id), {:title => oo.partner_user.name}) end
- column 'Name' do |oo| oo.partner_name end
- column 'Type' do |oo| oo.entity_type end
- column 'Code' do |oo| oo.id end
- column 'Referral Count' do |oo| oo.referral_user_count end
- column 'Earnings' do |oo| sprintf("$%.2f", oo.cumulative_earnings_in_dollars) end
- column 'Amount Owed' do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end
+ column 'User' do |oo|
+ link_to(oo.partner_user.name, admin_user_path(oo.partner_user.id), { :title => oo.partner_user.name })
+ end
+ column 'Name' do |oo|
+ oo.partner_name
+ end
+ column 'Type' do |oo|
+ oo.entity_type
+ end
+ column 'Code' do |oo|
+ oo.id
+ end
+ column 'Referral Count' do |oo|
+ oo.referral_user_count
+ end
+ column 'Earnings' do |oo|
+ sprintf("$%.2f", oo.cumulative_earnings_in_dollars)
+ end
+ column 'Amount Owed' do |oo|
+ sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
+ end
column 'Pay Actions' do |oo|
link_to('Mark Paid', mark_paid_admin_affiliate_path(oo.id), :confirm => "Mark this affiliate as PAID?") if oo.unpaid
end
@@ -32,6 +61,22 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
actions
end
+ show do |affiliate_partner|
+
+ attributes_table do
+ row :id
+ row :partner_name
+ row :entity_type
+ row :rate
+ row :address
+ row :tax_identifier
+ row :paypal_id
+ end
+
+
+ render 'earnings', { affiliate_partner: affiliate_partner }
+
+ end
action_item :only => [:show] do
link_to("Mark Paid",
diff --git a/admin/app/admin/jam_ruby_users.rb b/admin/app/admin/jam_ruby_users.rb
index 58dbe92f1..aaf2b70ca 100644
--- a/admin/app/admin/jam_ruby_users.rb
+++ b/admin/app/admin/jam_ruby_users.rb
@@ -1,5 +1,11 @@
ActiveAdmin.register JamRuby::User, :as => 'Users' do
+ searchable_select_options(scope: User.all,
+ text_attribute: :username,
+ filter: lambda do |term, scope|
+ scope.ransack(full_name_or_email_cont: term).result
+ end)
+
collection_action :autocomplete_user_email, :method => :get
actions :all, :except => [:destroy]
diff --git a/admin/app/assets/javascripts/active_admin.js b/admin/app/assets/javascripts/active_admin.js
index df9db3400..a79135b71 100644
--- a/admin/app/assets/javascripts/active_admin.js
+++ b/admin/app/assets/javascripts/active_admin.js
@@ -9,6 +9,7 @@
// require jquery.ui.autocomplete
//= require cocoon
//= require active_admin/base
+//= require active_admin/searchable_select
// //= require autocomplete-rails
//= require base
//= require_tree .
diff --git a/admin/app/assets/stylesheets/active_admin.css.scss b/admin/app/assets/stylesheets/active_admin.css.scss
index f5bb8a9c2..05c71f28a 100644
--- a/admin/app/assets/stylesheets/active_admin.css.scss
+++ b/admin/app/assets/stylesheets/active_admin.css.scss
@@ -15,6 +15,7 @@
// Active Admin's got SASS!
@import "active_admin/mixins";
@import "active_admin/base";
+@import "active_admin/searchable_select";
// Overriding any non-variable SASS must be done after the fact.
// For example, to change the default status-tag color:
diff --git a/admin/app/helpers/active_admin/subscription_helper.rb b/admin/app/helpers/active_admin/subscription_helper.rb
new file mode 100644
index 000000000..5b5344275
--- /dev/null
+++ b/admin/app/helpers/active_admin/subscription_helper.rb
@@ -0,0 +1,20 @@
+module ActiveAdmin
+ module SubscriptionHelper
+ def subscription_plan_name(code)
+ case code
+ when 'jamrubysilver'
+ 'Silver'
+ when 'jamrubygold'
+ 'Gold'
+ when 'jamrubyplatinum'
+ 'Platinum'
+ when 'jamsubgoldyearly'
+ 'Gold Yearly'
+ when 'jamsubsilveryearly'
+ 'Silver Yearly'
+ when 'jamsubplatinumyearly'
+ 'Platinum Yearly'
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/admin/app/helpers/application_helper.rb b/admin/app/helpers/application_helper.rb
index c1545e10f..2584194eb 100644
--- a/admin/app/helpers/application_helper.rb
+++ b/admin/app/helpers/application_helper.rb
@@ -39,5 +39,4 @@ module ApplicationHelper
end
-
end
diff --git a/admin/app/views/admin/affiliates/_earnings.html.erb b/admin/app/views/admin/affiliates/_earnings.html.erb
new file mode 100644
index 000000000..9e0b08dae
--- /dev/null
+++ b/admin/app/views/admin/affiliates/_earnings.html.erb
@@ -0,0 +1,42 @@
+
The JamKazam help desk offers 1:1 help desk support only to our Gold and Platinum plan
- subscribers. More information on subscription plans
can be found here. If you are not a Gold or Platinum subscriber,
we'd suggest that you look for help in our
extensive knowledge base of
help articles,
diff --git a/web/app/assets/stylesheets/client/account_affiliate.scss b/web/app/assets/stylesheets/client/account_affiliate.scss
index 9d52a318c..db6ad3b64 100644
--- a/web/app/assets/stylesheets/client/account_affiliate.scss
+++ b/web/app/assets/stylesheets/client/account_affiliate.scss
@@ -137,6 +137,8 @@
table.links-table {
min-width:100%;
margin-top:20px;
+ border-width: 1px 0 0 0;
+ border-style: solid;
th {
padding: 10px 0 20px;
@@ -157,7 +159,9 @@
.url {
+
input {
+ font-family:courier;
background-color: transparent;
-webkit-box-shadow:none;
box-shadow:none;
diff --git a/web/app/assets/stylesheets/landings/affiliate_program.scss b/web/app/assets/stylesheets/landings/affiliate_program.scss
index e8f936c42..f26c285c2 100644
--- a/web/app/assets/stylesheets/landings/affiliate_program.scss
+++ b/web/app/assets/stylesheets/landings/affiliate_program.scss
@@ -25,7 +25,7 @@ body.web.landing_page.full {
}
.wrapper {
- padding-top:20px;
+ //padding-top:20px;
}
.row {
text-align:left;
diff --git a/web/app/assets/stylesheets/landings/landing_page.scss b/web/app/assets/stylesheets/landings/landing_page.scss
index a644704db..cd7b4bee5 100644
--- a/web/app/assets/stylesheets/landings/landing_page.scss
+++ b/web/app/assets/stylesheets/landings/landing_page.scss
@@ -418,7 +418,7 @@ body.web.landing_page {
font-size:14px;
position: absolute;
left: 60%;
- top: 25px;
+ top: 45px;
margin: 0;
h1 {
diff --git a/web/app/controllers/api_controller.rb b/web/app/controllers/api_controller.rb
index cef52b25b..6ec166f45 100644
--- a/web/app/controllers/api_controller.rb
+++ b/web/app/controllers/api_controller.rb
@@ -113,7 +113,11 @@ class ApiController < ApplicationController
def affiliate_partner
if params[:affiliate_id]
@partner = AffiliatePartner.find(params[:affiliate_id])
- if @partner.partner_user.nil?
+ if @partner.nil?
+ raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
+ elsif @partner.partner_user.nil?
+ raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
+ elsif !current_user.admin || @partner.partner_user != current_user
raise JamPermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
end
elsif current_user
diff --git a/web/app/controllers/api_links_controller.rb b/web/app/controllers/api_links_controller.rb
index 9f50d979f..8cadf984a 100644
--- a/web/app/controllers/api_links_controller.rb
+++ b/web/app/controllers/api_links_controller.rb
@@ -9,7 +9,27 @@ class ApiLinksController < ApiController
@log || Logging.logger[ApiLinksController]
end
+ def all
+ links = AffiliateLink.all.order(:created_at)
+ results = []
+ links.each do |link|
+ url = nil
+ if link.link.index('?')
+ url = link.link + '&' + affiliate_params.to_query
+ else
+ url = link.link + '?' + affiliate_params.to_query
+ end
+
+ results << {url: url,
+ target: link.name }
+ end
+ render json: results, status: 200
+ end
+=begin
+
def jamtrack_song_index
+ @affiliate_params = affiliate_params()
+
@affiliate_params = affiliate_params('jamtrack-song')
results = []
@@ -106,9 +126,12 @@ class ApiLinksController < ApiController
render json: results, status: 200
end
+=end
private
- def affiliate_params(campaign)
- {utm_source:'affiliate', utm_medium: 'affiliate', utm_campaign: "#{Date.today.year}-affiliate-#{campaign}", affiliate: @partner.id}
+ def affiliate_params()
+ #{utm_source:'affiliate', utm_medium: 'affiliate', utm_campaign: "#{Date.today.year}-affiliate-#{campaign}", affiliate: @partner.id}#
+ # the above was deemed too noisy
+ {affiliate: @partner.id}
end
end
diff --git a/web/app/controllers/api_recurly_controller.rb b/web/app/controllers/api_recurly_controller.rb
index 6338d6ded..9c1e6bc10 100644
--- a/web/app/controllers/api_recurly_controller.rb
+++ b/web/app/controllers/api_recurly_controller.rb
@@ -162,6 +162,7 @@ class ApiRecurlyController < ApiController
render json: {:message => x.inspect, errors: x.errors}, :status => 404
end
end
+
def create_subscription
begin
sale = Sale.purchase_subscription(current_user, params[:recurly_token], params[:plan_code])
diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb
index 46df52ac8..33bfd9388 100644
--- a/web/app/controllers/api_users_controller.rb
+++ b/web/app/controllers/api_users_controller.rb
@@ -865,14 +865,16 @@ class ApiUsersController < ApiController
if request.post?
oo.address = params[:address]
oo.tax_identifier = params[:tax_identifier]
+ oo.paypal_id = params[:paypal_id]
oo.save!
- render nothing: true
+ render json: {}, status: 200
elsif request.get?
result = {}
result['account'] = {
'address' => oo.address.clone,
'tax_identifier' => oo.tax_identifier,
+ 'paypal_id' => oo.paypal_id,
'entity_type' => oo.entity_type,
'partner_name' => oo.partner_name,
'partner_id' => oo.partner_user_id,
diff --git a/web/app/controllers/supports_controller.rb b/web/app/controllers/supports_controller.rb
index 268276878..eec666d01 100644
--- a/web/app/controllers/supports_controller.rb
+++ b/web/app/controllers/supports_controller.rb
@@ -12,7 +12,7 @@ class SupportsController < ApplicationController
gon.plan_code = current_user.subscription_plan_code
@title = "Help Desk"
- @description = "The JamKazam help desk offers 1:1 help desk support only to in-trial and Gold and Platinum plan subscribers."
+ @description = "The JamKazam help desk offers 1:1 help desk support only to our Gold and Platinum plan subscribers, as well as those in their initial 30-day trial period."
render 'show', :layout => 'support'
end
diff --git a/web/app/views/api_affiliates/payment_show.rabl b/web/app/views/api_affiliates/payment_show.rabl
index 1ac51e258..c4063798b 100644
--- a/web/app/views/api_affiliates/payment_show.rabl
+++ b/web/app/views/api_affiliates/payment_show.rabl
@@ -1,3 +1,9 @@
object @quarterly
-attribute :closed, :paid, :due_amount_in_cents, :affiliate_partner_id, :quarter, :month, :year, :payment_type, :jamtracks_sold
\ No newline at end of file
+attribute :closed, :paid, :due_amount_in_cents, :affiliate_partner_id, :quarter, :month, :year, :payment_type, :jamtracks_sold
+
+node (:subscriptions) do |payment|
+ start_at = Date.new(payment.year, payment.month, 1)
+ end_at = Date.new(payment.year, payment.month, 1).end_of_month
+ AffiliateDistribution.subscription_plans_count(payment.affiliate_partner_id, start_at, end_at)
+end
\ No newline at end of file
diff --git a/web/app/views/clients/_account_affiliate_partner.html.slim b/web/app/views/clients/_account_affiliate_partner.html.slim
index 8280cf9b9..059b7f14c 100644
--- a/web/app/views/clients/_account_affiliate_partner.html.slim
+++ b/web/app/views/clients/_account_affiliate_partner.html.slim
@@ -41,12 +41,18 @@ script type="text/template" id="template-affiliate-partner-account"
.right-col
| We must have a complete mailing address and a valid tax ID in order to process and mail payments due to all affiliates. Per the terms of the affiliate agreement, if this information is not available within 90 days of the end of a calendar quarter, then any payment obligation due to the affiliate for such calendar quarter shall be considered fully and permanently discharged, and no further payment for such calendar quarter shall be due or payable to affiliate.
br
+ br
+ | For fastest receipt of payment, please specify a PayPal.Me account.
+ br
+ br
| So please provide this data, and be sure to keep it current!
.left-col
.affiliate-label Affiliate:
.w80= "{{ data.partner_name }} ({{data.entity_type}})"
br
+ br
+
.affiliate-label Street Address 1:
= text_field_tag('affiliate_partner_address1', "{{ data.address.address1 }}", {class: 'w60'})
br
@@ -69,6 +75,18 @@ script type="text/template" id="template-affiliate-partner-account"
.affiliate-label Tax ID:
= text_field_tag('affiliate_partner_tax_identifier', "{{ data.tax_identifier }}", {class: 'w60'})
br
+ br
+ .affiliate-label PayPal.Me:
+ = text_field_tag('affiliate_partner_paypal_id', "{{ data.paypal_id }}", { class: 'w60' })
+ br
+ span style="padding-left:138px"
+ | A PayPal.Me link looks like
+ b paypal.me/YourName
+ | Please read more info
+ a href="https://www.paypal.com/us/smarthelp/article/What-is-PayPalMe-FAQ3025"
+ | about PayPal.Me
+ br
+ br
.spacer
.input-buttons
.right
@@ -97,55 +115,17 @@ script type="text/template" id="template-affiliate-partner-signups"
table.traffic-table.jamtable
thead
tr
- th.day DATE
+ th.day MONTH
th.signups SIGNUPS
th.visits VISITS
- tbody
+ tbody
script type="text/template" id="template-affiliate-partner-links"
.links
p.prompt
- | This page provides you with lists of ready-to-use links you can use to direct your followers to JamKazam.
- | These links include your unique affiliate ID, and users who follow these links to JamKazam and register for an account will be
- | tagged with your affiliate ID, so that you will be paid on their purchase per the terms of the
- a.affiliate-agreement rel='#' affiliate agreement
- | . You can also find a
- a.affiliate-link-page href='#' rel="external" single page listing all affiliate links
- | which you can share with others who may need to share out affiliate links on your behalf.
- .link-type-section
- label Link Type:
- select.link_type.easydropdown name="link_type"
- option value="JamTrack Song" JamTrack Song
- option value="JamTrack Band" JamTrack Band
- option value="JamTrack General" JamTrack General
- option value="JamKazam General" JamKazam General
- option value="JamKazam Session" JamKazam Session
- option value="JamKazam Recording" JamKazam Recording
- option value="Custom Link" Custom Link
- .link-type-prompt data-type='jamtrack_songs'
- | These links take users directly to the "landing page" for a JamTrack - i.e. an individual piece of music. This would be a great fit, for example, if you have produced a YouTube tutorial on how to play a particular song, or if you have music notation for a particular song, etc.
- .link-type-prompt data-type='jamtrack_bands'
- | These links take users directly to the "landing page" for a band to promote all the JamTracks by that band, not just an individual song. This would be a great fit, for example, if you have music notation for several songs by a band, etc.
- .link-type-prompt data-type='jamtrack_general'
- | These links take users directly to a"landing page" that promotes JamTracks in general. This page will feature the song listed in the link as an example of a JamTrack, but the landing page is built to promote JamTracks in general versus promoting just the one song. This is a good fit if you want to let your followers know about JamTracks in general.
- .link-type-prompt data-type='jamkazam'
- | These links take users directly to a product page that promotes JamKazam more generally. This is a good fit if you want to let your followers know about JamKazam or its products in general.
- .link-type-prompt data-type='sessions'
- | These links take users to a page where they can listen to a session you have organized, and in which you are scheduled to perform, either alone or with others. This is a good fit if you can perform either solo or in a group with other musicians in a JamKazam session, and draw an audience to listen to your session. During the session, you can recommend that your audience members sign up for JamKazam from this page. Below is a list of your currently scheduled JamKazam sessions for which you may share links.
- .link-type-prompt data-type='recordings'
- | These links take users to a page with a recording you have made in a JamKazam session. This is a good fit if you have made a nice recording in a JamKazam session and can share it with your followers via Facebook, Twitter, email, and so on. Below is a list of your most recent JamKazam recordings for which you may share links.
- .link-type-prompt data-type='custom_links'
- p You may also link to any page on the JamKazam website and append the following text to the URL of the page to which you are linking:
-
- p.example-link
- | ?utm_source=affiliate&utm_medium=affiliate&utm_campaign=2015-affiliate-custom&affiliate=
- span.affiliate_id
-
- p For example, if you were linking to the JamKazam home page, you would combine https://www.jamkazam.com with the text above, and the result would be:
-
- p.example-link
- | https://www.jamkazam.com?utm_source=affiliate&utm_medium=affiliate&utm_campaign=2015-affiliate-custom&affiliate=
- span.affiliate_id
+ | This page provides you with a list of ready-to-use links you can share with your followers to let them know about JamKazam. These links include your unique affiliate ID, and users who follow these links to JamKazam and sign up for a JamKazam account will be tagged with your affiliate ID, so that when they purchase a subscription and/or JamTracks, you will be paid a revenue share on their purchase payments per the terms of the affiliate agreement.
+ p.prompt
+ | Click “select link” next to the link you want to use, then copy the link to the clipboard and paste it wherever you want to share it.
table.links-table
thead
@@ -153,12 +133,12 @@ script type="text/template" id="template-affiliate-partner-links"
th.target TARGET PAGE
th.copy-link
th.url URL
- tbody
+ tbody
script type="text/template" id="template-affiliate-partner-signups-row"
tr
- td.day
- | {{data.day}}
+ td.month
+ | {{data.month}}
td.signups
| {{data.signups}}
td.visits
@@ -169,9 +149,10 @@ script type="text/template" id="template-affiliate-partner-earnings"
thead
tr
th.month MONTH
- th.sales SALES
+ th.sales JAMTRACKS
+ th.subscriptions SUBSCRIPTIONS
th.earnings AFFILIATE EARNINGS
- tbody
+ tbody
script type="text/template" id="template-affiliate-partner-earnings-row"
tr data-type="{{data.payment_type}}"
@@ -179,6 +160,8 @@ script type="text/template" id="template-affiliate-partner-earnings-row"
| {{data.time}}
td.sales
| {{data.sold}}
+ td.subscriptions
+ | {{ data.subscriptions }}
td.earnings
| {{data.earnings}}
@@ -190,4 +173,4 @@ script type="text/template" id="template-affiliate-link-entry"
td.copy-link
a href='#' select link
td.url
- input type="text" value="{{data.url}}"
\ No newline at end of file
+ input type="text" value="{{data.url}}"
diff --git a/web/app/views/landings/affiliate_program.html.slim b/web/app/views/landings/affiliate_program.html.slim
index 728c40385..29ecbfec0 100644
--- a/web/app/views/landings/affiliate_program.html.slim
+++ b/web/app/views/landings/affiliate_program.html.slim
@@ -2,18 +2,14 @@
- provide(:description, 'Signup for JamKazam Affiliate Program')
.row
- .column
- h1.product-headline JamKazam Affiliate Program
- p Do you have a following of musicians on Facebook, YouTube, Twitter or an email list? Generate income simply by letting them know about JamKazam.
- p Let's say you make YouTube tutorial videos. You can link directly from a video on how to play "Back in Black" to our JamTrack for that song. Video watchers can get this first JamTrack free, and can buy others if they like. You get paid every time they buy something from us for 2 years.
- p Or let's say you have a Facebook group for guitarist with 5,000 members. You can let them know they can play together free on JamKazam. For everyone who signs up, you get paid every time they buy something from us for 2 years.
- p You don't have to sell anything. Just let your followers know about cool new stuff they'll like! To get started, simply review the affiliate agreement below, accept it (at the end of the agreement), and then start sharing links with your affiliate code. When referred users buy JamTracks, JamBlasters, JamLessons, and so on, you get paid!
- .column
- h1 Learn How to Make Money by Referring Users
- - if !Rails.env.test?
- .video-wrapper
- .video-container
- iframe src="//www.youtube.com/embed/96YTnO_H9a4" frameborder="0" allowfullscreen
+ h1 JamKazam Affiliate Program
+ p Do you have an audience of musician followers on social media like Facebook, YouTube, Instagram, or Twitter - or on your website, email list, etc?
+ br
+ p Most of the musicians in the world don't know JamKazam exists. Now you can let your audience know about JamKazam - which is something they'll be very excited to hear about - and also generate recurring income from any of your referrals that purchase JamKazam premium subscriptions and/or JamTracks.
+ br
+ p JamKazam provides a 30-day free trial that makes it fun and risk-free for anyone to check out the platform. After that, users can continue with a free plan or purchase an upgrade to a premium subscription, with plans available at $4.99, $9.99, or $19.99 per month. JamKazam will pay you 30% of these revenues for a period of 3 years from the signup date of each of your referred users.
+ br
+ p You don't sell anything. Just share the word about a service you really like and that most others haven't heard of yet. To get started, review the affiliate agreement details below and sign up as an affiliate at the bottom of this page. Then you can go to the Account/Affiliate page in our app or website to get special links tagged with your affiliate ID that you can share with your audience. You can also track signups and earnings from that page.
br clear="all"
.row
h1 JamKazam Affiliate Agreement
@@ -45,8 +41,9 @@
option value="Other" Other
.agree-disagree-buttons
- = link_to image_tag("content/agree_button.png", {:width => 213, :height => 50 }), '#', class: "agree-button"
- = link_to image_tag("content/disagree_button.png", {:width => 213, :height => 50 }), '#', class: "disagree-button"
+
+ = link_to "I Agree", '#', class: "agree-button button-orange"
+ = link_to "I Disagree", '#', class: "disagree-button button-grey"
p.disagree-text.hidden
| Thank you for your interest in the JamKazam affiliate program. We are sorry, but you cannot join the program without consenting to the terms of this Agreement.
diff --git a/web/app/views/legal/_partner_agreement_v1.html.erb b/web/app/views/legal/_partner_agreement_v1.html.erb
index 1dbc81472..293c9d869 100644
--- a/web/app/views/legal/_partner_agreement_v1.html.erb
+++ b/web/app/views/legal/_partner_agreement_v1.html.erb
@@ -1,7 +1,7 @@
-
Updated: April 30, 2015.
+
Updated: February 9, 2021.
@@ -23,7 +23,7 @@
The purpose of the Program is to permit you to advertise Products on Your Site and to earn advertising fees for Qualifying Purchases (defined in Section 7) made by your Qualifying Customers (defined in Section 7). A “Product”
- is an item sold on the JamKazam Site and listed in the Program Advertising Fee Schedule in Section 10. In order to facilitate your advertisement of Products, we may make available to you data, images, text, link formats, widgets, links, and other linking tools, and other information in connection with the Program (“Content”).
+ a product or service sold on the JamKazam Site and listed in the Program Advertising Fee Schedule in Section 10. In order to facilitate your advertisement of Products, we may make available to you data, images, text, link formats, widgets, links, and other linking tools, and other information in connection with the Program (“Content”).
@@ -157,7 +157,7 @@
We will pay you advertising fees on Qualifying Purchases in accordance with Section 8 and the Program Advertising Fee Schedule in Section 10. Subject to the exclusions set forth below, a “Qualifying Purchase”
- occurs when a Qualifying Customer: (a) purchases a Product within two (2) years of the date on which such Qualifying Customer registered to create his/her JamKazam account; and (b) pays for such Product. A “Qualifying Customer”
+ occurs when a Qualifying Customer purchases and pays for a Product within three (3) years of the date on which such Qualifying Customer registered to create his/her JamKazam account. A “Qualifying Customer”
is an end user who: (a) clicks through a Special Link on Your Site to the JamKazam Site; and (b) during the single Session created by this click through, registers to create a new JamKazam account. A “Session”
begins when an end user clicks through a Special Link on Your Site to the JamKazam Site and ends when such end user leaves the JamKazam Site.
@@ -192,7 +192,7 @@
- We will pay you advertising fees on a quarterly basis for Qualifying Purchases downloaded, shipped, or otherwise fulfilled (as applicable) in a given calendar quarter, subject to any applicable withholding or deduction described below. We will pay you approximately 30 days following the end of each calendar quarter by mailing a check in the amount of the advertising fees you earn to the mailing address then-currently associated with your JamKazam account, but we may accrue and withhold payment of advertising fees until the total amount due to you is at least US$50.00. If you do not have a valid mailing address associated with your JamKazam account within 30 days of the end of a calendar quarter, we will withhold any unpaid accrued advertising fees until you have associated a valid mailing address and notified us that you have done so.
+ We will pay you advertising fees on a quarterly basis for Qualifying Purchases paid for in a given calendar quarter, subject to any applicable withholding or deduction described below. We will pay you approximately 30 days following the end of each calendar quarter by mailing a check in the amount of the advertising fees you earn to the mailing address then-currently associated with your JamKazam account, or by or processing a digital funds transfer (e.g. PayPal) to an account you designate, but we may accrue and withhold payment of advertising fees until the total amount due to you is at least US$25.00. If you do not have a valid mailing address associated with your JamKazam account within 30 days of the end of a calendar quarter, we will withhold any unpaid accrued advertising fees until you have associated a valid mailing address and notified us that you have done so.
@@ -218,11 +218,32 @@
- We will determine and calculate amounts payable to you as advertising fees for Qualifying Purchases as set forth in the table below (the “Program Advertising Fee Schedule”).
+ We will determine and calculate amounts payable to you as advertising fees for Qualifying Purchases as set forth below (the “Program Advertising Fee Schedule”).
+
+
+ -
+
Product: Silver, Gold, and Platinum Monthly or Annual Subscriptions
+
+ JamKazam will pay advertising fees of 30% of the net revenues from Qualifying Purchases by Qualifying Customers of these Products.
+
+
+
+ -
+
Product: JamTracks
+
+ JamKazam will pay US$0.25 per JamTrack sold as a Qualifying Purchase by Qualifying Customers of these Products.
+
+
+
+
+
+
+ <%#
+
+ %>
+
- From time to time, we may modify this Program Advertising Fee Schedule as part of modifications made to this Agreement.
+ From time to time, we may modify this Program Advertising Fee Schedule as part of modifications made to this Agreement.
@@ -351,7 +373,7 @@
- To begin an arbitration proceeding, you must send a letter requesting arbitration and describing your claim to us at: JamKazam, Inc., Attn: Legal Department, 5813 Lookout Mountain Drive, Austin TX 78731. The arbitration will be conducted by the American Arbitration Association (“AAA”) under its rules, including the AAA’s Supplementary Procedures for Consumer-Related Disputes. The AAA’s rules are available at www.adr.org or by calling 1-800-778-7879. Payment of all filing, administration and arbitrator fees will be governed by the AAA’s rules. We will reimburse those fees for claims totaling less than $10,000 unless the arbitrator determines the claims are frivolous. Likewise, we will not seek attorneys’
+ To begin an arbitration proceeding, you must send a letter requesting arbitration and describing your claim to us at: JamKazam, Inc., Attn: Legal Department, 3924 Knollwood Drive, Austin TX 78731. The arbitration will be conducted by the American Arbitration Association (“AAA”) under its rules, including the AAA’s Supplementary Procedures for Consumer-Related Disputes. The AAA’s rules are available at www.adr.org or by calling 1-800-778-7879. Payment of all filing, administration and arbitrator fees will be governed by the AAA’s rules. We will reimburse those fees for claims totaling less than $10,000 unless the arbitrator determines the claims are frivolous. Likewise, we will not seek attorneys’
fees and costs in arbitration unless the arbitrator determines the claims are frivolous. You may choose to have the arbitration conducted by telephone, based on written submissions, or in person in the county where you live or at another mutually agreed location.
@@ -417,6 +439,6 @@
-->
- JamKazam Confidential 4/17/2015
+ JamKazam Confidential 02/09/2021
\ No newline at end of file
diff --git a/web/bin/test b/web/bin/test
index 025517a7b..b99e7eeb3 100755
--- a/web/bin/test
+++ b/web/bin/test
@@ -5,6 +5,10 @@
tests=(
"spec/features/signup_spec.rb"
"spec/features/signin_spec.rb"
+ "spec/features/affiliate_program_spec.rb"
+ "spec/features/affiliate_visit_tracking_spec.rb"
+ "spec/features/affiliate_referral_spec.rb"
+ "spec/controllers/api_affiliate_controller_spec.rb"
)
diff --git a/web/config/routes.rb b/web/config/routes.rb
index eb0e323ab..8e08735c0 100644
--- a/web/config/routes.rb
+++ b/web/config/routes.rb
@@ -759,12 +759,13 @@ Rails.application.routes.draw do
match '/live_streams/bad_audio' => 'api_alerts#bad_audio', :via => :post # used by client; don't change route
# links generated to help affiliates share relevant links
- get '/links/jamtrack_songs' => 'api_links#jamtrack_song_index'
- get '/links/jamtrack_bands' => 'api_links#jamtrack_band_index'
- get '/links/jamtrack_general' => 'api_links#jamtrack_general_index'
- get '/links/jamkazam' => 'api_links#jamkazam_general_index'
- get '/links/sessions' => 'api_links#session_index'
- get '/links/recordings' => 'api_links#recording_index'
+ #get '/links/jamtrack_songs' => 'api_links#jamtrack_song_index'
+ #get '/links/jamtrack_bands' => 'api_links#jamtrack_band_index'
+ #get '/links/jamtrack_general' => 'api_links#jamtrack_general_index'
+ #get '/links/jamkazam' => 'api_links#jamkazam_general_index'
+ #get '/links/sessions' => 'api_links#session_index'
+ #get '/links/recordings' => 'api_links#recording_index'
+ get '/links/all' => 'api_links#all'
match '/lesson_sessions' => 'api_lesson_sessions#index', :via => :get
match '/lesson_bookings/unprocessed' => 'api_lesson_bookings#unprocessed', :via => :get
diff --git a/web/migrate.sh b/web/migrate.sh
index a9afa1578..01e0cd2eb 100755
--- a/web/migrate.sh
+++ b/web/migrate.sh
@@ -1,2 +1,2 @@
#!/bin/bash
-bundle exec jam_db up --connopts=dbname:jam host:localhost user:postgres password:postgres --verbose
+RAILS_ENV=development bundle exec rake db:jam_ruby:migrate
diff --git a/web/spec/controllers/api_affiliate_controller_spec.rb b/web/spec/controllers/api_affiliate_controller_spec.rb
index 00f40c413..2475d2058 100644
--- a/web/spec/controllers/api_affiliate_controller_spec.rb
+++ b/web/spec/controllers/api_affiliate_controller_spec.rb
@@ -79,4 +79,37 @@ describe ApiAffiliateController, type: :controller do
end
end
+ describe "payment_index" do
+ it "empty" do
+ get :payment_index
+ response.should be_success
+ JSON.parse(response.body)['payments'].should eq([])
+ end
+
+ it "presents single JamTrack item" do
+ FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner: partner1, closed: true, due_amount_in_cents: 20, month: 1, year: 2015, jamtracks_sold: 1)
+
+ get :payment_index
+ response.should be_success
+ JSON.parse(response.body)['payments'].should eq([{"closed" => true, "paid" => nil, "payment_type" => "monthly", "quarter" => nil, "month" => 1, "year" => 2015, "due_amount_in_cents" => 20, "affiliate_partner_id" => partner1.id, "jamtracks_sold" => 1, "subscriptions" => [] }])
+ end
+
+ it "presents subscriptions" do
+ #Silver plan subscription on January
+ FactoryGirl.create(:affiliate_distribution,
+ product_type: 'Subscription',
+ product_code: 'jamsubsilver',
+ affiliate_referral: partner1,
+ affiliate_referral_fee_in_cents: 15,
+ created_at: Date.new(2015, 1, 1)
+ )
+ AffiliatePartner.tally_up(Date.new(2015, 1, 1))
+
+ get :payment_index
+ response.should be_success
+ expect(JSON.parse(response.body)['payments']).to have(6).things
+ expect(JSON.parse(response.body)['payments']).to include({"closed" => false, "paid" => nil, "payment_type" => "monthly", "quarter" => nil, "month" => 1, "year" => 2015, "due_amount_in_cents" => 15, "affiliate_partner_id" => partner1.id, "jamtracks_sold" => 0, "subscriptions" => [{ "plan" => "jamsubsilver", "count" => 1 }] })
+ end
+ end
+
end
diff --git a/web/spec/factories.rb b/web/spec/factories.rb
index 464528e49..3ed2fd869 100644
--- a/web/spec/factories.rb
+++ b/web/spec/factories.rb
@@ -863,6 +863,10 @@ FactoryGirl.define do
legalese Faker::Lorem.paragraphs(6).join("\n\n")
end
+ factory :affiliate_distribution, class: 'JamRuby::AffiliateDistribution' do
+ association :affiliate_referral, factory: :affiliate_partner
+ end
+
factory :gift_card, class: 'JamRuby::GiftCard' do
sequence(:code) {|n| n.to_s}
card_type GiftCard::JAM_TRACKS_5
diff --git a/web/spec/features/account_affiliate_spec.rb b/web/spec/features/account_affiliate_spec.rb
index 9747a373b..a66f953de 100644
--- a/web/spec/features/account_affiliate_spec.rb
+++ b/web/spec/features/account_affiliate_spec.rb
@@ -6,7 +6,9 @@ describe "Account Affiliate", :js => true, :type => :feature, :capybara_feature
let(:user) {FactoryGirl.create(:user)}
let(:partner) { FactoryGirl.create(:affiliate_partner) }
+ let(:user_partner) { FactoryGirl.create(:user, affiliate_referral: partner) }
let(:jam_track) {FactoryGirl.create(:jam_track)}
+ let(:sale) {Sale.create_jam_track_sale(user_partner)}
before(:each) do
JamTrackRight.delete_all
@@ -14,6 +16,7 @@ describe "Account Affiliate", :js => true, :type => :feature, :capybara_feature
AffiliateQuarterlyPayment.delete_all
AffiliateMonthlyPayment.delete_all
AffiliateTrafficTotal.delete_all
+ AffiliateDistribution.delete_all
UserMailer.deliveries.clear
emulate_client
end
@@ -44,109 +47,314 @@ describe "Account Affiliate", :js => true, :type => :feature, :capybara_feature
end
it "works on no data" do
- jam_track.touch
-
+
visit "/client#/account/affiliatePartner"
find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
# take a look at the links tab
- find('a#affiliate-partner-links-link').trigger(:click)
-
- find('#account-affiliate-partner tr td.target')
+ find('a#affiliate-partner-links-link').click
+ #find('#account-affiliate-partner tr td.target')
+ find('table.links-table')
# can't find this on the page for some reason:
#jk_select('Custom Link', '#account-affiliate-partner select.link_type')
#find('.link-type-prompt[data-type="custom_links"]')
- find('a#affiliate-partner-signups-link').trigger(:click)
+ find('a#affiliate-partner-signups-link').click
find('table.traffic-table')
- find('a#affiliate-partner-earnings-link').trigger(:click)
+ find('a#affiliate-partner-earnings-link').click
find('table.payment-table')
- find('a#affiliate-partner-agreement-link').trigger(:click)
+ find('a#affiliate-partner-agreement-link').click
find('h2', text: 'JamKazam Affiliate Agreement')
- find('span.c0', text: 'Updated: April 30, 2015')
+ find('span.c0', text: 'Updated: February 9, 2021.')
+
+ #save_screenshot("account_affiliate_agreement.png")
end
- it "shows data" do
+ it "shows signups data" do
+
visit "/client#/account/affiliatePartner"
find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
# verify traffic data shows correctly
- day1 = Date.parse('2015-04-05')
- FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day1, signups: 1, visits:2)
- find('a#affiliate-partner-signups-link').trigger(:click)
- find('table.traffic-table tr td.day', text: "April 5")
- find('table.traffic-table tr td.signups', text: '1')
- find('table.traffic-table tr td.visits', text: '2')
+ day1 = Date.parse('2015-01-01')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day1, signups: 1, visits: 5)
+ day2 = Date.parse('2015-01-15')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day2, signups: 5, visits: 10)
+ day3 = Date.parse('2015-01-31')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day3, signups: 10, visits: 20)
+ day4 = Date.parse('2015-02-01')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day4, signups: 1, visits: 2)
+
+ day5 = Date.parse('2015-03-15')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day5, signups: 10, visits: 20)
- find('a#affiliate-partner-earnings-link').trigger(:click)
+ day6 = Date.parse('2015-04-01')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day6, signups: 20, visits: 50)
+
+ day7 = Date.parse('2015-04-05')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day7, signups: 5, visits: 10)
+
+ find('a#affiliate-partner-signups-link').click
+
+ months = page.all('table.traffic-table tr td.month')
+ signups = page.all('table.traffic-table tr td.signups')
+ visits = page.all('table.traffic-table tr td.visits')
+
+ months[0].should have_content("April")
+ months[1].should have_content("March")
+ months[2].should have_content("February")
+ months[3].should have_content("January")
+
+ signups[0].should have_content("25")
+ signups[1].should have_content("10")
+ signups[2].should have_content("1")
+ signups[3].should have_content("16")
+
+ visits[0].should have_content("60")
+ visits[1].should have_content("20")
+ visits[2].should have_content("2")
+ visits[3].should have_content("35")
+
+ find('a#affiliate-partner-earnings-link').click
find('table.payment-table')
- day2 = Date.parse('2015-04-07')
- FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day2, signups: 3, visits:4)
- find('a#affiliate-partner-signups-link').trigger(:click)
- find('table.traffic-table tr td.day', text: "April 7")
- find('table.traffic-table tr td.signups', text: '3')
- find('table.traffic-table tr td.visits', text: '4')
+ day8 = Date.parse('2015-04-07')
+ FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day8, signups: 5, visits: 10)
+
+ find('a#affiliate-partner-signups-link').click
- # verify earnings data correctly
- FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:1, due_amount_in_cents:20, jamtracks_sold: 1, closed:true)
+ months = page.all('table.traffic-table tr td.month')
+ signups = page.all('table.traffic-table tr td.signups')
+ visits = page.all('table.traffic-table tr td.visits')
- find('a#affiliate-partner-earnings-link').trigger(:click)
- find('table.payment-table tr td.month', text: "January 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
- find('table.payment-table tr td.earnings', text: '$0.20')
+ months[0].should have_content("April")
+ signups[0].should have_content("30")
+ visits[0].should have_content("70")
+ #save_screenshot("account_affiliate_signup_links.png")
- find('a#affiliate-partner-signups-link').trigger(:click)
- find('table.traffic-table')
-
- FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:2, due_amount_in_cents:40, jamtracks_sold: 2, closed:true)
- FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:3, due_amount_in_cents:60, jamtracks_sold: 3, closed:true)
- quarter1 = FactoryGirl.create(:affiliate_quarterly_payment, affiliate_partner:partner, year:2015, quarter:0, due_amount_in_cents:120, jamtracks_sold: 6, closed:true, paid:false)
- FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:4, due_amount_in_cents:2000, jamtracks_sold: 100, closed:true)
-
- find('a#affiliate-partner-earnings-link').trigger(:click)
- find('table.payment-table tr td.month', text: "January 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
- find('table.payment-table tr td.earnings', text: '$0.20')
- find('table.payment-table tr td.month', text: "February 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 2 units sold')
- find('table.payment-table tr td.earnings', text: '$0.40')
- find('table.payment-table tr td.month', text: "March 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 3 units sold')
- find('table.payment-table tr td.earnings', text: '$0.60')
- find('table.payment-table tr td.month', text: "1st Quarter 2015")
- find('table.payment-table tr td.earnings', text: 'No earning were paid, as the $10 minimum threshold was not reached.')
-
-
-
- find('a#affiliate-partner-signups-link').trigger(:click)
- find('table.traffic-table')
-
- quarter1.paid = true
- quarter1.save!
- FactoryGirl.create(:affiliate_quarterly_payment, affiliate_partner:partner, year:2015, quarter:1, due_amount_in_cents:2000, jamtracks_sold: 100, closed:true, paid:true)
-
- find('a#affiliate-partner-earnings-link').trigger(:click)
- find('table.payment-table tr td.month', text: "January 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
- find('table.payment-table tr td.earnings', text: '$0.20')
- find('table.payment-table tr td.month', text: "February 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 2 units sold')
- find('table.payment-table tr td.earnings', text: '$0.40')
- find('table.payment-table tr td.month', text: "March 2015")
- find('table.payment-table tr td.sales', text: 'JamTracks: 3 units sold')
- find('table.payment-table tr td.earnings', text: '$0.60')
-
- find('table.payment-table tr td.month', text: "1st Quarter 2015")
- find('table.payment-table tr td.earnings', text: 'PAID $1.20')
- find('table.payment-table tr td.month', text: "2nd Quarter 2015")
- find('table.payment-table tr td.earnings', text: 'PAID $20.00')
end
+
+ it "shows earnings" do
+ jam_track.touch
+
+ visit "/client#/account/affiliatePartner"
+ find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
+
+ # verify earnings data correctly
+ FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:1, due_amount_in_cents:25, jamtracks_sold: 1, closed:true)
+
+ find('a#affiliate-partner-earnings-link').click
+ find('table.payment-table tr td.month', text: "January 2015")
+ find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
+ find('table.payment-table tr td.earnings', text: '$0.25')
+
+ find('a#affiliate-partner-signups-link').click
+ find('table.traffic-table')
+
+ FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:2, due_amount_in_cents:50, jamtracks_sold: 2, closed:true)
+ FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:3, due_amount_in_cents:75, jamtracks_sold: 3, closed:true)
+ FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:4, due_amount_in_cents:0, jamtracks_sold: 0, closed:true)
+
+
+ find('a#affiliate-partner-earnings-link').click
+
+
+ months = page.all("table.payment-table tr td.month")
+ sales = page.all("table.payment-table tr td.sales")
+ earnings = page.all("table.payment-table tr td.earnings")
+
+ months[0].should have_content("April 2015")
+ months[1].should have_content("March 2015")
+ months[2].should have_content("February 2015")
+ months[3].should have_content("January 2015")
+
+ sales[0].should have_content("")
+ sales[1].should have_content("JamTracks: 3 units sold")
+ sales[2].should have_content("JamTracks: 2 units sold")
+ sales[3].should have_content("JamTracks: 1 unit sold")
+
+ earnings[0].should have_content("")
+ earnings[1].should have_content("$0.75")
+ earnings[2].should have_content("$0.50")
+ earnings[3].should have_content("$0.25")
+
+ #save_screenshot("account_affiliate_earnings.png")
+ end
+
+ it "shows earnings by Subscription and JamTrack sales" do
+ #Silver plan subscription on January
+ FactoryGirl.create(:affiliate_distribution,
+ product_type: 'Subscription',
+ product_code: 'jamsubsilver',
+ affiliate_referral: partner,
+ affiliate_referral_fee_in_cents: 15,
+ created_at: Date.new(2015, 1, 1)
+ )
+
+ #JamTrack sale on January
+ jam_track.reload
+ shopping_cart = ShoppingCart.create user_partner, jam_track, 1, false
+ real_sale = SaleLineItem.create_from_shopping_cart(sale, shopping_cart, nil, nil, nil)
+ real_sale.affiliate_referral_fee_in_cents.should eq(25)
+ real_sale.created_at = Date.new(2015, 1, 1)
+ real_sale.save!
+ real_sale.affiliate_distributions.first.created_at = real_sale.created_at
+ real_sale.affiliate_distributions.first.save!
+
+
+ #Gold plan subscription on January
+ FactoryGirl.create(:affiliate_distribution,
+ product_type: 'Subscription',
+ product_code: 'jamsubgold',
+ affiliate_referral: partner,
+ affiliate_referral_fee_in_cents: 30,
+ created_at: Date.new(2015, 1, 1)
+ )
+
+ #Platinum plan subscription in February
+ FactoryGirl.create(:affiliate_distribution,
+ product_type: 'Subscription',
+ product_code: 'jamsubplatinum',
+ affiliate_referral: partner,
+ affiliate_referral_fee_in_cents: 60,
+ created_at: Date.new(2015, 2, 1)
+ )
+
+ AffiliatePartner.tally_up(Date.new(2015, 2, 1))
+
+ visit "/client#/account/affiliatePartner"
+ find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
+
+ find('a#affiliate-partner-earnings-link').click
+
+ # within('table.payment-table') do
+ # find('tr td.month', text: "January 2015")
+ # find('tr td.sales', text: 'JamTracks: 1 unit sold')
+ # find('tr td.subscriptions', text: 'Gold subscriptions - 1')
+ # find('tr td.subscriptions', text: 'Silver subscriptions - 1')
+ # find('tr td.earnings', text: '$1.70')
+ # end
+
+ months = page.all("table.payment-table tbody tr td.month")
+ months[0].should have_content("March 2015")
+ months[1].should have_content("February 2015")
+ months[2].should have_content("January 2015")
+
+ sales = page.all("table.payment-table tbody tr td.sales")
+ sales[0].should have_content("JamTracks: 0 units sold")
+ sales[1].should have_content("JamTracks: 0 units sold")
+ sales[2].should have_content("JamTracks: 1 unit sold")
+
+ subscriptions = page.all("table.payment-table tbody tr td.subscriptions")
+ subscriptions[0].should have_content("")
+ subscriptions[1].should have_content("")
+ subscriptions[2].should have_content("Gold subscriptions - 1")
+ subscriptions[2].should have_content("Silver subscriptions - 1")
+
+ earnings = page.all("table.payment-table tbody tr td.earnings")
+ earnings[0].should have_content("")
+ earnings[1].should have_content("$0.60")
+ earnings[2].should have_content("$0.70")
+
+ #save_screenshot("account_affiliate_earnings_with_subscriptions.png")
+
+ end
+
+
+ # it "shows data" do
+ # sign_in_poltergeist partner.partner_user
+
+ # visit "/client#/account/affiliatePartner"
+ # find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
+
+ # # verify traffic data shows correctly
+ # day1 = Date.parse('2015-04-05')
+ # FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day1, signups: 1, visits:2)
+
+ # #find('a#affiliate-partner-signups-link').trigger(:click)
+ # find('a#affiliate-partner-signups-link').click
+ # find('table.traffic-table tr td.month', text: "April 2015")
+ # find('table.traffic-table tr td.signups', text: '1')
+ # find('table.traffic-table tr td.visits', text: '2')
+
+
+ # #find('a#affiliate-partner-earnings-link').trigger(:click)
+ # find('a#affiliate-partner-earnings-link').click
+ # find('table.payment-table')
+
+ # day2 = Date.parse('2015-04-07')
+ # FactoryGirl.create(:affiliate_traffic_total, affiliate_partner: partner, day: day2, signups: 3, visits:4)
+ # #find('a#affiliate-partner-signups-link').trigger(:click)
+ # find('a#affiliate-partner-signups-link').click
+ # find('table.traffic-table tr td.month', text: "April 2015")
+ # find('table.traffic-table tr td.signups', text: '4')
+ # find('table.traffic-table tr td.visits', text: '6')
+
+ # # verify earnings data correctly
+ # FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:1, due_amount_in_cents:20, jamtracks_sold: 1, closed:true)
+
+ # #find('a#affiliate-partner-earnings-link').trigger(:click)
+ # find('a#affiliate-partner-earnings-link').click
+ # find('table.payment-table tr td.month', text: "January 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
+ # find('table.payment-table tr td.earnings', text: '$0.20')
+
+
+ # #find('a#affiliate-partner-signups-link').trigger(:click)
+ # find('a#affiliate-partner-signups-link').click
+ # find('table.traffic-table')
+
+ # FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:2, due_amount_in_cents:40, jamtracks_sold: 2, closed:true)
+ # FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:3, due_amount_in_cents:60, jamtracks_sold: 3, closed:true)
+ # quarter1 = FactoryGirl.create(:affiliate_quarterly_payment, affiliate_partner:partner, year:2015, quarter:0, due_amount_in_cents:120, jamtracks_sold: 6, closed:true, paid:false)
+ # FactoryGirl.create(:affiliate_monthly_payment, affiliate_partner:partner, year:2015, month:4, due_amount_in_cents:2000, jamtracks_sold: 100, closed:true)
+
+ # #find('a#affiliate-partner-earnings-link').trigger(:click)
+ # find('a#affiliate-partner-earnings-link').click
+ # find('table.payment-table tr td.month', text: "January 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
+ # find('table.payment-table tr td.earnings', text: '$0.20')
+ # find('table.payment-table tr td.month', text: "February 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 2 units sold')
+ # find('table.payment-table tr td.earnings', text: '$0.40')
+ # find('table.payment-table tr td.month', text: "March 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 3 units sold')
+ # find('table.payment-table tr td.earnings', text: '$0.60')
+ # find('table.payment-table tr td.month', text: "1st Quarter 2015")
+ # find('table.payment-table tr td.earnings', text: 'No earning were paid, as the $10 minimum threshold was not reached.')
+
+
+
+ # #find('a#affiliate-partner-signups-link').trigger(:click)
+ # find('a#affiliate-partner-signups-link').click
+ # find('table.traffic-table')
+
+ # quarter1.paid = true
+ # quarter1.save!
+ # FactoryGirl.create(:affiliate_quarterly_payment, affiliate_partner:partner, year:2015, quarter:1, due_amount_in_cents:2000, jamtracks_sold: 100, closed:true, paid:true)
+
+ # #find('a#affiliate-partner-earnings-link').trigger(:click)
+ # find('a#affiliate-partner-earnings-link').click
+ # find('table.payment-table tr td.month', text: "January 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 1 unit sold')
+ # find('table.payment-table tr td.earnings', text: '$0.20')
+ # find('table.payment-table tr td.month', text: "February 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 2 units sold')
+ # find('table.payment-table tr td.earnings', text: '$0.40')
+ # find('table.payment-table tr td.month', text: "March 2015")
+ # find('table.payment-table tr td.sales', text: 'JamTracks: 3 units sold')
+ # find('table.payment-table tr td.earnings', text: '$0.60')
+
+ # find('table.payment-table tr td.month', text: "1st Quarter 2015")
+ # find('table.payment-table tr td.earnings', text: 'PAID $1.20')
+ # find('table.payment-table tr td.month', text: "2nd Quarter 2015")
+ # find('table.payment-table tr td.earnings', text: 'PAID $20.00')
+ # end
end
end
diff --git a/web/spec/features/affiliate_program_spec.rb b/web/spec/features/affiliate_program_spec.rb
index 26378cd92..ea4edeeae 100644
--- a/web/spec/features/affiliate_program_spec.rb
+++ b/web/spec/features/affiliate_program_spec.rb
@@ -7,7 +7,6 @@ describe "Affiliate Program", :js => true, :type => :feature, :capybara_feature
let(:user) { FactoryGirl.create(:user) }
before(:each) do
- User.delete_all
AffiliateQuarterlyPayment.delete_all
AffiliateMonthlyPayment.delete_all
AffiliateTrafficTotal.delete_all
@@ -27,16 +26,16 @@ describe "Affiliate Program", :js => true, :type => :feature, :capybara_feature
it "logged in user creates affiliate" do
fast_signin user, '/affiliateProgram'
- find('input#entity_individual').trigger(:click)
+ find('input#entity_individual').click
- find('.agree-button').trigger(:click)
+ find('.agree-button').click
find('h1', text: 'congratulations')
- find('.button-orange', text: 'GO TO AFFILIATE PAGE').trigger(:click)
+ find('.button-orange', text: 'GO TO AFFILIATE PAGE').click
find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
- partner = AffiliatePartner.first
+ partner = AffiliatePartner.order('created_at desc').first
partner.partner_user.should eq(user)
partner.entity_type.should eq('Individual')
end
@@ -44,18 +43,18 @@ describe "Affiliate Program", :js => true, :type => :feature, :capybara_feature
it "logged in user creates entity affiliate" do
fast_signin user, '/affiliateProgram'
- find('input#entity_entity').trigger(:click)
+ find('input#entity_entity').click
fill_in('entity-name', with: 'Mr. Bubbles')
select('Sole Proprietor', from:'entity-type')
- find('.agree-button').trigger(:click)
+ find('.agree-button').click
find('h1', text: 'congratulations')
- find('.button-orange', text: 'GO TO AFFILIATE PAGE').trigger(:click)
+ find('.button-orange', text: 'GO TO AFFILIATE PAGE').click
find('.tab-account', text: 'So please provide this data, and be sure to keep it current!')
- partner = AffiliatePartner.first
+ partner = AffiliatePartner.order('created_at desc').first
partner.partner_user.should eq(user)
partner.entity_type.should eq('Sole Proprietor')
end
@@ -63,26 +62,25 @@ describe "Affiliate Program", :js => true, :type => :feature, :capybara_feature
it "new user creates individual affiliate" do
visit '/affiliateProgram'
- find('input#entity_individual').trigger(:click)
+ find('input#entity_individual').click
- find('.agree-button').trigger(:click)
+ find('.agree-button').click
find('h1', text: 'congratulations')
- find('.button-orange', text: 'GO SIGNUP').trigger(:click)
+ find('.button-orange', text: 'GO SIGNUP').click
fill_in "jam_ruby_user[first_name]", with: "Affiliate1"
fill_in "jam_ruby_user[last_name]", with: "Someone"
fill_in "jam_ruby_user[email]", with: "affiliate1@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
- check("jam_ruby_user[instruments][drums][selected]")
check("jam_ruby_user[terms_of_service]")
click_button "CREATE ACCOUNT"
should have_title("JamKazam | Congratulations")
- found_user = User.first
- partner = AffiliatePartner.first
+ found_user = User.order('created_at desc').first
+ partner = AffiliatePartner.order('created_at desc').first
partner.partner_user.should eq(found_user)
partner.entity_type.should eq('Individual')
end
diff --git a/web/spec/features/affiliate_referral_spec.rb b/web/spec/features/affiliate_referral_spec.rb
index c7d8b7854..3486acc63 100644
--- a/web/spec/features/affiliate_referral_spec.rb
+++ b/web/spec/features/affiliate_referral_spec.rb
@@ -39,7 +39,6 @@ describe "affiliate visit tracking", :js => true, :type => :feature, :capybara_
fill_in "jam_ruby_user[email]", with: "referral1@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
- check("jam_ruby_user[instruments][drums][selected]")
check("jam_ruby_user[terms_of_service]")
click_button "CREATE ACCOUNT"
diff --git a/web/spec/features/affiliate_visit_tracking.rb b/web/spec/features/affiliate_visit_tracking.rb
deleted file mode 100644
index 0afe3e131..000000000
--- a/web/spec/features/affiliate_visit_tracking.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'spec_helper'
-
-describe "affiliate visit tracking" do
-
- subject { page }
-
- let(:user) { FactoryGirl.create(:user) }
- let(:partner) { FactoryGirl.create(:affiliate_partner) }
- let(:affiliate_params) { partner.affiliate_query_params }
-
- before(:each) do
- AffiliateReferralVisit.delete_all
- end
-
- it "tracks" do
- visit '/?' + affiliate_params
-
- should_be_at_root
- AffiliateReferralVisit.count.should eq(1)
- visit = AffiliateReferralVisit.first
- visit.visited_url.should eq('/?' + affiliate_params)
- visit.affiliate_partner_id.should eq(partner.id)
- visit.first_visit.should be true
-
- download_url = '/downloads?' + affiliate_params
- visit download_url
- find('h2.create-account-header')
-
-
- AffiliateReferralVisit.count.should eq(2)
- visit = AffiliateReferralVisit.find_by_visited_url(download_url)
- visit.affiliate_partner_id.should eq(partner.id)
- visit.first_visit.should be false
- end
-
-end
diff --git a/web/spec/spec_helper.rb b/web/spec/spec_helper.rb
index c5007e977..b4a869629 100644
--- a/web/spec/spec_helper.rb
+++ b/web/spec/spec_helper.rb
@@ -165,6 +165,14 @@ Capybara.server = :puma
config.visible_text_only = true
end
+ Capybara.register_driver :jamkazam do |app|
+ require 'selenium/webdriver'
+ profile = Selenium::WebDriver::Firefox::Profile.new
+ profile['general.useragent.override'] = "jamkazam"
+
+ Capybara::Selenium::Driver.new(app, :profile => profile)
+ end
+
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
diff --git a/web/spec/support/utilities.rb b/web/spec/support/utilities.rb
index 38af9186f..b0e1569e6 100644
--- a/web/spec/support/utilities.rb
+++ b/web/spec/support/utilities.rb
@@ -137,6 +137,41 @@ def set_cookie(k, v)
end
end
+# def sign_in_poltergeist(user, options = {})
+# validate = options[:validate]
+# validate = true if validate.nil?
+
+# if user.password.nil? && !options[:password]
+# raise "user has no password. Use a user newly created so that it's password is still present"
+# end
+# uri = URI.parse(current_url)
+
+# # in tests, we often have an issue where an old signin screen is unloading
+# # as this one is loading.
+# # so one way to fix this is to go to a different page in this case, and then come back to /signin
+
+# if uri.path == signin_path
+# visit '/'
+# should_be_at_root
+# end
+
+# visit signin_path
+# page.should have_selector('#landing-inner form.signin-form')
+
+# within('#landing-inner form.signin-form') do
+# fill_in "Email Address:", with: user.email
+# fill_in "Password:", with: options[:password] || user.password
+# click_button "SIGN IN"
+# end
+
+# page.should have_no_selector('h1', text: 'sign in or register')
+
+# wait_until_curtain_gone
+
+# # presence of this means websocket gateway is not working
+# page.should have_no_selector('.no-websocket-connection') if validate
+#end
+
def sign_in_poltergeist(user, options = {})
validate = options[:validate]
validate = true if validate.nil?
@@ -175,6 +210,7 @@ end
# skip the typical login form, which redirects to /client (slow due to extra login step).
# So this just sets the cookie, and puts you where you want to be
def fast_signin(user, url)
+ visit '/'
set_login_cookie(user)
visit url
end
@@ -486,7 +522,11 @@ def request_to_join_session(joiner, options)
end
def emulate_client
- page.driver.headers = { 'User-Agent' => ' JamKazam ' }
+ #page.driver.headers = { 'User-Agent' => ' JamKazam ' }
+ #page.driver.header 'User-Agent', 'JamKazam'
+ #page.driver.options[:headers].merge!({ 'User-Agent' => ' JamKazam ' })
+ #Capybara.current_session.driver.header('User-Agent', 'JamKazam')
+ # page.driver.browser.header('User-Agent', ' JamKazam ')
end
def create_join_session(creator, joiners=[], options={})