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