Untitled
unknown
plain_text
3 years ago
7.3 kB
12
Indexable
<?php
namespace Modules\Billing\Util;
use App\Models\Account;
use App\Models\Instance;
use App\Models\InstanceBackup;
use App\Models\InstanceMarketPlaceAppVersion;
use App\Models\InstanceOsVersion;
use App\Models\InstanceSnapshot;
use App\Models\MarketplaceApp;
use App\Models\OsVersion;
use App\Models\PublicIpv4;
use App\Models\User;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Modules\Billing\Entities\Invoice;
use Modules\Billing\Entities\InvoiceDetail;
use Modules\BlockStorage\Entities\BlockStorage;
use Modules\BlockStorage\Entities\BlockstorageSnapshot;
use Modules\Kubernetes\Entities\KubernetesCluster;
use Modules\LoadBalancer\Entities\LoadBalancer;
use Modules\Partner\Entities\Addon;
use Modules\VPC\Entities\Vpc;
class UsageCalculator
{
public $billingMethods = ['hourly', 'monthly', 'quarterly', 'semi-annually', 'yearly'];
public $billingServices = [
Instance::class,
BlockStorage::class,
LoadBalancer::class,
KubernetesCluster::class,
InstanceBackup::class,
InstanceSnapshot::class,
PublicIpv4::class,
Vpc::class,
Addon::class,
InstanceOsVersion::class,
InstanceMarketPlaceAppVersion::class,
BlockstorageSnapshot::class,
];
public function calculateOwn($all = false, $startDate = null, $endDate = null): float
{
/** @var Account $account */
$account = auth()->user()->account;
return $this->calculateByAccount($account, $startDate, $endDate);
}
public function calculateOwnEstimated($startDate = null, $endDate = null): float
{
/** @var Account $account */
$account = auth()->user()->account;
$hours = now()->diffInHours(now()->endOfMonth());
return _round($this->getDetailUsageSum($account, $startDate, $endDate, 'usage', 'rate')) * $hours;
}
public function calculateTotalConsumption(Account $account, $startDate = null, $endDate = null): float
{
return $this->getDetailUsageSum($account, $startDate, $endDate, 'all');
}
public function calculateByAccount(Account $account, $startDate = null, $endDate = null): float
{
$usage = 0;
$startDate = Carbon::parse($startDate) ?? now()->startOfMonth();
$endDate = Carbon::parse($endDate) ?? now()->endOfMonth();
if (!getSetting('partner_module_enabled')) {
$usage += $account->invoices()
->whereNotNull('paid_at')
->whereBetween('paid_at', [$startDate, $endDate])
->sum('amount');
}
if ($account->customers()->count()) {
foreach ($account->customers as $account) {
$usage += $this->getDetailUsageSum($account, $startDate, $endDate);
$usage += $account->invoices()->whereBetween('start_at', [$startDate, $endDate])->whereType('payable')->sum('amount');
}
} else {
$usage += $this->getDetailUsageSum($account, $startDate, $endDate);
}
return $usage;
}
private function getDetailUsageSum(Account $account, $startDate, $endDate, $type = 'usage', string $column = 'amount'): float
{
$raw = 'ROUND(SUM(ROUND(invoice_details.'.$column.', 2)), 2) as '.$column;
$sum = Invoice::selectRaw($raw)
->join('invoice_details', 'invoices.id', 'invoice_details.invoice_id')
->where('invoices.account_id', $account->id)
->where(function($q) use($type){
if($type != 'all')
$q->where('invoices.type', $type);
})
->whereBetween('invoice_details.start_at', [$startDate, $endDate])
->first();
return $sum->$column ?? 0;
$sum = 0;
$invoiceIds = $account->invoices()->pluck('id')->toArray();
$details = InvoiceDetail::whereIn('invoice_id', $invoiceIds)->get();
foreach ($details as $detail) {
$sum += _round($detail->rate);
}
return $sum;
// $detailSum = $account->invoices()->withSum(['details as detail_amount' => function ($q) use ($startDate, $endDate) {
// $q->whereBetween('start_at', [$startDate, $endDate]);
// }], 'amount')->where(function($q) use ($type){
// if($type != 'all')
// $q->whereType($type);
// })->get();
// return $detailSum->sum('detail_amount');
}
public function getSelects($model)
{
$version_id = class_basename($model) == 'InstanceOsVersion' ? 'version_id' : 'created_at';
return 'id, name, project_id, created_at, deleted_at, frozen_at, suspended_at, terminate_at, "' . class_basename($model) . '" as product,' . $version_id;
}
public function getService(Account $account, $model, $billingMethod = null, $withTrash = true, $startDate = null, $endDate = null)
{
$q = $model::selectRaw((new UsageCalculator())->getSelects($model))
->with('offerings', function($q) use($billingMethod, $withTrash){
if($withTrash) $q->withTrashed();
if(!empty($billingMethod)) $q->where('billing_period', $billingMethod);
})
->with(['project', 'invoice_details'])
->whereIn('project_id', $account->projects()->select('id') )
->whereHas('offerings', function($q) use($billingMethod, $withTrash){
if($withTrash) $q->withTrashed();
if(!empty($billingMethod)) $q->where('billing_period', $billingMethod);
})
->whereHas('invoice_details')
->with('invoices', function($q) use($billingMethod){
if(!empty($billingMethod) && ($billingMethod) == 'yearly') {
$q->whereRaw(\DB::raw("DATE(DATE_ADD(invoices.due_at, INTERVAL 1 YEAR)) = DATE(NOW())"));
}
})
->withSum('offerings', 'total_price')
->withSum(['invoice_details' => function($q) use($startDate, $endDate){
if($startDate && $endDate) $q->whereBetween('created_at', [$startDate, $endDate]);
}], 'amount');
if ($withTrash)
$q->withTrashed();
return $q->get();
}
/**
* merge all services in one
*/
public function getServices(Account $account, $billingMethod = null, $withTrash = true, $startDate = null, $endDate = null)
{
$default = new Collection();
foreach ($this->billingServices as $model) {
$default = $default->merge($this->getService($account, $model, $billingMethod, $withTrash, $startDate, $endDate));
}
return $default->sortByDesc('created_at');
}
public function currentUsage(Account $account, $service = null, $billingMethod = null)
{
if ($billingMethod == 'quarterly') {
$endAt = now()->endOfQuarter();
} elseif ($billingMethod == 'semi-annually') {
$endAt = now()->month < 6 ? now()->month(6)->endOfMonth() : now()->month(12)->endOfMonth();
} else {
$endAt = now()->endOfMonth();
}
$currentUsage = $service->invoice_details()->whereBetween('created_at', [now()->startOfMonth(), $endAt])->sum('amount') ?? 0;
return $currentUsage;
}
}
Editor is loading...