CI =& get_instance(); $this->CI->load->model('JournalModel', 'journalModel'); $this->CI->load->model('AccountModel', 'accountModel'); $this->CI->load->library('TransactionService'); $this->CI->load->library('FiscalPeriodService'); $this->CI->load->library('JournalDescriptionService'); if ($this->CI->db->table_exists('companies')) $this->CI->load->library('CompanyContext'); } public function create(array $header, array $lines, $manageTransaction = true) { $normalized = $this->validateAndNormalize($header, $lines); $operation = function () use ($normalized) { $journalId = $this->CI->journalModel->createHeader($normalized['header']); $details = array(); foreach ($normalized['lines'] as $line) { $line['journal_id'] = $journalId; $details[] = $line; } $this->CI->journalModel->addLines($details); if ($this->CI->db->table_exists('journal_status_histories')) { $this->CI->journalModel->addStatusHistory( $journalId, null, $normalized['header']['status'], $normalized['header']['created_by'], 'Jurnal dibuat' ); } return $journalId; }; return $manageTransaction ? $this->CI->transactionservice->run($operation) : $operation(); } public function totals(array $lines) { $debit = 0.0; $credit = 0.0; foreach ($lines as $line) { $debit += isset($line['debit']) ? (float) $line['debit'] : 0; $credit += isset($line['kredit']) ? (float) $line['kredit'] : 0; } return array('debit' => round($debit, 2), 'kredit' => round($credit, 2)); } private function validateAndNormalize(array $header, array $lines) { foreach (array('tanggal', 'no_ref', 'keterangan', 'created_by') as $required) { if (!isset($header[$required]) || trim((string) $header[$required]) === '') { throw new BusinessException('Data header jurnal "' . $required . '" wajib diisi.'); } } $date = DateTime::createFromFormat('Y-m-d', $header['tanggal']); if (!$date || $date->format('Y-m-d') !== $header['tanggal']) { throw new BusinessException('Tanggal jurnal tidak valid.'); } if ($this->CI->journalModel->referenceExists($header['no_ref'])) { throw new BusinessException('Nomor referensi jurnal sudah digunakan.'); } $period = $this->CI->fiscalperiodservice->assertOpen($header['tanggal']); if (count($lines) < 2) { throw new BusinessException('Jurnal minimal mempunyai dua baris transaksi.'); } $normalized = array(); $accountIds = array(); foreach ($lines as $index => $line) { $accountId = isset($line['account_id']) ? (int) $line['account_id'] : 0; $debit = round(isset($line['debit']) ? (float) $line['debit'] : 0, 2); $credit = round(isset($line['kredit']) ? (float) $line['kredit'] : 0, 2); if ($accountId <= 0 || $debit < 0 || $credit < 0 || ($debit > 0 && $credit > 0) || ($debit <= 0 && $credit <= 0)) { throw new BusinessException('Baris jurnal ke-' . ($index + 1) . ' tidak valid.'); } $detail=array('account_id'=>$accountId,'debit'=>$debit,'kredit'=>$credit); foreach(array('currency_amount','currency_code','exchange_rate')as$currencyField)if(isset($line[$currencyField])&&$line[$currencyField]!=='')$detail[$currencyField]=$line[$currencyField]; if($this->CI->db->field_exists('company_id','journal_details'))$detail['company_id']=$this->CI->companycontext->id(); $normalized[]=$detail; $accountIds[] = $accountId; } $existingIds = $this->CI->accountModel->existingIds($accountIds); $missingIds = array_diff(array_unique($accountIds), $existingIds); if (!empty($missingIds)) { throw new BusinessException('Terdapat akun jurnal yang tidak ditemukan: ' . implode(', ', $missingIds)); } $totals = $this->totals($normalized); if ($totals['debit'] <= 0 || abs($totals['debit'] - $totals['kredit']) > 0.009) { throw new BusinessException('Total debit dan kredit jurnal harus seimbang.'); } $header['keterangan'] = $this->CI->journaldescriptionservice->build($header, $normalized); $header['status'] = isset($header['status']) ? $header['status'] : 'draft'; $header['accounting_period_id'] = (int) $period->id; $allowedHeader = array_intersect_key($header, array_flip(array( 'tanggal', 'no_ref', 'keterangan', 'ref_type', 'ref_id', 'created_by', 'status', 'accounting_period_id', 'posted_at', 'posted_by', 'reversal_of', 'reversal_reason','company_id','transaction_currency','exchange_rate','base_amount' ))); if($this->CI->db->field_exists('company_id','journals'))$allowedHeader['company_id']=$this->CI->companycontext->id(); return array('header' => $allowedHeader, 'lines' => $normalized, 'totals' => $totals); } }