@php // Scaling is restricted to regular sales invoices, not proformas or cash documents. $allowsPdfScaling = !($isProforma ?? false) && ($sale->mode ?? null) === 'bill' && ($sale->bill_type ?? null) === 'bill'; $pdfScale = $allowsPdfScaling && in_array($pdfScale ?? 100, [50, 60, 70, 80, 90, 100], true) ? $pdfScale : 100; $scaleRatio = $pdfScale / 100; $scaledPaddingY = number_format(2 * $scaleRatio, 1, '.', ''); $scaledPaddingX = number_format(4 * $scaleRatio, 1, '.', ''); @endphp @php // Determine if inter-state (IGST) or intra-state (CGST+SGST) // SEZ buyers are always treated as inter-state supply under GST → always IGST. $companyState = strtolower(trim($company->state ?? 'Maharashtra')); $partyState = strtolower(trim($sale->party->state ?? '')); $isInterState = ($companyState !== $partyState && !empty($partyState)) || ($sale->party->is_sez ?? false); // Get state code from GSTIN if available (first 2 digits) $companyStateCode = $company->state_code ?? (strlen($company->gstin ?? '') >= 2 ? substr($company->gstin, 0, 2) : '27'); $partyStateCode = strlen($sale->party->gst_number ?? '') >= 2 ? substr($sale->party->gst_number, 0, 2) : ''; // State code mapping $stateCodes = [ '01' => 'Jammu and Kashmir', '02' => 'Himachal Pradesh', '03' => 'Punjab', '04' => 'Chandigarh', '05' => 'Uttarakhand', '06' => 'Haryana', '07' => 'Delhi', '08' => 'Rajasthan', '09' => 'Uttar Pradesh', '10' => 'Bihar', '11' => 'Sikkim', '12' => 'Arunachal Pradesh', '13' => 'Nagaland', '14' => 'Manipur', '15' => 'Mizoram', '16' => 'Tripura', '17' => 'Meghalaya', '18' => 'Assam', '19' => 'West Bengal', '20' => 'Jharkhand', '21' => 'Odisha', '22' => 'Chhattisgarh', '23' => 'Madhya Pradesh', '24' => 'Gujarat', '26' => 'Dadra and Nagar Haveli', '27' => 'Maharashtra', '29' => 'Karnataka', '30' => 'Goa', '31' => 'Lakshadweep', '32' => 'Kerala', '33' => 'Tamil Nadu', '34' => 'Puducherry', '35' => 'Andaman and Nicobar', '36' => 'Telangana', '37' => 'Andhra Pradesh', '38' => 'Ladakh', ]; // Get default bank account for the company $bankAccount = $company->defaultBankAccount(); $pfAmt = $sale->pf_amount ?? 0; $pfTax = $sale->pf_tax_amount ?? 0; // Adjusted tax analysis including P&F $adjTaxAnalysis = $taxAnalysis->values()->toArray(); if ($pfAmt > 0 && count($adjTaxAnalysis) > 0) { $adjTaxAnalysis[0]['taxable_value'] += $pfAmt; $adjTaxAnalysis[0]['total_tax'] += $pfTax; if (!$isInterState) { $adjTaxAnalysis[0]['cgst_amount'] += $pfTax / 2; $adjTaxAnalysis[0]['sgst_amount'] += $pfTax / 2; } } $taxTableTotal = collect($adjTaxAnalysis)->sum('total_tax'); // Pagination: split items into page chunks // Page 1 has company+buyer header = fewer item rows (~15) // Page 2+ has only compact header = more item rows (~30) // Both pages have full header, so same item capacity $shipSameAsBilling = !$sale->shippingAddress || ( trim((string) $sale->shippingAddress->address) === trim((string) $sale->party->billing_address) && (string) $sale->shippingAddress->pincode === (string) $sale->party->pincode ); $allItems = $sale->items->values(); $totalItems = $allItems->count(); $itemsPerPage1 = (int) floor(($allItems->count() > 20 ? 30 : 18) / $scaleRatio); // When a separate Ship to block is rendered on page 1, it consumes ~3 rows of vertical space if (!$shipSameAsBilling) { $itemsPerPage1 = max(1, $itemsPerPage1 - 3); } $itemsPerPage2 = (int) floor(18 / $scaleRatio); $itemPages = []; if ($totalItems <= $itemsPerPage1) { $itemPages[] = $allItems; } else { $itemPages[] = $allItems->slice(0, $itemsPerPage1)->values(); $remaining = $allItems->slice($itemsPerPage1)->values(); while ($remaining->count() > 0) { $itemPages[] = $remaining->slice(0, $itemsPerPage2)->values(); $remaining = $remaining->slice($itemsPerPage2)->values(); } } $totalPages = count($itemPages); @endphp @php $copyLabels = ($isProforma ?? false) ? ['(NOT A TAX INVOICE)'] : ['(ORIGINAL FOR RECIPIENT)', '(DUPLICATE FOR SUPPLIER)']; @endphp @foreach($copyLabels as $copyIndex => $copyLabel) @if($copyIndex > 0)
@endif @for($pageNum = 0; $pageNum < $totalPages; $pageNum++) @php $pageItems = $itemPages[$pageNum]; $isFirstPage = ($pageNum === 0); $isLastPage = ($pageNum === $totalPages - 1); $startIndex = $isFirstPage ? 0 : $itemsPerPage1 + (($pageNum - 1) * $itemsPerPage2); // Filler rows for last page $maxSlots = $isFirstPage ? $itemsPerPage1 : $itemsPerPage2; $usedSlots = 0; foreach ($pageItems as $itm) { $nameLen = strlen($itm->product->name ?? 'Product'); $usedSlots += $nameLen > 30 ? 2 : 1; } $fillerRows = $isLastPage ? max(0, $maxSlots - $usedSlots) : 0; @endphp @if($pageNum > 0)
@endif {{-- Header --}} @if($sale->party->is_sez) @endif
{{ ($isProforma ?? false) ? 'PROFORMA INVOICE' : 'GST INVOICE' }} {{ $copyLabel }}
(SUPPLY MEANT FOR EXPORT/SUPPLY TO SEZ UNIT OR SEZ DEVELOPER FOR AUTHORISED OPERATIONS UNDER BOND OR LETTER OF UNDERTAKING WITHOUT PAYMENT OF IGST) @if($sale->arn_no)
ARN No: {{ $sale->arn_no }} @endif
{{-- Full company + buyer + invoice details header (repeats on every page) --}}
{{-- Company Details --}}
@if(!empty($logoBase64)) @elseif($company->logo_path) @endif
{{ $company->legal_name ?? $company->name }}
{{ $company->billing_address }}
GSTIN: {{ $company->gstin }} | State: {{ $company->state ?? 'Maharashtra' }}
Ph: {{ $company->phone }} | {{ $company->email }}@if($company->website) | {{ $company->website }}@endif
@if($sale->party->is_sez) @php $companyLut = $company->activeLutOn($sale->invoice_date); @endphp @if($companyLut)
LUT No. : {{ $companyLut->lut_number }}   From: {{ $companyLut->valid_from->format('d-m-Y') }}   To: {{ $companyLut->valid_to->format('d-m-Y') }}
@endif @endif @if($company->msme_number)
MSME/Udyam : {{ $company->msme_number }}
@endif
{{-- Buyer Details --}}
Buyer (Bill to)
{{ $sale->party->name }}
{{ $sale->party->billing_address }}
{{ $sale->party->state }} - {{ $sale->party->pincode }}, India
GSTIN/UIN : {{ $sale->party->gst_number ?? 'Unregistered' }}   State Name : {{ $sale->party->state ?? '' }}
Contact : {{ $sale->party->mobile }}@if($sale->party->contact_person)   Contact Person : {{ $sale->party->contact_person }}@endif
@if($sale->party->msme_number)
MSME/Udyam No. : {{ $sale->party->msme_number }}
@endif
{{-- Ship To — only shown if a separate shipping address differs from billing --}} @if(!$shipSameAsBilling)
Ship to
{{ $sale->shippingAddress->address }}
@if($sale->shippingAddress->pincode)
Pincode: {{ $sale->shippingAddress->pincode }}
@endif @if($sale->shippingAddress->contact_person || $sale->shippingAddress->mobile)
@if($sale->shippingAddress->contact_person)Contact : {{ $sale->shippingAddress->contact_person }}@endif @if($sale->shippingAddress->mobile)   Mob : {{ $sale->shippingAddress->mobile }}@endif
@endif
@endif
Invoice No.
{{ $sale->bill_no ?? $sale->proforma_no }}
Dated
{{ $sale->invoice_date->format('d-M-y') }}
Buyer's Order No.
{{ $sale->buyer_order_no ?? '' }}
Dated
{{ $sale->buyer_order_date ?? '' }}
Delivery Note
{{ $sale->delivery_note ?? '' }}
Delivery Note Date
{{ $sale->delivery_note_date ? $sale->delivery_note_date->format('d-M-y') : '' }}
Dispatched through
{{ $sale->dispatched_through ?? $sale->party->transportation_name ?? '' }}
Mode/Terms of Payment
{{ $sale->party->payment_type === 'credit' ? '15 Days' : '100% Advance' }}
Destination
{{ $sale->destination ?? $sale->party->state ?? '' }}
@if($isInterState) CC Attached
{{ $sale->cc_attached ?? '' }} @endif
E-Way Bill No.
{{ $sale->eway_bill_no ?? '' }}@if($sale->eway_bill_date) dated {{ $sale->eway_bill_date instanceof \Carbon\Carbon ? $sale->eway_bill_date->format('d-M-y') : $sale->eway_bill_date }}@endif
{{-- Items Table --}} @foreach($pageItems as $item) @php $itemHsn = $item->hsn ?: ($item->product->hsn ?? ''); $itemUnit = $item->unit ?: ($item->product->unit ?? ''); $itemTaxPercent = $item->tax_percent ?? ($item->product->latestTaxRate->percentage ?? 0); $rateInclTax = $item->rate * (1 + ($itemTaxPercent / 100)); @endphp @endforeach {{-- Filler rows on last page --}} @for($f = 0; $f < $fillerRows; $f++) @endfor @if(!$isLastPage) {{-- Page subtotal (continued) --}} @endif @if($isLastPage) {{-- Subtotal --}} {{-- P&F --}} @if($pfAmt > 0) @endif {{-- Tax Lines --}} @if($isInterState) @else @php $totalCgst = collect($adjTaxAnalysis)->sum('cgst_amount'); $totalSgst = collect($adjTaxAnalysis)->sum('sgst_amount'); @endphp @endif @if(($sale->discount ?? 0) != 0) @endif {{-- Round Off --}} @if($sale->roundoff != 0) @endif {{-- Grand Total --}} @php $firstItem = $sale->items->first(); $totalUnit = $firstItem->unit ?: ($firstItem->product->unit ?? 'Pcs'); @endphp @endif
Sl Description of Goods HSN/SAC GST% Quantity Rate Rate
(Incl. Tax)
Amount
{{ $startIndex + $loop->iteration }} {{ $item->product->name ?? 'Product' }} {{ $itemHsn }} {{ indian_number($itemTaxPercent, 0) }}% {{ indian_number($item->qty, 0) }} {{ $itemUnit }} {{ indian_number($item->rate, 2) }} {{ indian_number($rateInclTax, 2) }} {{ indian_number($item->line_amount, 2) }}
 
Continued on next page... {{ indian_number($pageItems->sum('line_amount'), 2) }}
Sub Total {{ indian_number($sale->amount_total, 2) }}
P&F {{ indian_number($pfAmt, 2) }}
IGST {{ indian_number($sale->tax_total + $pfTax, 2) }}
CGST {{ indian_number($totalCgst, 2) }}
SGST {{ indian_number($totalSgst, 2) }}
Discount {{ $sale->discount > 0 ? '(-)' : '(+)' }}{{ indian_number(abs($sale->discount), 2) }}
R.Off {{ $sale->roundoff < 0 ? '(-)' : '' }}{{ indian_number(abs($sale->roundoff), 2) }}
Total {{ indian_number($sale->items->sum('qty'), 0) }} {{ $totalUnit }} {{ indian_number($sale->grand_total, 2) }}
@if($isLastPage) {{-- Amount in Words --}}
Amount Chargeable (in words)
Indian Rupees {{ $amountInWords }} Only
E. & O.E
{{-- Tax Analysis Table + QR Code --}}
@if(!empty($qrBase64))
Scan to pay
@elseif($company->qr_code_path)
Scan to pay
@else
QR
@endif
@if($isInterState) @else @endif @foreach($adjTaxAnalysis as $tax) @if($isInterState) @else @endif @endforeach @if($isInterState) @else @endif
Taxable
Value
IGST Total
Tax Amount
Rate Amount
Taxable
Value
Central Tax State Tax Total
Tax Amount
Rate Amount Rate Amount
{{ indian_number($tax['taxable_value'], 2) }}{{ $tax['rate'] }}% {{ indian_number($tax['total_tax'], 2) }} {{ indian_number($tax['total_tax'], 2) }}{{ $tax['cgst_rate'] }}% {{ indian_number($tax['cgst_amount'], 2) }} {{ $tax['sgst_rate'] }}% {{ indian_number($tax['sgst_amount'], 2) }} {{ indian_number($tax['total_tax'], 2) }}
{{ indian_number($sale->amount_total + $pfAmt, 2) }} {{ indian_number($taxTableTotal, 2) }} {{ indian_number($taxTableTotal, 2) }} {{ indian_number($taxTableTotal / 2, 2) }} {{ indian_number($taxTableTotal / 2, 2) }} {{ indian_number($taxTableTotal, 2) }}
{{-- Declaration & Bank Details --}}
Declaration
We declare that this invoice shows the actual price of the goods described and that all particulars are true and correct. Not responsible for transit damage/loss. Report within 15 days. Debit notes without intimation attract 15% penalty.
@if($bankAccount)
Company's Bank Details
A/c Holder's Name : {{ $bankAccount->name ?? $company->name }}
Bank Name : {{ $bankAccount->bank_name }}
A/c No. : {{ $bankAccount->account_no }}
Branch & IFS Code : {{ $bankAccount->branch }} & {{ $bankAccount->ifsc }}
@endif
for {{ $company->name }}

Authorised Signatory
{{-- Footer --}}
This is a Computer Generated Invoice
@endif @endfor @endforeach