Skip to content

Commit

Permalink
Merge pull request #71 from liberu-billing/sweep/Implement-Hosting-Ac…
Browse files Browse the repository at this point in the history
…count-Management

Implement Hosting Account Management
  • Loading branch information
curtisdelicata authored Jul 27, 2024
2 parents 4d259c3 + 9b83c19 commit ffac5fb
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 1 deletion.
86 changes: 86 additions & 0 deletions app/Filament/Resources/HostingAccountResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace App\Filament\Resources;

use App\Filament\Resources\HostingAccountResource\Pages;
use App\Models\HostingAccount;
use Filament\Forms;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;

class HostingAccountResource extends Resource
{
protected static ?string $model = HostingAccount::class;

protected static ?string $navigationIcon = 'heroicon-o-server';

public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('customer_id')
->relationship('customer', 'name')
->required(),
Forms\Components\Select::make('subscription_id')
->relationship('subscription', 'id')
->required(),
Forms\Components\Select::make('control_panel')
->options([
'cpanel' => 'cPanel',
'plesk' => 'Plesk',
'directadmin' => 'DirectAdmin',
])
->required(),
Forms\Components\TextInput::make('username')
->required()
->maxLength(255),
Forms\Components\TextInput::make('domain')
->required()
->maxLength(255),
Forms\Components\TextInput::make('package')
->required()
->maxLength(255),
Forms\Components\Select::make('status')
->options([
'active' => 'Active',
'suspended' => 'Suspended',
])
->required(),
]);
}

public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('customer.name'),
Tables\Columns\TextColumn::make('subscription.id'),
Tables\Columns\TextColumn::make('control_panel'),
Tables\Columns\TextColumn::make('username'),
Tables\Columns\TextColumn::make('domain'),
Tables\Columns\TextColumn::make('package'),
Tables\Columns\TextColumn::make('status'),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}

public static function getRelations(): array
{
return [
//
];
}

public static function getPages(): array
{
return [
36 changes: 36 additions & 0 deletions app/Models/HostingAccount.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class HostingAccount extends Model
{
use HasFactory;

protected $fillable = [
'customer_id',
'subscription_id',
'control_panel',
'username',
'domain',
'package',
'status',
];

public function customer()
{
return $this->belongsTo(Customer::class);
}

public function subscription()
{
return $this->belongsTo(Subscription::class);
}

public function isActive()
{
return $this->status === 'active';
}
}
33 changes: 32 additions & 1 deletion app/Services/BillingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@
use App\Models\Invoice;
use App\Models\Subscription;
use App\Models\Customer;
use App\Models\HostingAccount;
use Carbon\Carbon;

class BillingService
{
protected $hostingService;

public function __construct(HostingService $hostingService)
{
$this->hostingService = $hostingService;
}

public function generateInvoice(Subscription $subscription)
{
$customer = $subscription->customer;
Expand All @@ -34,10 +42,16 @@ public function processRecurringBilling()
->get();

foreach ($dueSubscriptions as $subscription) {
$this->generateInvoice($subscription);
$invoice = $this->generateInvoice($subscription);
$subscription->update([
'end_date' => Carbon::parse($subscription->end_date)->add($subscription->renewal_period),
]);

if ($invoice->status === 'paid') {
$this->ensureHostingAccountActive($subscription);
} else {
$this->suspendHostingAccount($subscription);
}
}
}

Expand All @@ -49,11 +63,28 @@ public function sendOverdueReminders()

foreach ($overdueInvoices as $invoice) {
// TODO: Send overdue reminder email
$this->suspendHostingAccount($invoice->subscription);
}
}

private function generateInvoiceNumber()
{
return 'INV-' . strtoupper(uniqid());
}

private function ensureHostingAccountActive(Subscription $subscription)
{
$hostingAccount = HostingAccount::where('subscription_id', $subscription->id)->first();
if ($hostingAccount && !$hostingAccount->isActive()) {
$this->hostingService->unsuspendAccount($hostingAccount);
}
}

private function suspendHostingAccount(Subscription $subscription)
{
$hostingAccount = HostingAccount::where('subscription_id', $subscription->id)->first();
if ($hostingAccount && $hostingAccount->isActive()) {
$this->hostingService->suspendAccount($hostingAccount);
}
}
}
39 changes: 39 additions & 0 deletions app/Services/ControlPanels/CpanelClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Services\ControlPanels;

use GuzzleHttp\Client;

class CpanelClient
{
protected $client;
protected $apiUrl;
protected $apiToken;

public function __construct()
{
$this->client = new Client();
$this->apiUrl = config('services.cpanel.api_url');
$this->apiToken = config('services.cpanel.api_token');
}

public function createAccount($username, $domain, $package)
{
// Implement cPanel API call to create account
}

public function suspendAccount($username)
{
// Implement cPanel API call to suspend account
}

public function unsuspendAccount($username)
{
// Implement cPanel API call to unsuspend account
}

public function changePackage($username, $newPackage)
{
// Implement cPanel API call to change package
}
}
91 changes: 91 additions & 0 deletions app/Services/HostingService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace App\Services;

use App\Models\HostingAccount;
use App\Services\ControlPanels\CpanelClient;
use App\Services\ControlPanels\PleskClient;
use App\Services\ControlPanels\DirectAdminClient;

class HostingService
{
protected $cpanelClient;
protected $pleskClient;
protected $directAdminClient;

public function __construct(
CpanelClient $cpanelClient,
PleskClient $pleskClient,
DirectAdminClient $directAdminClient
) {
$this->cpanelClient = $cpanelClient;
$this->pleskClient = $pleskClient;
$this->directAdminClient = $directAdminClient;
}

public function provisionAccount(HostingAccount $account)
{
$client = $this->getClientForControlPanel($account->control_panel);
$result = $client->createAccount($account->username, $account->domain, $account->package);

if ($result) {
$account->status = 'active';
$account->save();
}

return $result;
}

public function suspendAccount(HostingAccount $account)
{
$client = $this->getClientForControlPanel($account->control_panel);
$result = $client->suspendAccount($account->username);

if ($result) {
$account->status = 'suspended';
$account->save();
}

return $result;
}

public function unsuspendAccount(HostingAccount $account)
{
$client = $this->getClientForControlPanel($account->control_panel);
$result = $client->unsuspendAccount($account->username);

if ($result) {
$account->status = 'active';
$account->save();
}

return $result;
}

public function upgradeAccount(HostingAccount $account, $newPackage)
{
$client = $this->getClientForControlPanel($account->control_panel);
$result = $client->changePackage($account->username, $newPackage);

if ($result) {
$account->package = $newPackage;
$account->save();
}

return $result;
}

protected function getClientForControlPanel($controlPanel)
{
switch ($controlPanel) {
case 'cpanel':
return $this->cpanelClient;
case 'plesk':
return $this->pleskClient;
case 'directadmin':
return $this->directAdminClient;
default:
throw new \Exception("Unsupported control panel: $controlPanel");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('hosting_accounts', function (Blueprint $table) {
$table->id();
$table->foreignId('customer_id')->constrained()->onDelete('cascade');
$table->foreignId('subscription_id')->constrained()->onDelete('cascade');
$table->string('control_panel');
$table->string('username');
$table->string('domain');
$table->string('package');
$table->string('status');
$table->timestamps();
});
}

public function down()
{
Schema::dropIfExists('hosting_accounts');
}
};

0 comments on commit ffac5fb

Please sign in to comment.