creation one order time
This commit is contained in:
@@ -10,6 +10,8 @@ class OneTimeOrder extends Equatable {
|
|||||||
required this.date,
|
required this.date,
|
||||||
required this.location,
|
required this.location,
|
||||||
required this.positions,
|
required this.positions,
|
||||||
|
this.vendorId,
|
||||||
|
this.roleRates = const <String, double>{},
|
||||||
});
|
});
|
||||||
/// The specific date for the shift or event.
|
/// The specific date for the shift or event.
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
@@ -20,6 +22,18 @@ class OneTimeOrder extends Equatable {
|
|||||||
/// The list of positions and headcounts required for this order.
|
/// The list of positions and headcounts required for this order.
|
||||||
final List<OneTimeOrderPosition> positions;
|
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
|
@override
|
||||||
List<Object?> get props => <Object?>[date, location, positions];
|
List<Object?> get props => <Object?>[
|
||||||
|
date,
|
||||||
|
location,
|
||||||
|
positions,
|
||||||
|
vendorId,
|
||||||
|
roleRates,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import 'package:firebase_auth/firebase_auth.dart' as firebase;
|
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_data_connect/krow_data_connect.dart' as dc;
|
||||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||||
import '../../domain/repositories/client_create_order_repository_interface.dart';
|
import '../../domain/repositories/client_create_order_repository_interface.dart';
|
||||||
@@ -49,8 +51,81 @@ class ClientCreateOrderRepositoryImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> createOneTimeOrder(domain.OneTimeOrder order) {
|
Future<void> createOneTimeOrder(domain.OneTimeOrder order) async {
|
||||||
return Future.value();
|
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
|
@override
|
||||||
@@ -58,4 +133,53 @@ class ClientCreateOrderRepositoryImpl
|
|||||||
// TO-DO: connect IA and return array with the information.
|
// TO-DO: connect IA and return array with the information.
|
||||||
throw UnimplementedError('Rapid order IA is not connected yet.');
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,11 +145,15 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState> {
|
|||||||
) async {
|
) async {
|
||||||
emit(state.copyWith(status: OneTimeOrderStatus.loading));
|
emit(state.copyWith(status: OneTimeOrderStatus.loading));
|
||||||
try {
|
try {
|
||||||
|
final Map<String, double> roleRates = <String, double>{
|
||||||
|
for (final role in state.roles) role.id: role.costPerHour,
|
||||||
|
};
|
||||||
final OneTimeOrder order = OneTimeOrder(
|
final OneTimeOrder order = OneTimeOrder(
|
||||||
date: state.date,
|
date: state.date,
|
||||||
location: state.location,
|
location: state.location,
|
||||||
positions: state.positions,
|
positions: state.positions,
|
||||||
// In a real app, we'd pass the vendorId here
|
vendorId: state.selectedVendor?.id,
|
||||||
|
roleRates: roleRates,
|
||||||
);
|
);
|
||||||
await _createOneTimeOrderUseCase(OneTimeOrderArguments(order: order));
|
await _createOneTimeOrderUseCase(OneTimeOrderArguments(order: order));
|
||||||
emit(state.copyWith(status: OneTimeOrderStatus.success));
|
emit(state.copyWith(status: OneTimeOrderStatus.success));
|
||||||
|
|||||||
Reference in New Issue
Block a user