Home > Mobile >  Laravel calculate sum of two columns with a condition
Laravel calculate sum of two columns with a condition

Time:09-30

I have this Warehouse collection I got from the database

[
    {
        "id": 1,
        "warehouse": "India"
        "sales": [
            {
                "id": 1,
                "warehouse_id": 1,
                "price": "120.00",
                "quantity": 1000,
                "status": 1
            },
            {
                "id": 2,
                "warehouse_id": 1,
                "price": "20.00",
                "quantity": 100,
                "status": 1
            },
            {
                "id": 3,
                "warehouse_id": 1,
                "price": "40.00",
                "quantity": 1000,
                "status": 2
            }
        ]
    },
    {
        "id": 2,
        "warehouse": "Malaysia"
        "sales": [
            {
                "id": 4,
                "warehouse_id": 2,
                "price": "160.00",
                "quantity": 100,
                "status": 1
            }
        ]
    }
]

I want to calculate the total income for each warehouse

Total income is calculated based on the sale status attribute

If status = 1, the products are delivered so it should add price * quantity to the total income

If status = 2, the products are returned so it should subtract price * quantity from the total income

A basic example for India warehouse:

total_income = 120*1000   20*100 - 40*1000

And for Malaysia:

total_income = 160*100

I tried using Warehouse::withSum(); but it didn't get me anywhere. I'm wondering if there's a good way to do with collections

CodePudding user response:

I honestly would go the route below:

Obviously my solution would have to be modified slightly if you aren't using completely whole numbers (as in your example). The if/else can be broadened out as well if you have more then the 2 statuses.

$total_income = 0;

foreach($warehouses as $warehouse)
{
    foreach($warehouse->sales as $sale)
    {
        if($sale->status = 1)
        {
            $total_income  = ($sale->price * $sale->quantity);
        }else{
            $total_income -= ($sale->price * $sale->quantity); 
        }
    }
}

This is a crude example of what how I would do it. It seems that each 'warehouse' has a different location ex. India vs. Malaysia. My example is more about the grand total, but you could always save the results of each different warehouse in different variables, or as a key/value pair in an array (which is how I would go).

CodePudding user response:

You could just pass a few callbacks to the collection's sum() method:

$warehouses_collection->sum(function ($warehouse) {
    return collect($warehouse->sales)->sum(function ($sale) {
            ((int) $sale->price) * $sale->quantity * ($sale->status == 1 ? 1 : -1)
        });
});

WithSum is a bit tricky to use here but calling withAggregate works.

Warehouse::withAggregate(
    'sales as total_income',
    'sum(case when status = 1 then convert(int, price) * quantity when status = 2 then convert(int, price) * quantity * -1 else 0 end)'
)->get() 
  • Related