Skip to content

Instantly share code, notes, and snippets.

@worstn8mare
Created April 30, 2020 08:35
Show Gist options
  • Save worstn8mare/b2c531c529f223e33d0a529c5bab3acb to your computer and use it in GitHub Desktop.
Save worstn8mare/b2c531c529f223e33d0a529c5bab3acb to your computer and use it in GitHub Desktop.
<?php
namespace Modules\Commission\Services;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Modules\Commission\Models\Goldmine2CommissionBypass;
use Modules\Commission\Models\Goldmine2CommissionBypassLevels;
use Modules\Credit\Models\BankAccount;
use Modules\Mt4\Models\Mt4Trade;
use Modules\Mt4\Models\Mt4User;
use Modules\Mt4Transfer\Models\Mt4TradeType;
use Modules\Mt4Transfer\Models\Trader;
use Modules\User\Models\User;
class Goldmine2CommissionService extends CommissionAbstract
{
public $goldmine2Settings;
protected $maxDepth = 12;
protected $goldmineType = 'goldmine 2 commission';
protected $goldmineTypeId;
private $masterTraderLots;
private $lotPerVolume;
/**
* @var string
*/
private $mt4TradesTable;
/**
* @var string
*/
private $mt4UsersTable;
/**
* @var bool|string
*/
private $enabledPromo;
/**
* @var bool|string
*/
private $enabledPromoValues;
private $usersPromoClassification;
private $qualifiedUsers;
private $qualifiedUsers6;
private $qualifiedUsers10;
/**
* @var bool|string
*/
private $bypassMinimumAmount;
private $transferSummary;
/**
* @var string
*/
private $directory;
/**
* @var string
*/
private $fileDate;
private $userTiersCurrent;
private $transferLifetimeSummary;
/**
* @var Goldmine2CommissionBypass
*/
private $gm2BypassModel;
public function __construct(Goldmine2CommissionBypass $gm2BypassModel)
{
$this->logText = '';
$this->directory = storage_path('logs') . '/goldmine2/';
if (!File::exists($this->directory)) {
File::makeDirectory($this->directory);
}
$this->fileDate = Carbon::now()->format('Y-m-d-h-i-s');
$this->path = $this->directory . "goldmine2-" . $this->fileDate;
$this->gm2BypassModel = $gm2BypassModel;
}
public function payout($tradeCommissions, $userTiers)
{
// commissions here is already the total of profit and volume from mt4_trades
$goldmineCommissionToInsert = [];
$goldminePayoutToInsert = [];
$goldmineCommissionUsers = $tradeCommissions->pluck('user_id', 'user_id')->toArray();
$bank_accounts = BankAccount::get()->pluck('id', 'reference_id')->toArray();
$this->userTiers = $userTiers;
if (count($goldmineCommissionUsers) > 0) {
$sponsorTreeNodes = $this->sponsorTreeData->filter(function ($sponsorNode) use ($goldmineCommissionUsers) {
return in_array($sponsorNode['user_id'], $goldmineCommissionUsers);
});
foreach ($sponsorTreeNodes as $node) {
$uplines = $this->sponsorTreeData->filter(function ($sponsorNode) use ($node) {
return $sponsorNode['lft'] < $node['lft'] && $sponsorNode['rgt'] > $node['rgt'];
});
$uplines_sorted = $uplines->sortByDesc('level');
$trade = $tradeCommissions[$node['user_id']];
$trade['level'] = 1;
$invested_amount = $this->getInvestedAmount($trade->user_id);
$this->logText .= "[Contributor]: " . $node['user_id'] . " [total trades] " . $trade->total_trades . " [invested_amount]: $invested_amount \n";
foreach ($uplines_sorted as $upline) {
if ($trade->level > $this->maxDepth) {
break;
}
$uplineUserId = $upline['user_id'];
if (!$this->isEligible($trade, $userTiers, $uplineUserId)) {
$trade->level++;
continue;
}
if (!$this->toCompressUser($uplineUserId, $userTiers, $trade->level)) {
$calculated_amount = $this->calculateAmount($trade, $userTiers, $uplineUserId);
if ($calculated_amount > 0) {
$goldmineCommissionToInsert[] = [
'user_id' => $uplineUserId,
'contributor_user_id' => $node['user_id'],
'amount' => $invested_amount, // amount field in goldmine 2 is the invested amount
'calculated_amount' => $calculated_amount,
'level_percentage' => 0,
'commission_percentage' => 0,
'level' => $trade->level,
'payout_date' => $trade->open_time,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
'goldmine_commission_type' => $this->goldmineTypeId,
];
$transactionCode = $this->generateTransactionCode($uplineUserId, $node['user_id'], $this->bankTransactionType);
$this->appendGoldmineCommissionLogs(
[
'user_id' => $uplineUserId,
'user_tier' => $userTiers[$uplineUserId]['tier'],
'user_isContract' => $userTiers[$uplineUserId]['contract_type_id'], //---> add contract for snapshot user_tier
'contributor_id' => $node['user_id'],
'amount' => $invested_amount, // amount field in goldmine 2 is the invested amount
'calculated_amount' => $calculated_amount,
'trade_volume' => $trade->total_trades,
'transaction_code' => $transactionCode,
'user_level' => $trade->level
]
);
$goldminePayoutToInsert[] = [
'credit' => $calculated_amount,
'transaction_code' => $transactionCode,
'transaction_date' => Carbon::now(),
'bank_transaction_type_id' => $this->bankTransactionType,
'bank_credit_type_id' => $this->bankCreditTypeId,
'transfer_account_id' => null,
'bank_account_id' => isset($bank_accounts[$uplineUserId]) ? $bank_accounts[$uplineUserId] : null,
'done_by' => 1, // assume admin
'remarks' => 'Goldmine 2 Commission',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
];
}
$trade->level++;
}
}
}
}
$this->persistCommissionTrades($goldmineCommissionToInsert);
$this->persistGoldmineCommissionLogs();
$this->persistBankAccountStatement($goldminePayoutToInsert);
return true;
}
public function setValues()
{
parent::setValues(); // TODO: Change the autogenerated stub
$this->goldmine2Settings = json_decode(setting('goldmine_payout_amount_per_lot'), true);
$this->mt4TradesTable = (new Mt4Trade())->getTable();
$this->mt4UsersTable = (new Mt4User())->getTable();
$this->lotPerVolume = setting('lot_per_volume');
$this->getEnabledPromo();
$this->setBypassMinimumAmount();
$this->fetchQualifiedUsers();
}
public function getTradeLots($tradeStartDate, $tradeEndDate)
{
return User::join('user_mt4_ids', function ($join) {
$join->on('user_mt4_ids.user_id', '=', 'users.id')
->whereNotNull('trader_id')
->where('mt4_trade_type_id', Mt4TradeType::COPY_TRADE); // do checking here
})
->join('traders', 'traders.id', '=', 'user_mt4_ids.trader_id')
->join($this->mt4TradesTable, function ($join) use ($tradeStartDate, $tradeEndDate) {
$join->on('user_mt4_ids.member_id', '=', $this->mt4TradesTable . '.login')
->whereBetween($this->mt4TradesTable . '.open_time', [$tradeStartDate, $tradeEndDate])
->whereIn($this->mt4TradesTable . '.cmd', $this->cmd);
})
->join($this->mt4UsersTable, $this->mt4UsersTable . '.login', '=', $this->mt4TradesTable . '.login')
->join('bank_accounts', 'bank_accounts.reference_id', '=', 'users.id');
}
public function getEnabledPromo()
{
$this->enabledPromo = json_decode(setting('goldmine_2_promotion_release_criteria'));
$this->enabledPromoValues = json_decode(setting('goldmine_2_promotion_registration_payout'), true);
$this->usersPromoClassification = [];
if ($this->enabledPromo->enabled) {
$this->usersPromoClassification = User::select(
[
'id',
'member_id',
'contract_type_id',
DB::raw("
CASE
WHEN created_at <= '" . Carbon::parse($this->enabledPromo->end)->endOfDay()->format('y-m-d H:i:s') . "' THEN true
ELSE false
END AS is_promotion
")
]
)->get()
->keyBy('id')
->toArray();
}
}
/*
* wdd666 ID:3459908 - 77
* wdd777 ID:3459952, - 90
* wdd888 ID:3459956, - 92
* wdd999 ID:3459959, - 93
*/
public function bypassCommQualificationCheck($uplineId, $userTiers, $level)
{
$returnValue = false;
if (isset($this->qualifiedUsers[$uplineId])) {
$qualifiedUser = $this->qualifiedUsers[$uplineId];
$balance = $this->getUserBalance($uplineId); // use current user tier for balance
if ($level <= $qualifiedUser['level'] && $this->checkMinimumAmountForBypass($balance)) {
$this->logText .= "ByPass qualified! ";
$returnValue = true;
} else {
$this->logText .= "ByPass not qualified! Only upto {$qualifiedUser['level']} ";
}
}
return $returnValue;
}
public function setTotalTransfer($transferSummary)
{
$this->transferSummary = $transferSummary;
$transferSummaryFile = $this->directory . 'transfer_summary_' . $this->fileDate . '.csv';
$fp = fopen($transferSummaryFile, 'w');
fputcsv($fp, ['total_deposit', 'total_withdrawal', 'total_amount', 'user_id']);
foreach ($this->transferSummary as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
}
public function setTotalTransferLifetime($transferSummary)
{
$this->transferLifetimeSummary = $transferSummary;
$transferSummaryFile = $this->directory . 'transfer_summary_lifetime' . $this->fileDate . '.csv';
$fp = fopen($transferSummaryFile, 'w');
fputcsv($fp, ['total_deposit', 'total_withdrawal', 'total_amount', 'user_id']);
foreach ($this->transferLifetimeSummary as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
}
/*
* $userTiersCurrent is the current day user tier snapshot runs (Saturday for weekly, current day for daily)
* while $userTiers is the previous user tier snapshot (Thursday for weekly, previous day for daily)
*/
public function setUserTierSnapshotCurrent($snapshot)
{
$this->userTiersCurrent = $snapshot;
}
public function fetchQualifiedUsers()
{
$noLevel = Goldmine2CommissionBypassLevels::where('level', 0)->firstOrFail();
$this->qualifiedUsers = Goldmine2CommissionBypass::join('goldmine2_commission_bypass_levels', 'goldmine2_commission_bypass_levels.id', '=', 'goldmine2_commission_bypass.level_id')
->where('level_id', '!=', $noLevel->id)->select([
'goldmine2_commission_bypass.user_id',
'goldmine2_commission_bypass_levels.level',
'goldmine2_commission_bypass_levels.amount',
])->get()->keyBy('user_id')->toArray();
}
/**
* @param $trade
* @param $userTiers
* @param $uplineUserId
* @return string
*/
protected function calculateAmount($trade, $userTiers, $uplineUserId)
{
// use goldmine2settings here
// get trade->level, and get values of goldmine2settings[trade->level]
// this should have tier_no_share, normal, contract amounts. only tier_no_share property to use here
$goldmineLevel = $this->goldmine2Settings[$trade->level];
$payoutAmount = $this->userHasContract($userTiers[$uplineUserId]['contract_type_id']) ? $goldmineLevel['contract'] : $goldmineLevel['normal']; // z
$amountFollowingTrader = $this->getInvestedAmount($trade->user_id); // x
$masterTraderTrades = $trade->total_trades; // L
$toDivide = 10000; // y
$calculated_amount = bcmul(bcmul(bcdiv($amountFollowingTrader, $toDivide, 8), $masterTraderTrades, 8), $payoutAmount, 2);
$this->logText .= "\t\t\t [calculated_amount]: $calculated_amount \n";
// x - amount following a trader --> (volume / 100)
// y - fixed amount 10,000
// L - master trader trades per week
// z - goldmine level amount (contract / normal)
// (x / y) (L) (z)
return $calculated_amount;
}
protected function isEligible($trade, $userTiers, $uplineUserId)
{
$goldmineLevel = $this->promotionQualified($uplineUserId, $trade->level);
$tierLog = isset($userTiers[$uplineUserId]) ? $userTiers[$uplineUserId]['tier'] : 0;
$result = false;
$this->logText .= "\t[upline_id]: " . $uplineUserId . " [upline_tier]: " . $tierLog . " [tier no share]: " . implode(",", $goldmineLevel['tier_no_share']) . " [current_level]: " . $trade->level;
$this->logText .= "\n\t\t\t [isEligible]: ";
if (isset($this->qualifiedUsers[$uplineUserId])) {
if ($this->bypassCommQualificationCheck($uplineUserId, $userTiers, $trade->level)) {
return true;
}
}
$result = $tierLog == 0 ? false : !in_array($tierLog, $goldmineLevel['tier_no_share']);
$this->logText .= ($result ? "yes!" : "no \n");
return $result;
// use goldmine2settings here
// get trade->level, and get values of goldmine2settings[trade->level]
// this should have tier_no_share, normal, contract amounts. only tier_no_share property to use here
}
protected function promotionQualified($uplineUserId, $level)
{
if ($this->enabledPromo->enabled) {
$isPromoQualified = $this->usersPromoClassification[$uplineUserId]['is_promotion'];
$this->logText .= "\t\t --- Promo Enabled, " . ($isPromoQualified ? "User qualified" : "Not Qualified") . "\n";
return $isPromoQualified ? $this->enabledPromoValues[$level] : $this->goldmine2Settings[$level];
}
// $this->logText .= "\t Promo Disabled\n";
return $this->goldmine2Settings[$level];
}
/**
* @param $uplineUserId
* @param $userTiers
* @param $level
* @return bool
*/
protected function toCompressUser($uplineUserId, $userTiers, $level = null)
{
if (isset($userTiers[$uplineUserId])) {
$userTiers[$uplineUserId]['balance'] = $this->getInvestedAmount($uplineUserId);
}
if ($this->bypassCommQualificationCheck($uplineUserId, $userTiers, $level)) {
$this->logText .= "\n";
return false;
}
return parent::toCompressUser($uplineUserId, $userTiers);
}
protected function getInvestedAmount($userId)
{
return isset($this->transferSummary[$userId]) ? $this->transferSummary[$userId]['amount'] : 0;
}
private function setBypassMinimumAmount()
{
$this->bypassMinimumAmount = setting('goldmine_2_bypass_minimum_balance');
}
private function checkMinimumAmountForBypass($balance)
{
return $balance >= $this->bypassMinimumAmount;
}
// get current balance
private function getUserBalance($uplineUserId)
{
return isset($this->transferLifetimeSummary[$uplineUserId]) ? $this->transferLifetimeSummary[$uplineUserId]['amount'] : 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment