creation one order time

This commit is contained in:
José Salazar
2026-01-23 16:03:43 -05:00
parent 2643037c0b
commit f0f8128625
3 changed files with 146 additions and 4 deletions

View File

@@ -10,6 +10,8 @@ class OneTimeOrder extends Equatable {
required this.date,
required this.location,
required this.positions,
this.vendorId,
this.roleRates = const <String, double>{},
});
/// The specific date for the shift or event.
final DateTime date;
@@ -20,6 +22,18 @@ class OneTimeOrder extends Equatable {
/// The list of positions and headcounts required for this order.
final List<OneTimeOrderPosition> positions;
/// Selected vendor id for this order.
final String? vendorId;
/// Role hourly rates keyed by role id.
final Map<String, double> roleRates;
@override
List<Object?> get props => <Object?>[date, location, positions];
List<Object?> get props => <Object?>[
date,
location,
positions,
vendorId,
roleRates,
];
}

View File

@@ -1,4 +1,6 @@
import 'package:firebase_auth/firebase_auth.dart' as firebase;
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:intl/intl.dart';
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_domain/krow_domain.dart' as domain;
import '../../domain/repositories/client_create_order_repository_interface.dart';
@@ -49,8 +51,81 @@ class ClientCreateOrderRepositoryImpl
}
@override
Future<void> createOneTimeOrder(domain.OneTimeOrder order) {
return Future.value();
Future<void> createOneTimeOrder(domain.OneTimeOrder order) async {
final businessId = dc.ClientSessionStore.instance.session?.business?.id;
if (businessId == null || businessId.isEmpty) {
await _firebaseAuth.signOut();
throw Exception('Business is missing. Please sign in again.');
}
final vendorId = order.vendorId;
if (vendorId == null || vendorId.isEmpty) {
throw Exception('Vendor is missing.');
}
final orderTimestamp = _toTimestamp(order.date);
final orderResult = await _dataConnect
.createOrder(businessId: businessId, orderType: dc.OrderType.ONE_TIME)
.vendorId(vendorId)
.location(order.location)
.status(dc.OrderStatus.POSTED)
.date(orderTimestamp)
.execute();
final orderId = orderResult.data?.order_insert.id;
if (orderId == null) {
throw Exception('Order creation failed.');
}
final workersNeeded = order.positions.fold<int>(
0,
(sum, position) => sum + position.count,
);
final shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
final shiftCost = _calculateShiftCost(order);
final shiftResult = await _dataConnect
.createShift(title: shiftTitle, orderId: orderId)
.date(orderTimestamp)
.location(order.location)
.locationAddress(order.location)
.status(dc.ShiftStatus.PENDING)
.workersNeeded(workersNeeded)
.filled(0)
.durationDays(1)
.cost(shiftCost)
.execute();
final shiftId = shiftResult.data?.shift_insert.id;
if (shiftId == null) {
throw Exception('Shift creation failed.');
}
for (final position in order.positions) {
final start = _parseTime(order.date, position.startTime);
final end = _parseTime(order.date, position.endTime);
final normalizedEnd =
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
final hours = normalizedEnd.difference(start).inMinutes / 60.0;
final rate = order.roleRates[position.role] ?? 0;
final totalValue = rate * hours;
await _dataConnect
.createShiftRole(
shiftId: shiftId,
roleId: position.role,
count: position.count,
)
.startTime(_toTimestamp(start))
.endTime(_toTimestamp(normalizedEnd))
.hours(hours)
.totalValue(totalValue)
.execute();
}
await _dataConnect
.updateOrder(id: orderId)
.shifts(fdc.AnyValue(<String>[shiftId]))
.execute();
}
@override
@@ -58,4 +133,53 @@ class ClientCreateOrderRepositoryImpl
// TO-DO: connect IA and return array with the information.
throw UnimplementedError('Rapid order IA is not connected yet.');
}
double _calculateShiftCost(domain.OneTimeOrder order) {
double total = 0;
for (final position in order.positions) {
final start = _parseTime(order.date, position.startTime);
final end = _parseTime(order.date, position.endTime);
final normalizedEnd =
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
final hours = normalizedEnd.difference(start).inMinutes / 60.0;
final rate = order.roleRates[position.role] ?? 0;
total += rate * hours;
}
return total;
}
DateTime _parseTime(DateTime date, String time) {
if (time.trim().isEmpty) {
throw Exception('Shift time is missing.');
}
DateTime parsed;
try {
parsed = DateFormat.jm().parse(time);
} catch (_) {
parsed = DateFormat.Hm().parse(time);
}
return DateTime(
date.year,
date.month,
date.day,
parsed.hour,
parsed.minute,
);
}
fdc.Timestamp _toTimestamp(DateTime dateTime) {
final utc = dateTime.toUtc();
final seconds = utc.millisecondsSinceEpoch ~/ 1000;
final nanoseconds = (utc.microsecondsSinceEpoch % 1000000) * 1000;
return fdc.Timestamp(nanoseconds, seconds);
}
String _formatDate(DateTime dateTime) {
final year = dateTime.year.toString().padLeft(4, '0');
final month = dateTime.month.toString().padLeft(2, '0');
final day = dateTime.day.toString().padLeft(2, '0');
return '$year-$month-$day';
}
}

View File

@@ -145,11 +145,15 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
) async {
emit(state.copyWith(status: OneTimeOrderStatus.loading));
try {
final Map<String, double> roleRates = <String, double>{
for (final role in state.roles) role.id: role.costPerHour,
};
final OneTimeOrder order = OneTimeOrder(
date: state.date,
location: state.location,
positions: state.positions,
// In a real app, we'd pass the vendorId here
vendorId: state.selectedVendor?.id,
roleRates: roleRates,
);
await _createOneTimeOrderUseCase(OneTimeOrderArguments(order: order));
emit(state.copyWith(status: OneTimeOrderStatus.success));