feat: Implement order details retrieval for pre-filling new order forms for reordering.
This commit is contained in:
@@ -42,6 +42,7 @@ export 'src/entities/orders/permanent_order.dart';
|
|||||||
export 'src/entities/orders/permanent_order_position.dart';
|
export 'src/entities/orders/permanent_order_position.dart';
|
||||||
export 'src/entities/orders/order_type.dart';
|
export 'src/entities/orders/order_type.dart';
|
||||||
export 'src/entities/orders/order_item.dart';
|
export 'src/entities/orders/order_item.dart';
|
||||||
|
export 'src/entities/orders/reorder_data.dart';
|
||||||
|
|
||||||
// Skills & Certs
|
// Skills & Certs
|
||||||
export 'src/entities/skills/skill.dart';
|
export 'src/entities/skills/skill.dart';
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'one_time_order.dart';
|
||||||
|
import 'order_type.dart';
|
||||||
|
|
||||||
|
/// Represents the full details of an order retrieved for reordering.
|
||||||
|
class ReorderData extends Equatable {
|
||||||
|
const ReorderData({
|
||||||
|
required this.orderId,
|
||||||
|
required this.orderType,
|
||||||
|
required this.eventName,
|
||||||
|
required this.vendorId,
|
||||||
|
required this.hub,
|
||||||
|
required this.positions,
|
||||||
|
this.date,
|
||||||
|
this.startDate,
|
||||||
|
this.endDate,
|
||||||
|
this.recurringDays = const <String>[],
|
||||||
|
this.permanentDays = const <String>[],
|
||||||
|
});
|
||||||
|
|
||||||
|
final String orderId;
|
||||||
|
final OrderType orderType;
|
||||||
|
final String eventName;
|
||||||
|
final String? vendorId;
|
||||||
|
final OneTimeOrderHubDetails hub;
|
||||||
|
final List<ReorderPosition> positions;
|
||||||
|
|
||||||
|
// One-time specific
|
||||||
|
final DateTime? date;
|
||||||
|
|
||||||
|
// Recurring/Permanent specific
|
||||||
|
final DateTime? startDate;
|
||||||
|
final DateTime? endDate;
|
||||||
|
final List<String> recurringDays;
|
||||||
|
final List<String> permanentDays;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => <Object?>[
|
||||||
|
orderId,
|
||||||
|
orderType,
|
||||||
|
eventName,
|
||||||
|
vendorId,
|
||||||
|
hub,
|
||||||
|
positions,
|
||||||
|
date,
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
recurringDays,
|
||||||
|
permanentDays,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReorderPosition extends Equatable {
|
||||||
|
const ReorderPosition({
|
||||||
|
required this.roleId,
|
||||||
|
required this.count,
|
||||||
|
required this.startTime,
|
||||||
|
required this.endTime,
|
||||||
|
this.lunchBreak = 'NO_BREAK',
|
||||||
|
});
|
||||||
|
|
||||||
|
final String roleId;
|
||||||
|
final int count;
|
||||||
|
final String startTime;
|
||||||
|
final String endTime;
|
||||||
|
final String lunchBreak;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => <Object?>[
|
||||||
|
roleId,
|
||||||
|
count,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
lunchBreak,
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import 'domain/usecases/create_one_time_order_usecase.dart';
|
|||||||
import 'domain/usecases/create_permanent_order_usecase.dart';
|
import 'domain/usecases/create_permanent_order_usecase.dart';
|
||||||
import 'domain/usecases/create_recurring_order_usecase.dart';
|
import 'domain/usecases/create_recurring_order_usecase.dart';
|
||||||
import 'domain/usecases/create_rapid_order_usecase.dart';
|
import 'domain/usecases/create_rapid_order_usecase.dart';
|
||||||
|
import 'domain/usecases/get_order_details_for_reorder_usecase.dart';
|
||||||
import 'presentation/blocs/index.dart';
|
import 'presentation/blocs/index.dart';
|
||||||
import 'presentation/pages/create_order_page.dart';
|
import 'presentation/pages/create_order_page.dart';
|
||||||
import 'presentation/pages/one_time_order_page.dart';
|
import 'presentation/pages/one_time_order_page.dart';
|
||||||
@@ -27,13 +28,16 @@ class ClientCreateOrderModule extends Module {
|
|||||||
@override
|
@override
|
||||||
void binds(Injector i) {
|
void binds(Injector i) {
|
||||||
// Repositories
|
// Repositories
|
||||||
i.addLazySingleton<ClientCreateOrderRepositoryInterface>(ClientCreateOrderRepositoryImpl.new);
|
i.addLazySingleton<ClientCreateOrderRepositoryInterface>(
|
||||||
|
ClientCreateOrderRepositoryImpl.new,
|
||||||
|
);
|
||||||
|
|
||||||
// UseCases
|
// UseCases
|
||||||
i.addLazySingleton(CreateOneTimeOrderUseCase.new);
|
i.addLazySingleton(CreateOneTimeOrderUseCase.new);
|
||||||
i.addLazySingleton(CreatePermanentOrderUseCase.new);
|
i.addLazySingleton(CreatePermanentOrderUseCase.new);
|
||||||
i.addLazySingleton(CreateRecurringOrderUseCase.new);
|
i.addLazySingleton(CreateRecurringOrderUseCase.new);
|
||||||
i.addLazySingleton(CreateRapidOrderUseCase.new);
|
i.addLazySingleton(CreateRapidOrderUseCase.new);
|
||||||
|
i.addLazySingleton(GetOrderDetailsForReorderUseCase.new);
|
||||||
|
|
||||||
// BLoCs
|
// BLoCs
|
||||||
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
i.add<RapidOrderBloc>(RapidOrderBloc.new);
|
||||||
@@ -49,19 +53,31 @@ class ClientCreateOrderModule extends Module {
|
|||||||
child: (BuildContext context) => const ClientCreateOrderPage(),
|
child: (BuildContext context) => const ClientCreateOrderPage(),
|
||||||
);
|
);
|
||||||
r.child(
|
r.child(
|
||||||
ClientPaths.childRoute(ClientPaths.createOrder, ClientPaths.createOrderRapid),
|
ClientPaths.childRoute(
|
||||||
|
ClientPaths.createOrder,
|
||||||
|
ClientPaths.createOrderRapid,
|
||||||
|
),
|
||||||
child: (BuildContext context) => const RapidOrderPage(),
|
child: (BuildContext context) => const RapidOrderPage(),
|
||||||
);
|
);
|
||||||
r.child(
|
r.child(
|
||||||
ClientPaths.childRoute(ClientPaths.createOrder, ClientPaths.createOrderOneTime),
|
ClientPaths.childRoute(
|
||||||
|
ClientPaths.createOrder,
|
||||||
|
ClientPaths.createOrderOneTime,
|
||||||
|
),
|
||||||
child: (BuildContext context) => const OneTimeOrderPage(),
|
child: (BuildContext context) => const OneTimeOrderPage(),
|
||||||
);
|
);
|
||||||
r.child(
|
r.child(
|
||||||
ClientPaths.childRoute(ClientPaths.createOrder, ClientPaths.createOrderRecurring),
|
ClientPaths.childRoute(
|
||||||
|
ClientPaths.createOrder,
|
||||||
|
ClientPaths.createOrderRecurring,
|
||||||
|
),
|
||||||
child: (BuildContext context) => const RecurringOrderPage(),
|
child: (BuildContext context) => const RecurringOrderPage(),
|
||||||
);
|
);
|
||||||
r.child(
|
r.child(
|
||||||
ClientPaths.childRoute(ClientPaths.createOrder, ClientPaths.createOrderPermanent),
|
ClientPaths.childRoute(
|
||||||
|
ClientPaths.createOrder,
|
||||||
|
ClientPaths.createOrderPermanent,
|
||||||
|
),
|
||||||
child: (BuildContext context) => const PermanentOrderPage(),
|
child: (BuildContext context) => const PermanentOrderPage(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
||||||
import 'package:intl/intl.dart';
|
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;
|
||||||
@@ -11,10 +11,10 @@ import '../../domain/repositories/client_create_order_repository_interface.dart'
|
|||||||
///
|
///
|
||||||
/// It follows the KROW Clean Architecture by keeping the data layer focused
|
/// It follows the KROW Clean Architecture by keeping the data layer focused
|
||||||
/// on delegation and data mapping, without business logic.
|
/// on delegation and data mapping, without business logic.
|
||||||
class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInterface {
|
class ClientCreateOrderRepositoryImpl
|
||||||
ClientCreateOrderRepositoryImpl({
|
implements ClientCreateOrderRepositoryInterface {
|
||||||
required dc.DataConnectService service,
|
ClientCreateOrderRepositoryImpl({required dc.DataConnectService service})
|
||||||
}) : _service = service;
|
: _service = service;
|
||||||
|
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
@@ -36,19 +36,19 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
order.date.month,
|
order.date.month,
|
||||||
order.date.day,
|
order.date.day,
|
||||||
);
|
);
|
||||||
final fdc.Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
final Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
||||||
final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables> orderResult =
|
final OperationResult<dc.CreateOrderData, dc.CreateOrderVariables>
|
||||||
await _service.connector
|
orderResult = await _service.connector
|
||||||
.createOrder(
|
.createOrder(
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
orderType: dc.OrderType.ONE_TIME,
|
orderType: dc.OrderType.ONE_TIME,
|
||||||
teamHubId: hub.id,
|
teamHubId: hub.id,
|
||||||
)
|
)
|
||||||
.vendorId(vendorId)
|
.vendorId(vendorId)
|
||||||
.eventName(order.eventName)
|
.eventName(order.eventName)
|
||||||
.status(dc.OrderStatus.POSTED)
|
.status(dc.OrderStatus.POSTED)
|
||||||
.date(orderTimestamp)
|
.date(orderTimestamp)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String orderId = orderResult.data.order_insert.id;
|
final String orderId = orderResult.data.order_insert.id;
|
||||||
|
|
||||||
@@ -59,32 +59,34 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
final String shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
|
final String shiftTitle = 'Shift 1 ${_formatDate(order.date)}';
|
||||||
final double shiftCost = _calculateShiftCost(order);
|
final double shiftCost = _calculateShiftCost(order);
|
||||||
|
|
||||||
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables> shiftResult =
|
final OperationResult<dc.CreateShiftData, dc.CreateShiftVariables>
|
||||||
await _service.connector
|
shiftResult = await _service.connector
|
||||||
.createShift(title: shiftTitle, orderId: orderId)
|
.createShift(title: shiftTitle, orderId: orderId)
|
||||||
.date(orderTimestamp)
|
.date(orderTimestamp)
|
||||||
.location(hub.name)
|
.location(hub.name)
|
||||||
.locationAddress(hub.address)
|
.locationAddress(hub.address)
|
||||||
.latitude(hub.latitude)
|
.latitude(hub.latitude)
|
||||||
.longitude(hub.longitude)
|
.longitude(hub.longitude)
|
||||||
.placeId(hub.placeId)
|
.placeId(hub.placeId)
|
||||||
.city(hub.city)
|
.city(hub.city)
|
||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.OPEN)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
.cost(shiftCost)
|
.cost(shiftCost)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String shiftId = shiftResult.data.shift_insert.id;
|
final String shiftId = shiftResult.data.shift_insert.id;
|
||||||
|
|
||||||
for (final domain.OneTimeOrderPosition position in order.positions) {
|
for (final domain.OneTimeOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(order.date, position.startTime);
|
final DateTime start = _parseTime(order.date, position.startTime);
|
||||||
final DateTime end = _parseTime(order.date, position.endTime);
|
final DateTime end = _parseTime(order.date, position.endTime);
|
||||||
final DateTime normalizedEnd = end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
final double totalValue = rate * hours * position.count;
|
final double totalValue = rate * hours * position.count;
|
||||||
@@ -106,7 +108,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
|
|
||||||
await _service.connector
|
await _service.connector
|
||||||
.updateOrder(id: orderId, teamHubId: hub.id)
|
.updateOrder(id: orderId, teamHubId: hub.id)
|
||||||
.shifts(fdc.AnyValue(<String>[shiftId]))
|
.shifts(AnyValue(<String>[shiftId]))
|
||||||
.execute();
|
.execute();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -129,74 +131,78 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
order.startDate.month,
|
order.startDate.month,
|
||||||
order.startDate.day,
|
order.startDate.day,
|
||||||
);
|
);
|
||||||
final fdc.Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
final Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
||||||
final fdc.Timestamp startTimestamp = orderTimestamp;
|
final Timestamp startTimestamp = orderTimestamp;
|
||||||
final fdc.Timestamp endTimestamp = _service.toTimestamp(order.endDate);
|
final Timestamp endTimestamp = _service.toTimestamp(order.endDate);
|
||||||
|
|
||||||
final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables> orderResult =
|
final OperationResult<dc.CreateOrderData, dc.CreateOrderVariables>
|
||||||
await _service.connector
|
orderResult = await _service.connector
|
||||||
.createOrder(
|
.createOrder(
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
orderType: dc.OrderType.RECURRING,
|
orderType: dc.OrderType.RECURRING,
|
||||||
teamHubId: hub.id,
|
teamHubId: hub.id,
|
||||||
)
|
)
|
||||||
.vendorId(vendorId)
|
.vendorId(vendorId)
|
||||||
.eventName(order.eventName)
|
.eventName(order.eventName)
|
||||||
.status(dc.OrderStatus.POSTED)
|
.status(dc.OrderStatus.POSTED)
|
||||||
.date(orderTimestamp)
|
.date(orderTimestamp)
|
||||||
.startDate(startTimestamp)
|
.startDate(startTimestamp)
|
||||||
.endDate(endTimestamp)
|
.endDate(endTimestamp)
|
||||||
.recurringDays(order.recurringDays)
|
.recurringDays(order.recurringDays)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String orderId = orderResult.data.order_insert.id;
|
final String orderId = orderResult.data.order_insert.id;
|
||||||
|
|
||||||
// NOTE: Recurring orders are limited to 30 days of generated shifts.
|
// NOTE: Recurring orders are limited to 30 days of generated shifts.
|
||||||
// Future shifts beyond 30 days should be created by a scheduled job.
|
// Future shifts beyond 30 days should be created by a scheduled job.
|
||||||
final DateTime maxEndDate = orderDateOnly.add(const Duration(days: 29));
|
final DateTime maxEndDate = orderDateOnly.add(const Duration(days: 29));
|
||||||
final DateTime effectiveEndDate =
|
final DateTime effectiveEndDate = order.endDate.isAfter(maxEndDate)
|
||||||
order.endDate.isAfter(maxEndDate) ? maxEndDate : order.endDate;
|
? maxEndDate
|
||||||
|
: order.endDate;
|
||||||
|
|
||||||
final Set<String> selectedDays = Set<String>.from(order.recurringDays);
|
final Set<String> selectedDays = Set<String>.from(order.recurringDays);
|
||||||
final int workersNeeded = order.positions.fold<int>(
|
final int workersNeeded = order.positions.fold<int>(
|
||||||
0,
|
0,
|
||||||
(int sum, domain.RecurringOrderPosition position) => sum + position.count,
|
(int sum, domain.RecurringOrderPosition position) =>
|
||||||
|
sum + position.count,
|
||||||
);
|
);
|
||||||
final double shiftCost = _calculateRecurringShiftCost(order);
|
final double shiftCost = _calculateRecurringShiftCost(order);
|
||||||
|
|
||||||
final List<String> shiftIds = <String>[];
|
final List<String> shiftIds = <String>[];
|
||||||
for (DateTime day = orderDateOnly;
|
for (
|
||||||
!day.isAfter(effectiveEndDate);
|
DateTime day = orderDateOnly;
|
||||||
day = day.add(const Duration(days: 1))) {
|
!day.isAfter(effectiveEndDate);
|
||||||
|
day = day.add(const Duration(days: 1))
|
||||||
|
) {
|
||||||
final String dayLabel = _weekdayLabel(day);
|
final String dayLabel = _weekdayLabel(day);
|
||||||
if (!selectedDays.contains(dayLabel)) {
|
if (!selectedDays.contains(dayLabel)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String shiftTitle = 'Shift ${_formatDate(day)}';
|
final String shiftTitle = 'Shift ${_formatDate(day)}';
|
||||||
final fdc.Timestamp dayTimestamp = _service.toTimestamp(
|
final Timestamp dayTimestamp = _service.toTimestamp(
|
||||||
DateTime(day.year, day.month, day.day),
|
DateTime(day.year, day.month, day.day),
|
||||||
);
|
);
|
||||||
|
|
||||||
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables> shiftResult =
|
final OperationResult<dc.CreateShiftData, dc.CreateShiftVariables>
|
||||||
await _service.connector
|
shiftResult = await _service.connector
|
||||||
.createShift(title: shiftTitle, orderId: orderId)
|
.createShift(title: shiftTitle, orderId: orderId)
|
||||||
.date(dayTimestamp)
|
.date(dayTimestamp)
|
||||||
.location(hub.name)
|
.location(hub.name)
|
||||||
.locationAddress(hub.address)
|
.locationAddress(hub.address)
|
||||||
.latitude(hub.latitude)
|
.latitude(hub.latitude)
|
||||||
.longitude(hub.longitude)
|
.longitude(hub.longitude)
|
||||||
.placeId(hub.placeId)
|
.placeId(hub.placeId)
|
||||||
.city(hub.city)
|
.city(hub.city)
|
||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.OPEN)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
.cost(shiftCost)
|
.cost(shiftCost)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String shiftId = shiftResult.data.shift_insert.id;
|
final String shiftId = shiftResult.data.shift_insert.id;
|
||||||
shiftIds.add(shiftId);
|
shiftIds.add(shiftId);
|
||||||
@@ -204,8 +210,9 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
for (final domain.RecurringOrderPosition position in order.positions) {
|
for (final domain.RecurringOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(day, position.startTime);
|
final DateTime start = _parseTime(day, position.startTime);
|
||||||
final DateTime end = _parseTime(day, position.endTime);
|
final DateTime end = _parseTime(day, position.endTime);
|
||||||
final DateTime normalizedEnd =
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
final double totalValue = rate * hours * position.count;
|
final double totalValue = rate * hours * position.count;
|
||||||
@@ -228,7 +235,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
|
|
||||||
await _service.connector
|
await _service.connector
|
||||||
.updateOrder(id: orderId, teamHubId: hub.id)
|
.updateOrder(id: orderId, teamHubId: hub.id)
|
||||||
.shifts(fdc.AnyValue(shiftIds))
|
.shifts(AnyValue(shiftIds))
|
||||||
.execute();
|
.execute();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -251,23 +258,23 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
order.startDate.month,
|
order.startDate.month,
|
||||||
order.startDate.day,
|
order.startDate.day,
|
||||||
);
|
);
|
||||||
final fdc.Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
final Timestamp orderTimestamp = _service.toTimestamp(orderDateOnly);
|
||||||
final fdc.Timestamp startTimestamp = orderTimestamp;
|
final Timestamp startTimestamp = orderTimestamp;
|
||||||
|
|
||||||
final fdc.OperationResult<dc.CreateOrderData, dc.CreateOrderVariables> orderResult =
|
final OperationResult<dc.CreateOrderData, dc.CreateOrderVariables>
|
||||||
await _service.connector
|
orderResult = await _service.connector
|
||||||
.createOrder(
|
.createOrder(
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
orderType: dc.OrderType.PERMANENT,
|
orderType: dc.OrderType.PERMANENT,
|
||||||
teamHubId: hub.id,
|
teamHubId: hub.id,
|
||||||
)
|
)
|
||||||
.vendorId(vendorId)
|
.vendorId(vendorId)
|
||||||
.eventName(order.eventName)
|
.eventName(order.eventName)
|
||||||
.status(dc.OrderStatus.POSTED)
|
.status(dc.OrderStatus.POSTED)
|
||||||
.date(orderTimestamp)
|
.date(orderTimestamp)
|
||||||
.startDate(startTimestamp)
|
.startDate(startTimestamp)
|
||||||
.permanentDays(order.permanentDays)
|
.permanentDays(order.permanentDays)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String orderId = orderResult.data.order_insert.id;
|
final String orderId = orderResult.data.order_insert.id;
|
||||||
|
|
||||||
@@ -283,38 +290,40 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
final double shiftCost = _calculatePermanentShiftCost(order);
|
final double shiftCost = _calculatePermanentShiftCost(order);
|
||||||
|
|
||||||
final List<String> shiftIds = <String>[];
|
final List<String> shiftIds = <String>[];
|
||||||
for (DateTime day = orderDateOnly;
|
for (
|
||||||
!day.isAfter(maxEndDate);
|
DateTime day = orderDateOnly;
|
||||||
day = day.add(const Duration(days: 1))) {
|
!day.isAfter(maxEndDate);
|
||||||
|
day = day.add(const Duration(days: 1))
|
||||||
|
) {
|
||||||
final String dayLabel = _weekdayLabel(day);
|
final String dayLabel = _weekdayLabel(day);
|
||||||
if (!selectedDays.contains(dayLabel)) {
|
if (!selectedDays.contains(dayLabel)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String shiftTitle = 'Shift ${_formatDate(day)}';
|
final String shiftTitle = 'Shift ${_formatDate(day)}';
|
||||||
final fdc.Timestamp dayTimestamp = _service.toTimestamp(
|
final Timestamp dayTimestamp = _service.toTimestamp(
|
||||||
DateTime(day.year, day.month, day.day),
|
DateTime(day.year, day.month, day.day),
|
||||||
);
|
);
|
||||||
|
|
||||||
final fdc.OperationResult<dc.CreateShiftData, dc.CreateShiftVariables> shiftResult =
|
final OperationResult<dc.CreateShiftData, dc.CreateShiftVariables>
|
||||||
await _service.connector
|
shiftResult = await _service.connector
|
||||||
.createShift(title: shiftTitle, orderId: orderId)
|
.createShift(title: shiftTitle, orderId: orderId)
|
||||||
.date(dayTimestamp)
|
.date(dayTimestamp)
|
||||||
.location(hub.name)
|
.location(hub.name)
|
||||||
.locationAddress(hub.address)
|
.locationAddress(hub.address)
|
||||||
.latitude(hub.latitude)
|
.latitude(hub.latitude)
|
||||||
.longitude(hub.longitude)
|
.longitude(hub.longitude)
|
||||||
.placeId(hub.placeId)
|
.placeId(hub.placeId)
|
||||||
.city(hub.city)
|
.city(hub.city)
|
||||||
.state(hub.state)
|
.state(hub.state)
|
||||||
.street(hub.street)
|
.street(hub.street)
|
||||||
.country(hub.country)
|
.country(hub.country)
|
||||||
.status(dc.ShiftStatus.OPEN)
|
.status(dc.ShiftStatus.OPEN)
|
||||||
.workersNeeded(workersNeeded)
|
.workersNeeded(workersNeeded)
|
||||||
.filled(0)
|
.filled(0)
|
||||||
.durationDays(1)
|
.durationDays(1)
|
||||||
.cost(shiftCost)
|
.cost(shiftCost)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
final String shiftId = shiftResult.data.shift_insert.id;
|
final String shiftId = shiftResult.data.shift_insert.id;
|
||||||
shiftIds.add(shiftId);
|
shiftIds.add(shiftId);
|
||||||
@@ -322,8 +331,9 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
for (final domain.OneTimeOrderPosition position in order.positions) {
|
for (final domain.OneTimeOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(day, position.startTime);
|
final DateTime start = _parseTime(day, position.startTime);
|
||||||
final DateTime end = _parseTime(day, position.endTime);
|
final DateTime end = _parseTime(day, position.endTime);
|
||||||
final DateTime normalizedEnd =
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
final double totalValue = rate * hours * position.count;
|
final double totalValue = rate * hours * position.count;
|
||||||
@@ -346,7 +356,7 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
|
|
||||||
await _service.connector
|
await _service.connector
|
||||||
.updateOrder(id: orderId, teamHubId: hub.id)
|
.updateOrder(id: orderId, teamHubId: hub.id)
|
||||||
.shifts(fdc.AnyValue(shiftIds))
|
.shifts(AnyValue(shiftIds))
|
||||||
.execute();
|
.execute();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -363,13 +373,76 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
throw UnimplementedError('Reorder functionality is not yet implemented.');
|
throw UnimplementedError('Reorder functionality is not yet implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<domain.ReorderData> getOrderDetailsForReorder(String orderId) async {
|
||||||
|
return _service.run(() async {
|
||||||
|
final String businessId = await _service.getBusinessId();
|
||||||
|
final QueryResult<
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderData,
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderVariables
|
||||||
|
>
|
||||||
|
result = await _service.connector
|
||||||
|
.listShiftRolesByBusinessAndOrder(
|
||||||
|
businessId: businessId,
|
||||||
|
orderId: orderId,
|
||||||
|
)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
final List<dc.ListShiftRolesByBusinessAndOrderShiftRoles> shiftRoles =
|
||||||
|
result.data.shiftRoles;
|
||||||
|
|
||||||
|
if (shiftRoles.isEmpty) {
|
||||||
|
throw Exception('Order not found or has no roles.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShiftOrder order =
|
||||||
|
shiftRoles.first.shift.order;
|
||||||
|
|
||||||
|
final domain.OrderType orderType = _mapOrderType(order.orderType);
|
||||||
|
|
||||||
|
final dc.ListShiftRolesByBusinessAndOrderShiftRolesShiftOrderTeamHub
|
||||||
|
teamHub = order.teamHub;
|
||||||
|
|
||||||
|
return domain.ReorderData(
|
||||||
|
orderId: orderId,
|
||||||
|
eventName: order.eventName ?? '',
|
||||||
|
vendorId: order.vendorId ?? '',
|
||||||
|
orderType: orderType,
|
||||||
|
hub: domain.OneTimeOrderHubDetails(
|
||||||
|
id: teamHub.id,
|
||||||
|
name: teamHub.hubName,
|
||||||
|
address: teamHub.address,
|
||||||
|
placeId: teamHub.placeId,
|
||||||
|
latitude: 0, // Not available in this query
|
||||||
|
longitude: 0,
|
||||||
|
),
|
||||||
|
positions: shiftRoles.map((
|
||||||
|
dc.ListShiftRolesByBusinessAndOrderShiftRoles role,
|
||||||
|
) {
|
||||||
|
return domain.ReorderPosition(
|
||||||
|
roleId: role.roleId,
|
||||||
|
count: role.count,
|
||||||
|
startTime: _formatTimestamp(role.startTime),
|
||||||
|
endTime: _formatTimestamp(role.endTime),
|
||||||
|
lunchBreak: _formatBreakDuration(role.breakType),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
startDate: order.startDate?.toDateTime(),
|
||||||
|
endDate: order.endDate?.toDateTime(),
|
||||||
|
recurringDays: order.recurringDays ?? const <String>[],
|
||||||
|
permanentDays: order.permanentDays ?? const <String>[],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
double _calculateShiftCost(domain.OneTimeOrder order) {
|
double _calculateShiftCost(domain.OneTimeOrder order) {
|
||||||
double total = 0;
|
double total = 0;
|
||||||
for (final domain.OneTimeOrderPosition position in order.positions) {
|
for (final domain.OneTimeOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(order.date, position.startTime);
|
final DateTime start = _parseTime(order.date, position.startTime);
|
||||||
final DateTime end = _parseTime(order.date, position.endTime);
|
final DateTime end = _parseTime(order.date, position.endTime);
|
||||||
final DateTime normalizedEnd =
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
total += rate * hours * position.count;
|
total += rate * hours * position.count;
|
||||||
@@ -382,8 +455,9 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
for (final domain.RecurringOrderPosition position in order.positions) {
|
for (final domain.RecurringOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(order.startDate, position.startTime);
|
final DateTime start = _parseTime(order.startDate, position.startTime);
|
||||||
final DateTime end = _parseTime(order.startDate, position.endTime);
|
final DateTime end = _parseTime(order.startDate, position.endTime);
|
||||||
final DateTime normalizedEnd =
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
total += rate * hours * position.count;
|
total += rate * hours * position.count;
|
||||||
@@ -396,8 +470,9 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
for (final domain.OneTimeOrderPosition position in order.positions) {
|
for (final domain.OneTimeOrderPosition position in order.positions) {
|
||||||
final DateTime start = _parseTime(order.startDate, position.startTime);
|
final DateTime start = _parseTime(order.startDate, position.startTime);
|
||||||
final DateTime end = _parseTime(order.startDate, position.endTime);
|
final DateTime end = _parseTime(order.startDate, position.endTime);
|
||||||
final DateTime normalizedEnd =
|
final DateTime normalizedEnd = end.isBefore(start)
|
||||||
end.isBefore(start) ? end.add(const Duration(days: 1)) : end;
|
? end.add(const Duration(days: 1))
|
||||||
|
: end;
|
||||||
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
final double hours = normalizedEnd.difference(start).inMinutes / 60.0;
|
||||||
final double rate = order.roleRates[position.role] ?? 0;
|
final double rate = order.roleRates[position.role] ?? 0;
|
||||||
total += rate * hours * position.count;
|
total += rate * hours * position.count;
|
||||||
@@ -473,4 +548,49 @@ class ClientCreateOrderRepositoryImpl implements ClientCreateOrderRepositoryInte
|
|||||||
final String day = dateTime.day.toString().padLeft(2, '0');
|
final String day = dateTime.day.toString().padLeft(2, '0');
|
||||||
return '$year-$month-$day';
|
return '$year-$month-$day';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _formatTimestamp(Timestamp? value) {
|
||||||
|
if (value == null) return '';
|
||||||
|
try {
|
||||||
|
return DateFormat('HH:mm').format(value.toDateTime());
|
||||||
|
} catch (_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatBreakDuration(dc.EnumValue<dc.BreakDuration>? breakType) {
|
||||||
|
if (breakType is dc.Known<dc.BreakDuration>) {
|
||||||
|
switch (breakType.value) {
|
||||||
|
case dc.BreakDuration.MIN_10:
|
||||||
|
return 'MIN_10';
|
||||||
|
case dc.BreakDuration.MIN_15:
|
||||||
|
return 'MIN_15';
|
||||||
|
case dc.BreakDuration.MIN_30:
|
||||||
|
return 'MIN_30';
|
||||||
|
case dc.BreakDuration.MIN_45:
|
||||||
|
return 'MIN_45';
|
||||||
|
case dc.BreakDuration.MIN_60:
|
||||||
|
return 'MIN_60';
|
||||||
|
case dc.BreakDuration.NO_BREAK:
|
||||||
|
return 'NO_BREAK';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'NO_BREAK';
|
||||||
|
}
|
||||||
|
|
||||||
|
domain.OrderType _mapOrderType(dc.EnumValue<dc.OrderType>? orderType) {
|
||||||
|
if (orderType is dc.Known<dc.OrderType>) {
|
||||||
|
switch (orderType.value) {
|
||||||
|
case dc.OrderType.ONE_TIME:
|
||||||
|
return domain.OrderType.oneTime;
|
||||||
|
case dc.OrderType.RECURRING:
|
||||||
|
return domain.OrderType.recurring;
|
||||||
|
case dc.OrderType.PERMANENT:
|
||||||
|
return domain.OrderType.permanent;
|
||||||
|
case dc.OrderType.RAPID:
|
||||||
|
return domain.OrderType.oneTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domain.OrderType.oneTime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,9 @@ abstract interface class ClientCreateOrderRepositoryInterface {
|
|||||||
/// [previousOrderId] is the ID of the order to reorder.
|
/// [previousOrderId] is the ID of the order to reorder.
|
||||||
/// [newDate] is the new date for the order.
|
/// [newDate] is the new date for the order.
|
||||||
Future<void> reorder(String previousOrderId, DateTime newDate);
|
Future<void> reorder(String previousOrderId, DateTime newDate);
|
||||||
|
|
||||||
|
/// Fetches the details of an existing order to be used as a template for a new order.
|
||||||
|
///
|
||||||
|
/// returns [ReorderData] containing the order details and positions.
|
||||||
|
Future<ReorderData> getOrderDetailsForReorder(String orderId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:krow_core/core.dart';
|
||||||
|
import 'package:krow_domain/krow_domain.dart';
|
||||||
|
import '../repositories/client_create_order_repository_interface.dart';
|
||||||
|
|
||||||
|
/// Use case for fetching order details for reordering.
|
||||||
|
class GetOrderDetailsForReorderUseCase implements UseCase<String, ReorderData> {
|
||||||
|
const GetOrderDetailsForReorderUseCase(this._repository);
|
||||||
|
final ClientCreateOrderRepositoryInterface _repository;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ReorderData> call(String orderId) {
|
||||||
|
return _repository.getOrderDetailsForReorder(orderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:client_create_order/src/domain/arguments/one_time_order_arguments.dart';
|
import 'package:client_create_order/src/domain/arguments/one_time_order_arguments.dart';
|
||||||
import 'package:client_create_order/src/domain/usecases/create_one_time_order_usecase.dart';
|
import 'package:client_create_order/src/domain/usecases/create_one_time_order_usecase.dart';
|
||||||
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
import 'package:client_create_order/src/domain/usecases/get_order_details_for_reorder_usecase.dart';
|
||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
@@ -14,8 +15,11 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
|
|||||||
with
|
with
|
||||||
BlocErrorHandler<OneTimeOrderState>,
|
BlocErrorHandler<OneTimeOrderState>,
|
||||||
SafeBloc<OneTimeOrderEvent, OneTimeOrderState> {
|
SafeBloc<OneTimeOrderEvent, OneTimeOrderState> {
|
||||||
OneTimeOrderBloc(this._createOneTimeOrderUseCase, this._service)
|
OneTimeOrderBloc(
|
||||||
: super(OneTimeOrderState.initial()) {
|
this._createOneTimeOrderUseCase,
|
||||||
|
this._getOrderDetailsForReorderUseCase,
|
||||||
|
this._service,
|
||||||
|
) : super(OneTimeOrderState.initial()) {
|
||||||
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
|
on<OneTimeOrderVendorsLoaded>(_onVendorsLoaded);
|
||||||
on<OneTimeOrderVendorChanged>(_onVendorChanged);
|
on<OneTimeOrderVendorChanged>(_onVendorChanged);
|
||||||
on<OneTimeOrderHubsLoaded>(_onHubsLoaded);
|
on<OneTimeOrderHubsLoaded>(_onHubsLoaded);
|
||||||
@@ -32,12 +36,13 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
|
|||||||
_loadHubs();
|
_loadHubs();
|
||||||
}
|
}
|
||||||
final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase;
|
final CreateOneTimeOrderUseCase _createOneTimeOrderUseCase;
|
||||||
|
final GetOrderDetailsForReorderUseCase _getOrderDetailsForReorderUseCase;
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
Future<void> _loadVendors() async {
|
Future<void> _loadVendors() async {
|
||||||
final List<Vendor>? vendors = await handleErrorWithResult(
|
final List<Vendor>? vendors = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<dc.ListVendorsData, void> result = await _service
|
final fdc.QueryResult<dc.ListVendorsData, void> result = await _service
|
||||||
.connector
|
.connector
|
||||||
.listVendors()
|
.listVendors()
|
||||||
.execute();
|
.execute();
|
||||||
@@ -65,7 +70,7 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
|
|||||||
) async {
|
) async {
|
||||||
final List<OneTimeOrderRoleOption>? roles = await handleErrorWithResult(
|
final List<OneTimeOrderRoleOption>? roles = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListRolesByVendorIdData,
|
dc.ListRolesByVendorIdData,
|
||||||
dc.ListRolesByVendorIdVariables
|
dc.ListRolesByVendorIdVariables
|
||||||
>
|
>
|
||||||
@@ -95,7 +100,7 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
|
|||||||
final List<OneTimeOrderHubOption>? hubs = await handleErrorWithResult(
|
final List<OneTimeOrderHubOption>? hubs = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final String businessId = await _service.getBusinessId();
|
final String businessId = await _service.getBusinessId();
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListTeamHubsByOwnerIdData,
|
dc.ListTeamHubsByOwnerIdData,
|
||||||
dc.ListTeamHubsByOwnerIdVariables
|
dc.ListTeamHubsByOwnerIdVariables
|
||||||
>
|
>
|
||||||
@@ -274,27 +279,72 @@ class OneTimeOrderBloc extends Bloc<OneTimeOrderEvent, OneTimeOrderState>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onInitialized(
|
Future<void> _onInitialized(
|
||||||
OneTimeOrderInitialized event,
|
OneTimeOrderInitialized event,
|
||||||
Emitter<OneTimeOrderState> emit,
|
Emitter<OneTimeOrderState> emit,
|
||||||
) {
|
) async {
|
||||||
final Map<String, dynamic> data = event.data;
|
final Map<String, dynamic> data = event.data;
|
||||||
final String title = data['title']?.toString() ?? '';
|
final String title = data['title']?.toString() ?? '';
|
||||||
final int workers = (data['workers'] as int?) ?? 1;
|
|
||||||
final DateTime? startDate = data['startDate'] as DateTime?;
|
final DateTime? startDate = data['startDate'] as DateTime?;
|
||||||
|
final String? orderId = data['orderId']?.toString();
|
||||||
|
|
||||||
emit(
|
emit(state.copyWith(eventName: title, date: startDate ?? DateTime.now()));
|
||||||
state.copyWith(
|
|
||||||
eventName: title,
|
if (orderId == null || orderId.isEmpty) return;
|
||||||
date: startDate ?? DateTime.now(),
|
|
||||||
positions: <OneTimeOrderPosition>[
|
emit(state.copyWith(status: OneTimeOrderStatus.loading));
|
||||||
OneTimeOrderPosition(
|
|
||||||
role: data['roleName']?.toString() ?? '',
|
await handleError(
|
||||||
count: workers,
|
emit: emit.call,
|
||||||
startTime: data['startTime']?.toString() ?? '09:00',
|
action: () async {
|
||||||
endTime: data['endTime']?.toString() ?? '17:00',
|
final ReorderData orderDetails =
|
||||||
|
await _getOrderDetailsForReorderUseCase(orderId);
|
||||||
|
|
||||||
|
// Map positions
|
||||||
|
final List<OneTimeOrderPosition> positions = orderDetails.positions.map(
|
||||||
|
(ReorderPosition role) {
|
||||||
|
return OneTimeOrderPosition(
|
||||||
|
role: role.roleId,
|
||||||
|
count: role.count,
|
||||||
|
startTime: role.startTime,
|
||||||
|
endTime: role.endTime,
|
||||||
|
lunchBreak: role.lunchBreak,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
// Update state with order details
|
||||||
|
final Vendor? selectedVendor = state.vendors
|
||||||
|
.where((Vendor v) => v.id == orderDetails.vendorId)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
final OneTimeOrderHubOption? selectedHub = state.hubs
|
||||||
|
.where(
|
||||||
|
(OneTimeOrderHubOption h) =>
|
||||||
|
h.placeId == orderDetails.hub.placeId,
|
||||||
|
)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
eventName: orderDetails.eventName.isNotEmpty
|
||||||
|
? orderDetails.eventName
|
||||||
|
: title,
|
||||||
|
positions: positions,
|
||||||
|
selectedVendor: selectedVendor,
|
||||||
|
selectedHub: selectedHub,
|
||||||
|
location: selectedHub?.name ?? '',
|
||||||
|
status: OneTimeOrderStatus.initial,
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
|
||||||
|
if (selectedVendor != null) {
|
||||||
|
await _loadRolesForVendor(selectedVendor.id, emit);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (String errorKey) => state.copyWith(
|
||||||
|
status: OneTimeOrderStatus.failure,
|
||||||
|
errorMessage: errorKey,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:client_create_order/src/domain/usecases/create_permanent_order_usecase.dart';
|
import 'package:client_create_order/src/domain/usecases/create_permanent_order_usecase.dart';
|
||||||
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
import 'package:client_create_order/src/domain/usecases/get_order_details_for_reorder_usecase.dart';
|
||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
@@ -13,8 +14,11 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
with
|
with
|
||||||
BlocErrorHandler<PermanentOrderState>,
|
BlocErrorHandler<PermanentOrderState>,
|
||||||
SafeBloc<PermanentOrderEvent, PermanentOrderState> {
|
SafeBloc<PermanentOrderEvent, PermanentOrderState> {
|
||||||
PermanentOrderBloc(this._createPermanentOrderUseCase, this._service)
|
PermanentOrderBloc(
|
||||||
: super(PermanentOrderState.initial()) {
|
this._createPermanentOrderUseCase,
|
||||||
|
this._getOrderDetailsForReorderUseCase,
|
||||||
|
this._service,
|
||||||
|
) : super(PermanentOrderState.initial()) {
|
||||||
on<PermanentOrderVendorsLoaded>(_onVendorsLoaded);
|
on<PermanentOrderVendorsLoaded>(_onVendorsLoaded);
|
||||||
on<PermanentOrderVendorChanged>(_onVendorChanged);
|
on<PermanentOrderVendorChanged>(_onVendorChanged);
|
||||||
on<PermanentOrderHubsLoaded>(_onHubsLoaded);
|
on<PermanentOrderHubsLoaded>(_onHubsLoaded);
|
||||||
@@ -33,6 +37,7 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final CreatePermanentOrderUseCase _createPermanentOrderUseCase;
|
final CreatePermanentOrderUseCase _createPermanentOrderUseCase;
|
||||||
|
final GetOrderDetailsForReorderUseCase _getOrderDetailsForReorderUseCase;
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
static const List<String> _dayLabels = <String>[
|
static const List<String> _dayLabels = <String>[
|
||||||
@@ -48,7 +53,7 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
Future<void> _loadVendors() async {
|
Future<void> _loadVendors() async {
|
||||||
final List<domain.Vendor>? vendors = await handleErrorWithResult(
|
final List<domain.Vendor>? vendors = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<dc.ListVendorsData, void> result = await _service
|
final fdc.QueryResult<dc.ListVendorsData, void> result = await _service
|
||||||
.connector
|
.connector
|
||||||
.listVendors()
|
.listVendors()
|
||||||
.execute();
|
.execute();
|
||||||
@@ -76,7 +81,7 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
) async {
|
) async {
|
||||||
final List<PermanentOrderRoleOption>? roles = await handleErrorWithResult(
|
final List<PermanentOrderRoleOption>? roles = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListRolesByVendorIdData,
|
dc.ListRolesByVendorIdData,
|
||||||
dc.ListRolesByVendorIdVariables
|
dc.ListRolesByVendorIdVariables
|
||||||
>
|
>
|
||||||
@@ -106,7 +111,7 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
final List<PermanentOrderHubOption>? hubs = await handleErrorWithResult(
|
final List<PermanentOrderHubOption>? hubs = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final String businessId = await _service.getBusinessId();
|
final String businessId = await _service.getBusinessId();
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListTeamHubsByOwnerIdData,
|
dc.ListTeamHubsByOwnerIdData,
|
||||||
dc.ListTeamHubsByOwnerIdVariables
|
dc.ListTeamHubsByOwnerIdVariables
|
||||||
>
|
>
|
||||||
@@ -337,27 +342,76 @@ class PermanentOrderBloc extends Bloc<PermanentOrderEvent, PermanentOrderState>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onInitialized(
|
Future<void> _onInitialized(
|
||||||
PermanentOrderInitialized event,
|
PermanentOrderInitialized event,
|
||||||
Emitter<PermanentOrderState> emit,
|
Emitter<PermanentOrderState> emit,
|
||||||
) {
|
) async {
|
||||||
final Map<String, dynamic> data = event.data;
|
final Map<String, dynamic> data = event.data;
|
||||||
final String title = data['title']?.toString() ?? '';
|
final String title = data['title']?.toString() ?? '';
|
||||||
final int workers = (data['workers'] as int?) ?? 1;
|
|
||||||
final DateTime? startDate = data['startDate'] as DateTime?;
|
final DateTime? startDate = data['startDate'] as DateTime?;
|
||||||
|
final String? orderId = data['orderId']?.toString();
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(eventName: title, startDate: startDate ?? DateTime.now()),
|
||||||
eventName: title,
|
);
|
||||||
startDate: startDate ?? DateTime.now(),
|
|
||||||
positions: <PermanentOrderPosition>[
|
if (orderId == null || orderId.isEmpty) return;
|
||||||
PermanentOrderPosition(
|
|
||||||
role: data['roleName']?.toString() ?? '',
|
emit(state.copyWith(status: PermanentOrderStatus.loading));
|
||||||
count: workers,
|
|
||||||
startTime: data['startTime']?.toString() ?? '09:00',
|
await handleError(
|
||||||
endTime: data['endTime']?.toString() ?? '17:00',
|
emit: emit.call,
|
||||||
|
action: () async {
|
||||||
|
final domain.ReorderData orderDetails =
|
||||||
|
await _getOrderDetailsForReorderUseCase(orderId);
|
||||||
|
|
||||||
|
// Map positions
|
||||||
|
final List<PermanentOrderPosition> positions = orderDetails.positions
|
||||||
|
.map((domain.ReorderPosition role) {
|
||||||
|
return PermanentOrderPosition(
|
||||||
|
role: role.roleId,
|
||||||
|
count: role.count,
|
||||||
|
startTime: role.startTime,
|
||||||
|
endTime: role.endTime,
|
||||||
|
lunchBreak: role.lunchBreak,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Update state with order details
|
||||||
|
final domain.Vendor? selectedVendor = state.vendors
|
||||||
|
.where((domain.Vendor v) => v.id == orderDetails.vendorId)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
final PermanentOrderHubOption? selectedHub = state.hubs
|
||||||
|
.where(
|
||||||
|
(PermanentOrderHubOption h) =>
|
||||||
|
h.placeId == orderDetails.hub.placeId,
|
||||||
|
)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
eventName: orderDetails.eventName.isNotEmpty
|
||||||
|
? orderDetails.eventName
|
||||||
|
: title,
|
||||||
|
positions: positions,
|
||||||
|
selectedVendor: selectedVendor,
|
||||||
|
selectedHub: selectedHub,
|
||||||
|
location: selectedHub?.name ?? '',
|
||||||
|
status: PermanentOrderStatus.initial,
|
||||||
|
startDate: startDate ?? orderDetails.startDate ?? DateTime.now(),
|
||||||
|
permanentDays: orderDetails.permanentDays,
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
|
||||||
|
if (selectedVendor != null) {
|
||||||
|
await _loadRolesForVendor(selectedVendor.id, emit);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (String errorKey) => state.copyWith(
|
||||||
|
status: PermanentOrderStatus.failure,
|
||||||
|
errorMessage: errorKey,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:client_create_order/src/domain/usecases/create_recurring_order_usecase.dart';
|
import 'package:client_create_order/src/domain/usecases/create_recurring_order_usecase.dart';
|
||||||
import 'package:firebase_data_connect/firebase_data_connect.dart';
|
import 'package:client_create_order/src/domain/usecases/get_order_details_for_reorder_usecase.dart';
|
||||||
|
import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:krow_core/core.dart';
|
import 'package:krow_core/core.dart';
|
||||||
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
|
||||||
@@ -13,8 +14,11 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
with
|
with
|
||||||
BlocErrorHandler<RecurringOrderState>,
|
BlocErrorHandler<RecurringOrderState>,
|
||||||
SafeBloc<RecurringOrderEvent, RecurringOrderState> {
|
SafeBloc<RecurringOrderEvent, RecurringOrderState> {
|
||||||
RecurringOrderBloc(this._createRecurringOrderUseCase, this._service)
|
RecurringOrderBloc(
|
||||||
: super(RecurringOrderState.initial()) {
|
this._createRecurringOrderUseCase,
|
||||||
|
this._getOrderDetailsForReorderUseCase,
|
||||||
|
this._service,
|
||||||
|
) : super(RecurringOrderState.initial()) {
|
||||||
on<RecurringOrderVendorsLoaded>(_onVendorsLoaded);
|
on<RecurringOrderVendorsLoaded>(_onVendorsLoaded);
|
||||||
on<RecurringOrderVendorChanged>(_onVendorChanged);
|
on<RecurringOrderVendorChanged>(_onVendorChanged);
|
||||||
on<RecurringOrderHubsLoaded>(_onHubsLoaded);
|
on<RecurringOrderHubsLoaded>(_onHubsLoaded);
|
||||||
@@ -34,6 +38,7 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final CreateRecurringOrderUseCase _createRecurringOrderUseCase;
|
final CreateRecurringOrderUseCase _createRecurringOrderUseCase;
|
||||||
|
final GetOrderDetailsForReorderUseCase _getOrderDetailsForReorderUseCase;
|
||||||
final dc.DataConnectService _service;
|
final dc.DataConnectService _service;
|
||||||
|
|
||||||
static const List<String> _dayLabels = <String>[
|
static const List<String> _dayLabels = <String>[
|
||||||
@@ -49,7 +54,7 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
Future<void> _loadVendors() async {
|
Future<void> _loadVendors() async {
|
||||||
final List<domain.Vendor>? vendors = await handleErrorWithResult(
|
final List<domain.Vendor>? vendors = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<dc.ListVendorsData, void> result = await _service
|
final fdc.QueryResult<dc.ListVendorsData, void> result = await _service
|
||||||
.connector
|
.connector
|
||||||
.listVendors()
|
.listVendors()
|
||||||
.execute();
|
.execute();
|
||||||
@@ -77,7 +82,7 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
) async {
|
) async {
|
||||||
final List<RecurringOrderRoleOption>? roles = await handleErrorWithResult(
|
final List<RecurringOrderRoleOption>? roles = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListRolesByVendorIdData,
|
dc.ListRolesByVendorIdData,
|
||||||
dc.ListRolesByVendorIdVariables
|
dc.ListRolesByVendorIdVariables
|
||||||
>
|
>
|
||||||
@@ -107,7 +112,7 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
final List<RecurringOrderHubOption>? hubs = await handleErrorWithResult(
|
final List<RecurringOrderHubOption>? hubs = await handleErrorWithResult(
|
||||||
action: () async {
|
action: () async {
|
||||||
final String businessId = await _service.getBusinessId();
|
final String businessId = await _service.getBusinessId();
|
||||||
final QueryResult<
|
final fdc.QueryResult<
|
||||||
dc.ListTeamHubsByOwnerIdData,
|
dc.ListTeamHubsByOwnerIdData,
|
||||||
dc.ListTeamHubsByOwnerIdVariables
|
dc.ListTeamHubsByOwnerIdVariables
|
||||||
>
|
>
|
||||||
@@ -356,27 +361,77 @@ class RecurringOrderBloc extends Bloc<RecurringOrderEvent, RecurringOrderState>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onInitialized(
|
Future<void> _onInitialized(
|
||||||
RecurringOrderInitialized event,
|
RecurringOrderInitialized event,
|
||||||
Emitter<RecurringOrderState> emit,
|
Emitter<RecurringOrderState> emit,
|
||||||
) {
|
) async {
|
||||||
final Map<String, dynamic> data = event.data;
|
final Map<String, dynamic> data = event.data;
|
||||||
final String title = data['title']?.toString() ?? '';
|
final String title = data['title']?.toString() ?? '';
|
||||||
final int workers = (data['workers'] as int?) ?? 1;
|
|
||||||
final DateTime? startDate = data['startDate'] as DateTime?;
|
final DateTime? startDate = data['startDate'] as DateTime?;
|
||||||
|
final String? orderId = data['orderId']?.toString();
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(eventName: title, startDate: startDate ?? DateTime.now()),
|
||||||
eventName: title,
|
);
|
||||||
startDate: startDate ?? DateTime.now(),
|
|
||||||
positions: <RecurringOrderPosition>[
|
if (orderId == null || orderId.isEmpty) return;
|
||||||
RecurringOrderPosition(
|
|
||||||
role: data['roleName']?.toString() ?? '',
|
emit(state.copyWith(status: RecurringOrderStatus.loading));
|
||||||
count: workers,
|
|
||||||
startTime: data['startTime']?.toString() ?? '09:00',
|
await handleError(
|
||||||
endTime: data['endTime']?.toString() ?? '17:00',
|
emit: emit.call,
|
||||||
|
action: () async {
|
||||||
|
final domain.ReorderData orderDetails =
|
||||||
|
await _getOrderDetailsForReorderUseCase(orderId);
|
||||||
|
|
||||||
|
// Map positions
|
||||||
|
final List<RecurringOrderPosition> positions = orderDetails.positions
|
||||||
|
.map((domain.ReorderPosition role) {
|
||||||
|
return RecurringOrderPosition(
|
||||||
|
role: role.roleId,
|
||||||
|
count: role.count,
|
||||||
|
startTime: role.startTime,
|
||||||
|
endTime: role.endTime,
|
||||||
|
lunchBreak: role.lunchBreak,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Update state with order details
|
||||||
|
final domain.Vendor? selectedVendor = state.vendors
|
||||||
|
.where((domain.Vendor v) => v.id == orderDetails.vendorId)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
final RecurringOrderHubOption? selectedHub = state.hubs
|
||||||
|
.where(
|
||||||
|
(RecurringOrderHubOption h) =>
|
||||||
|
h.placeId == orderDetails.hub.placeId,
|
||||||
|
)
|
||||||
|
.firstOrNull;
|
||||||
|
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
eventName: orderDetails.eventName.isNotEmpty
|
||||||
|
? orderDetails.eventName
|
||||||
|
: title,
|
||||||
|
positions: positions,
|
||||||
|
selectedVendor: selectedVendor,
|
||||||
|
selectedHub: selectedHub,
|
||||||
|
location: selectedHub?.name ?? '',
|
||||||
|
status: RecurringOrderStatus.initial,
|
||||||
|
startDate: startDate ?? orderDetails.startDate ?? DateTime.now(),
|
||||||
|
endDate: orderDetails.endDate ?? DateTime.now(),
|
||||||
|
recurringDays: orderDetails.recurringDays,
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
|
||||||
|
if (selectedVendor != null) {
|
||||||
|
await _loadRolesForVendor(selectedVendor.id, emit);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (String errorKey) => state.copyWith(
|
||||||
|
status: RecurringOrderStatus.failure,
|
||||||
|
errorMessage: errorKey,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,9 +404,15 @@ query listShiftRolesByBusinessAndOrder(
|
|||||||
vendorId
|
vendorId
|
||||||
eventName
|
eventName
|
||||||
date
|
date
|
||||||
|
startDate
|
||||||
|
endDate
|
||||||
|
recurringDays
|
||||||
|
permanentDays
|
||||||
|
orderType
|
||||||
#location
|
#location
|
||||||
|
|
||||||
teamHub {
|
teamHub {
|
||||||
|
id
|
||||||
address
|
address
|
||||||
placeId
|
placeId
|
||||||
hubName
|
hubName
|
||||||
|
|||||||
Reference in New Issue
Block a user