Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 8.1 snapshot #253

Merged
merged 2 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ spring.datasource.driver-class-name=org.postgresql.Driver
|===
|Stop|`docker stop projectforge-postgres`
|Start|`docker start projectforge-postgres`
|Import dump (optional)|`docker run -v ~/ProjectForgeBackup/pf.sql:/mnt/pf.sql -e PGPASSWORD=$PGPASSWORD -it --rm --link projectforge-postgres:postgres postgres:13.18 psql -h postgres -U projectforge -q -f /mnt/pf.sql 2>&1 > log.txt`
|Import dump (optional)|`docker run -v ~/ProjectForgeBackup/pf.sql:/mnt/pf.sql -e PGPASSWORD=$PGPASSWORD -it --rm --link projectforge-postgres:postgres postgres:13.18 psql -h postgres -U projectforge -q -f /mnt/pf.sql`
|PSQL|`docker run -e PGPASSWORD=$PGPASSWORD -it --rm --link projectforge-postgres:postgres postgres:13.18 psql -h postgres -U projectforge`
|Reset passwords (optional)|`update t_pf_user_password SET password_hash='SHA{BC871652288E56E306CFA093BEFC3FFCD0ED8872}', password_salt=null; update t_pf_user SET password='SHA{BC871652288E56E306CFA093BEFC3FFCD0ED8872}', password_salt=null, email='m.developer@localhost';` +
password is now `test123`.
Expand Down
35 changes: 17 additions & 18 deletions ToDo.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Aktuell:
- Scripting: Ergebnis Unresolved reference 'memo', 'todo'.: line 94 to 94 (add only activated plugins)
- Summen in DB-Exporten eintragen und serverseitig evaluieren.
- Groovy-scripts: remove or fix.
- AG-Grid: setColumnStates wird nicht in den UserPrefs gespeichert.
- Wicket: Auftragsbuch: org.apache.wicket.core.request.mapper.StalePageException: A request to page '[Page class = org.projectforge.web.fibu.AuftragEditPage, id = 9, render count = 3]' has been made with stale 'renderCount'. The page will be re-rendered.
Expand All @@ -25,10 +26,7 @@ Aktuell:
org.hibernate.persister.entity.AbstractEntityPersister#generateSelectLazy:

History
- Positionen etc. vernünftig anzeigen.

- Suche:
- Suche nach K+S (aktuell noch Provisorium)
- HistoryConvertContext: Am Ende alle displayProperties übernehmen.

- ProjektEdit: History enthält keine neuen Kost2DOs/Arten (Einträge sind aber da).
Expand All @@ -43,22 +41,13 @@ History
- History of AddressCampaignValueDO's (AddressCampaignValueDao.convertToDisplayHistoryEntries removed)

Später
- Hibernate-Search: K+S etc.
- Besuchsbuch und EmployeeValidSinceAttr: DisplayEntries von Besuchtagen mit Datum des Besuchs versehen.
- Fakturaquote
- Suche-Seite hat veraltete Bereiche, AddressListPage läuft auf Fehler.
- OrderExport: paymentSchedules werden gefetcht.
- Update caches after single load or modification.

Ganz später
- Kalenderlist ruft x-fach DB: FIND GroupDO resultClass=GroupDO auf.

Postgresql-Dump-Imports bechleunigen:

ALTER SYSTEM SET fsync = off;
ALTER SYSTEM SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';
drop view v_t_pf_user;

Rancher

docker system df
Expand All @@ -67,13 +56,23 @@ docker system df
docker volume ls
docker volume rm <volume-name>

drop table t_fibu_orderbook_storage;
delete from t_flyway_schema_history where version = '2023.11.01';

Postgresql-Dump-Imports bechleunigen:

ALTER SYSTEM SET fsync = off;
ALTER SYSTEM SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';


drop view v_t_pf_user;


Orderbooks importieren:
docker cp ~/ProjectForgeBackup/ProjectForge-Orderbook_*.gz projectforge-postgres:/tmp/

\set file_path '/tmp/ProjectForge-Orderbook_2023-11-01.gz'
INSERT INTO t_fibu_orderbook_storage (date, serialized_orderbook) VALUES ('2023-11-01', pg_read_binary_file(:'file_path')::bytea);
\set file_path '/tmp/ProjectForge-Orderbook_2023-12-01.gz'
INSERT INTO t_fibu_orderbook_storage (date, serialized_orderbook) VALUES ('2023-12-01', pg_read_binary_file(:'file_path')::bytea);
INSERT INTO t_fibu_orderbook_snapshots (date, created, serialized_orderbook, size) VALUES ('2023-11-01', NOW(), pg_read_binary_file(:'file_path')::bytea, (pg_stat_file(:'file_path')).size);

docker run -e PGPASSWORD=$PGPASSWORD -it --rm --link projectforge-postgres:postgres postgres:13.18 pg_dump -h postgres -U projectforge --data-only --column-inserts --table=t_fibu_orderbook_snapshots

psql -f export.sql
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,15 @@ class AuftragsCacheService {
order.bemerkung = getString(tuple, "bemerkung")
order.periodOfPerformanceBegin = getLocalDate(tuple, "periodOfPerformanceBegin")
order.periodOfPerformanceEnd = getLocalDate(tuple, "periodOfPerformanceEnd")
order.kundeText = getString(tuple, "kundeText")
getLong(tuple, "kundeId")?.let { kundeId ->
order.kunde = em.getReference(KundeDO::class.java, kundeId)
}
getLong(tuple, "projektId")?.let { projektId ->
order.projekt = em.getReference(ProjektDO::class.java, projektId)
}
getLong(tuple, "contactPersonId")?.let { userId ->
order.contactPerson = PFUserDO().also { it.id = userId }
order.contactPerson = em.getReference(PFUserDO::class.java, userId)
}
}
}
Expand All @@ -82,7 +89,7 @@ class AuftragsCacheService {
AuftragsPositionDO().also { pos ->
pos.id = getLong(tuple, "id")
getLong(tuple, "auftragId")?.let { auftragId ->
pos.auftrag = AuftragDO().also { it.id = auftragId }
pos.auftrag = em.getReference(AuftragDO::class.java, auftragId)
}
pos.number = getShort(tuple, "number")!!
pos.deleted = getBoolean(tuple, "deleted")!!
Expand Down Expand Up @@ -134,7 +141,7 @@ class AuftragsCacheService {
a.entscheidungsDatum as entscheidungsDatum,a.bemerkung as bemerkung,
a.probabilityOfOccurrence as probabilityOfOccurrence,
a.periodOfPerformanceBegin as periodOfPerformanceBegin, a.periodOfPerformanceEnd as periodOfPerformanceEnd,
a.contactPerson.id as contactPersonId
a.contactPerson.id as contactPersonId, a.kunde.id as kundeId, a.projekt.id as projektId, a.kundeText as kundeText
FROM ${AuftragDO::class.simpleName} a
""".trimIndent()
private val SELECT_POSITIONS = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.projectforge.Constants
import org.projectforge.business.excel.ExcelDateFormats
import org.projectforge.business.excel.XlsContentProvider
import org.projectforge.business.fibu.kost.ProjektCache
import org.projectforge.business.fibu.orderbooksnapshots.OrderbookSnapshotsService
import org.projectforge.business.task.TaskTree
import org.projectforge.business.user.ProjectForgeGroup
import org.projectforge.common.DateFormatType
Expand All @@ -48,6 +49,8 @@ import org.springframework.stereotype.Service
import java.io.IOException
import java.math.BigDecimal
import java.math.RoundingMode
import java.time.LocalDate
import java.time.Month
import java.time.format.DateTimeFormatter

private val log = KotlinLogging.logger {}
Expand All @@ -63,6 +66,9 @@ open class ForecastExport { // open needed by Wicket.
@Autowired
private lateinit var accessChecker: AccessChecker

@Autowired
private lateinit var orderbookSnapshotsService: OrderbookSnapshotsService

@Autowired
private lateinit var orderDao: AuftragDao

Expand Down Expand Up @@ -117,8 +123,9 @@ open class ForecastExport { // open needed by Wicket.
val forecastSheet: ExcelSheet,
val invoicesSheet: ExcelSheet,
val invoicesPriorYearSheet: ExcelSheet,
val baseDate: PFDay,
val invoices: List<RechnungDO>
val startDate: PFDay,
val invoices: List<RechnungDO>,
val today: PFDay = PFDay.now()
) {
val excelDateFormat =
ThreadLocalUserContext.loggedInUser?.excelDateFormat ?: ExcelDateFormats.EXCEL_DEFAULT_DATE
Expand All @@ -136,7 +143,6 @@ open class ForecastExport { // open needed by Wicket.
false // showAll is true, if no filter is given and for financial and controlling staff only.
val orderPositionMap = mutableMapOf<Long, OrderPositionInfo>()
val orderMapByPositionId = mutableMapOf<Long, OrderInfo>()
val today = PFDay.now()
val thisMonth = today.beginOfMonth

init {
Expand All @@ -147,35 +153,57 @@ open class ForecastExport { // open needed by Wicket.

@Throws(IOException::class)
open fun export(origFilter: AuftragFilter): ByteArray? {
val baseDateParam = origFilter.periodOfPerformanceStartDate
val baseDate = if (baseDateParam != null) PFDay.from(baseDateParam).beginOfMonth else PFDay.now().beginOfYear
val startDateParam = origFilter.periodOfPerformanceStartDate
val startDate = if (startDateParam != null) PFDay.from(startDateParam).beginOfMonth else PFDay.now().beginOfYear
val filter = AuftragFilter()
filter.searchString = origFilter.searchString
filter.projectList = origFilter.projectList
//filter.auftragFakturiertFilterStatus = origFilter.auftragFakturiertFilterStatus
//filter.auftragsPositionsPaymentType = origFilter.auftragsPositionsPaymentType
filter.periodOfPerformanceStartDate =
baseDate.plusYears(-2).localDate // Go 2 years back for getting all orders referred by invoices of prior year.
startDate.plusYears(-2).localDate // Go 2 years back for getting all orders referred by invoices of prior year.
filter.user = origFilter.user
val orderList = orderDao.select(filter)
log.info { "Exporting forecast script for date ${baseDate.isoString} with filter: str='${filter.searchString ?: ""}', projects=${filter.projectList?.joinToString { it.name ?: "???" }}" }
log.info { "Exporting forecast script for date ${startDate.isoString} with filter: str='${filter.searchString ?: ""}', projects=${filter.projectList?.joinToString { it.name ?: "???" }}" }
val showAll = accessChecker.isLoggedInUserMemberOfGroup(
ProjectForgeGroup.FINANCE_GROUP,
ProjectForgeGroup.CONTROLLING_GROUP
) &&
filter.searchString.isNullOrBlank() &&
filter.projectList.isNullOrEmpty()
return export(orderList, baseDate, showAll = showAll)
return export(orderList, startDate, showAll = showAll)
}

@Throws(IOException::class)
open fun export(orderList: Collection<AuftragDO>, baseDate: PFDay, showAll: Boolean): ByteArray? {
open fun export(startDate: PFDay, snapshotDate: PFDay): ByteArray? {
val orderList = orderbookSnapshotsService.readSnapshot(snapshotDate.localDate) ?: return null
return export(orderList, startDate, showAll = true, snapshotDate)
}

/**
* Export the forecast sheet.
* @param orderList The list of orders to export.
* @param startDate The start date for the forecast.
* @param showAll True, if no filter is given, for financial and controlling staff only.
* @param today Today (null) or, the day of the snapshot, if the orderList is loaded from order book snapshots.
* If the date is in the past, the forecast will be simulated with the specified date.
* If date is given, no caches will be used.
* @return The byte array of the Excel file.
*/
@Throws(IOException::class)
open fun export(
orderList: Collection<AuftragDO>,
startDate: PFDay,
showAll: Boolean,
today: PFDay? = null,
): ByteArray? {
if (orderList.isEmpty()) {
log.info { "No orders found for export." }
// No orders found, so we don't need the forecast sheet.
return null
}
val prevYearBaseDate = baseDate.plusYears(-1) // One year back for getting all invoices.
val useAuftragsCache = today == null
val prevYearBaseDate = startDate.plusYears(-1) // One year back for getting all invoices.
val invoiceFilter = RechnungFilter()
invoiceFilter.fromDate =
prevYearBaseDate.plusDays(-1).localDate // Go 1 day back, paranoia setting for getting all invoices for given time period.
Expand All @@ -201,7 +229,15 @@ open class ForecastExport { // open needed by Wicket.
InvoicesCol.entries.forEach { invoicesPriorYearSheet.registerColumn(it.header) }
MonthCol.entries.forEach { invoicesPriorYearSheet.registerColumn(it.header) }

val ctx = Context(workbook, forecastSheet, invoicesSheet, invoicesPriorYearSheet, baseDate, invoices)
val ctx = Context(
workbook,
forecastSheet = forecastSheet,
invoicesSheet = invoicesSheet,
invoicesPriorYearSheet = invoicesPriorYearSheet,
startDate = startDate,
invoices = invoices,
today = today ?: PFDay.now(),
)
ctx.showAll = showAll

var currentRow = 9
Expand All @@ -210,7 +246,7 @@ open class ForecastExport { // open needed by Wicket.
auftragDO.projekt?.id?.let { projektId ->
ctx.projectIds.add(projektId)
}
val orderInfo = ordersCache.getOrderInfo(auftragDO)
val orderInfo = if (useAuftragsCache) ordersCache.getOrderInfo(auftragDO) else auftragDO.info
auftragDO.id?.let { ctx.orderMap[it] = orderInfo }
orderInfo.infoPositions?.forEach { pos ->
pos.id?.let {
Expand All @@ -237,8 +273,8 @@ open class ForecastExport { // open needed by Wicket.
return null
}
fillInvoices(ctx)
replaceMonthDatesInHeaderRow(forecastSheet, baseDate)
replaceMonthDatesInHeaderRow(invoicesSheet, baseDate)
replaceMonthDatesInHeaderRow(forecastSheet, startDate)
replaceMonthDatesInHeaderRow(invoicesSheet, startDate)
replaceMonthDatesInHeaderRow(invoicesPriorYearSheet, prevYearBaseDate)
forecastSheet.setAutoFilter()
invoicesSheet.setAutoFilter()
Expand Down Expand Up @@ -386,16 +422,8 @@ open class ForecastExport { // open needed by Wicket.
ForecastCol.ABRECHNUNGSART.header,
if (pos.paymentType != null) translate(pos.paymentType.i18nKey) else ""
)
sheet.setStringValue(
row,
ForecastCol.AUFTRAG_STATUS.header,
if (order.status != null) translate(order.status!!.i18nKey) else ""
)
sheet.setStringValue(
row,
ForecastCol.POSITION_STATUS.header,
if (pos.status != null) translate(pos.status.i18nKey) else ""
)
sheet.setStringValue(row, ForecastCol.AUFTRAG_STATUS.header, translate(order.status.i18nKey))
sheet.setStringValue(row, ForecastCol.POSITION_STATUS.header, translate(pos.status.i18nKey))
sheet.setIntValue(row, ForecastCol.PT.header, pos.personDays?.toInt() ?: 0)
sheet.setBigDecimalValue(
row, ForecastCol.NETTOSUMME.header, pos.netSum
Expand Down Expand Up @@ -443,13 +471,13 @@ open class ForecastExport { // open needed by Wicket.
sheet.setDateValue(
row,
leistungsZeitraumColDef,
PFDay(order.periodOfPerformanceBegin!!).localDate,
PFDay.fromOrNull(order.periodOfPerformanceBegin)?.localDate,
ctx.excelDateFormat
)
sheet.setDateValue(
row,
leistungsZeitraumColDef.columnNumber + 1,
PFDay(order.periodOfPerformanceEnd!!).localDate,
PFDay.fromOrNull(order.periodOfPerformanceEnd)?.localDate,
ctx.excelDateFormat
)
}
Expand Down Expand Up @@ -546,7 +574,7 @@ open class ForecastExport { // open needed by Wicket.
order: OrderInfo, pos: OrderPositionInfo
) { // payment values
val probability = ForecastUtils.getProbabilityOfAccurence(order, pos)
var currentMonth = ctx.baseDate.plusMonths(-1).beginOfMonth
var currentMonth = ctx.startDate.plusMonths(-1).beginOfMonth
MonthCol.entries.forEach {
currentMonth = currentMonth.plusMonths(1)
if (checkAfterMonthBefore(currentMonth)) {
Expand Down Expand Up @@ -589,7 +617,7 @@ open class ForecastExport { // open needed by Wicket.

private fun getMonthIndex(ctx: Context, date: PFDay): Int {
val monthDate = date.year * 12 + date.monthValue
val monthBaseDate = ctx.baseDate.year * 12 + ctx.baseDate.monthValue
val monthBaseDate = ctx.startDate.year * 12 + ctx.startDate.monthValue
return monthDate - monthBaseDate // index from 0 to 11
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ object ForecastUtils { // open needed by Wicket.
*/
@JvmStatic
fun computeProbabilityNetSum(order: OrderInfo, pos: OrderPositionInfo): BigDecimal {
val netSum = if (pos.netSum != null) pos.netSum else BigDecimal.ZERO
val netSum = pos.netSum ?: BigDecimal.ZERO
val probability = getProbabilityOfAccurence(order, pos)
return netSum.multiply(probability)
}
Expand All @@ -88,13 +88,13 @@ object ForecastUtils { // open needed by Wicket.
fun getProbabilityOfAccurence(order: OrderInfo, pos: OrderPositionInfo): BigDecimal {
// See ForecastExportProbabilities.xlsx
// Excel rows: Order 1-4
if (order.status?.isIn(AuftragsStatus.ABGELEHNT, AuftragsStatus.ERSETZT) == true
|| pos.status?.isIn(AuftragsStatus.ABGELEHNT, AuftragsStatus.ERSETZT) == true
if (order.status.isIn(AuftragsStatus.ABGELEHNT, AuftragsStatus.ERSETZT) == true
|| pos.status.isIn(AuftragsStatus.ABGELEHNT, AuftragsStatus.ERSETZT) == true
) {
return BigDecimal.ZERO
}
// Excel rows: Order 5-6
if (pos.status?.isIn(AuftragsStatus.POTENZIAL, AuftragsStatus.OPTIONAL) == true) {
if (pos.status.isIn(AuftragsStatus.POTENZIAL, AuftragsStatus.OPTIONAL) == true) {
return getGivenProbability(order, BigDecimal.ZERO)
}
// Excel rows: Order 7
Expand All @@ -106,17 +106,17 @@ object ForecastUtils { // open needed by Wicket.
return getGivenProbability(order, BigDecimal.ZERO)
}
// Excel rows: Order 9-10
if (order.status?.isIn(AuftragsStatus.ABGESCHLOSSEN, AuftragsStatus.BEAUFTRAGT) == true) {
if (order.status.isIn(AuftragsStatus.ABGESCHLOSSEN, AuftragsStatus.BEAUFTRAGT) == true) {
return BigDecimal.ONE
}
// Excel rows: Order 11-12
if (order.status?.isIn(
if (order.status.isIn(
AuftragsStatus.ESKALATION,
AuftragsStatus.GELEGT,
AuftragsStatus.IN_ERSTELLUNG
) == true
) {
if (pos.status?.isIn(
if (pos.status.isIn(
AuftragsStatus.ESKALATION,
AuftragsStatus.GELEGT,
AuftragsStatus.IN_ERSTELLUNG
Expand All @@ -131,7 +131,7 @@ object ForecastUtils { // open needed by Wicket.
}
// Excel rows: Order 13
if (order.status == AuftragsStatus.LOI
&& pos.status?.isIn(
&& pos.status.isIn(
AuftragsStatus.ESKALATION,
AuftragsStatus.GELEGT,
AuftragsStatus.IN_ERSTELLUNG
Expand Down
Loading
Loading