add SMSpanel
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\SmsBilling;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\SmsLedger;
|
||||
use App\Models\SmsSendLog;
|
||||
use App\Models\SmsWallet;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class SmsWalletService
|
||||
{
|
||||
public const SUPER_ADMIN_MOBILE = '09128081392';
|
||||
|
||||
public const TYPE_CHARGE = 'charge';
|
||||
public const TYPE_DEBIT = 'debit';
|
||||
public const TYPE_ALERT_DEBIT = 'alert_debit';
|
||||
|
||||
/** Billing/panel فعال است مگر sms_panel صریحاً false باشد. */
|
||||
public static function isBillingEnabled(): bool
|
||||
{
|
||||
$value = Setting::where('key', 'sms_panel')->value('value');
|
||||
|
||||
if ($value === null || trim((string) $value) === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
$normalized = strtolower(trim((string) $value));
|
||||
|
||||
return ! in_array($normalized, ['false', '0', 'no', 'off'], true);
|
||||
}
|
||||
|
||||
public function getWallet(): SmsWallet
|
||||
{
|
||||
return SmsWallet::query()->firstOrCreate([], [
|
||||
'balance' => 0,
|
||||
'price_per_part' => 0,
|
||||
'is_blocked' => false,
|
||||
'alert_days_sent' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function isBlocked(): bool
|
||||
{
|
||||
if (! self::isBillingEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->getWallet()->is_blocked;
|
||||
}
|
||||
|
||||
public function setBlocked(bool $blocked): SmsWallet
|
||||
{
|
||||
$wallet = $this->getWallet();
|
||||
$wallet->is_blocked = $blocked;
|
||||
$wallet->save();
|
||||
|
||||
return $wallet->fresh();
|
||||
}
|
||||
|
||||
public function updatePricePerPart(int $pricePerPart): SmsWallet
|
||||
{
|
||||
$wallet = $this->getWallet();
|
||||
$wallet->price_per_part = max(0, $pricePerPart);
|
||||
$wallet->save();
|
||||
|
||||
return $wallet;
|
||||
}
|
||||
|
||||
public function charge(int $amount, ?int $adminUserId = null, ?string $note = null): SmsWallet
|
||||
{
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('مبلغ شارژ باید بزرگتر از صفر باشد.');
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($amount, $adminUserId, $note) {
|
||||
$wallet = SmsWallet::query()->lockForUpdate()->firstOrCreate([], [
|
||||
'balance' => 0,
|
||||
'price_per_part' => 0,
|
||||
'is_blocked' => false,
|
||||
'alert_days_sent' => 0,
|
||||
]);
|
||||
|
||||
$wallet->balance += $amount;
|
||||
|
||||
if ($wallet->balance > 0) {
|
||||
$wallet->alert_days_sent = 0;
|
||||
$wallet->last_alert_date = null;
|
||||
}
|
||||
|
||||
$wallet->save();
|
||||
|
||||
SmsLedger::create([
|
||||
'type' => self::TYPE_CHARGE,
|
||||
'amount' => $amount,
|
||||
'balance_after' => $wallet->balance,
|
||||
'note' => $note,
|
||||
'created_by' => $adminUserId,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
return $wallet;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{log: SmsSendLog, wallet: SmsWallet}
|
||||
*/
|
||||
public function debitSuccessfulSms(
|
||||
string $receiver,
|
||||
string $body,
|
||||
int $parts,
|
||||
string $provider,
|
||||
?string $source = null,
|
||||
bool $isAlert = false
|
||||
): array {
|
||||
return DB::transaction(function () use ($receiver, $body, $parts, $provider, $source, $isAlert) {
|
||||
$wallet = SmsWallet::query()->lockForUpdate()->firstOrCreate([], [
|
||||
'balance' => 0,
|
||||
'price_per_part' => 0,
|
||||
'is_blocked' => false,
|
||||
'alert_days_sent' => 0,
|
||||
]);
|
||||
|
||||
$pricePerPart = (int) $wallet->price_per_part;
|
||||
$totalAmount = $parts * $pricePerPart;
|
||||
|
||||
$wallet->balance -= $totalAmount;
|
||||
$wallet->save();
|
||||
|
||||
$log = SmsSendLog::create([
|
||||
'receiver' => $receiver,
|
||||
'body' => $body,
|
||||
'parts' => $parts,
|
||||
'price_per_part' => $pricePerPart,
|
||||
'total_amount' => $totalAmount,
|
||||
'provider' => $provider,
|
||||
'source' => $source,
|
||||
'is_alert' => $isAlert,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
SmsLedger::create([
|
||||
'type' => $isAlert ? self::TYPE_ALERT_DEBIT : self::TYPE_DEBIT,
|
||||
'amount' => -$totalAmount,
|
||||
'balance_after' => $wallet->balance,
|
||||
'price_per_part' => $pricePerPart,
|
||||
'parts' => $parts,
|
||||
'sms_send_log_id' => $log->id,
|
||||
'note' => $isAlert ? 'هشدار موجودی پیامک' : null,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
return ['log' => $log, 'wallet' => $wallet->fresh()];
|
||||
});
|
||||
}
|
||||
|
||||
public static function isSmsPanelSuperAdmin(?object $user): bool
|
||||
{
|
||||
if (! $user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return self::normalizeMobile((string) ($user->mobile ?? '')) === self::SUPER_ADMIN_MOBILE;
|
||||
}
|
||||
|
||||
public static function normalizeMobile(string $mobile): string
|
||||
{
|
||||
$digits = preg_replace('/\D/', '', $mobile) ?? '';
|
||||
|
||||
if (str_starts_with($digits, '98') && strlen($digits) === 12) {
|
||||
$digits = '0'.substr($digits, 2);
|
||||
} elseif (strlen($digits) === 10 && str_starts_with($digits, '9')) {
|
||||
$digits = '0'.$digits;
|
||||
}
|
||||
|
||||
return $digits;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user