Files
accounting_dev_v2/application/libraries/ReceivableAdjustmentsService.php
2026-09-11 18:06:17 +07:00

44 lines
5.3 KiB
PHP

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require_once APPPATH.'exceptions/BusinessException.php';
class ReceivableAdjustmentsService
{
private $CI;
public function __construct(){
$this->CI=&get_instance();
$this->CI->load->library(array('TransactionService','PostingService','NumberingService','AccountMappingService','FiscalPeriodService','AuditService'));
}
public function creditNote($invoiceId,$date,$amount,$reason,$userId){
return $this->CI->transactionservice->run(function()use($invoiceId,$date,$amount,$reason,$userId){
$invoice=$this->CI->db->query('SELECT * FROM invoices WHERE id=? FOR UPDATE',array((int)$invoiceId))->row();
$amount=round((float)$amount,2);
if(!$invoice||$invoice->workflow_status!=='posted'||$amount<=0||$amount>(float)$invoice->sisa_piutang)throw new BusinessException('Nilai credit note tidak valid.');
if(trim($reason)==='')throw new BusinessException('Alasan credit note wajib diisi.');
$this->CI->fiscalperiodservice->assertOpen($date);
$details=$this->CI->db->where('invoice_id',$invoice->id)->get('invoice_details')->result();
$entries=array();$debit=0;$base=max(.01,(float)$invoice->total);
foreach($details as $line){$part=$amount*((float)$line->subtotal/$base);$tax=$part*((float)$line->tax_amount/max(.01,(float)$line->subtotal));$net=$part-$tax;$entries[]=array('account_id'=>$line->account_id,'debit'=>$net,'kredit'=>0);$debit+=$net;if($tax>0){$entries[]=array('account_id'=>$this->CI->accountmappingservice->get('sales_tax_payable'),'debit'=>$tax,'kredit'=>0);$debit+=$tax;}}
$entries[]=array('account_id'=>$this->CI->accountmappingservice->get('accounts_receivable'),'debit'=>0,'kredit'=>$debit);
$no=$this->CI->numberingservice->next('credit_note',$date);
$customer=$this->CI->db->select('nama')->get_where('customers',array('id'=>$invoice->customer_id))->row();
$description='Pengurangan tagihan Invoice '.$invoice->no_invoice.' untuk '.($customer?$customer->nama:'Customer #'.$invoice->customer_id).' sebesar Rp '.number_format($amount,2,',','.').' karena '.trim($reason);
$journal=$this->CI->postingservice->post(array('tanggal'=>$date,'no_ref'=>$no,'keterangan'=>$description,'natural_description'=>true,'ref_type'=>'credit_note','ref_id'=>$invoice->id,'created_by'=>$userId),$entries,false,true);
$this->CI->db->insert('credit_notes',array('credit_note_no'=>$no,'invoice_id'=>$invoice->id,'customer_id'=>$invoice->customer_id,'credit_date'=>$date,'amount'=>$amount,'reason'=>$reason,'status'=>'posted','journal_id'=>$journal,'created_by'=>$userId,'created_at'=>date('Y-m-d H:i:s')));
$id=$this->CI->db->insert_id();$balance=max(0,(float)$invoice->sisa_piutang-$amount);
$this->CI->db->where('id',$invoice->id)->update('invoices',array('sisa_piutang'=>$balance,'status'=>$balance<=0?'paid':'partial'));
$this->CI->auditservice->record('receivable','credit_note',$id,'post',null,array('invoice_id'=>$invoice->id,'amount'=>$amount),$userId);return$id;
});
}
public function refund($advanceId,$date,$amount,$bankAccountId,$reason,$userId){
return $this->CI->transactionservice->run(function()use($advanceId,$date,$amount,$bankAccountId,$reason,$userId){
$advance=$this->CI->db->query('SELECT * FROM customer_advances WHERE id=? FOR UPDATE',array((int)$advanceId))->row();$amount=round((float)$amount,2);
if(!$advance||$amount<=0||$amount>(float)$advance->available_amount)throw new BusinessException('Nilai refund tidak valid.');if(trim($reason)==='')throw new BusinessException('Alasan refund wajib diisi.');
$this->CI->fiscalperiodservice->assertOpen($date);$no=$this->CI->numberingservice->next('refund',$date);
$customer=$this->CI->db->select('nama')->get_where('customers',array('id'=>$advance->customer_id))->row();
$description='Pengembalian dana '.$advance->advance_no.' kepada '.($customer?$customer->nama:'Customer #'.$advance->customer_id).' sebesar Rp '.number_format($amount,2,',','.').' karena '.trim($reason);
$journal=$this->CI->postingservice->post(array('tanggal'=>$date,'no_ref'=>$no,'keterangan'=>$description,'natural_description'=>true,'ref_type'=>'customer_refund','ref_id'=>$advance->id,'created_by'=>$userId),array(array('account_id'=>$this->CI->accountmappingservice->get('customer_advances'),'debit'=>$amount,'kredit'=>0),array('account_id'=>(int)$bankAccountId,'debit'=>0,'kredit'=>$amount)),false,true);
$this->CI->db->insert('customer_refunds',array('refund_no'=>$no,'customer_id'=>$advance->customer_id,'advance_id'=>$advance->id,'refund_date'=>$date,'amount'=>$amount,'bank_account_id'=>$bankAccountId,'reason'=>$reason,'status'=>'posted','journal_id'=>$journal,'created_by'=>$userId,'created_at'=>date('Y-m-d H:i:s')));$id=$this->CI->db->insert_id();$available=(float)$advance->available_amount-$amount;$this->CI->db->where('id',$advance->id)->update('customer_advances',array('available_amount'=>$available,'status'=>$available<=0?'refunded':'partially_used'));$this->CI->auditservice->record('receivable','refund',$id,'post',null,array('advance_id'=>$advance->id,'amount'=>$amount),$userId);return$id;
});
}
}