Files
boursecu_server/app/Services/TahesabSyncService.php
T
2026-07-05 16:43:34 +03:30

213 lines
7.3 KiB
PHP

<?php
namespace App\Services;
use App\Http\Controllers\Admin\TahesabController;
use App\Models\Customer;
use App\Models\Tahesab;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
class TahesabSyncService
{
public const STATUS_PENDING = 'pending';
public const STATUS_SUCCESS = 'success';
public const STATUS_FAILED = 'failed';
public function responseOk(mixed $response): bool
{
return is_array($response) && ! empty($response['OK']);
}
public function buildLog(mixed $response = null, ?string $extra = null): string
{
$parts = array_filter([
$extra,
is_array($response) ? json_encode($response, JSON_UNESCAPED_UNICODE) : (is_string($response) ? $response : null),
]);
return implode("\n", $parts);
}
public function markSuccess(Tahesab $tahesab, array $response, ?array $payload = null): void
{
$update = [
'sh_factor' => $response['Sh_factor'] ?? null,
'tahesab_id' => $response['OK'],
'factor_number' => $response['Factor_Number'] ?? null,
'tah_id' => $response['ID'] ?? null,
'res' => json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
'sync_status' => self::STATUS_SUCCESS,
'sync_log' => null,
];
if ($payload !== null) {
$update['data'] = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
if ($this->hasSyncColumns()) {
Tahesab::where('id', $tahesab->id)->update($update);
} else {
unset($update['sync_status'], $update['sync_log']);
Tahesab::where('id', $tahesab->id)->update($update);
}
}
public function markFailed(Tahesab $tahesab, mixed $response = null, ?string $extra = null): void
{
$update = [
'res' => is_array($response)
? json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
: (is_string($response) ? $response : null),
];
if ($this->hasSyncColumns()) {
$update['sync_status'] = self::STATUS_FAILED;
$update['sync_log'] = $this->buildLog($response, $extra);
}
Tahesab::where('id', $tahesab->id)->update($update);
}
public function isFailed(Tahesab $tahesab): bool
{
if ($this->hasSyncColumns()) {
return ($tahesab->sync_status ?? null) === self::STATUS_FAILED
|| (empty($tahesab->tahesab_id) && ($tahesab->sync_status ?? null) !== self::STATUS_SUCCESS);
}
return empty($tahesab->tahesab_id);
}
public function registerOnCreate(Customer $customer): void
{
if (! empty($customer->moshtari_code) || ! $this->isSyncEnabled()) {
return;
}
$customerId = (int) $customer->id;
dispatch(function () use ($customerId) {
$service = app(TahesabSyncService::class);
$customer = Customer::find($customerId);
if ($customer === null || ! empty($customer->moshtari_code) || ! $service->isSyncEnabled()) {
return;
}
try {
$result = $service->registerCustomer($customer);
if (! ($result['ok'] ?? false)) {
Log::warning('Tahesab auto-register on customer create failed', [
'customer_id' => $customerId,
'message' => $result['message'] ?? null,
]);
}
} catch (\Throwable $e) {
Log::warning('Tahesab auto-register on customer create threw', [
'customer_id' => $customerId,
'error' => $e->getMessage(),
]);
}
})->afterResponse();
}
public function registerCustomer(Customer $customer): array
{
$customer->refresh();
if (! empty($customer->moshtari_code)) {
return [
'ok' => true,
'message' => 'مشتری قبلاً در ته‌حساب ثبت شده است',
'moshtari_code' => $customer->moshtari_code,
];
}
$controller = app(TahesabController::class);
$result = $controller->createCustomerInTahesab($customer->id);
if (is_string($result)) {
return ['ok' => false, 'message' => $result];
}
$customer->refresh();
if (empty($customer->moshtari_code)) {
return ['ok' => false, 'message' => 'ثبت مشتری در ته‌حساب ناموفق بود'];
}
return [
'ok' => true,
'message' => 'مشتری با موفقیت در ته‌حساب ثبت شد',
'moshtari_code' => $customer->moshtari_code,
];
}
public function retry(Tahesab $tahesab): array
{
if (! $this->isFailed($tahesab) && ! empty($tahesab->tahesab_id)) {
return ['ok' => false, 'message' => 'این سند قبلاً در ته‌حساب ثبت شده است'];
}
$payload = json_decode((string) $tahesab->data, true) ?: [];
$handler = $payload['handler'] ?? $this->inferHandler($tahesab);
$controller = app(TahesabController::class);
$result = match ($handler) {
'wallet' => $controller->wallet(array_merge($payload, ['_retry_tahesab_id' => $tahesab->id]), $tahesab),
'walletGold' => $controller->walletGold(array_merge($payload, ['_retry_tahesab_id' => $tahesab->id]), $tahesab),
'storeTrade' => $controller->storeTrade(array_merge($payload, ['_retry_tahesab_id' => $tahesab->id]), $tahesab),
'goldReward' => $controller->goldReward(array_merge($payload, ['_retry_tahesab_id' => $tahesab->id]), $tahesab),
default => false,
};
$tahesab->refresh();
if ($result !== false && ! empty($tahesab->tahesab_id)) {
return ['ok' => true, 'message' => 'سند با موفقیت در ته‌حساب ثبت شد', 'tahesab' => $tahesab];
}
return [
'ok' => false,
'message' => $tahesab->sync_log ?: 'ارسال مجدد به ته‌حساب ناموفق بود',
'tahesab' => $tahesab,
];
}
private function inferHandler(Tahesab $tahesab): string
{
if ($tahesab->order_id) {
return 'storeTrade';
}
if ($tahesab->type === 'ريال') {
return 'wallet';
}
$desc = (string) $tahesab->desc;
if (str_contains($desc, 'شارژ کیف') || str_contains($desc, 'برداشت از کیف')) {
return 'walletGold';
}
return 'goldReward';
}
public function isSyncEnabled(): bool
{
$config = app(ConfigService::class);
return $config->isTahesabAccounting()
&& trim($config->getString('tahesab_host', '')) !== ''
&& trim($config->getString('tahesab_port', '')) !== ''
&& trim($config->getString('tahesab_token', '')) !== ''
&& trim($config->getString('tahesab_db', '')) !== '';
}
private function hasSyncColumns(): bool
{
return Schema::hasTable('tahesab') && Schema::hasColumn('tahesab', 'sync_status');
}
}