146 lines
4.6 KiB
PHP
146 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Repositories\Payments;
|
|
|
|
use App\Models\Payments\GcPaymentAttempt;
|
|
|
|
final class GcPaymentAttemptRepository
|
|
{
|
|
public function upsertForUpdate(array $data): GcPaymentAttempt
|
|
{
|
|
// uq_provider_oid_method 때문에 1개만 존재(동일 method 재시도는 정책적으로 “새 주문 생성” 권장)
|
|
$q = GcPaymentAttempt::query()
|
|
->where('provider', $data['provider'])
|
|
->where('oid', $data['oid'])
|
|
->where('pay_method', $data['pay_method'])
|
|
->lockForUpdate();
|
|
|
|
$row = $q->first();
|
|
|
|
if (!$row) {
|
|
$row = new GcPaymentAttempt();
|
|
$row->provider = $data['provider'];
|
|
$row->oid = $data['oid'];
|
|
$row->mem_no = $data['mem_no'];
|
|
$row->order_id = $data['order_id'] ?? null;
|
|
$row->pay_method = $data['pay_method'];
|
|
$row->amount = $data['amount'];
|
|
$row->currency = $data['currency'] ?? 'KRW';
|
|
$row->ready_at = now();
|
|
}
|
|
|
|
$row->status = 'ready';
|
|
$row->token_hash = $data['token_hash'];
|
|
$row->card_kind = $data['card_kind'] ?? null;
|
|
$row->vact_kind = $data['vact_kind'] ?? null;
|
|
|
|
$row->user_agent = $data['user_agent'] ?? null;
|
|
$row->user_ip = $data['user_ip'] ?? null;
|
|
|
|
$row->save();
|
|
return $row;
|
|
}
|
|
|
|
public function findByTokenForUpdate(string $method, string $token): ?GcPaymentAttempt
|
|
{
|
|
$hash = hash('sha256', $token);
|
|
|
|
return GcPaymentAttempt::query()
|
|
->where('provider', 'danal')
|
|
->where('pay_method', $method)
|
|
->where('token_hash', $hash)
|
|
->lockForUpdate()
|
|
->first();
|
|
}
|
|
|
|
public function markRedirected(GcPaymentAttempt $a, array $req, array $res): void
|
|
{
|
|
$a->status = 'redirected';
|
|
$a->redirected_at = now();
|
|
$a->request_payload = $this->jsonSafe($req);
|
|
$a->response_payload = $this->jsonSafe($res);
|
|
$a->save();
|
|
}
|
|
|
|
public function markReturned(GcPaymentAttempt $a, array $payload, ?string $tid, string $code, string $msg, string $status): void
|
|
{
|
|
// status: auth_ok/issued/paid/failed/cancelled
|
|
$a->status = $status;
|
|
$a->returned_at = now();
|
|
$a->pg_tid = $tid ?: $a->pg_tid;
|
|
$a->return_code = $code ?: $a->return_code;
|
|
$a->return_msg = $msg ?: $a->return_msg;
|
|
$a->return_payload = $this->jsonSafe($payload);
|
|
$a->save();
|
|
}
|
|
|
|
public function markNotiPaid(GcPaymentAttempt $a, array $payload, string $tid, int $amount): void
|
|
{
|
|
if ($a->status === 'paid') return;
|
|
$a->status = 'paid';
|
|
$a->pg_tid = $tid ?: $a->pg_tid;
|
|
$a->amount = $amount ?: $a->amount;
|
|
$a->noti_payload = $this->jsonSafe($payload);
|
|
$a->noti_at = now();
|
|
$a->save();
|
|
}
|
|
|
|
public function markCancelled(GcPaymentAttempt $a, array $payload = []): void
|
|
{
|
|
if ($a->status === 'paid') return;
|
|
$a->status = 'cancelled';
|
|
$a->returned_at = now();
|
|
if ($payload) $a->return_payload = $this->jsonSafe($payload);
|
|
$a->save();
|
|
}
|
|
|
|
public function markFailed(GcPaymentAttempt $a, string $code, string $msg, array $payload = []): void
|
|
{
|
|
if ($a->status === 'paid') return;
|
|
$a->status = 'failed';
|
|
$a->returned_at = now();
|
|
$a->return_code = $code;
|
|
$a->return_msg = $msg;
|
|
if ($payload) $a->return_payload = $this->jsonSafe($payload);
|
|
$a->save();
|
|
}
|
|
|
|
private function jsonSafe(mixed $v): mixed
|
|
{
|
|
if (is_array($v)) {
|
|
foreach ($v as $k => $vv) $v[$k] = $this->jsonSafe($vv);
|
|
return $v;
|
|
}
|
|
|
|
if (is_object($v)) {
|
|
return $this->jsonSafe((array)$v);
|
|
}
|
|
|
|
if (is_string($v)) {
|
|
// 이미 UTF-8이면 그대로
|
|
if (function_exists('mb_check_encoding') && mb_check_encoding($v, 'UTF-8')) return $v;
|
|
|
|
// EUC-KR로 가정하고 UTF-8로 변환(실패 시 깨진 바이트 제거)
|
|
$out = @iconv('EUC-KR', 'UTF-8//IGNORE', $v);
|
|
if ($out === false) $out = '';
|
|
if (function_exists('mb_check_encoding') && !mb_check_encoding($out, 'UTF-8')) {
|
|
$out = @iconv('UTF-8', 'UTF-8//IGNORE', $out) ?: '';
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
return $v;
|
|
}
|
|
|
|
public function findAnyByTokenForUpdate(string $token): ?GcPaymentAttempt
|
|
{
|
|
$hash = hash('sha256', $token);
|
|
|
|
return GcPaymentAttempt::query()
|
|
->where('provider', 'danal')
|
|
->where('token_hash', $hash)
|
|
->lockForUpdate()
|
|
->first();
|
|
}
|
|
}
|