@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
| 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) }} | ||