Files
boursecu_server/packages/rooyesh/wallet/src/interfaces/TransactionInterface.php
T
2026-07-26 14:15:26 +03:30

152 lines
6.0 KiB
PHP

<?php
namespace Rooyesh\Wallet\interfaces;
use Illuminate\Support\Facades\Validator;
use Rooyesh\Wallet\models\TransactionMeta;
use Rooyesh\Wallet\models\Wallet;
use Rooyesh\Wallet\models\Transaction;
use Rooyesh\Wallet\Exceptions;
use \Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class TransactionInterface
{
private $_inp;
private $_type;
private $wallet_interface;
private $transaction;
function __construct($wallet_interface = null, $_inp = null, $_type = null,$deposit_gold = false,$deposit_cash=false, $gold_block = 0,$meta = [], $allow_negative = false)
{
$this->transaction = TransactionInterface::apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold ,$deposit_cash,$gold_block,$meta,$allow_negative);
}
static function validate_last_transaction($wallet_id)
{
// $last_transaction = Transaction::where('wallet', '=', $wallet_id)->orderBy('created_at', 'DESC')->first();
// if ($last_transaction and $last_transaction->hash !== TransactionInterface::generate_hash($last_transaction)) {
// throw new Exceptions\LastTransactionValidateFailed();
// }
}
private static function generate_hash($transaction)
{
$last_transaction_hash = '';
$last_user_transaction = Transaction::where('wallet', '=', $transaction->wallet)->orderBy('created_at', 'DESC');
if ($last_user_transaction->count() and $last_user_transaction->first() != $transaction) {
$last_transaction_hash = $last_user_transaction->first()->hash;
}
return hash('sha256',
hash('sha256', $transaction->gold) .
hash('sha256', $transaction->cash) .
hash('sha256', $transaction->wallet) .
"yhoenszeaf" . $last_transaction_hash
);
}
private static function set_hash($transaction)
{
$transaction->hash = TransactionInterface::generate_hash($transaction);
$transaction->save();
}
/**
* کف موجودی طلا — فقط سمت کسر. شارژ مثبت هیچ‌وقت بسته نمی‌شود، حتی اگر مانده منفی باشد.
* ستون gold از نوع float است، پس رواداری نسبی می‌گذاریم تا «فروش کل موجودی» به خطای گرد کردن نخورد.
*/
private static function assert_gold_floor($wallet, $_inp, $deposit_gold)
{
if ($deposit_gold || !isset($_inp['gold'])) {
return;
}
$requested = abs((float) $_inp['gold']);
if ($requested <= 0) {
return;
}
$balance = (float) $wallet->gold;
$tolerance = 1e-6 + abs($balance) * 1e-6;
if ($balance + $tolerance < $requested) {
throw new UnprocessableEntityHttpException('مقدار وارد شده بیشتر از موجودی طلای شماست');
}
}
/** کف موجودی ریالی — فقط سمت کسر؛ واریز و شارژ مثبت همیشه باز است. */
private static function assert_cash_floor($wallet, $_inp, $deposit_cash)
{
if ($deposit_cash || !isset($_inp['cash'])) {
return;
}
$requested = abs((float) $_inp['cash']);
if ($requested > 0 && (float) $wallet->cash < $requested) {
throw new UnprocessableEntityHttpException('موجودی ریالی کافی نیست');
}
}
/**
* @param bool $allow_negative فقط برای تطبیق مانده با سیستم حسابداری؛ آنجا مانده می‌تواند
* واقعاً منفی باشد و کیف باید همان را بازتاب دهد.
*/
public static function apply_transaction($wallet_interface, $_inp, $_type,$deposit_gold,$deposit_cash,$gold_block, $meta = [], $allow_negative = false)
{
$wallet = $wallet_interface->wallet;
TransactionInterface::validate_last_transaction($wallet->id);
#-------------Check Balance --------
if (!$allow_negative) {
TransactionInterface::assert_gold_floor($wallet, $_inp, $deposit_gold);
TransactionInterface::assert_cash_floor($wallet, $_inp, $deposit_cash);
}
// $_inp['value'] = abs($_inp['value']) * ($deposit ? 1 : -1);
if (isset($_inp['gold'])){
$_inp['gold'] = abs($_inp['gold']) * ($deposit_gold ? 1 : -1);
$wallet->gold += $_inp['gold'];
}
if (isset($_inp['cash'])){
$_inp['cash'] = abs($_inp['cash']) * ($deposit_cash ? 1 : -1);
$wallet->cash += $_inp['cash'];
}
if($gold_block != 0){
$wallet->gold_block += $gold_block;
}
$_inp['balance_gold'] = $wallet->gold;
$_inp['balance_cash'] = $wallet->cash;
$_inp['wallet'] = $wallet->id;
$_inp['type'] = $_type;
// $_inp['transaction_type'] = $_type;
$_inp['customer_id'] = $wallet->owner;
// $_inp['balance'] = $wallet->cash + $_inp['cash'];
$transaction_validate_rules = [
'wallet' => 'required',
'type' => 'required',
'expire_at' => 'date',
'cash' => 'integer',
'note' => 'string',
'balance' => 'integer',
];
$transaction_validator = Validator::make($_inp, $transaction_validate_rules);
if ($transaction_validator->failed()) {
throw ValidationException::withMessages($transaction_validator->errors()->all());
}
$transaction = Transaction::create($_inp);
$transaction->save();
TransactionInterface::set_hash($transaction);
$meta['transaction'] = $transaction->id;
$transaction_metas = TransactionMeta::create($meta);
// if ($_inp['type'] == 1) {
// $wallet->cash += $_inp['value'];
// } elseif ($_inp['type'] == 2) {
// $wallet->gold += $_inp['value'];
// }
$wallet->save();
$wallet_interface->set_hash();
return $transaction;
}
}