300 || !hash_equals(hash_hmac('sha256', $ts . '.' . $raw, $secret), $sig)) { http_response_code(400); exit; } $ev = json_decode($raw, true); $o = $ev['data'] ?? []; $pdo = new PDO(getenv('DB_DSN'), getenv('DB_USER'), getenv('DB_PASS'), [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); // 받은 만큼 지급: 입금이 들어올 때마다(order.partial / order.paid) credit_delta 를 더함. // 부족하면 받은 만큼, 추가로 보내면 그만큼 더, 넘치면 넘친 만큼. 합계 = credit // 필요한 표: credits(event_id PK, order_id, amount) — 같은 웹훅이 두 번 와도 한 번만 if (in_array($ev['type'], ['order.partial', 'order.paid'], true) && (float)$o['credit_delta'] > 0) { $pdo->beginTransaction(); $ins = $pdo->prepare('INSERT IGNORE INTO credits(event_id,order_id,amount) VALUES(?,?,?)'); $ins->execute([$ev['id'], $o['order_id'], $o['credit_delta']]); if ($ins->rowCount() === 1) { $u = $pdo->prepare('SELECT user_id, currency FROM charges WHERE order_id=?'); $u->execute([$o['order_id']]); $c = $u->fetch(PDO::FETCH_ASSOC); $pdo->prepare('INSERT INTO balances(user_id,currency,amount) VALUES(?,?,?) ON DUPLICATE KEY UPDATE amount=amount+VALUES(amount)') ->execute([$c['user_id'], $c['currency'], $o['credit_delta']]); $pdo->prepare('UPDATE charges SET status=?, credit=? WHERE order_id=?')->execute([$o['status'], $o['credit'], $o['order_id']]); } $pdo->commit(); } elseif ($ev['type'] === 'order.expired') { $pdo->prepare("UPDATE charges SET status='expired' WHERE order_id=?")->execute([$o['order_id']]); } http_response_code(200);