From 0db6bac7492eab359c965e8c24f11e249d56df02 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 23 Mar 2025 13:54:53 -0500 Subject: [PATCH] Better reporting for quarterly payments --- admin/app/admin/affiliate_quarterly_totals.rb | 20 ++++- admin/app/admin/affiliate_users.rb | 20 ++--- admin/app/admin/affiliates.rb | 64 ++++++++++++-- admin/bin/start_mx | 1 + ...0250322000000_affiliate_tracking_totals.rb | 51 +++++++++++ ruby/lib/jam_ruby/models/affiliate_partner.rb | 86 ++++++++++++++++++- web/bin/start | 1 + web/bin/start_mx | 1 + 8 files changed, 224 insertions(+), 20 deletions(-) create mode 100755 admin/bin/start_mx create mode 100644 ruby/db/migrate/20250322000000_affiliate_tracking_totals.rb create mode 100755 web/bin/start_mx diff --git a/admin/app/admin/affiliate_quarterly_totals.rb b/admin/app/admin/affiliate_quarterly_totals.rb index 4f065c267..742cbd7e1 100644 --- a/admin/app/admin/affiliate_quarterly_totals.rb +++ b/admin/app/admin/affiliate_quarterly_totals.rb @@ -2,7 +2,7 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart menu :label => 'Quarterly Reports', :parent => 'Affiliates' - config.sort_order = 'due_amount_in_cents DESC' + config.sort_order = 'year desc, quarter desc, due_amount_in_cents desc' config.batch_actions = false config.clear_action_items! config.filters = true @@ -14,18 +14,32 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart filter :quarter filter :closed filter :paid + filter :jamtracks_sold + filter :subscriptions_count + filter :due_amount_in_cents form :partial => 'form' + scope("Sorted By Due Amount", default: true) { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') } + scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.order('year desc, quarter desc, jamtracks_sold desc') } + scope("Sorted By Subs", default: false) { |scope| scope.order('year desc, quarter desc, subscriptions_count desc') } + scope("Sorted By Newest First") { |scope| scope.order('year desc, quarter desc, id desc') } + scope("Any") { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') } + + index do # default_actions # use this for all view/edit/delete links column 'Year' do |oo| oo.year end column 'Quarter' do |oo| oo.quarter end + column 'Partner Id' do |oo| oo.affiliate_partner.id end column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end - column "Due (\u00A2)" do |oo| oo.due_amount_in_cents end - column 'JamTracks Sold' do |oo| oo.jamtracks_sold end + column "Tot ($)" do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end + column "Sub ($)" do |oo| sprintf("$%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) end + column "Jam ($)" do |oo| sprintf("$%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f) end + column 'JamTracks' do |oo| oo.jamtracks_sold end + column 'Subscriptions' do |oo| oo.subscriptions_count end column 'Paid' do |oo| oo.paid end column 'Closed' do |oo| oo.paid end diff --git a/admin/app/admin/affiliate_users.rb b/admin/app/admin/affiliate_users.rb index d2aa99969..0de0b57ed 100644 --- a/admin/app/admin/affiliate_users.rb +++ b/admin/app/admin/affiliate_users.rb @@ -23,17 +23,17 @@ ActiveAdmin.register JamRuby::User, :as => 'Referrals' do controller do - def scoped_collection - rel = end_of_association_chain - .includes([:affiliate_referral]) - .order('created_at DESC') - if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present? - qq = ['affiliate_referral_id = ?', ref_id] - else - qq = ['affiliate_referral_id IS NOT NULL'] - end - @users ||= rel.where(qq) + def scoped_collection + rel = end_of_association_chain + .includes([:affiliate_referral]) + .order('created_at DESC') + if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present? + qq = ['affiliate_referral_id = ?', ref_id] + else + qq = ['affiliate_referral_id IS NOT NULL'] end + @users ||= rel.where(qq) + end end end diff --git a/admin/app/admin/affiliates.rb b/admin/app/admin/affiliates.rb index dc99718c4..868d63fce 100644 --- a/admin/app/admin/affiliates.rb +++ b/admin/app/admin/affiliates.rb @@ -5,13 +5,23 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do config.sort_order = 'referral_user_count DESC' config.batch_actions = false # config.clear_action_items! - config.filters = false + config.filters = true config.per_page = 50 config.paginate = true #form :partial => 'form' - scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') } + + filter :partner_user + filter :partner_name + filter :id + + scope("Sorted By Current Quarter", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('current_quarter_in_cents desc') } + scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('jamtracks_sold desc') } + scope("Sorted By Subs", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('subscriptions_count desc') } + scope("Sorted By Signups", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') } + scope("Sorted By Newest First") { |scope| scope.where('partner_user_id IS NOT NULL').order('id desc') } + scope("Any") { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') } scope("Unpaid") { |partner| partner.unpaid } controller do @@ -45,14 +55,48 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do column 'Code' do |oo| oo.id end - column 'Referral Count' do |oo| + column 'Signups' do |oo| oo.referral_user_count end - column 'Earnings' do |oo| - sprintf("$%.2f", oo.cumulative_earnings_in_dollars) + column 'JamTracks' do |oo| + oo.jamtracks_sold + end + column 'Subs' do |oo| + oo.subscriptions_count + end + column 'Cum Earnings' do |oo| + div do + sprintf("Tot $%.2f", oo.cumulative_earnings_in_dollars) + end + div do + sprintf("Jam $%.2f", oo.jamtrack_cumulative_earnings_in_dollars) + end + div do + sprintf("Sub $%.2f", oo.subscriptions_cumulative_earnings_in_dollars) + end + + end + column 'Current Quarter' do |oo| + div do + sprintf("Tot $%.2f", oo.current_quarter_in_dollars) + end + div do + sprintf("Jam $%.2f", oo.jamtrack_current_quarter_in_dollars) + end + div do + sprintf("Sub $%.2f", oo.subscriptions_current_quarter_in_dollars) + end end column 'Amount Owed' do |oo| - sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) + div do + sprintf("Tot $%.2f", oo.due_amount_in_cents.to_f / 100.to_f) + end + div do + sprintf("Jam $%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f) + end + div do + sprintf("Sub $%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) + end 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 @@ -71,6 +115,14 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do row :address row :tax_identifier row :paypal_id + row :jamtracks_sold + row :subscriptions_count + row :cumulative_earnings_in_dollars + row :jamtrack_cumulative_earnings_in_dollars + row :subscriptions_cumulative_earnings_in_dollars + row :current_quarter_in_dollars + row :jamtrack_current_quarter_in_dollars + row :subscriptions_current_quarter_in_dollars end diff --git a/admin/bin/start_mx b/admin/bin/start_mx new file mode 100755 index 000000000..39c42149e --- /dev/null +++ b/admin/bin/start_mx @@ -0,0 +1 @@ +BUNDLE_GEMFILE=Gemfile.alt RAILS_ENV=development LOCAL_DEV=1 MODERN_OS=1 JAM_RUBY_VERSION=2.4.1 bundle _1.17.3_ exec rails server -b 0.0.0.0 -p 3333 diff --git a/ruby/db/migrate/20250322000000_affiliate_tracking_totals.rb b/ruby/db/migrate/20250322000000_affiliate_tracking_totals.rb new file mode 100644 index 000000000..5364944e4 --- /dev/null +++ b/ruby/db/migrate/20250322000000_affiliate_tracking_totals.rb @@ -0,0 +1,51 @@ +# Adds +# affiliate_partners.jamtrack_cumulative_earnings_in_cents +# affiliate_partners.subscriptions_cumulative_earnings_in_cents +# affiliate_partners.subscriptions_count +# affiliate_quarterly_payments.jamtrack_due_amount_in_cents +# affiliate_quarterly_payments.subscription_due_amount_in_cents +# affiliate_monthly_payments.jamtrack_due_amount_in_cents +# affiliate_monthly_payments.subscription_due_amount_in_cents +class AddTrackingTotalsToAffiliatePartners < ActiveRecord::Migration + + def self.up + execute "ALTER TABLE affiliate_partners ADD COLUMN jamtrack_cumulative_earnings_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN subscriptions_cumulative_earnings_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN current_quarter_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN jamtrack_current_quarter_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN subscriptions_current_quarter_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN jamtracks_sold INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_partners ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_monthy_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0" + execute "ALTER TABLE affiliate_monthly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0" + end +=begin + + ALTER TABLE affiliate_partners ADD COLUMN jamtrack_cumulative_earnings_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN subscriptions_cumulative_earnings_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN current_quarter_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN jamtrack_current_quarter_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN subscriptions_current_quarter_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN jamtracks_sold INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_partners ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_quarterly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_monthly_payments ADD COLUMN jamtrack_due_amount_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_monthly_payments ADD COLUMN subscription_due_amount_in_cents INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_quarterly_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0; + ALTER TABLE affiliate_monthly_payments ADD COLUMN subscriptions_count INTEGER NOT NULL DEFAULT 0; + + +=end + def self.down + execute "ALTER TABLE affiliate_partners DROP COLUMN jamtrack_cumulative_earnings_in_cents" + execute "ALTER TABLE affiliate_partners DROP COLUMN subscriptions_cumulative_earnings_in_cents" + execute "ALTER TABLE affiliate_partners DROP COLUMN subscriptions_count" + execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN jamtrack_due_amount_in_cents" + execute "ALTER TABLE affiliate_quarterly_payments DROP COLUMN subscription_due_amount_in_cents" + end +end diff --git a/ruby/lib/jam_ruby/models/affiliate_partner.rb b/ruby/lib/jam_ruby/models/affiliate_partner.rb index 89cbe123d..8c6f342d2 100644 --- a/ruby/lib/jam_ruby/models/affiliate_partner.rb +++ b/ruby/lib/jam_ruby/models/affiliate_partner.rb @@ -172,6 +172,26 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base cumulative_earnings_in_cents.to_f / 100.to_f end + def jamtrack_cumulative_earnings_in_dollars + jamtrack_cumulative_earnings_in_cents.to_f / 100.to_f + end + + def subscriptions_cumulative_earnings_in_dollars + subscriptions_cumulative_earnings_in_cents.to_f / 100.to_f + end + + def current_quarter_in_dollars + current_quarter_in_cents.to_f / 100.to_f + end + + def jamtrack_current_quarter_in_dollars + jamtrack_cumulative_earnings_in_cents.to_f / 100.to_f + end + + def subscriptions_current_quarter_in_dollars + subscriptions_current_quarter_in_cents.to_f / 100.to_f + end + def self.quarter_info(date) year = date.year @@ -330,6 +350,11 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base (SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END) #{sale_items_refunded_subquery(start_date, end_date, 'affiliate_monthly_payments')} ), 0), + subscriptions_count = + COALESCE( + (SELECT COUNT(CASE WHEN affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END) + #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_monthly_payments')} + ), 0), due_amount_in_cents = COALESCE( (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) @@ -344,6 +369,21 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base COALESCE( (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_monthly_payments')} + ), 0), + jamtrack_due_amount_in_cents = + COALESCE( + (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{sale_items_subquery(start_date, end_date, 'affiliate_monthly_payments')} + ), 0) + + + COALESCE( + (SELECT -SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{sale_items_refunded_subquery(start_date, end_date, 'affiliate_monthly_payments')} + ), 0), + subscription_due_amount_in_cents = + COALESCE( + (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_monthly_payments')} ), 0) WHERE closed = FALSE AND year = #{year} AND month = #{month} } @@ -387,6 +427,11 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base (SELECT -COUNT(CASE WHEN sale_line_items.product_type = 'JamTrack' AND affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END) #{sale_items_refunded_subquery(start_date, end_date, 'affiliate_quarterly_payments')} ), 0), + subscriptions_count = + COALESCE( + (SELECT COUNT(CASE WHEN affiliate_distributions.affiliate_referral_fee_in_cents > 0 THEN 1 ELSE NULL END) + #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_quarterly_payments')} + ), 0), due_amount_in_cents = COALESCE( (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) @@ -401,6 +446,21 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base COALESCE( (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_quarterly_payments')} + ), 0), + jamtrack_due_amount_in_cents = + COALESCE( + (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{sale_items_subquery(start_date, end_date, 'affiliate_quarterly_payments')} + ), 0) + + + COALESCE( + (SELECT -SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{sale_items_refunded_subquery(start_date, end_date, 'affiliate_quarterly_payments')} + ), 0), + subscription_due_amount_in_cents = + COALESCE( + (SELECT SUM(affiliate_distributions.affiliate_referral_fee_in_cents) + #{subscription_distribution_sub_query(start_date, end_date, 'affiliate_quarterly_payments')} ), 0) WHERE closed = FALSE AND paid = FALSE AND year = #{year} AND quarter = #{quarter} @@ -471,7 +531,15 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base sql = %{ UPDATE affiliate_partners SET referral_user_count = (SELECT count(*) FROM users WHERE affiliate_partners.id = users.affiliate_referral_id), - cumulative_earnings_in_cents = (SELECT COALESCE(SUM(due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = TRUE and paid = TRUE) + jamtracks_sold = (SELECT COALESCE(SUM(jamtracks_sold), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id), + subscriptions_count = (SELECT COALESCE(SUM(subscriptions_count), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id), + cumulative_earnings_in_cents = (SELECT COALESCE(SUM(due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = TRUE and paid = TRUE), + subscriptions_cumulative_earnings_in_cents = (SELECT COALESCE(SUM(subscription_due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = TRUE and paid = TRUE), + jamtrack_cumulative_earnings_in_cents = (SELECT COALESCE(SUM(jamtrack_due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = TRUE and paid = TRUE), + current_quarter_in_cents = (SELECT COALESCE(SUM(due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = FALSE), + subscriptions_current_quarter_in_cents = (SELECT COALESCE(SUM(subscription_due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = FALSE), + jamtrack_current_quarter_in_cents = (SELECT COALESCE(SUM(jamtrack_due_amount_in_cents), 0) FROM affiliate_quarterly_payments AS aqp WHERE aqp.affiliate_partner_id = affiliate_partners.id AND closed = FALSE) + } ActiveRecord::Base.connection.execute(sql) end @@ -564,6 +632,22 @@ class JamRuby::AffiliatePartner < ActiveRecord::Base total_in_cents end + def jamtrack_due_amount_in_cents + total_in_cents = 0 + quarters.where(paid:false, closed:true).each do |quarter| + total_in_cents = total_in_cents + quarter.jamtrack_due_amount_in_cents + end + total_in_cents + end + + def subscription_due_amount_in_cents + total_in_cents = 0 + quarters.where(paid:false, closed:true).each do |quarter| + total_in_cents = total_in_cents + quarter.subscription_due_amount_in_cents + end + total_in_cents + end + def affiliate_query_params AffiliatePartner::AFFILIATE_PARAMS + self.id.to_s end diff --git a/web/bin/start b/web/bin/start index 1bc4a496e..b8f19bafe 100755 --- a/web/bin/start +++ b/web/bin/start @@ -3,6 +3,7 @@ #REAL_IP=192.168.0.42 REAL_IP=127.0.0.1 REAL_IP=192.168.5.204 +REAL_IP=127.0.0.1 if [ ! -z "$1" ]; then REAL_IP="$1" fi diff --git a/web/bin/start_mx b/web/bin/start_mx new file mode 100755 index 000000000..827253118 --- /dev/null +++ b/web/bin/start_mx @@ -0,0 +1 @@ +BUNDLE_GEMFILE=Gemfile.alt RAILS_ENV=development LOCAL_DEV=1 MODERN_OS=1 JAM_RUBY_VERSION=2.4.1 NO_WEBSOCKET_GATEWAY=1 bundle _1.17.3_ exec rails server -b 0.0.0.0 -p 3000