2026-01-24 14:03:11 +00:00
<? php
namespace App\Http\Controllers\Single ;
use App\DB\Te\TableEngine ;
use App\Http\Controllers\Controller ;
use App\Http\Controllers\Admin\TahesabController ;
use App\Models\Customer ;
use App\Models\Order ;
use App\Models\Price ;
use App\Models\Product ;
use App\Models\User ;
use App\Mail\YourMailableClass ;
use Illuminate\Support\Facades\Mail ;
use App\Models\Withdraw ;
use Illuminate\Http\Request ;
use Rooyesh\Wallet\interfaces\TransactionInterface ;
use Rooyesh\Wallet\interfaces\WalletInterface ;
use Rooyesh\Wallet\models\Transaction ;
use Rooyesh\Wallet\models\Wallet ;
use App\Models\TransactionsAdmin ;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException ;
use Illuminate\Support\Facades\Http ;
2026-02-09 14:09:19 +03:30
use App\Models\Setting ;
2026-03-10 15:39:30 +03:30
use App\Models\Cnt ;
2026-05-25 12:47:04 +03:30
use App\Services\MontzarService ;
use App\Services\ConfigService ;
2026-06-28 10:46:09 +03:30
use App\Services\ProductDisplayPriceService ;
2026-07-01 22:27:51 +03:30
use App\Services\ReferralGiftService ;
2026-06-27 15:51:44 +03:30
use App\Services\WalletBroadcastService ;
2026-01-24 14:03:11 +00:00
class SingleOrderController extends Controller
{
public function store ( Request $request )
{
2026-04-04 07:47:17 +00:00
$data = $request -> all ();
2026-06-22 19:14:24 +03:30
$data [ 'payment_product_id' ] = $this -> resolveGoldPaymentProductId ( $data );
if ( preg_match ( '/^gold:\d+$/' , ( string ) ( $data [ 'method' ] ?? '' ))) {
$data [ 'method' ] = 'gold' ;
}
2026-06-03 19:53:14 +03:30
$data [ 'is_katod' ] = ( $data [ 'method' ] ?? null ) === 'katod' ;
if ( $data [ 'is_katod' ]) {
2026-06-03 19:45:08 +03:30
$data [ 'method' ] = 'gold' ;
}
2026-05-25 12:47:04 +03:30
$config = app ( ConfigService :: class );
2026-04-04 07:47:17 +00:00
2026-06-28 15:16:39 +03:30
// فیلتر ساعت معامله per-product (سراسری یا override محصول) پایینتر در assertProductTradingOpen اعمال میشود.
2026-06-14 22:00:21 +03:30
2026-01-24 14:03:11 +00:00
// throw new UnprocessableEntityHttpException('به دلیل نوسانات سفارشات بسته میباشد.');
$transactionType = $data [ 'direction' ] == 1 ? "خرید" : "فروش" ;
2026-06-05 16:24:15 +03:30
$customer = Customer :: find ( auth ( 'customer' ) -> id () ?? ( $data [ 'customer_id' ] ?? null ));
if ( $min_sell = Setting :: where ( 'key' , 'minimum_sell' ) -> where ( 'is_active' , 1 ) -> first ()) {
2026-06-09 09:57:58 +03:30
if (( int ) $data [ 'direction' ] === 2 ) {
$sellAmount = $this -> resolveOrderAmount ( $data );
if ( $sellAmount !== null && ( float ) $min_sell -> value > $sellAmount ) {
throw new UnprocessableEntityHttpException ( 'حداقل میزان فروش ' . $min_sell -> value . ' گرم میباشد' );
}
2026-06-05 16:24:15 +03:30
}
}
$data [ 'first_buy' ] = auth ( 'customer' ) -> id () && $customer && $customer -> first_buy_order !== 1 ;
2026-01-24 14:03:11 +00:00
if ( auth ( 'customer' ) -> id ()) {
$data [ 'customer_id' ] = auth ( 'customer' ) -> id ();
2026-05-02 18:47:02 +00:00
2026-06-28 10:46:09 +03:30
$orderProductId = ( int ) ( $data [ 'abshode_id' ] ?? $data [ 'product_id' ] ?? $config -> mainProductId () ?? 0 );
$orderProduct = $orderProductId > 0 ? Product :: find ( $orderProductId ) : null ;
$basePrice = app ( ProductDisplayPriceService :: class ) -> resolveOrderBasePrice ( $orderProduct );
if ( $basePrice <= 0 ) {
2026-06-14 22:00:21 +03:30
if ( $config -> isOutsideTradingHours ()) {
throw new UnprocessableEntityHttpException ( $config -> tradingClosedMessage ());
}
2026-05-02 18:47:02 +00:00
throw new UnprocessableEntityHttpException ( 'عدم ارائه سرویس.' );
}
2026-06-28 10:46:09 +03:30
$latestPrice = Price :: latest () -> first ();
2026-01-24 14:03:11 +00:00
$data [ 'all_price' ] = $latestPrice ;
2026-06-28 10:46:09 +03:30
$data [ 'price' ] = $basePrice ;
$data [ 'price_id' ] = $latestPrice ?-> id ;
2026-07-02 01:26:26 +03:30
$data [ 'difference' ] = $config -> orderPriceDiffRial ();
2026-07-01 16:33:15 +03:30
$data [ 'service_charge_percentage' ] = $config -> orderServiceChargePercentage ();
2026-02-10 11:19:51 +03:30
$fee_free = Setting :: where ( 'key' , 'fee_free' ) -> where ( 'is_active' , true ) -> value ( 'value' );
2026-03-10 15:39:30 +03:30
if ( $fee_free && $this -> feeFree ( $data [ 'customer_id' ], $fee_free )) {
2026-02-10 11:19:51 +03:30
$data [ 'service_charge_percentage' ] = 0 ;
2026-02-22 15:06:01 +03:30
// $data['difference'] = 0;
2026-02-10 11:19:51 +03:30
$data [ 'fee_free' ] = true ;
}
2026-01-24 14:03:11 +00:00
$data [ 'pay_at' ] = ( new \DateTime ()) -> format ( 'Y-m-d H:i:s' );
} else if ( auth ( 'user' ) -> id ()) { //admin
$data [ 'service_charge_percentage' ] = 0 ;
}
2026-03-31 18:28:27 +03:30
if ( $data [ 'price' ] === 0 ){
throw new UnprocessableEntityHttpException ( ' سفارشات بسته میباشد.' );
}
2026-01-24 14:03:11 +00:00
$data [ 'sts' ] = 2 ;
$data [ 'type' ] = 2 ;
$data [ 'payment_sts' ] = 4 ;
$data [ 'price_original' ] = $data [ 'price' ];
$data [ 'payment_remind' ] = 0 ;
$data [ 'fee' ] = $data [ 'difference' ];
2026-06-15 11:25:10 +03:30
$ownerType = ( int ) ( $customer ?-> type ?? 2 );
$wallet_interface = new WalletInterface ( $data [ 'customer_id' ], $ownerType );
$wallet = $wallet_interface -> wallet ;
2026-05-28 11:53:27 +03:30
if ( ! $wallet ) {
throw new UnprocessableEntityHttpException ( 'کیف پول یافت نشد.' );
}
2026-01-24 14:03:11 +00:00
$response = [];
// Check if the user wants to transact with a product or non-product (gold)
if ( isset ( $data [ 'product_id' ]) and $data [ 'product' ] = Product :: find ( $data [ 'product_id' ])) {
2026-06-14 22:00:21 +03:30
$config -> assertProductTradingOpen ( $data [ 'product' ]);
2026-01-24 14:03:11 +00:00
// Check if the user wants to buy
if ( $data [ 'direction' ] == 1 ) {
2026-02-22 15:06:01 +03:30
$data [ 'service_charge_percentage' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_buy' ]) * $data [ 'number' ];
2026-07-02 01:26:26 +03:30
$data [ 'difference' ] = $data [ 'fee' ] = $this -> resolveCashPriceDiff ( $config , $data [ 'product' ], 1 );
2026-02-22 15:06:01 +03:30
$data [ 'total_fee' ] = $data [ 'number' ] * $data [ 'fee' ];
$data [ 'price_original' ] = $data [ 'product' ][ 'price' ] + $data [ 'product' ][ 'price_profit' ];
2026-01-24 14:03:11 +00:00
$data [ 'total_price_original' ] = $data [ 'product' ][ 'amount' ] * ( $data [ 'price_original' ] ?? 0 );
// Check if the method is cash
if ( $data [ 'method' ] == "cash" ) {
2026-03-10 15:39:30 +03:30
$response [ 'buy' ] = $this -> processBuyTransactionProduct ( $data , $wallet , $wallet_interface );
2026-01-24 14:03:11 +00:00
} // Check if the method is gold
else if ( $data [ 'method' ] == "gold" ) {
$response [ 'buy' ] = $this -> processBuyTransactionProductByGold ( $data , $wallet , $wallet_interface );
2026-06-03 19:41:00 +03:30
} else {
throw new UnprocessableEntityHttpException ( 'روش پرداخت نامعتبر است.' );
2026-01-24 14:03:11 +00:00
}
} // Check if the user wants to sell
else if ( $data [ 'direction' ] == 2 ) {
2026-02-22 15:06:01 +03:30
$data [ 'service_charge_percentage' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_sell' ]) * $data [ 'number' ];
2026-07-02 01:26:26 +03:30
$data [ 'difference' ] = $data [ 'fee' ] = $this -> resolveCashPriceDiff ( $config , $data [ 'product' ], 2 );
2026-02-22 15:06:01 +03:30
$data [ 'total_fee' ] = $data [ 'number' ] * $data [ 'fee' ];
$data [ 'price_original' ] = $data [ 'product' ][ 'price' ] + $data [ 'product' ][ 'price_profit' ];
2026-01-24 14:03:11 +00:00
$data [ 'total_price_original' ] = $data [ 'product' ][ 'amount' ] * ( $data [ 'price_original' ] ?? 0 );
// Check if the method is cash
if ( $data [ 'method' ] == "cash" ) {
$response [ 'sell' ] = $this -> processSellTransactionProduct ( $data , $wallet , $wallet_interface );
} // Check if the method is gold
else if ( $data [ 'method' ] == "gold" ) {
$response [ 'sell' ] = $this -> processSellTransactionProductByGold ( $data , $wallet , $wallet_interface );
2026-06-03 19:41:00 +03:30
} else {
throw new UnprocessableEntityHttpException ( 'روش پرداخت نامعتبر است.' );
2026-01-24 14:03:11 +00:00
}
}
} else {
// Calculate total price and fee for non-product (gold) transaction
$data [ 'total_price_original' ] = $data [ 'amount' ] * ( $data [ 'price_original' ] ?? 0 );
2026-06-04 14:19:54 +03:30
$mainProductId = app ( \App\Services\ConfigService :: class ) -> mainProductId ();
2026-06-04 13:48:37 +03:30
$productId = $data [ 'abshode_id' ] ?? $data [ 'product_id' ] ?? $mainProductId ;
$data [ 'product' ] = $productId ? Product :: find ( $productId ) : null ;
2026-05-28 11:53:27 +03:30
if ( ! $data [ 'product' ]) {
throw new UnprocessableEntityHttpException ( 'محصول آبشده یافت نشد.' );
}
2026-06-14 22:00:21 +03:30
$config -> assertProductTradingOpen ( $data [ 'product' ]);
2026-06-04 13:48:37 +03:30
if ( $data [ 'direction' ] == 1 ) {
2026-07-02 01:26:26 +03:30
$data [ 'difference' ] = $this -> resolveCashPriceDiff ( $config , $data [ 'product' ], 1 );
2026-06-04 13:48:37 +03:30
$data [ 'service_charge_percentage' ] = $data [ 'product' ][ 'percent_fee_buy' ];
} elseif ( $data [ 'direction' ] == 2 ) {
2026-07-02 01:26:26 +03:30
$data [ 'difference' ] = $this -> resolveCashPriceDiff ( $config , $data [ 'product' ], 2 );
2026-06-04 13:48:37 +03:30
$data [ 'service_charge_percentage' ] = $data [ 'product' ][ 'percent_fee_sell' ];
}
$data [ 'total_fee' ] = $data [ 'amount' ] * $data [ 'difference' ];
2026-05-28 11:53:27 +03:30
$data [ 'product_id' ] = $data [ 'product' ] -> id ;
2026-01-24 14:03:11 +00:00
// Check if the user wants to buy
if ( $data [ 'direction' ] == 1 ) {
if ( ! $data [ 'product' ][ 'open_buy' ]) {
throw new UnprocessableEntityHttpException ( 'خرید این محصول در این لحظه مقدور نمیباشد' );
}
$response [ 'buy' ] = $this -> processBuyTransaction ( $data , $wallet , $wallet_interface );
} // Check if the user wants to sell
else if ( $data [ 'direction' ] == 2 ) {
if ( ! $data [ 'product' ][ 'open_sell' ]) {
throw new UnprocessableEntityHttpException ( 'خرید این محصول در این لحظه مقدور نمیباشد' );
}
$response [ 'sell' ] = $this -> processSellTransaction ( $data , $wallet , $wallet_interface );
}
}
2026-06-28 15:16:39 +03:30
// دفترکل داخلی همیشه ثبت شود — مستقل از اتصال به حسابداری بیرونی
if ( isset ( $data [ 'order' ])) {
try {
app ( \App\Services\AccountingLedgerService :: class ) -> recordTrade ( $data [ 'order' ]);
} catch ( \Throwable $e ) {
report ( $e );
}
}
2026-06-04 13:48:37 +03:30
if ( $config -> getString ( 'send_to_tahesab' , 'false' ) === 'true' ) {
2026-02-09 14:09:19 +03:30
try {
2026-06-25 22:20:40 +03:30
$data [ 'tahesab' ] = app ( TahesabController :: class ) -> storeTrade ( $data );
2026-03-10 15:39:30 +03:30
} catch ( \Exception $e ) {
2026-06-25 22:20:40 +03:30
report ( $e );
2026-02-09 14:09:19 +03:30
}
2026-02-08 08:02:11 +00:00
}
2026-01-24 14:03:11 +00:00
// $response['reward'] = $this->give_order_reward($data, $wallet, $wallet_interface);
2026-06-05 16:24:15 +03:30
if (( int ) $data [ 'direction' ] === 1 && $customer ) {
$referrer = Customer :: where ( 'referral_id' , $customer -> referral_to_id ) -> first ();
if ( ! empty ( $referrer ) && $referrer -> first_buy_order == 1 && $customer -> first_buy_order !== 1 ) {
$customer -> first_buy_order = true ;
$customer -> save ();
$response [ 'bonus_gift' ] = $this -> bonusGift ( $customer , $referrer );
}
}
2026-06-03 19:41:00 +03:30
if ( isset ( $data [ 'order' ])) {
2026-06-09 10:21:30 +03:30
try {
$response [ 'Notifications' ] = $this -> sendTransactionNotifications ( $data , $transactionType );
} catch ( \Throwable $e ) {
report ( $e );
}
2026-06-03 19:41:00 +03:30
}
2026-06-27 15:51:44 +03:30
if ( $customer ) {
app ( WalletBroadcastService :: class ) -> broadcastForCustomer (
( int ) $customer -> id ,
$ownerType
);
}
2026-01-24 14:03:11 +00:00
return response () -> json ([ $response , $data ]);
}
private function processBuyTransaction ( & $data , $wallet , $wallet_interface )
{
$response = [];
2026-07-01 20:59:24 +03:30
$config = app ( ConfigService :: class );
$feeFromGold = $config -> feeDeductFromGold ();
2026-07-02 20:59:26 +03:30
$targetCash = $this -> resolveTargetCash ( $data );
2026-01-24 14:03:11 +00:00
$data [ 'price' ] += $data [ 'difference' ];
2026-07-04 12:06:56 +03:30
if ( $targetCash !== null ) {
$data [ 'amount' ] = $this -> resolveBuyAmountFromTargetCash (
$targetCash ,
( float ) $data [ 'price' ],
( float ) ( $data [ 'service_charge_percentage' ] ?? 0 ),
$feeFromGold ,
isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true
);
} else {
$data [ 'amount' ] = $this -> normalizeGoldAmount (( float ) ( $data [ 'amount' ] ?? 0 ));
}
2026-01-24 14:03:11 +00:00
$data [ 'total_price' ] = $data [ 'amount' ] * $data [ 'price' ];
2026-06-06 22:06:53 +03:30
$this -> enforceProductOrderLimits ( $data , ( float ) $data [ 'total_price' ]);
2026-06-05 16:24:15 +03:30
if ( ! empty ( $data [ 'first_buy' ]) && ( $minFirstBuy = Setting :: where ( 'is_active' , 1 ) -> where ( 'key' , 'min_first_buy' ) -> value ( 'value' ))) {
if ( $data [ 'total_price' ] < ( int ) $minFirstBuy ) {
throw new UnprocessableEntityHttpException ( 'حداقل سفارش اول ' . number_format (( int ) $minFirstBuy ) . ' ریال میباشد.' );
}
}
2026-02-22 15:06:01 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : $data [ 'service_charge_percentage' ] * $data [ 'amount' ];
2026-01-24 14:03:11 +00:00
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
2026-07-01 20:59:24 +03:30
if ( $feeFromGold ) {
$data [ 'payment_amount' ] = $data [ 'total_price' ] + $data [ 'service_charge_price' ];
} else {
$data [ 'payment_amount' ] = $data [ 'total_price' ];
$data [ 'amount' ] -= $data [ 'service_charge' ];
2026-07-04 12:06:56 +03:30
$data [ 'amount' ] = $this -> normalizeGoldAmount (( float ) $data [ 'amount' ]);
2026-07-01 20:59:24 +03:30
}
2026-07-02 20:59:26 +03:30
if ( $targetCash !== null ) {
$data [ 'payment_amount' ] = $targetCash ;
if ( ! $feeFromGold ) {
$data [ 'total_price' ] = $targetCash ;
}
}
2026-01-24 14:03:11 +00:00
if ( $wallet -> cash < $data [ 'payment_amount' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
2026-07-02 21:24:26 +03:30
$this -> assertProviderOrderAccepted ( $data );
2026-01-24 14:03:11 +00:00
$data [ 'order' ] = $order = Order :: create ( $data );
2026-06-09 13:34:43 +03:30
$abshode = $this -> resolveAbshodeProductContext ( $data );
2026-06-22 21:42:48 +03:30
$productId = ( int ) ( $data [ 'product_id' ] ?? $abshode [ 'id' ] ?? 0 );
2026-06-09 13:28:02 +03:30
$buyTransaction = [
2026-01-24 14:03:11 +00:00
"cash" => $data [ 'payment_amount' ],
"gold" => $data [ 'amount' ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductBuyTitle ( $data ),
2026-06-09 13:28:02 +03:30
];
2026-06-22 21:42:48 +03:30
if ( $productId > 0 ) {
$buyTransaction [ 'product_id' ] = $productId ;
$buyTransaction [ 'note' ] = 'product_id:' . $productId ;
2026-06-09 13:28:02 +03:30
}
new TransactionInterface ( $wallet_interface , $buyTransaction , 1 , true , false );
2026-07-02 21:24:26 +03:30
$this -> finalizeProviderOrder ( $data );
2026-01-24 14:03:11 +00:00
$response [ '1' ] = 2 ;
2026-07-02 21:24:26 +03:30
2026-01-24 14:03:11 +00:00
return $response ;
}
private function processBuyTransactionProduct ( & $data , $wallet , $wallet_interface )
{
2026-03-10 15:39:30 +03:30
$data [ 'price' ] = $data [ 'product' ][ 'price' ] + $data [ 'product' ][ 'price_profit' ];
2026-01-24 14:03:11 +00:00
$data [ 'price' ] += $data [ 'difference' ];
$data [ 'amount' ] = $data [ 'number' ] * $data [ 'product' ][ 'amount' ];
2026-03-10 15:39:30 +03:30
$data [ 'total_amount' ] = $data [ 'amount' ] + ( $data [ 'product' ][ 'percent_fee_buy' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_price' ] = $data [ 'total_amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
2026-06-05 16:24:15 +03:30
2026-06-06 22:06:53 +03:30
$this -> enforceProductOrderLimits ( $data , ( float ) $data [ 'total_price' ]);
2026-06-05 16:24:15 +03:30
if ( ! empty ( $data [ 'first_buy' ]) && ( $minFirstBuy = Setting :: where ( 'is_active' , 1 ) -> where ( 'key' , 'min_first_buy' ) -> value ( 'value' ))) {
if ( $data [ 'total_price' ] < ( int ) $minFirstBuy ) {
throw new UnprocessableEntityHttpException ( 'حداقل سفارش اول ' . number_format (( int ) $minFirstBuy ) . ' ریال میباشد.' );
}
}
2026-03-10 15:39:30 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_buy' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
$data [ 'wallet' ] = $wallet ;
if ( $wallet -> cash < $data [ 'payment_amount' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
if ( ! $data [ 'product' ][ 'open_buy' ]) {
throw new UnprocessableEntityHttpException ( 'خرید این محصول در این لحظه مقدور نمیباشد' );
}
$data [ 'order' ] = $order = Order :: create ( $data );
$data [ 'transaction' ][] = new TransactionInterface ( $wallet_interface , $_inp = [
"number" => $data [ 'number' ],
"cash" => $data [ 'total_price' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'title' => "برداشت وجه نقد"
2026-03-10 15:39:30 +03:30
], 12 , false , false );
2026-06-10 17:31:38 +03:30
$wallet_interface_product = $this -> productWalletInterface (( int ) $data [ "product_id" ]);
$this -> normalizeProductWalletGold ( $wallet_interface_product );
2026-01-24 14:03:11 +00:00
new TransactionInterface ( $wallet_interface_product , [
"gold" => $data [ 'number' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductBuyTitle ( $data ),
2026-01-24 14:03:11 +00:00
], 1 , true , false );
}
private function processBuyTransactionProductByGold ( & $data , $wallet , $wallet_interface )
{
$data [ 'price' ] += $data [ 'difference' ];
$data [ 'amount' ] = $data [ 'number' ] * $data [ 'product' ][ 'amount' ];
2026-03-10 15:39:30 +03:30
$data [ 'total_amount' ] = $data [ 'amount' ] + ( $data [ 'product' ][ 'percent_fee_buy' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_price' ] = $data [ 'total_amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
2026-06-06 22:06:53 +03:30
$this -> enforceProductOrderLimits ( $data , ( float ) $data [ 'total_price' ]);
2026-03-10 15:39:30 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_buy' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_fee' ] = 0 ;
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
$data [ 'wallet' ] = $wallet ;
2026-06-22 19:14:24 +03:30
$paymentProductId = ( int ) ( $data [ 'payment_product_id' ] ?? 0 );
$paymentWalletInterface = $wallet_interface ;
$paymentProduct = null ;
$paymentWallet = $wallet ;
if ( $paymentProductId > 0 ) {
$paymentProduct = Product :: find ( $paymentProductId );
if (
! $paymentProduct
|| ( int ) ( $paymentProduct -> metal_id ?? 0 ) !== ( int ) ( $data [ 'product' ][ 'metal_id' ] ?? 0 )
) {
throw new UnprocessableEntityHttpException ( 'روش پرداخت نامعتبر است.' );
}
$paymentWalletInterface = $this -> productWalletInterface ( $paymentProductId );
$paymentWallet = $paymentWalletInterface -> wallet ;
if ( ! $paymentWallet ) {
throw new UnprocessableEntityHttpException ( 'کیف پول یافت نشد.' );
}
}
if (( float ) $paymentWallet -> gold < $data [ 'total_amount' ]) {
2026-06-03 19:53:14 +03:30
throw new UnprocessableEntityHttpException ( $this -> insufficientGoldBalanceMessage ( $data ));
2026-01-24 14:03:11 +00:00
}
if ( ! $data [ 'product' ][ 'open_buy' ]) {
throw new UnprocessableEntityHttpException ( 'خرید این محصول در این لحظه مقدور نمیباشد' );
}
$data [ 'order' ] = $order = Order :: create ( $data );
2026-06-22 19:14:24 +03:30
$paymentSellTitle = $paymentProduct
? self :: productSellTitle ( $paymentProduct -> title ?? '' )
: self :: mainMetalSellTitle ();
$paymentTransaction = [
2026-01-24 14:03:11 +00:00
"number" => $data [ 'number' ],
"gold" => $data [ 'total_amount' ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
2026-06-22 19:14:24 +03:30
'title' => $paymentSellTitle ,
];
if ( $paymentProductId > 0 ) {
$paymentTransaction [ 'product_id' ] = $paymentProductId ;
$this -> normalizeProductWalletGold ( $paymentWalletInterface );
$data [ 'transaction' ][] = new TransactionInterface (
$paymentWalletInterface ,
$paymentTransaction ,
1 ,
false ,
false
);
} else {
$data [ 'transaction' ][] = new TransactionInterface (
$paymentWalletInterface ,
$paymentTransaction ,
12 ,
false ,
true
);
}
2026-06-10 17:31:38 +03:30
$wallet_interface_product = $this -> productWalletInterface (( int ) $data [ "product_id" ]);
$this -> normalizeProductWalletGold ( $wallet_interface_product );
2026-01-24 14:03:11 +00:00
new TransactionInterface ( $wallet_interface_product , [
"gold" => $data [ 'number' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductBuyTitle ( $data ),
2026-01-24 14:03:11 +00:00
], 1 , true , false );
}
private function processSellTransaction ( & $data , $wallet , $wallet_interface )
{
$response = [];
2026-07-01 20:59:24 +03:30
$config = app ( ConfigService :: class );
$feeFromGold = $config -> feeDeductFromGold ();
2026-07-04 12:06:56 +03:30
$targetCash = $this -> resolveTargetCash ( $data );
2026-01-24 14:03:11 +00:00
$data [ 'price' ] -= $data [ 'difference' ];
2026-07-04 12:06:56 +03:30
if ( $targetCash !== null && $feeFromGold ) {
$price = ( float ) $data [ 'price' ];
$data [ 'amount' ] = $price > 0
? $this -> normalizeGoldAmount ( $targetCash / $price )
: 0.0 ;
} else {
$data [ 'amount' ] = $this -> normalizeGoldAmount (( float ) ( $data [ 'amount' ] ?? 0 ));
}
2026-06-06 22:06:53 +03:30
$grossTotal = $data [ 'amount' ] * $data [ 'price' ];
$this -> enforceProductOrderLimits ( $data , ( float ) $grossTotal );
2026-02-22 15:06:01 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : $data [ 'service_charge_percentage' ] * $data [ 'amount' ];
2026-01-24 14:03:11 +00:00
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
2026-07-01 20:59:24 +03:30
if ( $feeFromGold ) {
$data [ 'total_price' ] = $data [ 'amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
$goldDebit = $data [ 'amount' ] + $data [ 'service_charge' ];
} else {
$data [ 'total_price' ] = $data [ 'amount' ] * $data [ 'price' ] - $data [ 'service_charge_price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
$goldDebit = $data [ 'amount' ];
}
2026-07-02 20:59:26 +03:30
if ( $targetCash !== null ) {
$data [ 'payment_amount' ] = $targetCash ;
$data [ 'total_price' ] = $targetCash ;
}
2026-07-01 20:59:24 +03:30
if ( $wallet -> gold < $goldDebit ) {
2026-06-03 19:53:14 +03:30
throw new UnprocessableEntityHttpException ( $this -> insufficientGoldBalanceMessage ( $data ));
2026-01-24 14:03:11 +00:00
}
2026-07-02 21:24:26 +03:30
$this -> assertProviderOrderAccepted ( $data );
2026-01-24 14:03:11 +00:00
$data [ 'order' ] = $order = Order :: create ( $data );
2026-06-09 13:34:43 +03:30
$abshode = $this -> resolveAbshodeProductContext ( $data );
2026-06-22 21:42:48 +03:30
$productId = ( int ) ( $data [ 'product_id' ] ?? $abshode [ 'id' ] ?? 0 );
2026-06-09 13:28:02 +03:30
$sellTransaction = [
2026-07-01 20:59:24 +03:30
"gold" => $goldDebit ,
2026-01-24 14:03:11 +00:00
"cash" => $data [ 'total_price' ],
'expire_at' => now (),
'active' => true ,
2026-06-03 21:37:05 +03:30
'order_id' => $order -> id ,
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductSellTitle ( $data ),
2026-06-09 13:28:02 +03:30
];
2026-06-22 21:42:48 +03:30
if ( $productId > 0 ) {
$sellTransaction [ 'product_id' ] = $productId ;
$sellTransaction [ 'note' ] = 'product_id:' . $productId ;
2026-06-09 13:28:02 +03:30
}
new TransactionInterface ( $wallet_interface , $sellTransaction , 2 , false , true );
2026-07-02 21:24:26 +03:30
$this -> finalizeProviderOrder ( $data );
2026-01-24 14:03:11 +00:00
}
private function processSellTransactionProduct ( & $data , $wallet , $wallet_interface )
{
2026-03-10 15:39:30 +03:30
$data [ 'price' ] = $data [ 'product' ][ 'price' ] + $data [ 'product' ][ 'price_profit' ];
2026-01-24 14:03:11 +00:00
$data [ 'price' ] -= $data [ 'difference' ];
$data [ 'amount' ] = $data [ 'number' ] * $data [ 'product' ][ 'amount' ];
2026-03-10 15:39:30 +03:30
$data [ 'total_amount' ] = $data [ 'amount' ] - ( $data [ 'product' ][ 'percent_fee_sell' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_price' ] = $data [ 'total_amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
2026-06-06 22:06:53 +03:30
$grossTotal = ( float ) ( $data [ 'amount' ] * $data [ 'price' ]);
$this -> enforceProductOrderLimits ( $data , $grossTotal );
2026-03-10 15:39:30 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_sell' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
2026-06-10 17:31:38 +03:30
$wallet_interface_product = $this -> productWalletInterface (( int ) $data [ "product_id" ]);
2026-01-24 14:03:11 +00:00
if ( $wallet_interface_product -> wallet -> gold < $data [ 'number' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
if ( ! $data [ 'product' ][ 'open_sell' ]) {
throw new UnprocessableEntityHttpException ( 'فروش این محصول در این لحظه مقدور نمیباشد' );
}
$data [ 'order' ] = $order = Order :: create ( $data );
2026-06-10 17:31:38 +03:30
$this -> normalizeProductWalletGold ( $wallet_interface_product );
2026-01-24 14:03:11 +00:00
new TransactionInterface ( $wallet_interface_product , [
"gold" => $data [ 'number' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductSellTitle ( $data ),
2026-01-24 14:03:11 +00:00
], 1 , false , false );
$data [ 'transaction' ][] = new TransactionInterface ( $wallet_interface , $_inp = [
"number" => $data [ 'number' ],
"cash" => $data [ 'total_price' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'title' => "واریز وجه نقد"
2026-03-10 15:39:30 +03:30
], 12 , false , true );
2026-01-24 14:03:11 +00:00
}
2026-03-10 15:39:30 +03:30
2026-01-24 14:03:11 +00:00
private function processSellTransactionProductByGold ( & $data , $wallet , $wallet_interface )
{
$data [ 'price' ] -= $data [ 'difference' ];
$data [ 'amount' ] = $data [ 'number' ] * $data [ 'product' ][ 'amount' ];
2026-03-10 15:39:30 +03:30
$data [ 'total_amount' ] = $data [ 'amount' ] - ( $data [ 'product' ][ 'percent_fee_sell' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_price' ] = $data [ 'total_amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
2026-06-06 22:06:53 +03:30
$grossTotal = ( float ) ( $data [ 'amount' ] * $data [ 'price' ]);
$this -> enforceProductOrderLimits ( $data , $grossTotal );
2026-03-10 15:39:30 +03:30
$data [ 'service_charge' ] = isset ( $data [ 'fee_free' ]) && $data [ 'fee_free' ] === true ? 0 : ( $data [ 'product' ][ 'percent_fee_sell' ] * $data [ 'amount' ]);
2026-01-24 14:03:11 +00:00
$data [ 'total_fee' ] = 0 ;
$data [ 'service_charge_price' ] = $data [ 'service_charge' ] * $data [ 'price_original' ];
2026-06-10 17:31:38 +03:30
$wallet_interface_product = $this -> productWalletInterface (( int ) $data [ "product_id" ]);
2026-01-24 14:03:11 +00:00
if ( $wallet_interface_product -> wallet -> gold < $data [ 'number' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
if ( ! $data [ 'product' ][ 'open_sell' ]) {
throw new UnprocessableEntityHttpException ( 'فروش این محصول در این لحظه مقدور نمیباشد' );
}
$data [ 'order' ] = $order = Order :: create ( $data );
$data [ 'transaction' ][] = new TransactionInterface ( $wallet_interface , $_inp = [
"number" => $data [ 'number' ],
"gold" => $data [ 'total_amount' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductSellTitle ( $data ),
2026-03-10 15:39:30 +03:30
], 12 , true , false );
2026-06-10 17:31:38 +03:30
$this -> normalizeProductWalletGold ( $wallet_interface_product );
2026-01-24 14:03:11 +00:00
new TransactionInterface ( $wallet_interface_product , [
"gold" => $data [ 'number' ],
"product_id" => $data [ "product_id" ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
2026-06-22 21:42:48 +03:30
'title' => $this -> meltedOrProductSellTitle ( $data ),
2026-01-24 14:03:11 +00:00
], 1 , false , false );
}
2026-06-10 17:31:38 +03:30
/**
* کیف مؤثر محصول برای تراکنش سفارش.
* محصولات متصل به کیف اصلی (main_wallet_products) مستقیماً روی کیف اصلی مینشینند.
*/
private function productWalletInterface ( int $productId ) : WalletInterface
{
return new WalletInterface (
auth ( 'customer' ) -> id (),
auth ( 'customer' ) -> user () -> type ,
null ,
self :: effectiveProductWalletId ( $productId )
);
}
/** رفتار قدیمیِ رُند کردن موجودی فقط برای کیف خود محصول؛ کیف اصلی هرگز رُند نمیشود */
private function normalizeProductWalletGold ( WalletInterface $walletInterface ) : void
{
if ( $walletInterface -> wallet -> product_id === null ) {
return ;
}
$walletInterface -> wallet -> gold = intval ( $walletInterface -> wallet -> gold );
$walletInterface -> wallet -> save ();
}
2026-03-10 15:39:30 +03:30
2026-01-24 14:03:11 +00:00
private function give_order_reward ( & $data , $wallet , $wallet_interface )
{
$data [ 'aCustomers' ] = [];
$i = 0 ;
$data [ 'aCustomers' ][ $i ] = Customer :: findOrFail ( $data [ 'customer_id' ]);
while ( $data [ 'aCustomers' ][ $i + 1 ] = Customer :: where ( 'referral_id' , $data [ 'aCustomers' ][ $i ] -> referral_to_id ) -> first ()) {
if ( $data [ 'aCustomers' ][ $i + 1 ] -> profit_amount_by_lvl ) {
$levels = json_decode ( str_replace ([ '{' , '}' ], [ '[' , ']' ], $data [ 'aCustomers' ][ $i + 1 ] -> profit_amount_by_lvl ), true );
foreach ( $levels as $level ) {
if ( $level [ 0 ] == $i + 1 ) {
// [$level[1],$data['aCustomers'][$i+1]];
if ( $this -> Config ( 'has_page_earn_money' ) == true ) {
$gift_for_invite = ( $data [ 'order' ][ 'service_charge' ] * $level [ 1 ]) / 100 ;
$profit_receiver = $data [ 'aCustomers' ][ $i + 1 ] -> id ;
$profit_sender = $data [ 'aCustomers' ][ 0 ] -> id ;
$Withdraw = Withdraw :: create ([
'user_id' => $profit_sender ,
'customer_id' => $profit_receiver ,
"cash" => 0 ,
"gold" => $gift_for_invite ,
'sts' => 9 ,
]);
$wallet_interface = new WalletInterface ( $profit_receiver , 2 );
new TransactionInterface ( $wallet_interface , $_inp = [
"cash" => 0 ,
"gold" => $gift_for_invite ,
'expire_at' => now (),
'active' => true ,
'withdraw_id' => $Withdraw -> id ,
'start_at' => now (),
], 9 , true , false );
$transaction = Transaction :: where ( 'customer_id' , $profit_receiver ) -> latest () -> first ();
TransactionsAdmin :: create ([
'customer_id' => $profit_sender ,
'customer_to_id' => $profit_receiver ,
'user_id' => $profit_sender ,
'order_id' => $data [ 'order' ][ 'id' ],
'wallet' => null , // یا مقدار مناسب دیگری
'transaction_id' => $transaction -> id ,
'cash' => 0 ,
'note' => ' سود بابت سفارش' ,
'type' => 1 , // یا مقدار مناسب دیگری
'gold' => $gift_for_invite ,
'balance_cash' => 0 , // یا مقدار مناسب دیگری
'balance_gold' => $gift_for_invite , // مقدار صحیح برای `balance_gold`
'withdraw_id' => $Withdraw -> id ,
]);
}
}
}
}
if ( $i == 100 ) break ;
$i ++ ; // برای جلوگیری از حلقه بینهایت
}
return $data ;
}
private function sendTransactionNotifications ( array $data , string $transactionType )
{
$customer = Customer :: findOrFail ( $data [ 'customer_id' ]);
$companyName = $this -> Config ( 'name_fa' );
2026-06-03 19:41:00 +03:30
$amount = $data [ 'amount' ] ?? (
isset ( $data [ 'number' ], $data [ 'product' ][ 'amount' ])
? $data [ 'number' ] * $data [ 'product' ][ 'amount' ]
: 0
);
$totalPrice = $data [ 'total_price' ] ?? ( $data [ 'payment_amount' ] ?? 0 );
2026-06-03 21:37:05 +03:30
$subjectTitle = $this -> transactionSubjectTitle ( $data );
2026-01-24 14:03:11 +00:00
2026-06-03 21:37:05 +03:30
$message = "کاربر { $customer -> name } با شماره موبایل { $customer -> mobile } اقدام به $transactionType { $subjectTitle } به مقدار " .
2026-06-03 19:41:00 +03:30
" { $amount } گرم به مبلغ " . number_format ( $totalPrice ) .
2026-01-24 14:03:11 +00:00
" ریال کرد. با تشکر، $companyName " ;
User :: where ( 'send_sms' , 1 ) -> get () -> each ( function ( $admin ) use ( $message , $data , $transactionType , $companyName ) {
$this -> send ( $admin -> mobile , $message );
});
2026-06-14 21:09:43 +03:30
$wallet = Wallet :: where ( 'owner' , $data [ 'customer_id' ])
-> whereNull ( 'fund_id' )
-> whereNull ( 'product_id' )
-> first ();
2026-06-03 21:37:05 +03:30
$balanceLabel = self :: metalTypeLabel ();
2026-06-14 21:09:43 +03:30
$goldBalance = $wallet ? ( $wallet -> gold ?? 0 ) : 0 ;
$cashBalance = $wallet ? ( $wallet -> cash ?? 0 ) : 0 ;
2026-06-03 21:37:05 +03:30
$customerMessage = " $companyName \n $transactionType { $subjectTitle } \n گرم: { $amount } \n " .
2026-06-03 19:41:00 +03:30
"مبلغ کل: " . number_format ( $totalPrice ) . " \n\n " .
2026-06-14 21:09:43 +03:30
"موجودی { $balanceLabel } : { $goldBalance } \n " .
"مانده ریالی: " . number_format ( $cashBalance ) . " \n " .
2026-01-24 14:03:11 +00:00
$this -> Config ( 'app_url' );
// ارسال SMS به مشتری
$this -> send ( $customer -> mobile , $customerMessage );
}
2026-07-02 21:24:26 +03:30
private function assertProviderOrderAccepted ( array & $data ) : void
2026-05-24 22:29:43 +03:30
{
2026-07-02 21:24:26 +03:30
if ( ! app ( ConfigService :: class ) -> usesMontzarPricing ()) {
2026-05-24 22:29:43 +03:30
return ;
}
2026-07-02 21:24:26 +03:30
$this -> assertNoRecentDuplicateLocalOrder ( $data );
$data [ '_montzar_parsed' ] = app ( MontzarService :: class ) -> submitOrder ( $data );
}
private function finalizeProviderOrder ( array & $data ) : void
{
if ( ! app ( ConfigService :: class ) -> usesMontzarPricing ()) {
return ;
2026-05-24 22:29:43 +03:30
}
2026-07-02 21:24:26 +03:30
$parsed = $data [ '_montzar_parsed' ] ?? null ;
if ( ! is_array ( $parsed )) {
return ;
}
app ( MontzarService :: class ) -> applyParsedOrder ( $data , $parsed );
unset ( $data [ '_montzar_parsed' ]);
}
private function assertNoRecentDuplicateLocalOrder ( array $data ) : void
{
$customerId = ( int ) ( $data [ 'customer_id' ] ?? 0 );
if ( $customerId <= 0 ) {
return ;
}
$direction = ( int ) ( $data [ 'direction' ] ?? 0 );
$amount = round (( float ) ( $data [ 'amount' ] ?? 0 ), 6 );
$windowSeconds = 20 ;
$duplicate = Order :: where ( 'customer_id' , $customerId )
-> where ( 'direction' , $direction )
-> where ( 'created_at' , '>=' , now () -> subSeconds ( $windowSeconds ))
-> whereRaw ( 'ROUND(amount, 6) = ?' , [ $amount ])
-> exists ();
if ( $duplicate ) {
throw new UnprocessableEntityHttpException (
'در حال حاضر سفارش مشابه ثبت شده است. لطفاً چند ثانیه دیگر تلاش کنید.'
);
}
2026-05-24 22:29:43 +03:30
}
2026-01-24 14:03:11 +00:00
public function storeBackUp ( Request $request )
{
$data = $request -> all ();
if ( auth ( 'customer' ) -> id ()) { // متد در پنل کاربر
$data [ 'customer_id' ] = auth ( 'customer' ) -> id ();
$data [ 'price' ] = Price :: orderBy ( 'id' , 'desc' ) -> first () -> price ;
} elseif ( auth ( 'user' ) -> user ()) { // متد در پنل ادمین
$data [ 'customer_id' ] = $request -> customer_id ;
$data [ 'price' ] = $request -> price ;
}
$data [ 'sts' ] = 2 ;
$data [ 'type' ] = 2 ;
$data [ 'payment_sts' ] = 4 ;
$data [ 'price_original' ] = $data [ 'price' ];
$add_sell_price = config ( 'add_sell_price.single' );
2026-06-15 11:25:10 +03:30
$customer = Customer :: findOrFail ( $data [ 'customer_id' ]);
$wallet_interface = new WalletInterface ( $data [ 'customer_id' ], ( int ) $customer -> type );
$wallet = $wallet_interface -> wallet ;
2026-01-24 14:03:11 +00:00
$data [ 'total_price_original' ] = $data [ 'amount' ] * $data [ 'price_original' ];
$data [ 'payment_remind' ] = 0 ;
$data [ 'fee' ] = $add_sell_price ;
$data [ 'total_fee' ] = $data [ 'amount' ] * $data [ 'fee' ];
if ( $data [ 'direction' ] == 1 ) {
$data [ 'price' ] += $add_sell_price ;
$data [ 'total_price' ] = $data [ 'amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
if ( $wallet -> cash < $data [ 'total_price' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
$order = Order :: create ( $data ); //buy
new TransactionInterface ( $wallet_interface , $_inp = [
"cash" => $data [ 'total_price' ],
"gold" => $data [ 'amount' ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id ,
'start_at' => now (),
], 1 , true , false );
} else { //sell
$data [ 'price' ] -= $add_sell_price ;
$data [ 'total_price' ] = $data [ 'amount' ] * $data [ 'price' ];
$data [ 'payment_amount' ] = $data [ 'total_price' ];
if ( $wallet -> gold < $data [ 'amount' ]) {
throw new UnprocessableEntityHttpException ( 'موجودی شما کمتر از میزان سفارش است' );
}
$order = Order :: create ( $data );
new TransactionInterface ( $wallet_interface , $_inp = [
"gold" => $data [ 'amount' ],
"cash" => $data [ 'total_price' ],
'expire_at' => now (),
'active' => true ,
'order_id' => $order -> id
], 2 , false , true );
}
//----------------------------------------------------------------------------sms
// Determine transaction type
$transactionType = ( $data [ 'direction' ] == 1 ) ? "خرید" : "فروش" ;
// User information
$customer = Customer :: where ( "id" , $data [ 'customer_id' ]) -> firstOrFail ();
$userMobile = $customer -> mobile ; // User's mobile number
$userName = $customer -> name ; // User's name
$chargedAmount = $data [ 'total_price' ]; // Total price in Rial
$chargedAmountGold = $data [ 'amount' ]; // Amount of gold
// Company name
$companyName = $this -> Config ( 'name_fa' ); // Company name from configuration
// Constructing the SMS message
$message = "کاربر $userName با شماره موبایل $userMobile اقدام به $transactionType طلا به مقدار " . $chargedAmountGold . " گرم به مبلغ " . number_format ( $chargedAmount ) . " ریال کرد. با تشکر، $companyName " ;
// Getting admin mobile numbers and sending the SMS
User :: where ( 'active' , 1 ) -> get () -> each ( function ( $admin ) use ( $message ) {
$this -> Send ( $admin -> mobile , $message );
});
2026-06-15 11:25:10 +03:30
$mainWallet = Wallet :: where ( 'owner' , $data [ 'customer_id' ])
-> where ( 'owner_type' , $customer -> type )
-> main ()
-> first ();
2026-01-24 14:03:11 +00:00
$companyurl = $this -> Config ( 'app_url' );
$weight = $data [ 'amount' ];
$totalAmount = $data [ 'total_price' ];
2026-06-15 11:25:10 +03:30
$pricePerGram = $weight > 0 ? $totalAmount / $weight : 0 ;
$goldBalance = $mainWallet -> gold ?? 0 ;
$remainingBalance = $mainWallet -> cash ?? 0 ;
2026-01-24 14:03:11 +00:00
$message = " $companyName \n " ;
$message .= "خرید آبشده \n " ;
$message .= "گرم: $weight \n " ;
$message .= "قیمت گرم: " . number_format ( $pricePerGram ) . " \n " ;
$message .= "مبلغ کل: " . number_format ( $totalAmount ) . " \n\n " ;
$message .= "موجودی طلایی: $goldBalance \n " ;
$message .= "مانده ریالی: " . number_format ( $remainingBalance ) . " \n " ;
$message .= " $companyurl " . " \n " ;
$this -> Send ( $customer -> mobile , $message );
return response () -> json ( $order );
}
public function table ( Request $request )
{
$records = Order :: where ( 'customer_id' , auth ( 'customer' ) -> id ())
-> where ( 'type' , 2 );
TableEngine :: create ( $records , $request -> all ())
-> initSearch ([])
-> select ([
'*' , Order :: $SELECT_STS_STR
]) -> export ( $records );
return response () -> json ( $records );
}
2026-02-10 11:19:51 +03:30
private function feeFree ( $customer_id , $count )
{
return Order :: where ( 'customer_id' , $customer_id )
2026-03-10 15:39:30 +03:30
-> where ( 'type' , 2 )
-> where ( 'sts' , 2 )
-> where ( 'payment_sts' , 4 )
-> count () < ( int ) $count ;
2026-02-10 11:19:51 +03:30
}
2026-06-03 19:53:14 +03:30
2026-06-09 09:57:58 +03:30
private function resolveOrderAmount ( array $data ) : ? float
{
if ( isset ( $data [ 'amount' ])) {
return ( float ) $data [ 'amount' ];
}
if ( ! empty ( $data [ 'product_id' ]) && isset ( $data [ 'number' ])) {
$product = $data [ 'product' ] ?? Product :: find ( $data [ 'product_id' ]);
if ( $product ) {
return ( float ) $data [ 'number' ] * ( float ) $product -> amount ;
}
}
return null ;
}
2026-07-02 20:59:26 +03:30
private function resolveTargetCash ( array $data ) : ? int
{
if ( ! isset ( $data [ 'target_cash' ])) {
return null ;
}
$target = ( int ) round (( float ) $data [ 'target_cash' ]);
return $target > 0 ? $target : null ;
}
2026-07-04 12:06:56 +03:30
private function normalizeGoldAmount ( float $amount ) : float
{
return round ( $amount , 10 );
}
private function resolveBuyAmountFromTargetCash (
int $targetCash ,
float $unitPrice ,
float $serviceChargePercentage ,
bool $feeFromGold ,
bool $feeFree
) : float {
if ( $unitPrice <= 0 || $targetCash <= 0 ) {
return 0.0 ;
}
$feeRate = $feeFree ? 0.0 : $serviceChargePercentage ;
if ( $feeFromGold ) {
return $this -> normalizeGoldAmount ( $targetCash / ( $unitPrice * ( 1 + $feeRate )));
}
return $this -> normalizeGoldAmount ( $targetCash / $unitPrice );
}
2026-06-22 19:14:24 +03:30
private function resolveGoldPaymentProductId ( array $data ) : ? int
{
if ( ! empty ( $data [ 'payment_product_id' ])) {
return ( int ) $data [ 'payment_product_id' ];
}
$method = ( string ) ( $data [ 'method' ] ?? '' );
if ( preg_match ( '/^gold:(\d+)$/' , $method , $matches )) {
return ( int ) $matches [ 1 ];
}
return null ;
}
2026-06-09 13:34:43 +03:30
private function resolveAbshodeProductContext ( array $data ) : array
{
$productId = ( int ) ( $data [ 'product_id' ] ?? $data [ 'abshode_id' ] ?? 0 );
$product = null ;
if ( ! empty ( $data [ 'product' ])) {
$candidate = $data [ 'product' ];
if ( $candidate instanceof Product ) {
$product = $candidate ;
} elseif ( is_array ( $candidate ) && ! empty ( $candidate [ 'id' ])) {
$product = Product :: find ( $candidate [ 'id' ]);
}
}
if ( ! $product && $productId > 0 ) {
$product = Product :: find ( $productId );
}
if ( ! $product ) {
return [ 'id' => 0 , 'title' => '' ];
}
return [
'id' => ( int ) $product -> id ,
'title' => trim (( string ) $product -> title ),
];
}
2026-06-09 13:28:02 +03:30
private function productTitleFromData ( array $data ) : ? string
{
$product = $data [ 'product' ] ?? null ;
2026-06-22 21:42:48 +03:30
$title = null ;
2026-06-09 13:28:02 +03:30
2026-06-22 21:42:48 +03:30
if ( $product ) {
if ( is_array ( $product )) {
$title = $product [ 'title' ] ?? null ;
} else {
$title = $product -> title ?? null ;
}
2026-06-09 13:28:02 +03:30
}
$title = trim (( string ) $title );
2026-06-22 21:42:48 +03:30
if ( $title === '' && ! empty ( $data [ 'product_id' ])) {
$title = trim (( string ) Product :: query () -> whereKey (( int ) $data [ 'product_id' ]) -> value ( 'title' ));
}
2026-06-09 13:28:02 +03:30
return $title !== '' ? $title : null ;
}
2026-06-03 21:37:05 +03:30
private function isProductOrder ( array $data ) : bool
2026-06-03 19:53:14 +03:30
{
2026-06-09 13:28:02 +03:30
return ! empty ( $data [ 'product_id' ]) && $this -> productTitleFromData ( $data ) !== null ;
2026-06-03 19:53:14 +03:30
}
2026-06-03 21:37:05 +03:30
private function transactionSubjectTitle ( array $data ) : string
2026-06-03 19:53:14 +03:30
{
2026-06-09 13:28:02 +03:30
return $this -> productTitleFromData ( $data ) ?? self :: meltedGoldLabel ();
}
2026-06-03 21:37:05 +03:30
2026-06-09 13:28:02 +03:30
private function meltedOrProductBuyTitle ( array $data ) : string
{
$productTitle = $this -> productTitleFromData ( $data );
return $productTitle !== null
? self :: productBuyTitle ( $productTitle )
: self :: meltedGoldBuyTitle ();
}
private function meltedOrProductSellTitle ( array $data ) : string
{
$productTitle = $this -> productTitleFromData ( $data );
return $productTitle !== null
? self :: productSellTitle ( $productTitle )
: self :: meltedGoldSellTitle ();
2026-06-03 19:53:14 +03:30
}
private function insufficientGoldBalanceMessage ( array $data ) : string
{
2026-06-03 20:24:07 +03:30
return 'موجودی ' . self :: metalTypeLabel () . ' شما کمتر از میزان سفارش است' ;
2026-06-03 19:53:14 +03:30
}
2026-06-04 15:30:34 +03:30
/**
* گلد علی / zaarbox / main_product: اختلاف سفارش = buy_fee/sell_fee نمایش (مثل /api/price/last).
* montzar و بقیه: همان cash_fee_buy/sell محصول (رفتار قبلی ابشدهخانگی).
*/
2026-07-02 01:26:26 +03:30
private function resolveCashPriceDiff ( ConfigService $config , Product $product , int $direction ) : float
2026-06-04 15:30:34 +03:30
{
$provider = $config -> priceProvider ();
$alignWithDisplay = in_array ( $provider , [ 'zaarbox' , 'main_product' ], true );
if ( $alignWithDisplay ) {
$display = $direction === 1
2026-07-02 01:26:26 +03:30
? $config -> displayBuyPriceDiffRial ()
: $config -> displaySellPriceDiffRial ();
2026-06-04 15:30:34 +03:30
if ( $display > 0 ) {
return $display ;
}
}
return ( float ) ( $direction === 1 ? $product -> cash_fee_buy : $product -> cash_fee_sell );
}
2026-06-05 16:24:15 +03:30
private function bonusGift ( $customer , $referrer )
{
$bonus = Setting :: where ( 'key' , 'referral_bonus_amount' ) -> where ( 'is_active' , 1 ) -> first ();
if ( $bonus === null ) {
return false ;
}
$bonus = json_decode ( $bonus -> value , true );
$customer_bonus = $bonus [ 0 ][ 'customer' ] ?? 0 ;
$referrer_bonus = $bonus [ 0 ][ 'referrer' ] ?? 0 ;
if ( $customer_bonus > 0 ) {
$wallet_interface = new WalletInterface ( $customer -> id , $customer -> type );
$Withdraw = Withdraw :: create ([
'customer_id' => $customer -> id ,
'cash' => $customer_bonus ,
'note' => 'پاداش اولین سفارش' ,
'sts' => 4 ,
]);
$transaction = new TransactionInterface ( $wallet_interface , $_inp = [
'gold' => 0 ,
'cash' => $customer_bonus ,
'expire_at' => now (),
'note' => 'پاداش اولین سفارش' ,
'withdraw_id' => $Withdraw -> id ,
'active' => true ,
], 3 , true , true , 0 );
$message = 'کیف پول شما به اندازه ' . number_format ( $customer_bonus ) . ' ریال در تاریخ ' . verta () -> format ( 'Y/n/j H:i:s' ) . " شارژ شد بابت \n "
. 'پاداش اولین سفارش'
. ' '
. $this -> Config ( 'name_fa' );
$this -> Send ( $customer -> mobile , $message );
TransactionsAdmin :: create ([
'customer_id' => $customer -> id ,
'customer_to_id' => $customer -> referral -> id ?? null ,
'user_id' => $customer -> id ,
'wallet' => null ,
'transaction_id' => $transaction -> id ?? null ,
'cash' => $customer_bonus ,
'note' => 'پاداش خرید اول' ,
'type' => 1 ,
'gold' => 0 ,
'balance_cash' => 0 ,
'withdraw_id' => $Withdraw -> id ,
]);
}
if ( $referrer_bonus > 0 ) {
$wallet_interface = new WalletInterface ( $referrer -> id , $referrer -> type );
$Withdraw = Withdraw :: create ([
'customer_id' => $referrer -> id ,
'cash' => $referrer_bonus ,
'note' => 'پاداش اولین سفارش زیرمجموعه' ,
'sts' => 4 ,
]);
$referrerTransaction = new TransactionInterface ( $wallet_interface , $_inp = [
'gold' => 0 ,
'cash' => $referrer_bonus ,
'expire_at' => now (),
'note' => 'پاداش اولین سفارش زیرمجموعه' ,
'withdraw_id' => $Withdraw -> id ,
'active' => true ,
], 3 , true , true , 0 );
$message = 'کیف پول شما به اندازه ' . number_format ( $referrer_bonus ) . ' ریال در تاریخ ' . verta () -> format ( 'Y/n/j H:i:s' ) . " شارژ شد بابت \n "
. 'بابت پاداش اولین سفارش زیرمجموعه'
. ' '
. $this -> Config ( 'name_fa' );
$this -> Send ( $referrer -> mobile , $message );
TransactionsAdmin :: create ([
'customer_id' => $customer -> id ,
'customer_to_id' => $referrer -> id ,
'user_id' => $customer -> id ,
'wallet' => null ,
'transaction_id' => $referrerTransaction -> id ?? null ,
'cash' => $referrer_bonus ,
'note' => 'پاداش خرید اول زیرمجموعه' ,
'type' => 1 ,
'gold' => 0 ,
'balance_cash' => 0 ,
'withdraw_id' => $Withdraw -> id ,
]);
}
return false ;
}
2026-06-06 22:06:53 +03:30
private function enforceProductOrderLimits ( array & $data , float $totalPriceRial ) : void
{
$product = $data [ 'product' ] ?? null ;
if ( ! $product instanceof Product ) {
$productId = ( int ) ( $data [ 'abshode_id' ] ?? $data [ 'product_id' ] ?? 0 );
if ( $productId ) {
$product = Product :: find ( $productId );
if ( $product ) {
$data [ 'product' ] = $product ;
}
}
} elseif ( is_array ( $product )) {
$product = Product :: find ( $product [ 'id' ] ?? $data [ 'product_id' ] ?? 0 );
if ( $product ) {
$data [ 'product' ] = $product ;
}
}
if ( $product instanceof Product ) {
$product -> validateOrderCashLimit ( $totalPriceRial );
}
}
2026-01-24 14:03:11 +00:00
}