Files
boursecu_server/app/Services/Payment/WalletDepositCreditor.php
T
safavimohadeseh78andCursor a42261c06e feat(accounting): add Shayegan as fixed boursecu provider
Wire outbound Invoice/Document sync after confirmed ops, store sync status with timeout lock, and keep SQL credentials out of frontend responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-05 17:12:43 +03:30

138 lines
4.6 KiB
PHP

<?php
namespace App\Services\Payment;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\User;
use App\Models\Withdraw;
use App\Services\ConfigService;
use Illuminate\Support\Facades\DB;
use Rooyesh\Wallet\interfaces\TransactionInterface;
use Rooyesh\Wallet\interfaces\WalletInterface;
/**
* شارژ idempotent کیف بعد از پرداخت موفق درگاه.
*/
class WalletDepositCreditor
{
public function __construct(private ConfigService $config)
{
}
public function findByReference(string $referenceId): ?Withdraw
{
if ($referenceId === '') {
return null;
}
if (preg_match('/^WD-(\d+)$/', $referenceId, $matches)) {
return Withdraw::with('customer')->find((int) $matches[1]);
}
return Withdraw::with('customer')
->where('tracked_number', $referenceId)
->orderByDesc('id')
->first();
}
public function markPaidAndCredit(Withdraw $withdraw, string $trackNumber, string $note = 'واریز درگاه'): void
{
DB::transaction(function () use ($withdraw, $trackNumber, $note) {
$locked = Withdraw::query()->whereKey($withdraw->id)->lockForUpdate()->first();
if (!$locked || (int) $locked->sts === 2) {
return;
}
if ($trackNumber !== '') {
$locked->tracked_number = $trackNumber;
}
$locked->sts = 2;
$locked->save();
$user = Customer::find($locked->customer_id);
if (!$user) {
return;
}
$wallet = new WalletInterface($user->id, $user->type);
new TransactionInterface($wallet, [
'cash' => (int) $locked->cash,
'expire_at' => now(),
'withdraw_id' => $locked->id,
'active' => true,
], 3, false, true);
try {
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
$user,
'cash',
(float) $locked->cash,
[
'withdraw_id' => $locked->id,
'note' => $note,
'source' => 'gateway',
]
);
} catch (\Throwable $e) {
report($e);
}
$this->syncGatewayDepositToAccounting($user, $locked, $note);
$locked->loadMissing('customer');
$message = 'کاربر ' . ($locked->customer->name ?? '') . ' با شماره موبایل ' . ($locked->customer->mobile ?? '')
. ' حساب خود را به مقدار ' . number_format((int) $locked->cash) . ' ریال شارژ کرد. با تشکر، '
. $this->config->getString('name_fa', '');
User::where('send_sms', 1)->get()->each(function ($admin) use ($message) {
if (Controller::isSmsNotifEnabled('sms_notif_gateway_charge_admin')) {
Controller::Send($admin->mobile, $message);
}
});
});
}
/** سند بانکی ته‌حساب/زرین — قبلاً فقط پرگار می‌رفت و در ته‌حساب «خرید» دستی ثبت می‌شد */
private function syncGatewayDepositToAccounting(Customer $customer, Withdraw $withdraw, string $note): void
{
$cash = (int) round(abs((float) $withdraw->cash));
if ($cash <= 0) {
return;
}
$accountingNote = trim($note) !== '' ? $note : 'دریافت وجه بابت شارژ';
$payload = [
'customer_id' => (int) $customer->id,
'value' => $cash,
'direction' => 0,
'withdraw_id' => (int) $withdraw->id,
'note' => $accountingNote,
];
if ($this->config->isTahesabAccounting()) {
try {
app(\App\Http\Controllers\Admin\TahesabController::class)->wallet($payload);
} catch (\Throwable $e) {
report($e);
}
}
if ($this->config->isZarinAccounting()) {
try {
app(\App\Http\Controllers\Admin\ZarinController::class)->wallet($payload);
} catch (\Throwable $e) {
report($e);
}
}
if ($this->config->isShayeganAccounting()) {
try {
app(\App\Http\Controllers\Admin\ShayeganController::class)->wallet($payload);
} catch (\Throwable $e) {
report($e);
}
}
}
}