CookieMonster's avatar

how to group multiple orders as a single entity?

I am using snappy pdf to output a list of items bought by a user on a table in pdf. I want each table to limit only 5 items to display and the subsequent next 5 items will be on the next page with a new table and so on.

I thought of using chunk() to achieve this but my relationship model causes some issues. I have a purchase that can have many orders. Each order can have many items. So if I bought from:

Seller A: Item 1 Item 2

Seller B: Item 3

Seller C: Item 4 Item 5 Item 6

This means I will have 3 orders with 6 items. Though I want to display Item 1-5 in my first table but the chunk() loops each orders as separate, so items in seller A will be in first table and items in seller B will be in second table and so on (with a limit of 5).

My blade code:

  <div class="row ">
            <div class="col-xs-12 pl-1 pr-1">
                     
                <div style="border: 1px solid #000; width: 100%; height: 625px;">
                    @foreach($purchase->orders as $order)
                    @foreach($order->items->chunk(5) as $page)
                    <table style="width: 100%;">
                        <tr style="text-align: center; font-weight: 600;">
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 5%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 624px;"></div>
                                No.
                            </td>
                            <td style="position:relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 12%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 624px;"></div>
                                Product Code
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 53%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 624px;"></div>
                                Description
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 6%">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 624px;"></div>
                                Quantity
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 12%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 624px;"></div>
                                Unit Price (RM)
                            </td>
                            <td style="font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; width: 12%;">Amount (RM)</td>
                        </tr>

                        <?php
                        $iterationNo = 0;
                        ?>
                        
                       
                        {{---Iterate each page--}}
                        @foreach ($page as $item)
                                   
                        <tr style="font-size: 10pt;">  
                        
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                <?php
                                $iterationNo = $iterationNo + 1;
                                
                                ?>
                                {{ $iterationNo }}
                            </td>
                            <td style="padding: 16px; vertical-align: top;">
                                {{ $item->product->parentProduct->product_code }}
                            </td>
                            <td style="padding: 6px; vertical-align: top;">
                                <table>
                                    <tr style="font-size: 10pt;">
                                        <td style="padding: 4px; vertical-align: top;">
                                          
                                            <img src="{{ asset('storage/' . $item->product->parentProduct->images[0]->path . '/' . $item->product->parentProduct->images[0]->filename) }}" alt="{{ $item->product->parentProduct->name }}" style="width: 105px; height: 90px; border-radius: 10px;">
                                        </td>
                                        <td style="padding: 14px; vertical-align: top;">
                                            <p style="margin-bottom: 10px;">
                                                {{ $item->quantity }} x {{ $item->product->parentProduct->name }}
                                            </p>
                                            <p style="margin: 0;">
                                                @if(array_key_exists('product_color_name', $item->product_information))
                                                Color: {{ $item->product_information['product_color_name'] }}
                                                @endif
                                                @if(array_key_exists('product_size', $item->product_information))
                                                Color Temperature: {{ $item->product_information['product_size'] }}
                                                @endif
                                                @if(array_key_exists('product_temperature', $item->product_information))
                                                Color Temperature: {{ $item->product_information['product_temperature'] }}
                                                @endif
                                            </p>
                                        </td>
                                    </tr>
                                </table>
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ $item->quantity }}
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ $item->product->getDecimalPrice() }}
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ number_format(($item->subtotal_price / 100), 2) }}
                            </td>
                        </tr>
                       
                        @endforeach     
                       
                    </table>
                    @endforeach
                    @endforeach
                </div>
            </div>

How do I chunk items as one instead of orders?

0 likes
14 replies
MichalOravec's avatar

@nickywan123 It's impossible what do you want. change your logic that you will have 5 orders in one table, and show all items for each order.

CookieMonster's avatar

Impossible to do what I want you mean?

Because of model relationship?

Would array_slice or array_chunk solve it?

I want to accomplish this issue without messing with the model.

CookieMonster's avatar

@michaloravec He did explain to loop each page of what I want which works if I only make 1 order from 1 seller with items more than 5 items. If there's multiple sellers, then it's gonna treat each order as a new page.

buzzyburrows's avatar

I've done similar where table joins were not cutting it, and there are a few pitfalls to know about.

You want to start with a new empty collection using $items=collect();

Then merge each of your eloquent collections with it using $items->merge($collection_to_merge). Be aware that if you merge eloquent collections directly they will overwrite each other, so create a new collection first, then be sure to merge the eloquent models into it.

Sort if needed using any of the collection sorting methods eg: $items->sortBy('column_name') and reset the key sequence: $items->values()->all() (as it says in the manual).

Lastly in your view file loop through the collection as normal - you can continue to use @foreach($items->chunk(5) as $page) then @foreach($page as $item)

CookieMonster's avatar

@buzzyburrows Do you mean use collect() in my blade file?

Do you mind sharing how it looks for my code?

Cause I don't follow

Snapey's avatar

change your query

Instead of getting purchases with orders, get all the customers orders with the purchase as the child. Then you only have one set to iterate over, and each order can reference purchase details if it needs to.

buzzyburrows's avatar

OK, with the caveat that Snapey and Michaloravec are right - you're better off pulling all items for a customer in 1 query, there might be a situation in which that's not possible - eg skipping returned and pending orders for instance. But in this case I'd add a column to the items table so I could query that instead for completed items.

I'm on my phone right now, so editing code is not so easy. The collect() code goes in the controller, and builds up a collection of all the rows you want to pass to the view. Then pass the collection using view('view_name')->with('items', $items);

Then add the blade loops from my previous message to iterate over the collection and pages.

Not the best solution, and it will potentially require a lot of database calls, but should work

CookieMonster's avatar

@buzzyburrows Ok let me try, as the controller logic is written by a colleague so I need to work on that. So instead of passing purchase(parent), I should pass item (items table) directly straight to my view right?

buzzyburrows's avatar

Right, I understand. Yes, moving the logic to the controller and pulling the items directly from the database will save you a lot of code and make the page load much more quickly.

As others have said you're looking to use the $customers->items relationship so you make a single database request instead of lots.

Good luck!

CookieMonster's avatar

So I changed to passing $orders instead, tried buying two items from two different sellers. Apparently, in my pdf, only the first item displays and the second item missing from one iteration.

CookieMonster's avatar

My new single iteration:

  @foreach($order->items->chunk(5) as $page)
    <table style="table-layout: fixed; border-collapse: collapse; width: 100%;">
        <tr>
            <td>
                <img style="width: 130px; height: auto;" src="{{ asset('images/Invoice-Logo.png') }}" alt="">
            </td>
            {{-- <td style="text-align: right;">
                <img style="height: 100px; width: 100px;" src="data:images/png;base64, {{ base64_encode(QrCode::format('png')->size(100)->generate($url)) }} ">
            </td> --}}
        </tr>
    </table> <br>
    <!-- End Logo / Letterhead -->

    <!-- Document Header -->
    <div class="container-fluid">
        <div class="row">
            <!-- 1st Box -->
            <div class="col-xs-3 pl-1 pr-1">
                <div style="border: 1px solid #000000;">
                    <table style="width: 100%;">
                        <tr>
                            <td colspan="2" style="font-weight: 600; padding: 6px 4px;">
                                Receiver
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2" style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->shippingAddress->address_1 }}
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2" style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->shippingAddress->address_2 }}
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2" style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->shippingAddress->postcode }},
                                {{ $order->purchase->user->userInfo->shippingAddress->city }}
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2" style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->shippingAddress->state->name }},
                                Malaysia
                            </td>
                        </tr>
                        <tr>
                            <td style="font-size: 9pt; font-weight: 600; padding: 4px;">
                                Attention To
                            </td>
                            <td style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->full_name }}
                            </td>
                        </tr>
                        <tr>
                            <td style="font-size: 9pt; font-weight: 600; padding: 4px;">
                                Contact No.
                            </td>
                            <td style="font-size: 9pt; padding: 2px 4px; border-bottom: 1px solid #cccccc; margin: 0;">
                                {{ $order->purchase->user->userInfo->mobileContact->contact_num }}
                            </td>
                        </tr>
                        <tr>
                            <td colspan="2" style="border-bottom: 1px solid #000000;">
                                <div style="height: 5px; width: 100%;">
                                </div>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>

........
......

<div class="row ">
            
            <div class="col-xs-12 pl-1 pr-1">
             
                <div style="border: 1px solid #000; width: 100%; height:625px;">
                  
                    <table style="width: 100%;" >
                        <tr style="text-align: center; font-weight: 600;">
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 5%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 625px;"></div>
                                No.
                            </td>
                            <td style="position:relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 12%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 625px;"></div>
                                Product Code
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 53%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 625px;"></div>
                                Description
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 6%">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 625px;"></div>
                                Quantity
                            </td>
                            <td style="position: relative; font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; width: 12%;">
                                <div style="position: absolute; top: 0; right: 0; margin-right: -1px; border-right: 1px solid #000000; height: 625px;"></div>
                                Unit Price (RM)
                            </td>
                            <td style="font-size: 10pt; padding: 4px; border-bottom: 1px solid #000000; width: 12%;">Amount (RM)</td>
                        </tr>

                        <?php
                        $iterationNo = 0;
                        ?>
                        
                       
                        {{---Iterate each page--}}
                        @foreach ($page as $item)
                        <?php
                        $iterationNo = $iterationNo + 1;
                        
                         ?>
                        <tr style="font-size: 10pt;">  
                        
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                
                                {{ $iterationNo}}
                                
                                
                            </td>
                            <td style="padding: 16px; vertical-align: top;">
                                {{ $item->product->parentProduct->product_code }}
                            </td>
                            <td style="padding: 6px; vertical-align: top;">
                                <table>
                                    <tr style="font-size: 10pt;">
                                        <td style="padding: 4px; vertical-align: top;">
                                          
                                            <img src="{{ asset('storage/' . $item->product->parentProduct->images[0]->path . '/' . $item->product->parentProduct->images[0]->filename) }}" alt="{{ $item->product->parentProduct->name }}" style="width: 105px; height: 90px; border-radius: 10px;">
                                        </td>
                                        <td style="padding: 14px; vertical-align: top;">
                                            <p style="margin-bottom: 10px;">
                                                {{ $item->quantity }} x {{ $item->product->parentProduct->name }}
                                            </p>
                                            <p style="margin: 0;">
                                                @if(array_key_exists('product_color_name', $item->product_information))
                                                Color: {{ $item->product_information['product_color_name'] }}
                                                @endif
                                                @if(array_key_exists('product_size', $item->product_information))
                                                Color Temperature: {{ $item->product_information['product_size'] }}
                                                @endif
                                                @if(array_key_exists('product_temperature', $item->product_information))
                                                Color Temperature: {{ $item->product_information['product_temperature'] }}
                                                @endif
                                            </p>
                                        </td>
                                    </tr>
                                </table>
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ $item->quantity }}
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ $item->product->getDecimalPrice() }}
                            </td>
                            <td style="padding: 16px; text-align: center; vertical-align: top;">
                                {{ number_format(($item->subtotal_price / 100), 2) }}
                            </td>
                        </tr>
                       
                        @endforeach     
                    </table>
                    
                </div>    
            </div>
                            
            </div>
            @if (!$loop->last)
            <div style="page-break-before:always;">
            @endif
            @endforeach



buzzyburrows's avatar

Looks like you're only iterating over 1 order?

@foreach($order->items->chunk(5) as $page)

Are you passing all orders for the customer to the view?

Also once that's fixed you'll end up back where you started where a new $order will start a new page as you'll have 2 loops!

You need to either pull a list of all items from the database (in the table model - I would use joins from 'customers' to 'orders' to 'items'). If that won't work then combine them into a single collection in the controller as I suggested earlier.

CookieMonster's avatar

In my controller: I passed in my $order to the pdf:

   // Generate Invoice PDF.
            // Generate PDF.
            foreach($purchase->orders as $order){
            $pdf = PDF::loadView('documents.purchase.invoice', compact('order'));
            // Get PDF content.
            $content = $pdf->download()->getOriginalContent();
            // Set path to store PDF file.
            $pdfDestination = public_path('/storage/documents/invoice/' . $purchase->getFormattedNumber() . '/');
            // Set PDF file name.
            $pdfName = $purchase->getFormattedNumber();
            // Check if directory exist or not.
            if (!File::isDirectory($pdfDestination)) {
                // If not exist, create the directory.
                File::makeDirectory($pdfDestination, 0777, true);
            }

Please or to participate in this conversation.