Problem with value as integer - shows different values
Hi!
I am having an issue storing order data in the database. I convert all amounts to cents to be stored as integer in the database. The field net_amount has the value of 246320 and tax_amount has 61580, both set as integers.
When combining these like this: $order->net_amount + $order->tax_amount I get the result: 307900.0
But to remove the decimal point, I cast it to integers: (int) $order->net_amount + (int) $order->tax_amount I get the result: 307898
The issue you're facing is due to the order of operations in your code. When you cast the values to integers separately, you're performing the addition after the casting. To fix this, you need to group the addition operation before casting the result to an integer.
Here's the corrected code:
(int) ($order->net_amount + $order->tax_amount)
By wrapping the addition operation in parentheses, you ensure that the addition is performed first, and then the result is cast to an integer. This will give you the correct result of 307900.
"... both set as integers. When combining these like this: $order->net_amount + $order->tax_amount I get the result: 307900.0" - if they are both integers their sum can't be float. At least one of your values is a float.
@krisi_gjika You are right in a sense, when I do gettype() for both variables, it returns double. But it is stored as integer in the database. Where is that conversion happening?
I now tried casting them to integer in the model, and that changed the type, but I still get the value 307898 after doing $order->net_amount + $order->tax_amount.
@eriktobben either your model casts, some model attribute/accesor or somewhere in your business logic. Please provide more code of what you are doing, how you are storing/retrieving the data.
When only doing (int) $order->net_amount the value is 246319 which is 246320 in the database. So it seems like the issue is happening with the value of net_amount .
@DhPandya Hi! That is correct, but the value in the database is 246320 + 61580 = 307900. I have checked that the database field is integer, and that net_amount and tax_amount is cast to integer in the model.
The issue is that there is a 2 cent different shown in PHP compared to the database. 307898 (php) - 307900 (db) = -2
@eriktobben Have you tried using number_format(246320,2); ?
If you want to store decimal values in your database then you should set the type of your column to decimal.
Like decimal(8,2)
@Snapey Including tax the value should be NOK 3079 (after /100). Using Table Plus the values are 246320 (net_amount) and 61580 (tax_amount) = 307900 / 100 = 3079.
Both database fields are integer, and gettype() returns 'Integer' on both fields, but in PHP the value is still 307898. If I remove the cast to integer it shows 307900.0
It looks like each field is showing 1 less making the total 2 less than expected when casting to integer in PHP.
@eriktobben The reason you are missing two cents when you cast the values to integers is due to the way PHP handles floating-point numbers and type casting.
In PHP, when you cast a floating-point number to an integer using (int), it truncates the decimal portion without rounding. So, in your case, when you cast $order->net_amount and $order->tax_amount to integers separately and then add them, you are effectively truncating the cents part of each value separately. This can lead to a loss of precision in the final result.
class Order extends Model
{
use HasFactory, SoftDeletes;
protected $casts = [
'payment_authorized_at' => 'datetime',
'net_amount' => 'integer',
'tax_amount' => 'integer',
];
public function items(): HasMany
{
return $this->hasMany(OrderItem::class, 'order_id');
}
public function company(): BelongsTo
{
return $this->belongsTo(Company::class, 'company_id');
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function files(): HasMany
{
return $this->hasMany(OrderFile::class, 'order_id');
}
public function shipments(): HasMany
{
return $this->hasMany(OrderShipment::class, 'order_id');
}
public function transactions(): HasMany
{
return $this->hasMany(OrderTransaction::class, 'order_id');
}
public function paymentMethod()
{
return (new PaymentService)->getMethod($this->payment_method_id);
}
public function orderAmounts()
{
return [
'net_amount' => $this->net_amount,
'tax_amount' => $this->tax_amount,
'total' => $this->net_amount + $this->tax_amount,
];
}
}
@Snapey That is weird. I have just dd'ed $order->net_amount, $order->tax_amount or $order->orderAmounts()
So I would assume that $order->net_amount straight from the Eloquent query should not modify the data type from the database unless it is set in the $casts array, right? Or are there other places which can manipulate the data?
I also assume that no matter what the data type is when storing the data to the database, the data would be converted to the fields data type? So if the net_amount value was a float at save, as long as the field type is integer in the database and the value is correct in the database it would not carry over when retrieving the data?
I think I found the issue. I thought that the Order resource was retrieved from the database, when in fact the resource was returned from the store logic, which (I didn't know this) seems to only return the values added when creating the resource, not data from the resource itself. So when it stored the original values from PHP (which is float) to the database (which is integer) it returns the model with the fields set as float.
This also means that the values in the database is correct as the type is set to integer.
When I fetched the model again from the database it returns the correct types and thus the correct values.
I want to thank all of you for helping me with this issue, and I'm sorry if this is common knowledge, but this was news to me.