auto-claude: subtask-3-4 - Implement command methods (complete, uncomplete, skip)

Adds gRPC command methods to GrpcCqrsApiClient for delivery operations:
- completeDelivery: Mark delivery as completed with optional timestamp
- markDeliveryAsUncompleted: Revert completed delivery to pending
- skipDelivery: Skip a delivery that cannot be completed

All methods follow the Result<T> pattern for consistent error handling,
check CommandResponse.success flag, and map error messages appropriately.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mathias Beaulieu-Duncan 2026-01-20 13:06:08 -05:00
parent 7c1832dd4f
commit 823f9107fd

View File

@ -400,6 +400,131 @@ class GrpcCqrsApiClient {
);
}
// ============================================================
// Command Methods
// ============================================================
/// Marks a delivery as completed.
///
/// Returns a [Result] indicating success or failure. Optionally accepts
/// a [deliveredAt] timestamp; if not provided, the server will use the
/// current time.
///
/// Example:
/// ```dart
/// final result = await client.completeDelivery(deliveryId: 123);
/// result.when(
/// success: (_) => showSuccess('Delivery completed'),
/// onError: (error) => showError(error.message),
/// );
/// ```
Future<Result<void>> completeDelivery({
required int deliveryId,
String? deliveredAt,
}) async {
final request = CompleteDeliveryRequest(
deliveryId: deliveryId,
deliveredAt: deliveredAt,
);
final result = await _executeWithAuth<CommandResponse>(
(options) => deliveryClient.completeDelivery(request, options: options),
);
return result.when(
success: (response) {
if (response.success) {
return Result.success(null);
}
return Result.error(
ApiError.unknown(response.message.isNotEmpty
? response.message
: 'Failed to complete delivery'),
);
},
onError: (error) => Result.error(error),
);
}
/// Marks a delivery as uncompleted.
///
/// Returns a [Result] indicating success or failure. Use this to revert
/// a previously completed delivery back to pending status.
///
/// Example:
/// ```dart
/// final result = await client.markDeliveryAsUncompleted(deliveryId: 123);
/// result.when(
/// success: (_) => showSuccess('Delivery marked as uncompleted'),
/// onError: (error) => showError(error.message),
/// );
/// ```
Future<Result<void>> markDeliveryAsUncompleted({
required int deliveryId,
}) async {
final request = MarkDeliveryUncompletedRequest(
deliveryId: deliveryId,
);
final result = await _executeWithAuth<CommandResponse>(
(options) =>
deliveryClient.markDeliveryUncompleted(request, options: options),
);
return result.when(
success: (response) {
if (response.success) {
return Result.success(null);
}
return Result.error(
ApiError.unknown(response.message.isNotEmpty
? response.message
: 'Failed to mark delivery as uncompleted'),
);
},
onError: (error) => Result.error(error),
);
}
/// Skips a delivery.
///
/// Returns a [Result] indicating success or failure. Use this when a
/// delivery cannot be completed and needs to be skipped.
///
/// Example:
/// ```dart
/// final result = await client.skipDelivery(deliveryId: 123);
/// result.when(
/// success: (_) => showSuccess('Delivery skipped'),
/// onError: (error) => showError(error.message),
/// );
/// ```
Future<Result<void>> skipDelivery({
required int deliveryId,
}) async {
final request = SkipDeliveryRequest(
deliveryId: deliveryId,
);
final result = await _executeWithAuth<CommandResponse>(
(options) => deliveryClient.skipDelivery(request, options: options),
);
return result.when(
success: (response) {
if (response.success) {
return Result.success(null);
}
return Result.error(
ApiError.unknown(response.message.isNotEmpty
? response.message
: 'Failed to skip delivery'),
);
},
onError: (error) => Result.error(error),
);
}
/// Shuts down the gRPC channel and releases resources.
///
/// Should be called when the client is no longer needed to properly