|null */ private ?array $accounts = null; /** @return array */ public function all(): array { if ($this->accounts !== null) { return $this->accounts; } $path = resource_path('data/coa.json'); $payload = File::exists($path) ? json_decode((string) File::get($path), true) : null; $rows = is_array($payload['accounts'] ?? null) ? $payload['accounts'] : []; $this->accounts = array_map(static fn (array $row): array => [ 'code' => (string) ($row[0] ?? ''), 'name' => (string) ($row[1] ?? ''), 'level' => (int) ($row[2] ?? 1), 'category' => (string) ($row[3] ?? ''), 'balance' => (string) ($row[4] ?? ''), ], $rows); return $this->accounts; } /** @return array 一级科目(用于下拉第一级) */ public function level1(): array { return array_values(array_map( static fn (array $a): array => ['code' => $a['code'], 'name' => $a['name']], array_filter($this->all(), static fn (array $a): bool => $a['level'] === 1 && $a['name'] !== '') )); } /** @return array 某编码子树下的非一级科目 */ public function descendants(string $code): array { if ($code === '') { return []; } $prefix = $code . '.'; $hits = []; foreach ($this->all() as $a) { if ($a['code'] !== $code && str_starts_with($a['code'], $prefix)) { $hits[] = ['code' => $a['code'], 'name' => $a['name'], 'level' => $a['level']]; } } return $hits; } /** 一级科目名 → 编码(账套里一级科目名唯一) */ public function level1Code(string $name): ?string { $name = trim($name); if ($name === '') { return null; } foreach ($this->all() as $a) { if ($a['level'] === 1 && $a['name'] === $name) { return $a['code']; } } return null; } /** * 在「一级科目」子树下按名称找科目编码。 * * @return array 命中编码;空数组 = 不存在;多于 1 个 = 同名歧义 */ public function resolve(string $level1Name, string $subName): array { $subName = trim($subName); if ($subName === '') { return []; } $base = $this->level1Code($level1Name); if ($base === null) { return []; } $hits = []; foreach ($this->all() as $a) { if ($a['name'] === $subName && ($a['code'] === $base || str_starts_with($a['code'], $base . '.'))) { $hits[] = $a['code']; } } sort($hits); return $hits; } /** 全账套里同名的编码(用于解释「为什么找不到」) @return array */ public function anywhereByName(string $name): array { $name = trim($name); if ($name === '') { return []; } $hits = []; foreach ($this->all() as $a) { if ($a['name'] === $name) { $hits[] = $a['code']; } } sort($hits); return $hits; } /** 名称或编码 → 编码(映射表里偶尔会直接写编码) */ public function toCode(string $level1Token): ?string { $token = trim($level1Token); if ($token === '') { return null; } if (preg_match('/^\d+(\.\d+)*$/', $token) === 1) { foreach ($this->all() as $a) { if ($a['code'] === $token) { return $token; } } return null; } return $this->level1Code($token); } }