| 221 | |
| 222 | == Интегритет |
| 223 | |
| 224 | === Тригери |
| 225 | |
| 226 | {{{#!sql |
| 227 | |
| 228 | create or replace function check_expiry_date() returns trigger |
| 229 | as |
| 230 | $$ |
| 231 | begin |
| 232 | if exists( |
| 233 | select 1 |
| 234 | from vozenje v |
| 235 | where v.patnik_id = new.patnik_id and v.end_date is null |
| 236 | ) then |
| 237 | update vozenje set end_date = now(), status = 'FINISHED' where id in (select v.id |
| 238 | from vozenje v |
| 239 | where v.patnik_id = new.patnik_id and v.end_date is null); |
| 240 | end if; |
| 241 | |
| 242 | if exists( |
| 243 | select 1 |
| 244 | from bilet |
| 245 | where id = new.bilet_id and datum_aktivacija is null |
| 246 | ) then |
| 247 | update bilet set datum_aktivacija = now(), status = 'ACTIVE' where id = new.bilet_id; |
| 248 | end if; |
| 249 | |
| 250 | if exists( |
| 251 | select 1 |
| 252 | from bilet b |
| 253 | join tipbilet tb on b.tip_id = tb.id |
| 254 | where b.id = new.bilet_id and ((b.datum_aktivacija + (tb.trajnost || ' milliseconds')::interval) < now()) |
| 255 | ) then |
| 256 | update bilet set status = 'EXPIRED' where id = new.bilet_id; |
| 257 | end if; |
| 258 | |
| 259 | if exists( |
| 260 | select 1 |
| 261 | from bilet b |
| 262 | join tipbilet tb on b.tip_id = tb.id |
| 263 | where b.id = new.bilet_id and ((b.datum_aktivacija + (tb.trajnost || ' milliseconds')::interval) < now()) |
| 264 | ) then |
| 265 | RAISE exception 'Ticket is expired'; |
| 266 | end if; |
| 267 | return new; |
| 268 | end; |
| 269 | $$ language plpgsql; |
| 270 | |
| 271 | create or replace trigger check_validity_of_ticket |
| 272 | before insert on vozenje |
| 273 | for each row |
| 274 | execute function check_expiry_date(); |
| 275 | |
| 276 | |
| 277 | }}} |
| 278 | |
| 279 | === Трансакции |
| 280 | |
| 281 | {{{#!java |
| 282 | |
| 283 | @Transactional |
| 284 | fun refreshAverageTimeDiffs() { |
| 285 | val sql = "REFRESH MATERIALIZED VIEW CONCURRENTLY avg_time_diffs;" |
| 286 | jdbcTemplate.execute(sql) |
| 287 | } |
| 288 | |
| 289 | @Transactional |
| 290 | fun refreshCommutesByHour() { |
| 291 | val sql = "refresh materialized view concurrently most_busy_part_of_the_day;" |
| 292 | jdbcTemplate.execute(sql) |
| 293 | } |
| 294 | |
| 295 | @Transactional |
| 296 | fun refreshFinesPerLine() { |
| 297 | val sql = "refresh materialized view concurrently kazna_po_linija;" |
| 298 | jdbcTemplate.execute(sql) |
| 299 | } |
| 300 | |
| 301 | @Transactional |
| 302 | fun refreshTotalIncome() { |
| 303 | val sql = "refresh materialized view concurrently total_income;" |
| 304 | jdbcTemplate.execute(sql) |
| 305 | } |
| 306 | |
| 307 | }}} |
| 308 | |
| 309 | {{{#!java |
| 310 | @Transactional |
| 311 | fun createFine(request: FineRequest): FineResponse { |
| 312 | val kontrola = kontrolaRepository.findByIdOrNull(request.kontrolaId) ?: throw NotFoundException("Kontrola") |
| 313 | val now = Timestamp.valueOf(LocalDateTime.now()) |
| 314 | val kazna = |
| 315 | kaznaRepository.save( |
| 316 | Kazna( |
| 317 | dateCreated = now, |
| 318 | id = 0L, |
| 319 | kondukter = authService.getConductor(), |
| 320 | datePayed = |
| 321 | if (request.plateno) { |
| 322 | now |
| 323 | } else { |
| 324 | null |
| 325 | }, |
| 326 | iznos = request.iznos, |
| 327 | dokument = request.dokument, |
| 328 | kontrola = kontrola, |
| 329 | plateno = request.plateno, |
| 330 | ), |
| 331 | ) |
| 332 | |
| 333 | if (request.patnikId != null) { |
| 334 | val korisnik = korisnikRepository.findByIdOrNull(request.patnikId!!) ?: throw NotFoundException("Korisnik") |
| 335 | val patnik = patnikRepository.findByKorisnik(korisnik) ?: throw NotFoundException("Patnik") |
| 336 | val kzr = |
| 337 | kaznaZaRegistriranRepository.save( |
| 338 | KaznaZaRegistriran( |
| 339 | patnik = patnik, |
| 340 | id = 0L, |
| 341 | kazna = kazna, |
| 342 | ), |
| 343 | ) |
| 344 | return kzr.let { dtoMapper.toFineResponse(kazna = kazna, kzr = kzr, kzn = null) } |
| 345 | } |
| 346 | |
| 347 | if (request.adresa != null && request.ime != null && request.telefon != null) { |
| 348 | val kzn = |
| 349 | kaznaZaNeregistriranRepository.save( |
| 350 | KaznaZaNeregistriran( |
| 351 | id = 0L, |
| 352 | kazna = kazna, |
| 353 | ime = request.ime!!, |
| 354 | telefon = request.telefon!!, |
| 355 | adresa = request.adresa!!, |
| 356 | ), |
| 357 | ) |
| 358 | |
| 359 | return kzn.let { dtoMapper.toFineResponse(kazna = kazna, kzn = kzn, kzr = null) } |
| 360 | } |
| 361 | return dtoMapper.toFineResponse(kazna = kazna, kzr = null, kzn = null) |
| 362 | } |
| 363 | }}} |
| 364 | |
| 365 | |
| 366 | {{{#!java |
| 367 | |
| 368 | @Transactional |
| 369 | fun start(request: StartCommuteRequest): CommuteResponse { |
| 370 | if (!this.authService.hasAuthority(RoleEnum.ROLE_PASSENGER)) throw UnauthorizedAccessException("Unauthorised role") |
| 371 | val korisnik = this.authService.getAuthenticatedUser() |
| 372 | val patnik = patnikRepository.findByKorisnik(korisnik) ?: throw NotFoundException("Korisnik") |
| 373 | |
| 374 | var bilet = biletRepository.findByIdAndPatnik(request.ticketId, patnik) ?: throw NotFoundException("Bilet") |
| 375 | |
| 376 | val instancaNaLinija = |
| 377 | instancaNaLinijaRepository.findByIdOrNull(request.routeInstanceId) ?: throw NotFoundException("RouteInstanceId") |
| 378 | val postojka = postojkaRepository.findByIdOrNull(request.stationId) ?: throw NotFoundException("StationId") |
| 379 | |
| 380 | val postojkaNaLinijaStart = |
| 381 | postojkaNaLinijaRepository.findByLinijaAndPostojkaAndPravec(instancaNaLinija.linija, postojka, instancaNaLinija.pravec) |
| 382 | ?: throw NotFoundException("Station not found") |
| 383 | |
| 384 | if (bilet.status == BiletEnum.INACTIVE) { |
| 385 | bilet.status = BiletEnum.ACTIVE |
| 386 | bilet.datumAktivacija = Timestamp.valueOf(LocalDateTime.now()) |
| 387 | bilet = biletRepository.save(bilet) |
| 388 | } |
| 389 | |
| 390 | val vozenje = |
| 391 | Vozenje( |
| 392 | id = 0L, |
| 393 | startDate = Timestamp.valueOf(LocalDateTime.now()), |
| 394 | endDate = null, |
| 395 | status = VozenjeStatus.ACTIVE, |
| 396 | patnik = patnik, |
| 397 | postojkaNaLinijaStart = postojkaNaLinijaStart, |
| 398 | instancaNaLinija = instancaNaLinija, |
| 399 | bilet = bilet, |
| 400 | ) |
| 401 | return vozenjeRepository.save(vozenje).let { dtoMapper.toCommuteResponse(it) } |
| 402 | } |
| 403 | |
| 404 | }}} |