Deploy Ladill Woo Manager / deploy (push) Failing after 2s
Standalone app with SSO shell, WordPress plugin connect flow, webhook ingest, fulfillment inbox, and plugin activation API — no payment processing. Co-authored-by: Cursor <cursoragent@cursor.com>
149 lines
4.2 KiB
PHP
149 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Mini;
|
|
|
|
use App\Models\QrSetting;
|
|
use App\Models\User;
|
|
use App\Services\Billing\BillingClient;
|
|
use App\Services\Notifications\MiniNotificationService;
|
|
use Illuminate\Http\Client\Response as HttpResponse;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Throwable;
|
|
|
|
class AutoWithdrawService
|
|
{
|
|
public function __construct(
|
|
private BillingClient $billing,
|
|
private MiniNotificationService $notifications,
|
|
) {}
|
|
|
|
public function attemptForUser(User $user): bool
|
|
{
|
|
$settings = $user->getOrCreateQrSetting();
|
|
$thresholdMinor = $settings->auto_withdraw_amount_minor;
|
|
|
|
if ($thresholdMinor === null || $thresholdMinor < 100) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$balanceMinor = $this->billing->balanceMinor($user->public_id);
|
|
} catch (Throwable $e) {
|
|
Log::warning('Auto-withdraw balance check failed', [
|
|
'user' => $user->public_id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
|
|
if ($balanceMinor < $thresholdMinor) {
|
|
return false;
|
|
}
|
|
|
|
if (! $this->hasPayoutAccount($user)) {
|
|
return false;
|
|
}
|
|
|
|
if ($this->hasPendingWithdrawal($user)) {
|
|
return false;
|
|
}
|
|
|
|
$amountMajor = round($balanceMinor / 100, 2);
|
|
if ($amountMajor < 1) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$response = $this->identitySend('POST', '/api/identity/wallet/withdraw', [
|
|
'user' => $user->public_id,
|
|
'amount' => $amountMajor,
|
|
]);
|
|
|
|
if (! $response->successful()) {
|
|
Log::warning('Auto-withdraw failed', [
|
|
'user' => $user->public_id,
|
|
'status' => $response->status(),
|
|
'body' => $response->body(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
|
|
$this->notifications->withdrawalSubmitted($user, $amountMajor);
|
|
|
|
return true;
|
|
} catch (Throwable $e) {
|
|
Log::warning('Auto-withdraw exception', [
|
|
'user' => $user->public_id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function processAll(): int
|
|
{
|
|
$count = 0;
|
|
|
|
QrSetting::query()
|
|
->whereNotNull('auto_withdraw_amount_minor')
|
|
->where('auto_withdraw_amount_minor', '>=', 100)
|
|
->with('user')
|
|
->chunkById(50, function ($settings) use (&$count) {
|
|
foreach ($settings as $setting) {
|
|
$user = $setting->user;
|
|
if ($user && $this->attemptForUser($user)) {
|
|
$count++;
|
|
}
|
|
}
|
|
});
|
|
|
|
return $count;
|
|
}
|
|
|
|
private function hasPayoutAccount(User $user): bool
|
|
{
|
|
$response = $this->identitySend(
|
|
'GET',
|
|
'/api/identity/payout-account?user='.urlencode((string) $user->public_id),
|
|
[],
|
|
);
|
|
|
|
if (! $response->successful()) {
|
|
return false;
|
|
}
|
|
|
|
return filled($response->json('data.payout_account.account_number'));
|
|
}
|
|
|
|
private function hasPendingWithdrawal(User $user): bool
|
|
{
|
|
$response = $this->identitySend(
|
|
'GET',
|
|
'/api/identity/wallet/withdrawals?user='.urlencode((string) $user->public_id),
|
|
[],
|
|
);
|
|
|
|
if (! $response->successful()) {
|
|
return false;
|
|
}
|
|
|
|
return collect($response->json('data', []))
|
|
->contains(fn ($withdrawal) => in_array($withdrawal['status'] ?? '', ['pending', 'processing'], true));
|
|
}
|
|
|
|
private function identitySend(string $method, string $path, array $payload): HttpResponse
|
|
{
|
|
return Http::baseUrl(rtrim((string) config('services.ladill_identity.url'), '/'))
|
|
->withToken((string) config('services.ladill_identity.key'))
|
|
->connectTimeout(10)
|
|
->timeout(20)
|
|
->acceptJson()
|
|
->asJson()
|
|
->send($method, $path, ['json' => $payload]);
|
|
}
|
|
}
|