Add the GL Accounts settings screen

Pickers are populated from GL's own chart of accounts, postable and active
accounts only, so a user can only choose a code the server will accept. A
stored code GL does not have is shown flagged and still selected rather
than appearing blank, which is the state 11 of the 12 mappings are in until
GL's chart is seeded - the broken mapping stays visible instead of looking
merely unset.

Options come from /gl-account-config rather than the GL proxy: that proxy
is gated on the `ledgers` nav permission while this screen is on
`settings`, and one endpoint keeps the picker and the server-side
validation working from the same list. Gated on the existing `settings` key
so no role_permissions edit is needed.

Saving is disabled outright while GL is unreachable, matching the server,
which refuses to store a mapping it could not verify.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 13:17:22 +05:30
parent c41aed9a80
commit c30ff473f5
4 changed files with 357 additions and 1 deletions
@@ -0,0 +1,20 @@
// Role → GL account mapping. Singleton, ETag-guarded, same shape as branch-config/grn-config.
//
// Note this is ERPCore's own endpoint, not the GL proxy in lib/api/general-ledger.ts: it speaks
// ProblemDetails and ETags like the rest of the app. It also serves the selectable accounts
// itself rather than the page calling the GL proxy, for two reasons — the GL proxy is gated on the
// `ledgers` nav permission while this screen is on `settings`, and serving both from one endpoint
// guarantees the picker offers exactly the accounts the server will accept.
import { apiRequestWithETag } from "@/lib/api-client"
import { ApiResult } from "@/types/common"
import { GlAccountConfig, UpdateGlAccountConfigRequest } from "@/types/gl-account-config"
export const glAccountConfigApi = {
get(): Promise<ApiResult<GlAccountConfig>> {
return apiRequestWithETag<GlAccountConfig>("/gl-account-config")
},
update(request: UpdateGlAccountConfigRequest, ifMatch: string): Promise<ApiResult<GlAccountConfig>> {
return apiRequestWithETag<GlAccountConfig>("/gl-account-config", { method: "PUT", body: request, ifMatch })
},
}