mivita/app/Http/Controllers/Api/PayoneController.php
2026-02-20 17:55:06 +01:00

221 lines
7.7 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\PaymentTransaction;
use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Services\MyLog;
use App\Services\Payment;
use App\Services\ShoppingUserService;
use App\Services\Util;
class PayoneController extends Controller
{
public function __construct() {}
public function paymentStatus()
{
$data = \Request::all();
// test para
/* $data = [
'key' => '698fb2555f8b2efc74f60b2121421f45',
'txaction' => 'paid',
'clearingtype' => 'wlt',
'userid' => '158723953',
'txid' => '321623031',
'price' => '89.00',
'param' => '1', //$this->shopping_order->id,
'reference' => '15c83aee2766c3',
];
*/
if (! isset($data['key']) || ! isset($data['param']) || ! isset($data['userid']) || ! isset($data['txid']) || ! isset($data['reference']) || ! isset($data['price'])) {
MyLog::writeLog(
'payone',
'error',
'Error:2001 App\Http\Controllers\Api\PayoneController::paymentStatus parameter incomplete',
$data
);
echo 'TSOK';
exit;
}
if ($data['key'] != config('payone.defaults.key')) {
MyLog::writeLog(
'payone',
'error',
'Error:2002 App\Http\Controllers\Api\PayoneController::paymentStatus Key error',
$data
);
echo 'TSOK';
exit;
}
$shopping_order = ShoppingOrder::find($data['param']);
if (! $shopping_order) {
MyLog::writeLog(
'payone',
'error',
'Error:2003 App\Http\Controllers\Api\PayoneController::paymentStatus ShoppingOrder not found:',
$data
);
echo 'TSOK';
exit;
}
$shopping_payment = ShoppingPayment::where('reference', $data['reference'])->first();
if (! $shopping_payment) {
MyLog::writeLog(
'payone',
'error',
'Error:2004 App\Http\Controllers\Api\PayoneController::paymentStatus ShoppingPayment not found',
$data
);
echo 'TSOK';
exit;
}
if ($shopping_payment->shopping_order_id != $shopping_order->id) {
MyLog::writeLog(
'payone',
'error',
'Error:2005 App\Http\Controllers\Api\PayoneController::paymentStatus ShoppingPayment no realation ShoppingOrder',
$data
);
echo 'TSOK';
exit;
}
$price = number_format((round($data['price'], 2) * 100), 0, '.', '');
$price_amount = number_format($shopping_payment->amount, 0, '.', '');
if ($price_amount != $price) {
$data['shopping_payment-amount'] = $price_amount;
$data['price-amount'] = $price;
MyLog::writeLog(
'payone',
'error',
'Error:2006 App\Http\Controllers\Api\PayoneController::paymentStatus Price error',
$data
);
echo 'TSOK';
exit;
}
/* TODO -- need this? */
if ($shopping_payment->txaction == $data['txaction']) {
if ($data['txaction'] === 'paid' && $shopping_order->txaction === 'paid') {
MyLog::writeLog(
'payone',
'error',
'Error:2007 App\Http\Controllers\Api\PayoneController::paymentStatus same txaction - was already paid',
$data,
false
);
// was already paid
echo 'TSOK';
exit;
} else {
MyLog::writeLog(
'payone',
'error',
'Error:2007 App\Http\Controllers\Api\PayoneController::paymentStatus same txaction - show',
$data,
false
);
}
}
// create transaction
PaymentTransaction::create([
'shopping_payment_id' => $shopping_payment->id,
'request' => 'transaction',
'txid' => $data['txid'],
'userid' => $data['userid'],
'status' => 'PAYONE',
'key' => $data['key'],
'txaction' => $data['txaction'],
'transmitted_data' => Util::utf8ize($data),
'mode' => $data['mode'],
]);
// Define txaction priority (higher number = higher priority)
$txaction_priority = [
'appointed' => 1,
'pending' => 2,
'failed' => 3,
'paid' => 10, // highest priority - final state
];
$current_priority = isset($txaction_priority[$shopping_order->txaction]) ? $txaction_priority[$shopping_order->txaction] : 0;
$new_priority = isset($txaction_priority[$data['txaction']]) ? $txaction_priority[$data['txaction']] : 0;
// Only update txaction if new priority is higher than current
if ($new_priority > $current_priority) {
$shopping_order->txaction = $data['txaction'];
$shopping_order->save();
$shopping_payment->txaction = $data['txaction'];
$shopping_payment->save();
} else {
MyLog::writeLog(
'payone',
'info',
'App\Http\Controllers\Api\PayoneController::paymentStatus - txaction not updated (current: '.$shopping_order->txaction.' has higher/equal priority than new: '.$data['txaction'].')',
$data,
false
);
}
$send_link = false;
$send_mail = true;
if ($data['txaction'] === 'failed') {
$shopping_order->setUserHistoryValue(['status' => 6]);
Util::setInstanceStatusByPayment($shopping_payment, 5);
}
if ($data['txaction'] === 'appointed') {
$shopping_order->setUserHistoryValue(['status' => 7]);
ShoppingUserService::snycOrdersByShoppingOrder($shopping_order);
Util::setInstanceStatusByPayment($shopping_payment, 4);
}
if ($data['txaction'] === 'paid') {
// Use DB transaction and row locking to prevent race conditions
\DB::beginTransaction();
try {
// Lock the shopping order row to prevent concurrent processing
$locked_order = ShoppingOrder::where('id', $shopping_order->id)
->lockForUpdate()
->first();
// Double-check if payment was already processed
if (! $locked_order->paid) {
$send_link = Payment::paymentStatusPaidAction($locked_order, true, $shopping_payment);
\DB::commit();
} else {
$send_mail = false;
\DB::commit();
}
} catch (\Exception $e) {
\DB::rollBack();
MyLog::writeLog(
'payone',
'error',
'Error:2008 App\Http\Controllers\Api\PayoneController::paymentStatus Transaction failed',
['error' => $e->getMessage(), 'data' => $data]
);
throw $e;
}
}
$data['send_link'] = $send_link;
if ($send_mail) {
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
}
echo 'TSOK';
exit;
}
}