@php use Illuminate\Support\Carbon; use Illuminate\Support\Str; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Schema; $account = $account ?? $installment->account; $payment = $installment->payment ?? null; // pago real de esta mensualidad $hasReceiptColumn = Schema::hasTable('payments') && Schema::hasColumn('payments', 'transfer_receipt_path'); // Para el COMPROBANTE (imagen/PDF), busca el pago de esta mensualidad primero; // si no tiene archivo, busca el último abono de la cuenta que sí lo tenga. // IMPORTANTE: $payment NO se reemplaza — sigue apuntando al pago real de la mensualidad // para que fecha, monto, método y concepto sean siempre los correctos. $proofPayment = $payment; if ($hasReceiptColumn && (! $proofPayment || empty($proofPayment->transfer_receipt_path)) && $account) { try { $proofPayment = $account->payments() ->whereNotNull('transfer_receipt_path') ->latest('id') ->first() ?: $proofPayment; } catch (\Throwable $e) { // No bloquear el recibo. } } $proofPath = $hasReceiptColumn ? ($proofPayment?->transfer_receipt_path ?? null) : null; $proofExtension = $proofPath ? strtolower(pathinfo($proofPath, PATHINFO_EXTENSION)) : ''; $proofIsImage = in_array($proofExtension, ['jpg', 'jpeg', 'png', 'webp'], true); $proofUrl = $proofPath ? Storage::url($proofPath) : null; $proofDataUri = null; // Para que se visualice en pantalla y en PDF, embebe la imagen como base64. if ($proofPath && $proofIsImage) { try { if (Storage::disk('public')->exists($proofPath)) { $mime = match ($proofExtension) { 'jpg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'webp' => 'image/webp', default => 'image/jpeg', }; $proofDataUri = 'data:'.$mime.';base64,'.base64_encode(Storage::disk('public')->get($proofPath)); } } catch (\Throwable $e) { // Fallback a URL publica. } } $proofImageSrc = $proofDataUri ?: $proofUrl; $hasProof = (bool) $proofImageSrc; $companyName = $company['name'] ?? 'Casa Amiga Inmobiliaria'; $companyAddress = $company['address'] ?? 'Domicilio no configurado'; // Divide el domicilio para que desde "Col." / "Colonia" pase a otro renglón. $addressMain = trim((string) $companyAddress); $addressColony = ''; if (preg_match('/\b(Col\.?|Colonia)\b/i', $addressMain, $match, PREG_OFFSET_CAPTURE)) { $pos = $match[0][1]; $addressColony = trim(substr($addressMain, $pos)); $addressMain = trim(substr($addressMain, 0, $pos)); $addressMain = rtrim($addressMain, " ,.-"); } $cityState = $company['city_state'] ?? 'Tepic, Nayarit'; $companyPhone = $company['phone'] ?? ''; $companyEmail = $company['email'] ?? ''; $logo = brand_logo_url(); $clientName = $account->client?->name ?? '—'; $lote = $account->lote; $projectName = $lote?->project?->name ?? $lote?->manzana?->project?->name ?? $account->property?->name ?? '—'; $manzana = $lote?->manzana?->nombre; $loteNumero = $lote?->numero; $referenceAction = $lote ? trim('LOTE '.($loteNumero ?: '—').($manzana ? ' MZA '.$manzana : '')) : ($account->unit_label ?? ('Cuenta #'.$account->id)); $conceptRaw = $payment?->concept ?: (($installment->is_annuity ? 'Aportación con anualidad #' : 'Aportación #').$installment->number); $concept = str_replace(['Mensualidad', 'mensualidad'], ['Aportación', 'aportación'], $conceptRaw); $amount = (float) ($installment->amount ?? 0); $currentBalance = (float) ($account->balance ?? 0); $previousBalance = $installment->status === 'Pagado' ? ($currentBalance + $amount) : max(0, (float) ($account->total_price ?? 0) - (float) ($account->paid_amount ?? 0)); // Saldo nuevo mostrado en el recibo: // Saldo anterior menos la aportación registrada en este recibo. $newBalance = max(0, $previousBalance - $amount); // DESGLOSE del recibo: // el primer mes cubierto por un abono se toma como mensualidad normal; // lo aplicado a meses posteriores del mismo abono se muestra como aportacion extraordinaria. $monthlyAmount = $amount; $extraordinaryAmount = 0.0; if ($payment && $account) { $paymentInstallments = collect($account->installments ?? []) ->filter(fn ($row) => (int) ($row->payment_id ?? 0) === (int) $payment->id) ->sortBy(fn ($row) => sprintf('%010d-%010d', (int) ($row->number ?? 0), (int) ($row->id ?? 0))) ->values(); $firstInstallment = $paymentInstallments->first(); $isAdvanceInstallment = $firstInstallment && (int) ($firstInstallment->id ?? 0) !== (int) $installment->id; if ($isAdvanceInstallment) { $remainingFromPayment = round((float) ($payment->amount ?? 0), 2); foreach ($paymentInstallments as $row) { $rowAmount = (float) ($row->amount ?? 0); $rowPaid = (float) ($row->paid_amount ?? 0); $rowApplied = min($rowAmount, $rowPaid > 0 ? $rowPaid : $rowAmount, $remainingFromPayment); if ((int) ($row->id ?? 0) === (int) $installment->id) { $extraordinaryAmount = max(0, min($amount, $rowApplied)); break; } $remainingFromPayment = max(0, round($remainingFromPayment - $rowApplied, 2)); } if ($extraordinaryAmount <= 0) { $extraordinaryAmount = max(0, min($amount, (float) ($installment->paid_amount ?? 0))); } $monthlyAmount = max(0, round($amount - $extraordinaryAmount, 2)); } } $periodInterest = (float) ($payment?->period_interest ?? $payment?->interest ?? 0); $collectionFees = (float) ($payment?->collection_fees ?? $payment?->collection_fee ?? 0); $importAmount = $monthlyAmount + $extraordinaryAmount + $periodInterest + $collectionFees; $referenceCopropiedad = mb_strtoupper(trim( 'LOTE '.($loteNumero ?: '—'). ' MZA '.($manzana ?: '—'). ' DEL PROYECTO '.($projectName ?: '—') )); $paymentDate = $payment?->payment_date ? Carbon::parse($payment->payment_date)->format('d/m/Y') : ($installment->paid_at ? $installment->paid_at->format('d/m/Y') : now()->format('d/m/Y')); $dueDate = $installment->due_date ? Carbon::parse($installment->due_date)->format('d/m/Y') : '—'; $issuedDate = now()->format('d/m/Y'); $generatedAt = now()->format('d/m/Y H:i'); $method = $payment?->method ?: '—'; $reference = $payment?->reference ?: ('INST-'.$installment->id); $receiptNo = str_pad((string) $installment->id, 5, '0', STR_PAD_LEFT); $paymentNo = 'No. '.str_pad((string) $installment->number, 2, '0', STR_PAD_LEFT); $status = $installment->status ?: 'Pendiente'; $money = fn($v) => number_format((float)$v, 2); @endphp
⬇ Descargar PDF
@foreach (['Original', 'Copia'] as $copyLabel)
{{ strtoupper($copyLabel) }}
RECIBO DE
APORTACIÓN
GENERADO {{ $generatedAt }}
{{ $addressMain }}
@if($addressColony)
{{ $addressColony }}
@endif
{{ $cityState }}
@if($companyPhone)
TEL. {{ $companyPhone }}
@endif @if($companyEmail)
{{ $companyEmail }}
@endif
NOMBRE DEL PROYECTO: {{ $projectName }} {{ $paymentNo }}
FECHA DE PAGO: {{ $paymentDate }} CIUDAD Y ESTADO: {{ $cityState }}
SE RECIBE DE: {{ $clientName }}
REFERENCIA ACCIÓN EN COPROPIEDAD: {{ $referenceCopropiedad }}
MONTO TOTAL A CUBRIR EN APORT. MENS.: $ {{ $money($previousBalance) }}
SALDO ANTERIOR: $ {{ $money($previousBalance) }} MONTO DE MENSUALIDAD {{ $installment->number }}: $ {{ $money($monthlyAmount) }}
DESGLOSE
MONTO DE MENSUALIDAD {{ $installment->number }}: $ {{ $money($monthlyAmount) }}
MONTO DE APORTACIÓN EXTRAORDINARIA: $ {{ $money($extraordinaryAmount) }}
INTERÉS DEL PERIODO: $ {{ $money($periodInterest) }}
GASTOS DE COBRANZA: $ {{ $money($collectionFees) }}
IMPORTE: $ {{ $money($importAmount) }}
SALDO ACTUAL $ {{ $money($newBalance) }}
Este no es un recibo fiscal, se considera como comprobante de que EL ASOCIADO ha realizado una aportacion, pago de servicio o la adquisicion de una accion en coopropiedad. Este comprobante debera ser entregado directamente a EL ASOCIADO despues del pago con la firma y sello oficial del ejecutivo o auxiliar de pagos.
FIRMA Y SELLO DEL EJECUTIVO O AUXILIAR DE PAGOS
COMPROBANTE:
@if($hasProof && $proofIsImage) Comprobante de pago @elseif($hasProof)
Comprobante adjunto: {{ strtoupper($proofExtension ?: 'ARCHIVO') }} @if($proofUrl)
Abrir comprobante @endif
@else
@endif
@endforeach