<?php
namespace Modules\Groovesell\Repositories;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Modules\Groovesell\Entities\AffiliateAnalytic;
use Modules\Groovesell\Entities\AffiliateLink;
use Modules\Groovesell\Entities\Domain;
use Modules\Groovesell\Entities\Funnel;
use Modules\Groovesell\Entities\FunnelAffiliate;
use Modules\Groovesell\Entities\FunnelResource;
use Modules\Groovesell\Entities\PricePoint;
use Modules\Groovesell\Entities\Product;
use Modules\Groovesell\Entities\SecondTierLink;
use Modules\Groovesell\Entities\Transaction;
use Modules\Groovesell\Entities\AffiliateLog;
class PromosRepository
{
public function getDashboardStats(User $user, $funnelId, $request)
{
$dateRange = $this->getFromToDates($request);
list($fromDate, $toDate) = $dateRange;
// Calculate impressions and uniques using MongoDB aggregation
$impressionsData = $this->calculateImpressionsAndUniques($funnelId, $user, $fromDate, $toDate);
list($uniques, $impressions) = $this->extractImpressionData($impressionsData);
// Calculate other statistics
$stats = $this->calculateStatistics($user, $funnelId, $fromDate, $toDate);
$optins = $stats->signup_count ?? 0;
$transactions = $stats->sales_count ?? 0;
$commissions = ($stats->commission_amount ?? 0) / 100;
// Retrieve the funnel and checkout domain information
list($funnel, $checkoutDomain) = $this->getFunnelAndDomain($funnelId);
// Generate affiliate links
$affiliateLinks = $this->generateAffiliateLinks($user, $funnel, $funnelId, $checkoutDomain);
// Retrieve funnel resource
$funnelResource = FunnelResource::where([
['funnel_id', $funnelId],
['is_default', 1],
])->first();
$response = [
'impressions' => $impressions,
'uniques' => $uniques,
'optins' => $optins,
'sales' => $transactions,
'commissions' => '$' . $commissions,
'affiliate_links' => $affiliateLinks,
'resource_permalink' => $funnelResource->permalink,
];
return $response;
}
public function getMainDashboardStats(User $user, $request)
{
$dateRange = $this->getFromToDates($request);
list($fromDate, $toDate) = $dateRange;
$funnels = FunnelAffiliate::where('user_id', $user->id)->get();
$promosArray = [];
$hasPromos = 0;
$hasData = 0;
foreach ($funnels as $singleFunnel) {
$funnelId = $singleFunnel->funnel_id;
$fetchedFunnel = Funnel::find($funnelId);
if (!$fetchedFunnel) {
continue;
}
$hasPromos = 1;
// Calculate impressions and uniques using MongoDB aggregation
$impressionsData = $this->calculateImpressionsAndUniques($funnelId, $user, $fromDate, $toDate);
list($uniques, $impressions) = $this->extractImpressionData($impressionsData);
// Calculate other statistics
$stats = $this->calculateStatistics($user, $funnelId, $fromDate, $toDate);
$optins = $stats->signup_count ?? 0;
$transactions = $stats->sales_count ?? 0;
$commissions = ($stats->commission_amount ?? 0) / 100;
if ($impressions > 0 || $uniques > 0 || $commissions > 0 || $transactions > 0 || $optins > 0) {
$hasData = 1;
}
$singlePromoResource = [
'id' => $funnelId,
'name' => $fetchedFunnel->name,
'impressions' => $impressions,
'uniques' => $uniques,
'commissions' => number_format((float) $commissions, 2, '.', ''),
'conversions' => $transactions,
'optins' => $optins,
];
$promosArray[] = $singlePromoResource;
}
return ['data' => $promosArray, 'has_used' => $hasPromos, 'has_data' => $hasData];
}
private function getFromToDates($request)
{
if ($request->has('fromDate') && $request->has('toDate')) {
$fromDate = Carbon::createFromFormat('m/d/Y', $request->fromDate, 'US/Eastern')->startOfDay()->setTimezone('UTC');
$toDate = Carbon::createFromFormat('m/d/Y', $request->toDate, 'US/Eastern')->endOfDay()->setTimezone('UTC');
} else {
$fromDate = Carbon::now('US/Eastern')->startOfDay()->setTimezone('UTC');
$toDate = Carbon::now('US/Eastern')->endOfDay()->setTimezone('UTC');
}
return [$fromDate, $toDate];
}
private function calculateImpressionsAndUniques($funnelId, $user, $fromDate, $toDate)
{
$result = AffiliateLog::where('funnel_id', $funnelId)
->where('affiliate_id', $user->id)
->whereBetween('created_timestamp', [$fromDate->timestamp, $toDate->timestamp])
->aggregate([
['$group' => [
'_id' => '$affiliate_id',
'impressions' => ['$sum' => 1],
'uniqueIps' => ['$addToSet' => '$client_ip']
]],
['$project' => [
'impressions' => '$impressions',
'uniques' => ['$size' => '$uniqueIps']
]]
])->first();
return [
'impressions' => $result->impressions ?? 0,
'uniques' => $result->uniques ?? 0,
];
}
private function extractImpressionData($impressionsData)
{
return [$impressionsData->uniques ?? 0, $impressionsData->impressions ?? 0];
}
private function calculateStatistics($user, $funnelId, $fromDate, $toDate)
{
return Transaction::where('affiliate_id', $user->id)
->where('computed_status', 2)
->where('funnel_id', $funnelId)
->whereBetween('created_timestamp', [$fromDate->timestamp, $toDate->timestamp])
->select(
DB::raw("SUM(CASE WHEN gateway_type = 'FREE' THEN 1 ELSE 0 END) AS signup_count"),
DB::raw("SUM(CASE WHEN gateway_type != 'FREE' AND gateway_type != 'test' AND is_refunded = 0 THEN 1 ELSE 0 END) AS sales_count"),
DB::raw("SUM(CASE WHEN gateway_type != 'FREE' AND gateway_type != 'test' AND is_refunded = 0 AND commission > 0 THEN commission ELSE 0 END) AS commission_amount")
)
->first();
}
private function getFunnelAndDomain($funnelId)
{
$fetchedFunnel = Funnel::find($funnelId);
if ($fetchedFunnel && $fetchedFunnel->cross_aff_program_id > 0) {
$funnel = Funnel::find($fetchedFunnel->cross_aff_program_id);
$affFunnelId = $fetchedFunnel->cross_aff_program_id;
} else {
$funnel = $fetchedFunnel;
$affFunnelId = $funnelId;
}
$checkoutDomain = Domain::where([
['type', 1],
['funnel_assigned_to', $funnel->id],
])->first();
return [$funnel, $checkoutDomain];
}
private function generateAffiliateLinks($user, $funnel, $affFunnelId, $checkoutDomain)
{
$affiliateLinks = [];
$mainProduct = Product::where([
['funnel_id', $affFunnelId],
['affiliates_enabled', 1],
['is_main', 1],
])->first();
if ($mainProduct && $mainProduct->affiliate_landing_pages && count($mainProduct->affiliate_landing_pages) > 0) {
foreach ($mainProduct->affiliate_landing_pages as $singleAffiliateLandingPage) {
if ($this->isLandingPageAssignedToAffiliate($singleAffiliateLandingPage, $user)) {
$affiliateLinkForThisLandingPage = AffiliateLink::where([
['affiliate_id', $user->id],
['funnel_id', $affFunnelId],
['product_id', $mainProduct->id],
['landing_page_id', $singleAffiliateLandingPage['id']],
])->orderBy('id', 'desc')->first();
if (!$affiliateLinkForThisLandingPage) {
$affiliateLinkForThisLandingPage = new AffiliateLink;
$affiliateLinkForThisLandingPage->affiliate_id = $user->id;
$affiliateLinkForThisLandingPage->funnel_id = $affFunnelId;
$affiliateLinkForThisLandingPage->product_id = $mainProduct->id;
$affiliateLinkForThisLandingPage->landing_page_id = $singleAffiliateLandingPage['id'];
$affiliateLinkForThisLandingPage->permalink = str_random(12);
$affiliateLinkForThisLandingPage->save();
}
$singleAffiliateLink['name'] = $singleAffiliateLandingPage['description'];
$urlArray = parse_url(env('GROOVESELL_FRONTEND_URL'));
if ($checkoutDomain) {
$singleAffiliateLink['link'] = 'https://' . $checkoutDomain->name . '/a/' . $affiliateLinkForThisLandingPage->permalink;
} else {
$singleAffiliateLink['link'] = 'https://' . $funnel->slug . '.groovesell.com/a/' . $affiliateLinkForThisLandingPage->permalink;
}
$singleAffiliateLink['type'] = 'affiliate';
$affiliateLinks[] = $singleAffiliateLink;
}
}
$has2ndTier = $this->has2ndTier($user, $affFunnelId);
if ($has2ndTier == 1) {
$secondTierLinkForThisFunnel = SecondTierLink::where([
['affiliate_id', $user->id],
['funnel_id', $affFunnelId],
])->orderBy('id', 'desc')->first();
if (!$secondTierLinkForThisFunnel) {
$secondTierLinkForThisFunnel = new SecondTierLink;
$secondTierLinkForThisFunnel->affiliate_id = $user->id;
$secondTierLinkForThisFunnel->funnel_id = $affFunnelId;
$secondTierLinkForThisFunnel->permalink = str_random(12);
$secondTierLinkForThisFunnel->save();
}
$singleSecondTierLink = [];
$singleSecondTierLink['name'] = '2nd Tier Affiliate Link';
$urlArray = parse_url(env('GROOVESELL_FRONTEND_URL'));
if ($checkoutDomain) {
$singleSecondTierLink['link'] = 'https://' . $checkoutDomain->name . '/jv/' . $secondTierLinkForThisFunnel->permalink;
} else {
$singleSecondTierLink['link'] = 'https://' . $funnel->slug . '.groovesell.com/jv/' . $secondTierLinkForThisFunnel->permalink;
}
$affiliateLinks[] = $singleSecondTierLink;
}
}
return $affiliateLinks;
}
private function isLandingPageAssignedToAffiliate($landingPage, $user)
{
foreach ($landingPage['assigned_to'] as $singleAssignedTo) {
if ($singleAssignedTo['id'] == 0 || $singleAssignedTo['id'] == $user->id) {
return true;
}
}
return false;
}
private function has2ndTier($user, $affFunnelId)
{
$has2ndTier = 0;
$allAffiliateEnabledProducts = Product::where([
['funnel_id', $affFunnelId],
['affiliates_enabled', 1],
])->get();
foreach ($allAffiliateEnabledProducts as $product) {
if ($this->productHasSecondTier($product, $user)) {
$has2ndTier = 1;
break;
}
}
return $has2ndTier;
}
private function productHasSecondTier($product, $user)
{
$pricePoints = PricePoint::where('product_id', $product->id)->get();
foreach ($pricePoints as $pricePoint) {
$commissionDetails = $pricePoint->commission_details;
if ($this->hasSecondTierCommission($commissionDetails, $user)) {
return true;
}
}
return false;
}
private function hasSecondTierCommission($commissionDetails, $user)
{
foreach ($commissionDetails as $commissionTier) {
if (
empty($commissionTier['assigned_to']) ||
in_array($user->id, $commissionTier['assigned_to'])
) {
if (
$this->hasSecondTierTrialCommission($commissionTier) ||
$this->hasSecondTierSalesCommission($commissionTier) ||
$this->hasSecondTierRebillCommission($commissionTier)
) {
return true;
}
}
}
return false;
}
private function hasSecondTierTrialCommission($commissionTier)
{
return $commissionTier['trial_commission']['jv_broker_commission'] > 0;
}
private function hasSecondTierSalesCommission($commissionTier)
{
return (
($commissionTier['sales_commission']['jv_broker_commission'] > 0) &&
($commissionTier['sales_commission']['jv_broker_commission'] > 0)
);
}
private function hasSecondTierRebillCommission($commissionTier)
{
foreach ($commissionTier['rebill_commissions'] as $rebillCommission) {
if ($rebillCommission['jv_broker_commission'] > 0) {
return true;
}
}
return false;
}
}