CI =& get_instance(); $this->CI->config->load('accounting', true); $this->CI->load->library('CompanyContext'); $this->sequenceTableAvailable = $this->CI->db->table_exists('document_sequences'); } public function next($type, $date = null) { $date = $date ?: date('Y-m-d'); $timestamp = strtotime($date); if ($timestamp === false) { throw new BusinessException('Tanggal penomoran dokumen tidak valid.'); } $settings = (array) $this->CI->config->item('document_numbering', 'accounting'); if (!isset($settings[$type])) { throw new BusinessException('Jenis penomoran "' . $type . '" belum dikonfigurasi.'); } $prefix = $settings[$type]['prefix'] . '-' . date('Ymd', $timestamp) . '-'; $padding = (int) $settings[$type]['padding']; $period = date('Ymd', $timestamp); if ($this->sequenceTableAvailable) { $initialValue = $this->nextLegacyValue($type, $prefix); $number = $this->nextAtomicValue($type, $period, $prefix, $initialValue); } else { $number = $this->nextLegacyValue($type, $prefix); } return $prefix . str_pad($number, $padding, '0', STR_PAD_LEFT); } private function nextAtomicValue($type, $period, $prefix, $initialValue) { $companyId = (int) $this->CI->companycontext->id(); $sql = 'INSERT INTO document_sequences (company_id, document_type, period_key, prefix, current_value, updated_at) ' . 'VALUES (?, ?, ?, ?, ?, NOW()) ' . 'ON DUPLICATE KEY UPDATE prefix = VALUES(prefix), current_value = LAST_INSERT_ID(current_value + 1), updated_at = NOW()'; if (!$this->CI->db->query($sql, array($companyId, $type, $period, $prefix, $initialValue))) { throw new RuntimeException('Gagal mengambil nomor dokumen berikutnya.'); } if ($this->CI->db->affected_rows() === 1) { return (int) $initialValue; } return (int) $this->CI->db->insert_id(); } private function nextLegacyValue($type, $prefix) { $source = $type === 'invoice' ? array('invoices', 'no_invoice') : array('journals', 'no_ref'); $builder = $this->CI->db->select($source[1]); if ($this->CI->db->field_exists('company_id', $source[0])) $builder->where('company_id', (int)$this->CI->companycontext->id()); $row = $builder->like($source[1], $prefix, 'after') ->order_by($source[1], 'DESC') ->limit(1) ->get($source[0]) ->row(); if (!$row) { return 1; } $value = $row->{$source[1]}; return ((int) substr($value, strlen($prefix))) + 1; } }