Untitled
unknown
plain_text
2 years ago
7.3 kB
5
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...