import 'dart:typed_data'; import 'dart:convert'; import 'package:http/http.dart' as http; import '../models/work_day.dart'; import '../models/work_interval.dart'; import '../models/month_start.dart'; import '../utils/helpers.dart'; class BookingApi { final http.Client client; BookingApi({required this.client}); /// Monatliche Buchungen holen (für YYYY-MM) Future> getBookingList(DateTime monthStart) async { final y = monthStart.year.toString().padLeft(4, '0'); final m = monthStart.month.toString().padLeft(2, '0'); final uri = Uri.parse( 'https://api.windesign.at/workinghours.php?module=booking&function=getList&date=$y-$m', ); final res = await client.get(uri); if (res.statusCode != 200) { throw Exception('booking/getList failed: ${res.statusCode} ${res.body}'); } final map = jsonDecode(res.body) as Map; if (map['error'] == true) { throw Exception('booking/getList error: ${map['errmsg']}'); } final list = (map['bookings'] as List?) ?? const []; final items = []; for (final e in list) { final row = e as Map; final dayStr = (row['bookingDay'] as String?) ?? ''; final date = DateTime.tryParse(dayStr); if (date == null) continue; String? code = (row['code'] as String?)?.trim(); if (code != null && code.isEmpty) code = null; final starts = [ row['come1'] as String?, row['come2'] as String?, row['come3'] as String?, row['come4'] as String?, row['come5'] as String?, ]; final ends = [ row['leave1'] as String?, row['leave2'] as String?, row['leave3'] as String?, row['leave4'] as String?, row['leave5'] as String?, ]; final intervals = []; for (int i = 0; i < 5; i++) { final s = parseDbTime(starts[i]); final e2 = parseDbTime(ends[i]); if (s != null && e2 != null) { intervals.add(WorkInterval(s, e2)); } } items.add(WorkDay( date: DateTime(date.year, date.month, date.day), intervals: intervals, targetMinutes: 0, // wird im UI mit Tagesplan/Feiertag ersetzt code: code, )); } return items; } /// Monatliche Startdaten (Startsaldo, Vacation, Overtime, Correction) Future getMonthStart(DateTime monthStart) async { final y = monthStart.year.toString().padLeft(4, '0'); final m = monthStart.month.toString().padLeft(2, '0'); final uri = Uri.parse( 'https://api.windesign.at/workinghours.php' '?module=monthlybooking&function=getList&date=$y-$m-01', ); final res = await client.get(uri); if (res.statusCode != 200) { throw Exception('monthlybooking/getList failed: ${res.statusCode} ${res.body}'); } final map = jsonDecode(res.body) as Map; if (map['error'] == true) { throw Exception('monthlybooking/getList error: ${map['errmsg']}'); } return MonthStart.fromJson(map); } /// Einen Tag speichern: date (YYYY-MM-DD), code, come1..leave5 ("HH:mm" oder null/leer) Future saveDay(WorkDay day) async { final y = day.date.year.toString().padLeft(4, '0'); final m = day.date.month.toString().padLeft(2, '0'); final d = day.date.day.toString().padLeft(2, '0'); final dateStr = '$y-$m-$d'; // Intervalle in 5 Slots abbilden final starts = List.filled(5, null); final ends = List.filled(5, null); for (int i = 0; i < day.intervals.length && i < 5; i++) { starts[i] = fmtTimeOfDay(day.intervals[i].start); ends[i] = fmtTimeOfDay(day.intervals[i].end); } // Codes, die Zeiten serverseitig leeren final lockCodes = {'G', 'U', 'SU', 'K'}; final payload = { 'module': 'booking', 'function': 'saveDay', 'date': dateStr, 'code': day.code, // null → wird als NULL gespeichert 'come1': lockCodes.contains(day.code) ? null : starts[0], 'leave1': lockCodes.contains(day.code) ? null : ends[0], 'come2': lockCodes.contains(day.code) ? null : starts[1], 'leave2': lockCodes.contains(day.code) ? null : ends[1], 'come3': lockCodes.contains(day.code) ? null : starts[2], 'leave3': lockCodes.contains(day.code) ? null : ends[2], 'come4': lockCodes.contains(day.code) ? null : starts[3], 'leave4': lockCodes.contains(day.code) ? null : ends[3], 'come5': lockCodes.contains(day.code) ? null : starts[4], 'leave5': lockCodes.contains(day.code) ? null : ends[4], }; final uri = Uri.parse('https://api.windesign.at/workinghours.php'); final res = await client.post( uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode(payload), ); if (res.statusCode != 200) { throw Exception('booking/saveDay failed: ${res.statusCode} ${res.body}'); } final map = jsonDecode(res.body) as Map; if (map['error'] == true) { throw Exception('booking/saveDay error: ${map['errmsg']}'); } } /// Startwerte für einen Monat speichern (Upsert auf monthlybooking). /// `monthStart` = 1. des Monats. Future saveMonthStart( DateTime monthStart, { required int starthours, required int startvacation, int overtime = 0, int correction = 0, }) async { final y = monthStart.year.toString().padLeft(4, '0'); final m = monthStart.month.toString().padLeft(2, '0'); final d = '01'; // normalize final uri = Uri.parse('https://api.windesign.at/workinghours.php'); final payload = { 'module': 'monthlybooking', 'function': 'saveStart', 'date': '$y-$m-$d', 'starthours': starthours, 'startvacation': startvacation, 'overtime': overtime, 'correction': correction, }; final res = await client.post( uri, headers: {'Content-Type': 'application/json'}, body: jsonEncode(payload), ); if (res.statusCode != 200) { throw Exception('monthlybooking/saveStart failed: ${res.statusCode} ${res.body}'); } final map = jsonDecode(res.body) as Map; if (map['error'] == true) { throw Exception('monthlybooking/saveStart error: ${map['errmsg']}'); } } }