AMS_Backend/app/Controllers/Frontend/TopupController.php
2025-11-06 13:41:06 +08:00

345 lines
12 KiB
PHP

<?php
namespace App\Controllers\Frontend;
use App\Controllers\BaseController;
use App\Models\TopupModel;
use App\Libraries\Fiuu;
use CodeIgniter\API\ResponseTrait;
use App\Models\Customer;
use App\Models\CustomerWallet;
class TopupController extends BaseController
{
use ResponseTrait;
private $topups;
private $fiuu;
private $customer;
private $wallets;
private $db;
public function __construct()
{
$this->topups = new TopupModel();
$this->fiuu = new Fiuu();
$this->customer = new Customer();
$this->wallets = new CustomerWallet();
$this->db = db_connect();
}
public function index()
{
$data = $this->topups
->orderBy('created_at', 'DESC')
->findAll();
return $this->respond([
'status' => 200,
'data' => $data,
]);
}
private function createPendingWalletRow(array $topupRow, array $customer): void
{
$current = (float)($customer['customer_wallet'] ?? 0);
$incoming = (float)($topupRow['credit'] ?? 0);
if ($incoming <= 0) {
$incoming = (float)($topupRow['other_amount'] ?? 0);
}
$walletData = [
'customer_id' => $topupRow['customer_id'],
'related_type' => 'topup',
'related_id' => $topupRow['id'],
'action' => 'in',
'current' => $current,
'in' => $incoming,
'out' => 0,
'balance' => $current,
'remark' => 'Topup '.$topupRow['topup_number'].' (pending)',
'status' => 'Pending',
'created_at' => date('Y-m-d H:i:s'),
];
try {
$this->wallets->insert($walletData, true);
} catch (\Throwable $e) {
}
}
public function createTopupPayment()
{
$data = $this->request->getJSON(true);
$rules = [
'customer_id' => 'required|integer',
'payment_method' => 'required|string|max_length[50]',
'topup_setting_id' => 'permit_empty|integer',
'amount' => 'permit_empty|decimal',
'credit' => 'permit_empty|decimal',
'other_amount' => 'permit_empty|decimal'
];
if (!$this->validate($rules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
$topupSettingId = !empty($data['topup_setting_id']) ? (int)$data['topup_setting_id'] : null;
if ($topupSettingId) {
// MODE 1: package top-up
$pkg = model('App\Models\TopupSettingModel')
->where('id', $topupSettingId)
->where('deleted_at', null)
->first();
if (!$pkg || ($pkg['status'] ?? '') !== 'active') {
return $this->failValidationErrors(['topup_setting_id' => 'Selected package is invalid or inactive']);
}
$amount = (float)$pkg['topup_amount'];
$credit = (float)$pkg['credit_amount'];
if ($amount <= 0 || $credit <= 0) {
return $this->failValidationErrors(['topup_setting' => 'Package amounts must be > 0']);
}
$otherAmount = null;
} else {
$otherAmount = isset($data['other_amount']) && $data['other_amount'] !== '' ? (float)$data['other_amount'] : 0.0;
if ($otherAmount <= 0) {
return $this->failValidationErrors(['other_amount' => 'Provide a positive amount for custom top-up']);
}
$amount = 0.0;
$credit = 0.0;
}
$topupNumber = 'T' . strtoupper(bin2hex(random_bytes(6)));
$insertData = [
'topup_setting_id' => $topupSettingId,
'customer_id' => (int)$data['customer_id'],
'topup_number' => $topupNumber,
'amount' => $amount, // package cash (0 for custom)
'credit' => $credit, // package credit (0 for custom)
'payment_method' => $data['payment_method'],
'other_amount' => $otherAmount, // used for custom
'status' => 'Pending',
];
$id = $this->topups->insert($insertData, true);
if (!$id) return $this->fail('Topup failed', 400);
$topup = $this->topups->find($id);
$customer = $this->customer->find((int)$data['customer_id']) ?? [];
// Write PENDING wallet ledger (no balance change yet)
$this->createPendingWalletRow($topup, $customer);
// Payment link uses the payable amount:
// - package mode → $amount
// - custom mode → $otherAmount
$payable = $topupSettingId ? $amount : $otherAmount;
$payment_details = [
'bill_name' => $customer['name'] ?? '',
'bill_email' => $customer['email'] ?? '',
'bill_mobile' => $customer['phone'] ?? '',
'bill_desc' => 'US Pizza - Wallet Topup - ' . $topupNumber,
];
$result = $this->fiuu->createTopup($topupNumber, $payable, $payment_details);
return $this->respond([
'status' => 201,
'message' => 'Topup created successfully',
'data' => $this->topups->find($id),
'redirect_url' => $result['redirect_url'] ?? null
]);
}
public function fiuuTopupNotification()
{
$payload = $this->request->getPost();
// $payload = $this->request->getJSON(true);
// print_r($payload);exit;
$result = $this->fiuu->topupNotification($payload);
log_message('error', 'Fiuu Payload: '.json_encode($payload));
log_message('error', 'Fiuu Result: '.json_encode($result));
$topupNumber = $payload['orderid'] ?? null;
if (!$topupNumber) {
return $this->respond(['status' => 400, 'message' => 'Missing orderid'], 400);
}
$topup = $this->topups->where('topup_number', $topupNumber)->first();
if (!$topup) {
return $this->respond(['status' => 404, 'message' => 'Topup not found'], 404);
}
if (in_array($topup['status'], ['completed','failed'], true)) {
return $this->respond(['status' => 200, 'message' => 'Already processed', 'result' => $result]);
}
$payStat = strtolower((string)($payload['status'] ?? ''));
$resStat = is_array($result) ? strtolower((string)($result['status'] ?? '')) : strtolower((string)$result);
$isSuccess = in_array($payStat, ['00','success','approved'], true)
|| (is_string($resStat) && strpos($resStat, 'success') !== false);
$this->db->transStart();
if ($isSuccess) {
$table = $this->customer->builder()->getTable();
$customer = $this->db->query(
'SELECT * FROM `'.$table.'` WHERE `id` = ? FOR UPDATE',
[$topup['customer_id']]
)->getRowArray();
if (!$customer) {
$this->db->transRollback();
return $this->respond(['status' => 404, 'message' => 'Customer not found'], 404);
}
$current = (float)($customer['customer_wallet'] ?? 0);
$delta = $topup['amount'] + $topup['credit'];
// print_r($delta);exit;
if ($delta <= 0) $delta = (float)$topup['other_amount'];
if ($delta <= 0) {
$this->topups->update($topup['id'], ['status' => 'failed']);
$this->db->transComplete();
return $this->respond(['status' => 400, 'message' => 'Invalid topup amount'], 400);
}
$newBal = $current + $delta;
$walletRow = $this->wallets
->where('related_type', 'topup')
->where('related_id', $topup['id'])
->orderBy('id', 'desc')
->first();
if ($walletRow) {
$this->wallets->update($walletRow['id'], [
'status' => 'completed',
'current' => $current,
'balance' => $newBal,
'remark' => 'Topup '.$topupNumber.' (completed)',
'in' => $delta,
]);
} else {
$this->wallets->insert([
'customer_id' => $topup['customer_id'],
'related_type' => 'topup',
'related_id' => $topup['id'],
'action' => 'in',
'current' => $current,
'in' => $delta,
'out' => 0,
'balance' => $newBal,
'remark' => 'Topup '.$topupNumber.' (completed)',
'status' => 'completed',
'created_at' => date('Y-m-d H:i:s'),
], true);
}
$this->customer->update($customer['id'], ['customer_wallet' => $newBal]);
$this->topups->update($topup['id'], ['status' => 'Success']);
} else {
$this->topups->update($topup['id'], ['status' => 'Failed']);
$this->wallets
->where('related_type', 'topup')
->where('related_id', $topup['id'])
->set([
'status' => 'failed',
'remark' => 'Topup '.$topupNumber.' (failed)'
])->update();
}
$this->db->transComplete();
if ($this->db->transStatus() === false) {
return $this->respond(['status' => 500, 'message' => 'Transaction error'], 500);
}
return $this->respond(['status' => 200, 'message' => 'Notification processed', 'result' => $result]);
}
public function fiuuTopupReturn()
{
$data = $this->request->getPost();
$this->fiuu->topupNotification($data);
}
public function checkTopupPayment($topup_id = null)
{
// echo(123123);exit;
$topup = $this->topups->find($topup_id);
if (!$topup) {
return $this->fail('Topup not found', 400);
}
// print_r($topup);exit;
$status = strtolower($topup['status'] ?? '');
// print_r($status);exit;
if ($status === 'success') {
return $this->respond(['status' => 200, 'result' => 'Success', 'topup_id' => $topup_id]);
} elseif ($status === 'pending') {
return $this->respond(['status' => 200, 'result' => 'Pending', 'topup_id' => $topup_id]);
}
return $this->respond(['status' => 400, 'result' => 'Failed', 'topup_id' => $topup_id]);
}
public function show($id = null)
{
$id = (int) $id;
$row = $this->topups
->select('topup.*, topup_setting.id AS setting_id, topup_setting.topup_amount, topup_setting.credit_amount, topup_setting.status AS setting_status')
->join('topup_setting', 'topup_setting.id = topup.topup_setting_id', 'left')
->where('topup.id', $id)
->first();
if (!$row) {
return $this->failNotFound('Topup record not found');
}
$data = [
'id' => $row['id'],
'topup_setting_id' => $row['topup_setting_id'],
'customer_id' => $row['customer_id'],
'topup_number' => $row['topup_number'],
'amount' => $row['amount'],
'credit' => $row['credit'],
'payment_method' => $row['payment_method'],
'other_amount' => $row['other_amount'],
'status' => $row['status'],
'created_at' => $row['created_at'],
'updated_at' => $row['updated_at'],
'topup_setting' => [
'id' => $row['setting_id'],
'topup_amount' => $row['topup_amount'],
'credit_amount' => $row['credit_amount'],
'status' => $row['setting_status']
]
];
return $this->respond([
'status' => 200,
'data' => $data
]);
}
}