Skip to content

Commit 2cf5332

Browse files
committed
Cost-Search added for Fakturafuexe (for copying cost numbers into DATEV).
1 parent 10131de commit 2cf5332

File tree

10 files changed

+190
-7
lines changed

10 files changed

+190
-7
lines changed

projectforge-application/src/main/resources/i18nKeys.json

Lines changed: 6 additions & 5 deletions
Large diffs are not rendered by default.

projectforge-business/src/main/java/org/projectforge/business/jobs/ExternalCalendarSubscriptionJob.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// //////////////////////////////////////////////////////////////////////////
1+
/////////////////////////////////////////////////////////////////////////////
22
//
33
// Project ProjectForge Community Edition
44
// www.projectforge.org

projectforge-business/src/main/kotlin/org/projectforge/business/fibu/KostFormatter.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,18 @@ class KostFormatter {
187187
}
188188
}
189189
}
190+
if (formatType == FormatType.LONG && useProjekt != null) {
191+
useProjekt.kunde?.let { kunde ->
192+
sb.append(" - ")
193+
kunde.identifier.let { identifier ->
194+
if (identifier.isNullOrBlank()) {
195+
sb.append(kunde.name.abbreviate(20))
196+
} else {
197+
sb.append(identifier)
198+
}
199+
}
200+
}
201+
}
190202
return abbreviateIfRequired(sb.toString(), formatType, abbreviationLength)
191203
}
192204

projectforge-business/src/main/kotlin/org/projectforge/menu/builder/MenuCreator.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,14 @@ open class MenuCreator {
405405
isInGroup(ProjectForgeGroup.CONTROLLING_GROUP)
406406
})
407407
)
408+
.add(
409+
MenuItemDef(MenuItemDefId.COST_SEARCH,
410+
checkAccess =
411+
{
412+
hasRight(Kost2Dao.USER_RIGHT_ID, *READONLY_READWRITE) ||
413+
isInGroup(ProjectForgeGroup.CONTROLLING_GROUP)
414+
})
415+
)
408416
.add(
409417
MenuItemDef(MenuItemDefId.COST2_TYPE_LIST,
410418
checkAccess =

projectforge-business/src/main/kotlin/org/projectforge/menu/builder/MenuItemDefId.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ enum class MenuItemDefId constructor(val i18nKey: String, val url: String? = nul
5858
COST1_LIST("menu.fibu.kost1", "wa/cost1List"), // getReactListUrl("cost1")), //
5959
COST2_LIST("menu.fibu.kost2", "wa/cost2List"), //
6060
COST2_TYPE_LIST("menu.fibu.kost2arten", "wa/cost2TypeList"), //
61+
COST_SEARCH("menu.fibu.kostSearch", getReactDynamicPageUrl("costSearch")), //
62+
6163
CUSTOMER_LIST("menu.fibu.kunden", "wa/customerList"), //
6264
//CUSTOMER_LIST("menu.fibu.kunden", getReactListUrl("customer")), // Doesn't work yet
6365

projectforge-business/src/main/resources/I18nResources.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,7 @@ menu.fibu.kost=Cost
16671667
menu.fibu.kost1=Cost 1 ids
16681668
menu.fibu.kost2=Cost 2 ids
16691669
menu.fibu.kost2arten=Cost 2 types
1670+
menu.fibu.kostSearch=Cost search
16701671
menu.fibu.kunden=Customers
16711672
menu.fibu.orderbook=Order book
16721673
menu.fibu.orderbook.htmlSuffixTooltip=Finished but not fully invoiced orders.

projectforge-business/src/main/resources/I18nResources_de.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,7 @@ menu.fibu.kost=Kost
17531753
menu.fibu.kost1=Kost1
17541754
menu.fibu.kost2=Kost2
17551755
menu.fibu.kost2arten=Kost2-Arten
1756+
menu.fibu.kostSearch=Kost-Suche
17561757
menu.fibu.kunden=Kunden
17571758
menu.fibu.orderbook=Auftragsbuch
17581759
menu.fibu.orderbook.htmlSuffixTooltip=Abgeschlossene und noch nicht vollständig fakturierte Aufträge.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Project ProjectForge Community Edition
4+
// www.projectforge.org
5+
//
6+
// Copyright (C) 2001-2025 Micromata GmbH, Germany (www.micromata.com)
7+
//
8+
// ProjectForge is dual-licensed.
9+
//
10+
// This community edition is free software; you can redistribute it and/or
11+
// modify it under the terms of the GNU General Public License as published
12+
// by the Free Software Foundation; version 3 of the License.
13+
//
14+
// This community edition is distributed in the hope that it will be useful,
15+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17+
// Public License for more details.
18+
//
19+
// You should have received a copy of the GNU General Public License along
20+
// with this program; if not, see http://www.gnu.org/licenses/.
21+
//
22+
/////////////////////////////////////////////////////////////////////////////
23+
24+
package org.projectforge.rest.fibu.kost
25+
26+
import jakarta.servlet.http.HttpServletRequest
27+
import jakarta.validation.Valid
28+
import org.projectforge.business.fibu.KostFormatter
29+
import org.projectforge.business.fibu.kost.Kost1Dao
30+
import org.projectforge.business.fibu.kost.Kost2Dao
31+
import org.projectforge.framework.DisplayNameCapable
32+
import org.projectforge.model.rest.RestPaths
33+
import org.projectforge.rest.config.Rest
34+
import org.projectforge.rest.core.AbstractDynamicPageRest
35+
import org.projectforge.rest.dto.FormLayoutData
36+
import org.projectforge.rest.dto.PostData
37+
import org.projectforge.ui.*
38+
import org.springframework.beans.factory.annotation.Autowired
39+
import org.springframework.http.ResponseEntity
40+
import org.springframework.web.bind.annotation.*
41+
42+
@RestController
43+
@RequestMapping("${Rest.URL}/costSearch")
44+
class CostSearchPageRest : AbstractDynamicPageRest() {
45+
class CostObject(
46+
var id: Long? = null,
47+
override val displayName: String?
48+
) : DisplayNameCapable
49+
50+
class SearchData {
51+
var cost1: CostObject? = null
52+
var cost2: CostObject? = null
53+
var cost1Number: Int? = null
54+
var cost1Name: String? = null
55+
var cost2Number: Int? = null
56+
var cost2Name: String? = null
57+
}
58+
59+
@Autowired
60+
private lateinit var kost1Dao: Kost1Dao
61+
62+
@Autowired
63+
private lateinit var kost2Dao: Kost2Dao
64+
65+
@GetMapping("dynamic")
66+
fun getForm(request: HttpServletRequest): FormLayoutData {
67+
val layout = UILayout("menu.fibu.kostSearch")
68+
69+
layout.add(
70+
UIRow().add(
71+
UICol(sm = 6).add(
72+
UIRow().add(
73+
UIInput(
74+
"cost1",
75+
label = "fibu.kost1",
76+
dataType = UIDataType.COST1,
77+
)
78+
)
79+
).add(
80+
UIRow().add(
81+
UICol(xs = 4).add(
82+
UIReadOnlyField("cost1Number", canCopy = true)
83+
)
84+
).add(
85+
UICol(xs = 8).add(
86+
UIReadOnlyField("cost1Name")
87+
)
88+
)
89+
)
90+
).add(
91+
UICol(sm = 6).add(
92+
UIRow().add(
93+
UIInput(
94+
"cost2",
95+
label = "fibu.kost2",
96+
dataType = UIDataType.COST2,
97+
)
98+
)
99+
).add(
100+
UIRow().add(
101+
UICol(xs = 4).add(
102+
UIReadOnlyField("cost2Number", canCopy = true)
103+
)
104+
).add(
105+
UICol(xs = 8).add(
106+
UIReadOnlyField("cost2Name")
107+
)
108+
)
109+
)
110+
)
111+
)
112+
layout.watchFields.addAll(arrayOf("cost1", "cost2"))
113+
LayoutUtils.process(layout)
114+
return FormLayoutData(SearchData(), layout, createServerData(request))
115+
}
116+
117+
@PostMapping(RestPaths.WATCH_FIELDS)
118+
fun watchFields(@Valid @RequestBody postData: PostData<SearchData>): ResponseEntity<ResponseAction> {
119+
val data = postData.data
120+
postData.watchFieldsTriggered?.let { watchFieldsTriggered ->
121+
if (watchFieldsTriggered.contains("cost1")) {
122+
data.cost1?.id?.let { id ->
123+
kost1Dao.find(id)?.let { kost ->
124+
data.cost1Number = kost.nummer
125+
data.cost1Name = KostFormatter.instance.formatKost1(kost, KostFormatter.FormatType.LONG)
126+
}
127+
}
128+
data.cost1 = null
129+
}
130+
if (watchFieldsTriggered.contains("cost2")) {
131+
data.cost2?.id?.let { id ->
132+
kost2Dao.find(id)?.let { kost ->
133+
data.cost2Number = kost.nummer
134+
data.cost2Name = KostFormatter.instance.formatKost2(kost, KostFormatter.FormatType.LONG)
135+
}
136+
}
137+
data.cost2 = null
138+
}
139+
}
140+
return ResponseEntity.ok(
141+
ResponseAction(targetType = TargetType.UPDATE)
142+
.addVariable("data", data)
143+
)
144+
}
145+
}

projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/kost/Kost2PagesRest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,26 @@ package org.projectforge.rest.fibu.kost
2525

2626
import jakarta.servlet.http.HttpServletRequest
2727
import org.projectforge.business.fibu.KostFormatter
28+
import org.projectforge.business.fibu.kost.Kost1DO
2829
import org.projectforge.business.fibu.kost.Kost2DO
2930
import org.projectforge.business.fibu.kost.Kost2Dao
31+
import org.projectforge.framework.persistence.api.BaseSearchFilter
3032
import org.projectforge.framework.persistence.api.MagicFilter
3133
import org.projectforge.rest.config.Rest
3234
import org.projectforge.rest.core.AbstractDTOPagesRest
3335
import org.projectforge.rest.dto.Customer
3436
import org.projectforge.rest.dto.Kost2
3537
import org.projectforge.rest.dto.Project
3638
import org.projectforge.ui.*
39+
import org.springframework.beans.factory.annotation.Autowired
3740
import org.springframework.web.bind.annotation.RequestMapping
3841
import org.springframework.web.bind.annotation.RestController
3942

4043
@RestController
4144
@RequestMapping("${Rest.URL}/cost2")
4245
class Kost2PagesRest : AbstractDTOPagesRest<Kost2DO, Kost2, Kost2Dao>(Kost2Dao::class.java, "fibu.kost2.title") {
46+
@Autowired
47+
private lateinit var kostFormatter: KostFormatter
4348

4449
override fun transformFromDB(obj: Kost2DO, editMode: Boolean): Kost2 {
4550
val kost2 = Kost2()
@@ -110,4 +115,12 @@ class Kost2PagesRest : AbstractDTOPagesRest<Kost2DO, Kost2, Kost2Dao>(Kost2Dao::
110115
)
111116
return LayoutUtils.processEditPage(layout, dto, this)
112117
}
118+
119+
override fun queryAutocompleteObjects(request: HttpServletRequest, filter: BaseSearchFilter): List<Kost2DO> {
120+
val list = super.queryAutocompleteObjects(request, filter)
121+
list.forEach { it.displayName = kostFormatter.formatKost2(it, KostFormatter.FormatType.LONG) }
122+
return list.sortedBy { it.displayName }
123+
}
124+
125+
override val autoCompleteSearchFields = arrayOf("description", "nummer", "projekt.name", "projekt.kunde.name")
113126
}

projectforge-wicket/src/main/java/org/projectforge/renderer/custom/MicromataFormatter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// //////////////////////////////////////////////////////////////////////////
1+
/////////////////////////////////////////////////////////////////////////////
22
//
33
// Project ProjectForge Community Edition
44
// www.projectforge.org

0 commit comments

Comments
 (0)