From ae202023912d0ee14afbd7190a7f609ba45ebe32 Mon Sep 17 00:00:00 2001 From: Kaylahray Date: Sun, 8 Mar 2026 15:07:43 +0100 Subject: [PATCH] fix(workspace_booking): address type safety and error coverage gaps --- contracts/workspace_booking/src/errors.rs | 85 +++++++++++++ contracts/workspace_booking/src/types.rs | 139 ++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 contracts/workspace_booking/src/errors.rs create mode 100644 contracts/workspace_booking/src/types.rs diff --git a/contracts/workspace_booking/src/errors.rs b/contracts/workspace_booking/src/errors.rs new file mode 100644 index 0000000..4a71458 --- /dev/null +++ b/contracts/workspace_booking/src/errors.rs @@ -0,0 +1,85 @@ +use soroban_sdk::contracterror; + +/// Contract error definitions. +/// +/// Error codes are stable and should never be reordered. +/// Reserved ranges are used for future compatibility. +/// +/// 1–99 → Core contract errors +/// 100–199 → Booking related errors +/// 200–299 → Workspace related errors +#[contracterror] +#[derive(Copy, Clone, Debug, PartialEq)] +#[repr(u32)] +pub enum Error { + + /// No admin has been set yet. + AdminNotSet = 1, + + /// Caller is not authorized. + Unauthorized = 2, + + /// Contract already initialized. + AlreadyInitialized = 3, + + /// Payment token not configured. + PaymentTokenNotSet = 4, + + /// Provided string exceeds allowed length. + StringTooLong = 5, + + /// Workspace capacity must be >= 1. + InvalidCapacity = 6, + + /// Hourly rate must be > 0. + InvalidRate = 7, + + /// Invalid booking time window. + InvalidTimeRange = 8, + + + // ----------------------------- + // Booking Errors (100–199) + // ----------------------------- + + /// Booking ID not found. + BookingNotFound = 100, + + /// Booking already exists. + BookingAlreadyExists = 101, + + /// Booking overlaps with another booking. + BookingConflict = 102, + + /// Booking must be active for this operation. + BookingNotActive = 103, + + /// Booking expired. + BookingExpired = 104, + + /// Booking already cancelled. + BookingAlreadyCancelled = 105, + + /// Booking already completed. + BookingAlreadyCompleted = 106, + + /// Member balance insufficient for payment. + InsufficientBalance = 107, + + + // ----------------------------- + // Workspace Errors (200–299) + // ----------------------------- + + /// Workspace ID not found. + WorkspaceNotFound = 200, + + /// Workspace already exists. + WorkspaceAlreadyExists = 201, + + /// Workspace currently unavailable. + WorkspaceUnavailable = 202, + + /// Cannot modify workspace while active bookings exist. + WorkspaceHasActiveBookings = 203, +} \ No newline at end of file diff --git a/contracts/workspace_booking/src/types.rs b/contracts/workspace_booking/src/types.rs new file mode 100644 index 0000000..aef8401 --- /dev/null +++ b/contracts/workspace_booking/src/types.rs @@ -0,0 +1,139 @@ +use soroban_sdk::{contracttype, Address, String}; + +/// Maximum allowed length for workspace identifiers. +pub const MAX_ID_LEN: u32 = 64; + +/// Maximum allowed length for workspace names. +pub const MAX_NAME_LEN: u32 = 128; + +/// Category of workspace being registered. +/// +/// NOTE: +/// New variants may be added in future versions. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub enum WorkspaceType { + /// Open hot-desk — shared, no dedicated assignment. + HotDesk, + + /// Reserved desk for a specific member or team. + DedicatedDesk, + + /// Enclosed private office. + PrivateOffice, + + /// Meeting / conference room. + MeetingRoom, + + /// Fully remote / online meeting space. + Virtual, + + /// Combined physical desk and integrated video-conferencing setup. + Hybrid, +} + +/// Reason a workspace is unavailable. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub enum UnavailabilityReason { + /// Temporary maintenance work + Maintenance, + + /// Workspace permanently removed + Decommissioned, + + /// Held by administrator + AdminHold, +} + +/// Availability state of a workspace. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub enum WorkspaceAvailability { + /// Workspace can be booked + Available, + + /// Workspace cannot be booked with reason + Unavailable(UnavailabilityReason), +} + +/// Lifecycle state of a booking. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub enum BookingStatus { + /// Booking is confirmed and currently active. + Active, + + /// Booking finished successfully. + Completed, + + /// Booking cancelled by member or admin. + Cancelled, + + /// Member never showed up for the reservation. + NoShow, + + /// Reservation window passed without completion. + Expired, +} + +/// A physical or logical workspace that can be booked. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub struct Workspace { + /// Unique workspace identifier (max 64 chars) + pub id: String, + + /// Human-readable name (max 128 chars) + pub name: String, + + /// Category of workspace + pub workspace_type: WorkspaceType, + + /// Maximum simultaneous occupants + pub capacity: u32, + + /// Hourly rate in smallest unit of payment token + pub hourly_rate: u128, + + /// Current availability state + pub availability: WorkspaceAvailability, + + /// Ledger timestamp when workspace was created + pub created_at: u64, +} + +/// A confirmed reservation for a workspace. +#[contracttype] +#[derive(Clone, Debug, PartialEq)] +pub struct Booking { + /// Caller-provided booking identifier (max 64 chars) + pub id: String, + + /// ID of workspace being booked + pub workspace_id: String, + + /// Member who created the booking + pub member: Address, + + /// Reservation start time (unix seconds) + pub start_time: u64, + + /// Reservation end time (unix seconds) + pub end_time: u64, + + /// Current booking lifecycle status + pub status: BookingStatus, + + /// Amount paid for booking + pub amount_paid: u128, + + /// Timestamp when booking was created + pub created_at: u64, + + /// Timestamp booking was cancelled + pub cancelled_at: Option, + + /// Timestamp booking was completed + pub completed_at: Option, +} \ No newline at end of file