<?php
declare(strict_types=1);
require __DIR__.'/app/bootstrap.php';require_permission('treasury.receipts.manage');require __DIR__.'/app/layout.php';
$pdo=db();$companyId=company_id();$userId=(int)user()['id'];$currencyId=(int)scalar('SELECT base_currency_id FROM companies WHERE id=?',[$companyId]);
if($_SERVER['REQUEST_METHOD']==='POST'){verify_csrf();try{$action=(string)($_POST['action']??'');
 if($action==='create'){$invoiceId=(int)($_POST['sales_invoice_id']??0);$amount=round((float)($_POST['amount']??0),2);$q=$pdo->prepare("SELECT si.*,c.partner_id,bp.legal_name_ar customer_name FROM sales_invoices si JOIN customers c ON c.id=si.customer_id JOIN business_partners bp ON bp.id=c.partner_id WHERE si.id=? AND si.company_id=? AND si.status IN ('issued','partially_collected','overdue')");$q->execute([$invoiceId,$companyId]);$inv=$q->fetch();if(!$inv)throw new RuntimeException('فاتورة العميل غير متاحة للتحصيل.');$outstanding=round((float)$inv['net_due_amount']-(float)$inv['collected_amount'],2);if($amount<=0||$amount>$outstanding+0.001)throw new RuntimeException('المبلغ يجب أن يكون موجبًا ولا يتجاوز رصيد الفاتورة.');$method=(string)($_POST['payment_method']??'bank_transfer');$bankId=(int)($_POST['bank_account_id']??0);$cashboxId=(int)($_POST['cashbox_id']??0);if(!in_array($method,['bank_transfer','cash','cheque','card','other'],true))throw new RuntimeException('طريقة التحصيل غير صالحة.');if($method==='cash'&&!$cashboxId)throw new RuntimeException('اختر الصندوق.');if($method!=='cash'&&!$bankId)throw new RuntimeException('اختر الحساب البنكي لطريقة التحصيل المحددة.');$date=(string)($_POST['receipt_date']??'');if(!$date)throw new RuntimeException('تاريخ التحصيل مطلوب.');$no='RV-'.date('Ym',strtotime($date)).'-'.str_pad((string)((int)scalar('SELECT COUNT(*)+1 FROM receipt_vouchers WHERE company_id=?',[$companyId])),5,'0',STR_PAD_LEFT);$pdo->beginTransaction();$s=$pdo->prepare("INSERT INTO receipt_vouchers(company_id,branch_id,customer_id,partner_id,receipt_no,receipt_date,payment_method,bank_account_id,cashbox_id,currency_id,amount,reference_no,description,status,created_by,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,'draft',?,NOW())");$s->execute([$companyId,$inv['branch_id'],$inv['customer_id'],$inv['partner_id'],$no,$date,$method,$bankId?:null,$cashboxId?:null,$currencyId,$amount,trim((string)($_POST['reference_no']??''))?:null,'تحصيل فاتورة '.$inv['invoice_no'],$userId]);$receiptId=(int)$pdo->lastInsertId();$pdo->prepare("INSERT INTO receipt_allocations(receipt_voucher_id,sales_invoice_id,allocation_type,allocated_amount,created_at) VALUES (?,?,'invoice',?,NOW())")->execute([$receiptId,$invoiceId,$amount]);$pdo->commit();audit('customer_receipt.create','receipt_voucher',(string)$receiptId,['invoice'=>$inv['invoice_no']]);flash('success','تم إنشاء سند القبض كمسودة: '.$no);
 }elseif(in_array($action,['submit','approve','post'],true)){$id=(int)($_POST['id']??0);if($action==='submit'){$s=$pdo->prepare("UPDATE receipt_vouchers SET status='submitted' WHERE id=? AND company_id=? AND status='draft' AND EXISTS(SELECT 1 FROM receipt_allocations ra WHERE ra.receipt_voucher_id=receipt_vouchers.id AND ra.sales_invoice_id IS NOT NULL)");$s->execute([$id,$companyId]);}elseif($action==='approve'){$s=$pdo->prepare("UPDATE receipt_vouchers SET status='approved',approved_by=? WHERE id=? AND company_id=? AND status='submitted'");$s->execute([$userId,$id,$companyId]);}else{$pdo->beginTransaction();$q=$pdo->prepare("SELECT rv.*,ra.sales_invoice_id,ra.allocated_amount FROM receipt_vouchers rv JOIN receipt_allocations ra ON ra.receipt_voucher_id=rv.id AND ra.allocation_type='invoice' WHERE rv.id=? AND rv.company_id=? AND rv.status='approved' FOR UPDATE");$q->execute([$id,$companyId]);$voucher=$q->fetch();if(!$voucher)throw new RuntimeException('سند القبض غير متاح للترحيل.');$q=$pdo->prepare("SELECT * FROM sales_invoices WHERE id=? AND company_id=? AND status IN ('issued','partially_collected','overdue') FOR UPDATE");$q->execute([$voucher['sales_invoice_id'],$companyId]);$inv=$q->fetch();if(!$inv)throw new RuntimeException('الفاتورة غير متاحة للتحصيل.');$amount=(float)$voucher['allocated_amount'];$outstanding=round((float)$inv['net_due_amount']-(float)$inv['collected_amount'],2);if($amount>$outstanding+0.001)throw new RuntimeException('المبلغ أصبح أكبر من رصيد الفاتورة؛ راجع التحصيلات السابقة.');$cashAccount=0;if($voucher['bank_account_id'])$cashAccount=(int)scalar('SELECT account_id FROM bank_accounts WHERE id=? AND company_id=?',[$voucher['bank_account_id'],$companyId]);elseif($voucher['cashbox_id'])$cashAccount=(int)scalar('SELECT account_id FROM cashboxes WHERE id=? AND company_id=?',[$voucher['cashbox_id'],$companyId]);if(!$cashAccount)throw new RuntimeException('يلزم ربط السند بحساب بنكي أو صندوق صالح.');$journalId=post_system_journal($voucher['receipt_date'],'تحصيل عميل '.$voucher['receipt_no'],'receipt_voucher',$id,[['account_id'=>$cashAccount,'debit'=>$amount,'project_id'=>$inv['project_id']],['account_id'=>mapped_account('AR_CONTROL'),'credit'=>$amount,'project_id'=>$inv['project_id']]]);$s=$pdo->prepare("UPDATE receipt_vouchers SET status='posted',journal_entry_id=? WHERE id=?");$s->execute([$journalId,$id]);$newCollected=round((float)$inv['collected_amount']+$amount,2);$newStatus=$newCollected+0.001>=(float)$inv['net_due_amount']?'collected':'partially_collected';$pdo->prepare('UPDATE sales_invoices SET collected_amount=?,status=? WHERE id=?')->execute([$newCollected,$newStatus,$inv['id']]);if($inv['customer_certificate_id'])$pdo->prepare('UPDATE customer_certificates SET status=? WHERE id=?')->execute([$newStatus,$inv['customer_certificate_id']]);$pdo->commit();}if(!$s->rowCount())throw new RuntimeException('تعذر تنفيذ الإجراء على سند القبض.');audit('customer_receipt.'.$action,'receipt_voucher',(string)$id);flash('success','تم تحديث دورة التحصيل بنجاح.');
 }}catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();flash('error',$e instanceof PDOException?'تعذر حفظ التحصيل؛ تحقق من البيانات والمرجع.':$e->getMessage());}redirect('customer_receipts.php');}
$invoices=$pdo->prepare("SELECT si.id,si.invoice_no,si.invoice_date,si.due_date,si.net_due_amount,si.collected_amount,si.net_due_amount-si.collected_amount outstanding,bp.legal_name_ar customer_name,p.name_ar project_name FROM sales_invoices si JOIN customers c ON c.id=si.customer_id JOIN business_partners bp ON bp.id=c.partner_id LEFT JOIN projects p ON p.id=si.project_id WHERE si.company_id=? AND si.status IN ('issued','partially_collected','overdue') AND si.collected_amount<si.net_due_amount ORDER BY COALESCE(si.due_date,si.invoice_date),si.id");$invoices->execute([$companyId]);$invoices=$invoices->fetchAll();$selectedInvoice=(int)($_GET['invoice_id']??0);$selected=null;foreach($invoices as $i)if((int)$i['id']===$selectedInvoice)$selected=$i;$banks=$pdo->prepare('SELECT id,code,bank_name FROM bank_accounts WHERE company_id=? AND is_active=1 ORDER BY code');$banks->execute([$companyId]);$banks=$banks->fetchAll();$cashboxes=$pdo->prepare('SELECT id,code,name_ar FROM cashboxes WHERE company_id=? AND is_active=1 ORDER BY code');$cashboxes->execute([$companyId]);$cashboxes=$cashboxes->fetchAll();$receipts=$pdo->prepare("SELECT rv.*,ra.sales_invoice_id,ra.allocated_amount,si.invoice_no,bp.legal_name_ar customer_name FROM receipt_vouchers rv JOIN receipt_allocations ra ON ra.receipt_voucher_id=rv.id AND ra.allocation_type='invoice' JOIN sales_invoices si ON si.id=ra.sales_invoice_id JOIN business_partners bp ON bp.id=rv.partner_id WHERE rv.company_id=? ORDER BY rv.id DESC LIMIT 100");$receipts->execute([$companyId]);$receipts=$receipts->fetchAll();
render_header('customer_receipts','تحصيل العملاء','تحصيل جزئي أو كامل مرتبط بفواتير العملاء الصادرة.');?>
<section class="panel data-card"><header><h2>فواتير العملاء المستحقة</h2></header><div class="responsive-table"><table><thead><tr><th>الفاتورة</th><th>العميل</th><th>المشروع</th><th>الاستحقاق</th><th>الصافي</th><th>المحصل</th><th>المتبقي</th><th></th></tr></thead><tbody><?php foreach($invoices as $i):?><tr><td><?= e($i['invoice_no']) ?></td><td><?= e($i['customer_name']) ?></td><td><?= e($i['project_name']?:'عام') ?></td><td><?= e($i['due_date']?:'—') ?></td><td><?= number_format((float)$i['net_due_amount'],2) ?></td><td><?= number_format((float)$i['collected_amount'],2) ?></td><td><?= number_format((float)$i['outstanding'],2) ?></td><td><a href="?invoice_id=<?= (int)$i['id'] ?>">إنشاء تحصيل</a></td></tr><?php endforeach;?></tbody></table></div></section>
<?php if($selected):?><details class="panel quick-add" open><summary>＋ سند قبض للفاتورة <?= e($selected['invoice_no']) ?></summary><form method="post"><?= csrf_field() ?><input type="hidden" name="action" value="create"><input type="hidden" name="sales_invoice_id" value="<?= (int)$selected['id'] ?>"><div class="form-grid"><label>الرصيد المتبقي<input value="<?= number_format((float)$selected['outstanding'],2,'.','') ?>" readonly></label><label>المبلغ المحصل<input type="number" step="0.01" min="0.01" max="<?= e((string)$selected['outstanding']) ?>" name="amount" value="<?= e((string)$selected['outstanding']) ?>" required></label><label>تاريخ التحصيل<input type="date" name="receipt_date" value="<?= date('Y-m-d') ?>" required></label><label>طريقة التحصيل<select name="payment_method"><option value="bank_transfer">تحويل بنكي</option><option value="cash">نقدي</option><option value="cheque">شيك</option><option value="card">بطاقة</option><option value="other">أخرى</option></select></label><label>الحساب البنكي<select name="bank_account_id"><option value="0">—</option><?php foreach($banks as $b):?><option value="<?= (int)$b['id'] ?>"><?= e($b['code'].' — '.$b['bank_name']) ?></option><?php endforeach;?></select></label><label>الصندوق<select name="cashbox_id"><option value="0">—</option><?php foreach($cashboxes as $c):?><option value="<?= (int)$c['id'] ?>"><?= e($c['code'].' — '.$c['name_ar']) ?></option><?php endforeach;?></select></label><label>مرجع التحويل أو الشيك<input name="reference_no"></label></div><button class="primary-btn">حفظ سند القبض</button></form></details><?php endif;?>
<section class="panel data-card"><header><h2>تحصيلات العملاء</h2></header><div class="responsive-table"><table><thead><tr><th>السند</th><th>الفاتورة</th><th>العميل</th><th>التاريخ</th><th>المبلغ</th><th>الطريقة</th><th>الحالة</th><th>الإجراء</th></tr></thead><tbody><?php foreach($receipts as $r):?><tr><td><?= e($r['receipt_no']) ?></td><td><?= e($r['invoice_no']) ?></td><td><?= e($r['customer_name']) ?></td><td><?= e($r['receipt_date']) ?></td><td><?= number_format((float)$r['allocated_amount'],2) ?></td><td><?= e($r['payment_method']) ?></td><td><span class="chip"><?= e($r['status']) ?></span></td><td><?php $next=$r['status']==='draft'?'submit':($r['status']==='submitted'?'approve':($r['status']==='approved'?'post':''));$label=['submit'=>'تقديم','approve'=>'اعتماد','post'=>'ترحيل'];if($next):?><form method="post"><?= csrf_field() ?><input type="hidden" name="action" value="<?= $next ?>"><input type="hidden" name="id" value="<?= (int)$r['id'] ?>"><button><?= e($label[$next]) ?></button></form><?php endif;?></td></tr><?php endforeach;?></tbody></table></div></section>
<?php render_footer();
