Files
votianng/backend/src/main/java/de/stadtbote/votian/CourierDispositionRollcard.java
T
Sven 781a2b82dc Erweitere VoTiAn NG um Fachfunktionen und verbessere die Listenoberfläche
Ergänze Auftragsbearbeitung, Disposition, Stammdaten, Kunden- und
Transporteurportale, Lagerverwaltung, Abrechnung, Exporte und Statistik.
Füge Kontoeinstellungen, Mitteilungen, Automatikdienste und Betriebsstatus
sowie die zugehörigen Tests und PHP-Abgleichsdokumentation hinzu.

Vergrößere die persönlichen Auftragslisten auf einheitliche Höhen und
richte Statusanzeigen sowie die Ranking-Vorschau-Steuerelemente bündig aus.

Validierung: 44 Frontendtests und Produktionsbuild erfolgreich.
Backend funktional unverändert gegenüber dem vollständigen Lauf mit 1.624
erfolgreichen und drei übersprungenen Tests. Layout im Browser und lokale
Bereitstellung geprüft.
2026-10-20 11:19:43 +02:00

46 lines
5.0 KiB
Java

package de.stadtbote.votian;
import de.stadtbote.votian.database.DatabaseService;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import java.time.*;
import java.util.*;
import static de.stadtbote.votian.AdminSupport.*;
import static de.stadtbote.votian.LegacyMapping.*;
import static de.stadtbote.votian.OrderEntryService.fields;
/** The standard PHP rollcard within the courier's released vehicle/day/job scope. */
@RestController
@RequestMapping("/api/courier-portal/disposition/rollcard")
class CourierDispositionRollcard {
final DatabaseService db;final BusinessSupport support;
CourierDispositionRollcard(DatabaseService db,BusinessSupport support){this.db=db;this.support=support;}
@GetMapping Map<String,Object> get(Authentication a,@RequestParam long vehicle,@RequestParam LocalDate day,@RequestParam(defaultValue="ALL") String selection){return view(ApiController.user(a),vehicle,day,selection);}
@GetMapping("/pdf") org.springframework.http.ResponseEntity<byte[]> pdf(Authentication a,@RequestParam long vehicle,@RequestParam LocalDate day,@RequestParam(defaultValue="ALL") String selection,@RequestParam String revision){
var data=view(ApiController.user(a),vehicle,day,selection);if(!Objects.equals(data.get("revision"),revision))throw VehicleDisposition.conflict();
return org.springframework.http.ResponseEntity.ok().header("Cache-Control","no-store").header("Content-Disposition","attachment; filename=Rollkarte-"+vehicle+"-"+day+".pdf").contentType(org.springframework.http.MediaType.APPLICATION_PDF).body(VehicleRollcardPdf.create(data));
}
@SuppressWarnings("unchecked") Map<String,Object> view(LegacyUser u,long vehicle,LocalDate day,String selection){return db.readTransaction(()->{
if(vehicle<=0)throw bad("Fahrzeug fehlt.");VehicleDisposition.date(day);if(selection==null||!Set.of("ALL","RESERVED","ACCEPTED").contains(selection))throw bad("Ungültige Rollkartenauswahl.");
var board=new CourierDisposition(db,support);long courier=board.courier(u);var scope=board.view(u,day,0,vehicle);var vehicles=(List<Map<String,Object>>)scope.get("rows");if(vehicles.size()!=1)throw CourierPortal.denied();var row=vehicles.getFirst();
var allowed=((List<Map<String,Object>>)row.get("jobs")).stream().map(j->id(j,"id")).toList();
var jobs=List.<Map<String,Object>>of();
if(!allowed.isEmpty()){
String reserved="(j.jb_status IN (9,0) AND j.jb_offer=0 AND EXISTS (SELECT 1 FROM vehicledisposition d WHERE d.crvh_id=? AND d.jb_id=j.jb_id AND d.vhd_timeslot>=? AND d.vhd_timeslot<?))";
String accepted="(j.jb_status=1 AND j.jb_ordertime>=? AND j.jb_ordertime<? AND EXISTS (SELECT 1 FROM courier c WHERE c.cr_id=j.cr_id AND c.cr_sid=? AND c.cr_sid<>''))";
var args=new ArrayList<Object>(allowed);args.add(mandator(db,u));String clause;
if(selection.equals("RESERVED")){clause=reserved;args.addAll(List.of(vehicle,day.toString(),day.plusDays(1).toString()));}
else if(selection.equals("ACCEPTED")){clause=accepted;args.addAll(List.of(day,day.plusDays(1),text(row,"sid")));}
else {clause="("+reserved+" OR "+accepted+")";args.addAll(List.of(vehicle,day.toString(),day.plusDays(1).toString(),day,day.plusDays(1),text(row,"sid")));}
jobs=db.queryForList("SELECT j.jb_id,j.jb_id_parent,j.jb_ordertime,j.jb_status,j.jb_service,j.jb_totalprice,csc.cs_id,csc.csc_name,cs.cs_eid AS customer_label FROM job j JOIN costcenter csc ON csc.csc_id=j.csc_id_related JOIN customer cs ON cs.cs_id=csc.cs_id WHERE j.jb_id IN ("+CourierPortal.placeholders(allowed.size())+") AND (j.jb_storno IS NULL OR j.jb_storno IN (0,1,3)) AND j.jb_timeunits>0 AND cs.hq_id IN (SELECT hq_id FROM mandatorheadquarters GROUP BY hq_id HAVING COUNT(*)=1 AND MAX(md_id)=?) AND "+clause+" ORDER BY CASE WHEN j.jb_status=1 THEN 1 ELSE 0 END,TIME(j.jb_ordertime),j.jb_id LIMIT 301",args.toArray());
if(jobs.size()>300)throw bad("Mehr als 300 Aufträge auf der Rollkarte. Bitte die Auswahl eingrenzen.");
}
var cards=new VehicleRollcards(db);var warnings=new LinkedHashSet<String>();warnings.add("Die Rollkarte enthält ausschließlich die für Ihren Zugang freigegebenen Aufträge dieses Fahrzeugs.");
String format=cards.parameter("MASK_DISPOSITION_FUNCTIONNAME_CARTAGE_NOTE",u.headquartersId());if(format.isBlank())format=cards.parameter("MASK_DISPOSITION_FUNCTIONNAME_CARTAGE_NOTE",0);
if(!format.isBlank()&&!Set.of("getCartageNote","getServiceCartageNote").contains(format))warnings.add("Für diese Niederlassung ist ein besonderes PHP-Rollkartenformat eingerichtet. Diese Vorschau verwendet die Standardrollkarte; zusätzliche Felder des Sonderformats sind nicht enthalten.");
var parents=new HashSet<>(allowed);var v=fields("crvh_id",vehicle,"crvh_sid",text(row,"sid"),"crvh_vh_sign",text(row,"registration"));
var result=cards.document(u,vehicle,day,selection,v,jobs,parents,warnings);
if(board.courier(u)!=courier)throw CourierPortal.denied();return result;
});}
}