Help checking 'balance' after 'wallet'

I am using a php web video script which allows Users to purchase videos successfully. The purchases are made from the amount available in the Users’ “wallet” (the User can also earn compensation, which gets added to his “balance”.). When there’s not enough available in the “wallet” for the purchase, the script checks and displays a message “not enough money”. I’d like help adding the ability where the script first checks the “wallet” amount, and if empty will then check the “balance” amount, and use a required amount from the balance, and if both are empty, then the “not enough money” appears. Here’s the portion of the code that I believe needs the modification:

 // get cost video
    $db->where('name', 'video_play_price');
    $db_cost = $db->getOne('config');
    $video_cost = (float)$db_cost->value;

    $count_video = count($id_array);
    $user_id = $user->id;
    $wallet = (float)str_replace(',', '', $user->wallet);


	$amout = 0;
	foreach ($id_array as $id) {
            $video_id = (int)PT_Secure($id);

            // get video data
            $video = $db->where('id', $id)->getOne(T_VIDEOS);
			$amout += $video->video_play_price?$video->video_play_price:$video_cost;
	}

//   $amout = $video_cost * $count_video;

    $charge = ( $video_cost *0.50 );



    if ($wallet >= $amout) {

        //$new_wallet = (string)($wallet - $amout);
        $wallet = (string)($wallet - $amout);

        $db->startTransaction();

        $inserted_records = 0;
        foreach ($id_array as $id) {
            $video_id = (int)PT_Secure($id);


		// $uploader_amount = $video_cost - $charge; //100 - 20% = 80

            // get video data
            $video = $db->where('id', $id)->getOne(T_VIDEOS);



			$video_cost_new = $video->video_play_price?$video->video_play_price:$video_cost;

			$uploader_amount = ( $video_cost_new *0.50 );
            // add data to paid table
            $insert_buy = $db->insert('u_paid_videos', [
                'id_user' => $user_id,
                'id_video' => $video_id,
                'session_key' => $_SESSION['session_key'],
                'video_play_price' => (string)$video_cost,
                'video_title' => $video->title,
                'user_id_uploaded' => $video->user_id,
            ]);

            if ($insert_buy) { $inserted_records++; }
            //add wallet users' video
        $userwallet = $db->where('id', $video->user_id)->getOne(T_USERS);


        //$videouserwallet = $userwallet->balance+$video_cost;
        $videouserwallet = $userwallet->balance+$uploader_amount;
        $db->where('id', $video->user_id);
        $update_balance = $db->update(T_USERS, [
          // 'wallet' => $videouserwallet,
            'balance' => number_format($videouserwallet, 1, '.', ''),
        ]);
        }


        $db->where('id', $user_id);
        //$update_wallet = $db->update(T_USERS, [
        $update_wallet = $db->update(T_USERS, [
            'wallet' => $wallet,
        ]);


        if (($inserted_records == $count_video) && $update_wallet) {
            $db->commit();

            echo json_encode([
                'status' => 200
            ]);
            exit();
        } else {
            $db->rollback();

            echo json_encode([
                'status' => 400,
                'error' => 'Buy process error'
            ]);
            exit();
        }

    } else {

        echo json_encode([
            'status' => 400,
            'error_num' => 1,
            'error' => 'Not enough money'
        ]);
        exit();

    }

} else {

    echo json_encode([
        'status' => 400,
        'error' => 'Bad Request, Invalid or missing parameter'
    ]);
    exit();

I’d like to try this question again:
Currently, with the php web script that I’m using, this code works successfully (where the ‘wallet’ amount is used to buy videos).

// get cost video
	$db->where('name', 'video_play_price');
	$db_cost = $db->getOne('config');
	$video_cost = (float)$db_cost->value;

	$count_video = count($id_array);
	$user_id = $user->id; // copy the user id for some reason

	$wallet = (float)str_replace(',', '', $user->wallet);

	$amount = 0;
	foreach ($id_array as $id) {

		$video_id = (int)PT_Secure($id);

		// get video data
		$video = $db->where('id', $id)->getOne(T_VIDEOS);

		$amount += $video->video_play_price?$video->video_play_price:$video_cost;
	}

	if ($wallet >= $amount) {

		$wallet = (string)($wallet - $amount);

		$db->startTransaction();

When videos are purchased the uploader of the video gets some earnings.I’m trying to modify it so that when the ‘wallet’ amount isn’t enough to make the purchase, the ‘earnings’ of the User are used for the purchase. So, I tried this without success:

if($wallet + $earnings >= $amount) {
$wallet = (string)($wallet - $amount);
$db->startTransaction();

By ‘without success’, I mean that the same message appears as if just the ‘wallet’ doesn’t have enough “Not Enough Money” - when I test by having 3 in ‘wallet’ and 3 in earnings (equals a total of 6) but try to purchase something that costs 5.

Any ideas suggestion will be appreciated

Why are you casting $wallet as a string?

Why do you not modify the amount in $earnings?

Have you verified your values in $wallet, $earnings, and $amount?

Much thanks for your reply.
I didn’t write this file code. I know that it works successfully casting $wallet as a string.
I’m not sure how to ‘modify the amount in $earnings’
I have checked the balances of wallet and earnings with every test I perform

Any other help/suggestion will be welcomed.

I mean… if you dont know the basics of how to do math in PHP, then i’m afraid you’re just asking for someone to do your code for you.

I really don’t know how to help you at this point, because i’m not going to write your code for you. I wish you luck with others.

1 Like

Thanks for your reply.
I am learning as I go. I don’t expect anyone to write the code for me.
I would like a hint or some guidance, even a guess, please (as to why this is still showing ‘not enough money’, when the wallet is 0, and the earnings is 3, when I try to purchase with a cost of 2), with this revised attempted code:

	if ($wallet >= $amount) {
		$wallet = (string)($wallet - $amount);
		} elseif ($wallet + $earnings >= $amount) {
		$earnings = (string)($earnings - $amount);
		$db->startTransaction();

It’s just 5 lines of code, fill the variables with dummy data and have a look what happens.

How do those values relate to the variable names in your code? I can guess about $wallet and $earnings, am I to presume that the cost is stored in $amount? If so, why don’t you call it $cost, or refer to it as “the amount” to make things clearer?

In the code you posted, presuming that the cost is in $amount, and using the figures you showed, your code will run into the elseif part of the code, and it will subtract the cost from $earnings instead of from $wallet. At that point, you then start the transaction. However, because you haven’t closed the curly-brace for the elseif(), the transaction doesn’t get started if the amount is deducted from the wallet. This seems like an oversight to me, unless it’s elsewhere in the code. I would think the close-brace should go before the startTransaction() line.

But, I see a flaw in your logic here. What happens in this situation?

Wallet = 3
Earnings = 2
Cost (or Amount) = 4

Do you really want your earnings to go negative, or wouldn’t you want to deduct as much of the cost from your earnings, then deduct the remainder from your wallet? In fact, to me the logic seems the wrong way around (though I don’t know what your sites Ts and Cs say) - if I’ve earned money from somewhere (my ‘earnings’) I’d want to use that first when I want to buy something, not after I’ve used my wallet (which presumably is money I’ve actually paid in).

To me the pseudo-code would be something like

if (cost < earnings) 
   subtract cost from earnings
else if (cost < earnings + wallet)
   subtract earnings from cost
   set earnings to zero
   subtract remainder from wallet
else
   not enough money

Or if your site really does need to use wallet before earnings, you could swap them around in the above for that scenario.

Are you familiar with the term “dry run”? It’s used to describe manually running through your code with test values as @chorn suggested, doing the calculations and seeing that you get the results you want. On a piece of paper, long before you write any code. I think that would be a good thing for you to do in this case, once you have a section of code on paper that behaves correctly for your test values, then you can write it in PHP on your test environment and see that it still works with your test data. Then, when you know your code works, you can try to insert it into the code you didn’t write.

Thanks for your replies.
I have tried what has been suggested (and many other attempts) without success.

I see a pop-up dialog box that displays: “Something went wrong. Please try again later!!” (from the script.js file):

function PT_MultipleBuyVideo() {
    var checked = getSelectedVideos();
    if (!checked) { return false; }

    swal({
        title: "",
        type: "info",
        html:"Simply proceed to purchase " + countSelectedVideos() + " video(s) at a total cost of " + countTotalCredits() +" credits",
        showCancelButton: true,
        cancelButtonText: "Close",
        customClass: 'sweetalert-lg',
        confirmButtonText:'Proceed'
    }).then(function(){

        $.ajax({
            url: PT_Ajax_Requests_File() + 'aj/buy-video',
            type: 'POST',
            dataType: 'json',
            data: {id:checked},
        }).done(function(data){
            if (data.status == 200) {
                for (var i = 0; i < checked.length; i++) {
                    var button = $("button[data-action='multiple_select_button'][data-id='" + checked[i] + "']")
                    buttonMultipleSelectingStyle(button, 'purchased');
                }

                swal({
                    title: "Success",
                    type: "success",
                    html:"",
                    showCancelButton: true,
                    cancelButtonText: "Close",
                    customClass: 'sweetalert-lg',
                    confirmButtonText:'Go To Video(s)'
                }).then(function(){
                    window.location.href='/paid-list';
                });

            } else {
                if (data.error_num == 1) {
                    swal(
                        'Error!',
                        'Not enough money(test)',
                        'error'
                    );
                } else {
                    swal(
                        'Error!',
                        'Something went wrong. Please try again later!',
                        'error'
                    );
                }
            }
        }).fail(function() {
            swal(
                'Error!',
                'Something went wrong. Please try again later!!',
                'error'
            );
        })
    });
}

Currently, I have this working to some degree:

		if($wallet + $earnings >= $amount) {
		$wallet = (string)($wallet - $amount);
		$wallet = 0;
		$earnings = (string)($earnings - $amount);

		$db->startTransaction();

Presently, this proceeds as a ‘successful’ transaction, but brings ‘wallet’ to 0, and ‘earnings’ is deducted from. Any curly bracket added causes a message from the js file “Something went wrong. Please try again later!!”, as does adding any “else”, any additional “if”, or “elseif”

It may be of use to show the code from the top thru $db->start transaction:

<?php
ob_start();
if (IS_LOGGED == false) {
    $data = array('status' => 400, 'error' => 'Not logged in');
    echo json_encode($data);
    exit();
}

if (!empty($_POST['id'])) {

    if (!is_array($_POST['id'])) {
        $id_array[] = $_POST['id'];
    } else {
        $id_array = $_POST['id'];
 }

	// get cost video
	$db->where('name', 'video_play_price');
	$db_cost = $db->getOne('config');
	$video_cost = (float)$db_cost->value;

	$count_video = count($id_array);

	$wallet = (float)str_replace(',', '', $user->wallet);
	$earnings = (float)str_replace(',', '', $user->earnings);

	// add up the video prices
	$amount = 0;
	foreach ($id_array as $id) {

		$video_id = (int)PT_Secure($id);

		// get video data
		$video = $db->where('id', $id)->getOne(T_VIDEOS);
		$amount += $video->video_play_price?$video->video_play_price:$video_cost;
	}

		if($wallet + $earnings >= $amount) {
		$wallet = (string)($wallet - $amount);
		$wallet = 0;
		$earnings = (string)($earnings - $amount);
		$db->startTransaction();

I look forward to any additional assistance. Thanks again

With this line of code in the short code snippet directly above that sentence

$wallet = 0;

you surely cannot be surprised that it sets the wallet to zero? As the line immediately before it deducts the $amount from $wallet, surely one of them is incorrect? If you’re about to zero the wallet, there’s no point deducting anything from it just beforehand. And if the subtraction is correct, why would you then zero it?

You can’t just add random brackets, elses, ifs to see if it helps. You need to have exactly the correct number of them. I did say that it appears that a close-brace is missing, but I also commented that it might just not have been in the forum post.

That tells you that the call to your PHP script has failed. It’s hard to tell why that is - your PHP code does echo some stuff out, but your error message doesn’t show it. It might just be because the user isn’t logged in, or it might be something else.

I still don’t understand the logic of this code:

		if($wallet + $earnings >= $amount) {
		$wallet = (string)($wallet - $amount);
		$wallet = 0;
		$earnings = (string)($earnings - $amount);

Written out in pseudo-code, you are saying:

if the wallet and the earnings is greater than the amount:
   subtract the amount from the wallet
   zero the wallet
   subtract the amount also from earnings

That means that it will only work properly if both the wallet and the earnings are greater than the amount - if either is not greater or equal, then that value will go negative. Crucially, though, you’re subtracting the amount twice, so the user seems to be paying twice. That seems, shall we say, unfair.

Do a dry run through that pseudo code with some test values and see what I mean.

1 Like

Thank you for your reply and explanation/help. Much appreciated.
Yes, I know the line sets wallet to zero. Just wanted to see if that line could be improved by someone who knows more. And yes, I know you can’t just add brackets randomly. Was trying to say any that it wasn’t missing a bracket.

And yes, the php has failed. I agree. Because that “Something went wrong…” message is coming form the js file (code posted earlier),
It was also suggested that:
the PHP code is sending back a value called “status” from what Javascript code is checking. It’s coming from PHP. The error message “Something went wrong…” only gets shown if data.status is not 200, and if data.error_num is 1. So, that’s what PHP is sending. It’s sending a status that is not 200, and a value for error_num of 1. To know why that Javascript is showing that, look at the PHP code to figure out what status it is sending, and why.

I’ve have looked at the file, but can’t tell. If anyone is interested in looking to provide a suggestion as to where the code might be creating that status, it would be greatly appreciated, here it is:

<?php
ob_start();
if (IS_LOGGED == false) {
    $data = array('status' => 400, 'error' => 'Not logged in');
    echo json_encode($data);
    exit();
}

if (!empty($_POST['id'])) {

if (!is_array($_POST['id'])) {
    $id_array[] = $_POST['id'];
} else {
    $id_array = $_POST['id'];
 }

// get cost video
$db->where('name', 'video_play_price');
$db_cost = $db->getOne('config');
$video_cost = (float)$db_cost->value;

// the number of submitted videos - used to determine if all records were inserted
$count_video = count($id_array);

$wallet = (float)str_replace(',', '', $user->wallet);
$earnings = (float)str_replace(',', '', $user->balance);

// add up the video prices
$amount = 0;
foreach ($id_array as $id) {

	$video_id = (int)PT_Secure($id);

	// get video data
	$video = $db->where('id', $id)->getOne(T_VIDEOS);
	// add the video play price if any, or the default price
	$amount += $video->video_play_price?$video->video_play_price:$video_cost;
}

	if($wallet + $earnings >= $amount) {
	$wallet = (string)($wallet - $amount);
	$earnings = (string)($earnings - $amount);

	$db->startTransaction();

	$inserted_records = 0;
	foreach ($id_array as $id)
	{

		$video_id = (int)PT_Secure($id);

		// get video data
		$video = $db->where('id', $id)->getOne(T_VIDEOS);

		// use the video play price if any, or the default price
		$video_cost_new = $video->video_play_price?$video->video_play_price:$video_cost;

		// add data to paid table
		$insert_buy = $db->insert('u_paid_videos', [
			'id_user' => $user_id,
			'id_video' => $video_id,
			'session_key' => $_SESSION['session_key'],
			'video_play_price' => (string)$video_cost, // the cost at the time of purchase // this is the default video cost not the $video_cost_new
			'video_title' => $video->title, // storing the title
			'user_id_uploaded' => $video->user_id, // the user who uploaded the video
			]);

		// count successful inserted records
		if ($insert_buy) {
			$inserted_records++;
		}

		//update the 'balance' of the user who uploaded the video
		// get the user's record
		$userwallet = $db->where('id', $video->user_id)->getOne(T_USERS);

		// credit the user 50% of the video cost
		$uploader_amount = $video_cost_new *0.50;

		// add to the balance
		$videouserwallet = $userwallet->balance+$uploader_amount;
		// update the record
		$db->where('id', $video->user_id);
		$update_balance = $db->update(T_USERS, [
			'earnings' => number_format($videouserwallet, 1, '.', ''),
		]);
	}

	// update the current user's wallet amount
	$db->where('id', $user_id);
	$update_wallet = $db->update(T_USERS, [
		'wallet' => $wallet,
	]);

	// if all the video records were inserted and the current user's wallet was updated, commit the changes
	if (($inserted_records == $count_video) && $update_wallet) {
		$db->commit();

		echo json_encode([
			'status' => 200
		]);
		exit();
	} else {
		$db->rollback();

		echo json_encode([
			'status' => 400,
			'error' => 'Buy process error'
		]);
		exit();
	}

} else {

	echo json_encode([
		'status' => 400,
		'error_num' => 1,
		'error' => 'Not enough money'
	]);
	exit();
}

} else {
	echo json_encode([
		'status' => 400,
		'error' => 'Bad Request, Invalid or missing parameter'
		]);
	exit();

echo('$video_play_price: '.$video_play_price.PHP_EOL);
echo('$charge: '.$charge.PHP_EOL);
echo('$amount: '.$amount.PHP_EOL);
$uploader_amount = $video_play_price - $charge;
$uploader_amount = $amount - $charge;
exit;

echo "$uploader_amount";

}

Not quite. The message you posted at the start of this thread is shown as part of your .fail() handling, so that means that a status code of 200 is not being returned, correct. But in that section of code, you do not check the value of data.error_num at all, so it could be anything.

If your PHP code does return status 200, and your data.error_num does not equal 1, then you display a very similar error message, but not the one you said it was displaying.

Perhaps you could change one of the two almost-identical error messages that your JS code displays for two different scenarios, just to clarify things.

What status is it returning, if it is not 200?

This is still confusing

$wallet = (string)($wallet - $amount);
	$earnings = (string)($earnings - $amount);

subtracting the amount from earnings and wallet.

I am getting confused now as to what is going on. More error information is needed for anyone to help. I think. If you can say what the status returned is, that points to a specific part of the code, though there are several areas that return the same thing. Would help to narrow it down though.

Thanks for your reply and help. Much appreciated.
This seems to work successfully, where a purchase uses the amount in ‘wallet’ first, and then uses the amount in ‘earnings’ if there is not enough in ‘wallet’

		// Check if user has enough wallet amount to purchase video
		if($wallet >= $amount){

			$wallet = (string)($wallet - $amount);
			$db->where('id', $user_id);
			$update_wallet = $db->update(T_USERS, [
				'wallet' => $wallet
			]);
		}else{

			// Check if user has enough earnings amount to purchase video
			if($earnings >= $amount){
				$earnings = (string)($earnings - $amount);
	
				$db->where('id', $user_id);
				$update_user_balance = $db->update(T_USERS, [
					'earnings' => $earnings
				]);
			}
		}

however, if all videos cost 2 (or higher), and there is “1” left in the ‘wallet’, it will never get used. I am looking to see how I can make more like if ‘wallet’ is zero then deduct from ‘earnings’ (or wallet + earnings = amount)…

I have tried this revision without success:

if($wallet + earnings >= $amount){

			$wallet = (string)($wallet - $amount);
			$db->where('id', $user_id);
			$update_wallet = $db->update(T_USERS, [
				'wallet' => $wallet
			]);
		}else{

			// Check if user has enough balance amount to purchase video
			if( ($wallet <=1) and ($earnings >= $amount) ) {
			//if($earnings >= $amount){
				$earnings = (string)($earnings + wallet - $amount);

				$db->where('id', $user_id);
				$update_user_balance = $db->update(T_USERS, [
					'earnings' => $earnings
				]);
			}
		}

Any ideas/suggestions will be appreciated.

As you say, while the code you post runs successfully for certain numbers, it will not run for all values. If you ever hit a situation where the cost is higher than either the wallet, or the earnings, but not both combined, your code will reject the purchase.

All I can do is point you back to the description I posted a few days ago.

This will use the money from the earnings first, then the wallet. If you want it the other way around, wallet first, then earnings, you can swap things around to make it work that way.

The problem you have in your revision as posted above is that you check to see whether “wallet + earnings” can afford the purchase, but then if they have you only deduct the amount from the wallet, not from the earnings. You need to deduct as much as you can from the wallet, then deduct the rest from the earnings, if you want to use the wallet first. Unless you don’t mind one or both going negative, that is.

I don’t understand your else clause at all. Surely if “wallet + earnings” is not >= the amount, then the user does not have enough funds? Inside your else, you check to see if they can afford the purchase just from their earnings (which will never be true, because if it was, the initial if would have been true), then you add the wallet amount to the earnings and deduct the amount. You don’t then zero the wallet, so whatever was in the wallet gets duplicated. Or it would, if there wasn’t a typo in the line - don’t you get an error message for that?

Like I said earlier, dry run through your code with some test values and you can see where it’s going astray from what you need.

… and all these cases are so damn easy to test: just put the logic into a function, three parameters, and loop over arrays with dummy data.

1 Like

Thanks for your replies.

I am still getting a ‘not enough money’ message with this:

		if($wallet >= $amount){

			$wallet = (string)($wallet - $amount);
			$db->where('id', $user_id);
			$update_wallet = $db->update(T_USERS, [
				'wallet' => $wallet
			]);

			} else {

			if($wallet < $amount && $wallet + $earnings >= $amount){

			$wallet = (string)($wallet - $amount) + $earnings = (string)($earnings - $amount);

							$db->where('id', $user_id);
							$update_user_balance = $db->update(T_USERS, [
								'earnings' => $earnings
								]);
							$db->where('id', $user_id);
							$update_wallet = $db->update(T_USERS, [
							'wallet' => $wallet
							]);
						}
			}

Any additional guidance will be appreciated.

(regarding “logic into function…”, etc… I’m sure you are right, but I don’t know how to do that)

You can turn virtually any chunk of php code into a custom function so it may be re-used over and over in your project.

function MyFunction($inputParameters, $asManyAsYouNeed){

    // Whatever code you want to use the process the input data

    return $valueYouWantToReturn ;
}

Then call it as and when you need it.

$result = MyFunction($param1, $param2);

More here:-
http://php.net/manual/en/functions.user-defined.php

What are you trying to do with this line? Probably not what you intend.

$wallet = (string)($wallet - $amount) + $earnings = (string)($earnings - $amount);

Once that line is fixed, I suspect it will still deduct $amount from both user fields, which seems to me that you’re charging double.

Thanks again for your message. I appreciate it.

I’m trying to say this;
if what’s in the ‘wallet’ is less than the amount AND earnings has more than or equal to the amount:

if($wallet < $amount && $wallet + $earnings >= $amount){

then proceed to deduct whatever is left in wallet to satisfy the amount + the balance of the amount from earnings:

$wallet = (string)($wallet - $amount) + $earnings = (string)($earnings - $amount);

but, apparently I need to say this better in code:
“then proceed to deduct whatever is left in wallet to satisfy the amount + the balance of the amount from earnings”

any additional help is greatly appreciated.

Yes, that’s nothing like what that code is doing. I started to write out what that line does, but I cannot - perhaps someone with more PHP knowledge can explain it better than when I just say it’s “wrong”. The first thing that should ring alarm bells is that you have an assignment operator (=) in the middle of a formula. That’s sometimes correct, but I don’t think so here. I did a test run of this line with some values and it didn’t do what I think you wanted.

What’s the issue with using the pseudo-code I posted and converting that to actual code?