#51: BankAccountPagesRest.kt

plugins/org.projectforge.plugins.banking/src/main/kotlin/org/projectforge/plugins/banking/BankAccountPagesRest.kt

Path: ./plugins/.../BankAccountPagesRest.kt · Type: Kotlin REST controller · Lines: 190 · Source: GitHub

190 lines · 148 code · 30 comments · 12 blank

What it does

The REST controller for bank account CRUD — generates list/create/edit/delete endpoints at ${Rest.URL}/bankAccount. Extends AbstractDTOPagesRest which auto-generates REST endpoints for the paired DO/DTO/DAO types. Defines UI layouts (list + edit pages) programmatically via ProjectForge's UI DSL — no HTML templates, the React frontend reads the layout JSON and renders accordingly.

Generated endpoints

AbstractDTOPagesRest auto-generates these REST endpoints from the type parameters:

MethodEndpointPurpose
GET/bankAccountList page layout + data
GET/bankAccount/{id}Edit page layout + loaded entity
POST/bankAccountCreate new bank account
PUT/bankAccount/{id}Update existing bank account
DELETE/bankAccount/{id}Soft-delete bank account

Layout definitions

List page (lines 85-107)

89 agGridSupport.prepareUIGrid4ListPage(...)
98   .add(lc, BankAccountDO::name, BankAccountDO::bank,
             BankAccountDO::iban, BankAccountDO::description)
100 layout.add(MenuItem("banking.account.record.list", ...))  ← link to balance records

The list page shows an AG Grid table with 4 columns. A MenuItem link navigates to BankAccountRecordPagesRest (the balance records list).

Edit page (lines 112-189)

112 override fun createEditLayout(dto: BankAccount, userAccess: ...): UILayout {
113   val layout = super.createEditLayout(dto, userAccess)  ← base fields (name, etc.)
115   layout.add(UIDropArea("plugins.banking.account.importDropArea", ...))  ← file drop zone for bank imports
123   layout.add(lc, BankAccountDO::name, BankAccountDO::bank,
                  BankAccountDO::iban, BankAccountDO::bic, ...)
131   layout.add(UIFieldset("access.title.heading")               ← access control section
132     .add(UIRow()
133       .add(UIFieldset(6, "access.users")                       ← left half: user selectors
136         .add(UISelect.createUserSelect(lc, "fullAccessUsers", ...))
146         .add(UISelect.createUserSelect(lc, "readonlyAccessUsers", ...)))
148       .add(UIFieldset(6, "access.groups")                     ← right half: group selectors
150         .add(UISelect.createGroupSelect(lc, "fullAccessGroups", ...))
157         .add(UISelect.createGroupSelect(lc, "readonlyAccessGroups", ...)))))

Data conversion pipeline

// DB → API response:
60 transformFromDB(obj: BankAccountDO, editMode): BankAccount {
62   bankAccount.copyFrom(obj)                 ← DO → DTO (simple fields)
64   Group.restoreDisplayNames(bankAccount.fullAccessGroups)  ← IDs → names for ReactSelect
69   User.restoreDisplayNames(bankAccount.fullAccessUsers)

// API request → DB:
76 transformForDB(dto: BankAccount): BankAccountDO {
78   dto.copyTo(bankAccountDO)                 ← DTO → DO

New entity default (lines 52-58)

52 override fun newBaseDTO(request: ...): BankAccount {
54   User.getUser(ThreadLocalUserContext.loggedInUserId)?.let {
55     account.fullAccessUsers = listOf(it)    ← creator gets full access by default
56   }
57 }

Key takeaways