Overview
Once you publish a service request, professionals can apply with their proposed price and message. You’ll review applications, select a professional, and manage the job through completion.
Viewing Your Requests
Access your service requests at /requests/my-requests:
MyRequestsController.java:42-55
@GetMapping("/my-requests")
public String showMyRequests(Authentication auth, Model model) {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
List<ServiceRequest> solicitudesUsuario = serviceRequestService.getMyRequests();
List<ServiceJob> trabajosUsuario = serviceJobRepository.findByCliente(usuarioLogueado);
// Prepare data for view
model.addAttribute("solicitudesExistentes", solicitudesUsuario);
model.addAttribute("trabajosDelCliente", trabajosUsuario);
return "jobs/myrequest";
}
This page shows:
- All your service requests (any status)
- Active jobs in progress
- Request status and application counts
Managing Request Status
You can change the status of your requests based on their current state.
Publishing a Draft
Make a draft request visible to professionals:
MyRequestsController.java:60-81
@PostMapping("/publish/{id}")
public String publishRequest(@PathVariable Long id,
Authentication auth,
RedirectAttributes redirectAttributes) {
try {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Publish the request using the service
serviceRequestService.publishRequest(id, usuarioLogueado);
// Prepare success response
String mensajeExito = "Solicitud publicada correctamente.";
redirectAttributes.addFlashAttribute("success", mensajeExito);
return "redirect:/requests/my-requests";
} catch (IllegalArgumentException error) {
// Handle publication errors
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Unpublishing a Request
Hide a published request from professionals (returns to DRAFT):
MyRequestsController.java:86-107
@PostMapping("/unpublish/{id}")
public String unpublishRequest(@PathVariable Long id,
Authentication auth,
RedirectAttributes redirectAttributes) {
try {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Unpublish the request using the service
serviceRequestService.unpublishRequest(id, usuarioLogueado);
// Prepare success response
String mensajeExito = "Solicitud despublicada correctamente.";
redirectAttributes.addFlashAttribute("success", mensajeExito);
return "redirect:/requests/my-requests";
} catch (IllegalArgumentException error) {
// Handle unpublish errors
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Cancelling a Request
Cancel a request you no longer need:
MyRequestsController.java:112-133
@PostMapping("/cancel/{id}")
public String cancelRequest(@PathVariable Long id,
Authentication auth,
RedirectAttributes redirectAttributes) {
try {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Cancel the request using the service
serviceRequestService.cancelRequest(id, usuarioLogueado);
// Prepare success response
String mensajeExito = "Solicitud cancelada correctamente.";
redirectAttributes.addFlashAttribute("success", mensajeExito);
return "redirect:/requests/my-requests";
} catch (IllegalArgumentException error) {
// Handle cancellation errors
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Reactivating a Cancelled Request
Bring a cancelled request back to published status:
MyRequestsController.java:138-159
@PostMapping("/reactivate/{id}")
public String reactivateRequest(@PathVariable Long id,
Authentication auth,
RedirectAttributes redirectAttributes) {
try {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Reactivate the request using the service
serviceRequestService.reactivateRequest(id, usuarioLogueado);
// Prepare success response
String mensajeExito = "Solicitud reactivada correctamente.";
redirectAttributes.addFlashAttribute("success", mensajeExito);
return "redirect:/requests/my-requests";
} catch (IllegalArgumentException error) {
// Handle reactivation errors
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Deleting a Request
Permanently delete a request:
MyRequestsController.java:164-185
@PostMapping("/delete/{id}")
public String deleteRequest(@PathVariable Long id,
Authentication auth,
RedirectAttributes redirectAttributes) {
try {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Delete the request using the service
serviceRequestService.deleteRequest(id, usuarioLogueado);
// Prepare success response
String mensajeExito = "Solicitud eliminada correctamente.";
redirectAttributes.addFlashAttribute("success", mensajeExito);
return "redirect:/requests/my-requests";
} catch (IllegalArgumentException error) {
// Handle deletion errors
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Deleting a request is permanent and cannot be undone. Consider cancelling instead if you might need the information later.
Viewing Applications
Once your request is published, professionals will submit applications. View them at /requests/applications/{requestId}:
MyRequestsController.java:355-372
@GetMapping("/applications/{requestId}")
public String viewApplications(@PathVariable Long requestId, Model model,
RedirectAttributes redirectAttributes) {
try {
List<JobApplication> aplicaciones = serviceRequestService.getApplicationsForMyRequest(requestId);
ServiceRequest solicitud = serviceRequestService.getMyRequestById(requestId);
model.addAttribute("aplicaciones", aplicaciones);
model.addAttribute("solicitud", solicitud);
return "jobs/applications";
} catch (RuntimeException error) {
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Each application contains:
JobApplication.java:21-76
@Entity
@Table(name = "job_application")
public class JobApplication extends BaseEntity {
public enum Status {
PENDING, ACCEPTED, REJECTED, WITHDRAWN
}
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "id_request", nullable = false)
private ServiceRequest request;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "id_professional", nullable = false)
private ProfessionalProfile professional;
@Size(max = 1000, message = "El mensaje no puede exceder los 1000 caracteres")
@Column(name = "message", columnDefinition = "TEXT")
private String message;
@DecimalMin(value = "0.00", message = "El precio propuesto debe ser positivo")
@Column(name = "proposed_price", precision = 8, scale = 2)
private BigDecimal proposedPrice;
@Column(name = "applied_at")
private LocalDateTime appliedAt;
@Column(name = "responded_at")
private LocalDateTime respondedAt;
@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private Status status = Status.PENDING;
}
For each application you can see:
- Professional’s profile and ratings
- Proposed price
- Personal message
- Application date
- Application status (PENDING, ACCEPTED, REJECTED, WITHDRAWN)
Accepting an Application
When you find the right professional, accept their application:
MyRequestsController.java:320-334
@PostMapping("/accept-application")
public String acceptApplicationWithParams(@RequestParam Long requestId,
@RequestParam Long applicationId,
RedirectAttributes redirectAttributes) {
try {
serviceRequestService.acceptRequest(requestId, applicationId);
redirectAttributes.addFlashAttribute("success", "Aplicación aceptada correctamente.");
return "redirect:/requests/my-requests";
} catch (RuntimeException error) {
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/my-requests";
}
}
Accepting an application:
- Creates a new
ServiceJob with status CREATED
- Changes the request status to
IN_PROGRESS
- Sets the application status to
ACCEPTED
- Automatically rejects all other pending applications
Rejecting an Application
If an application doesn’t meet your needs:
MyRequestsController.java:336-350
@PostMapping("/reject-application")
public String rejectApplicationWithParams(@RequestParam Long requestId,
@RequestParam Long applicationId,
RedirectAttributes redirectAttributes) {
try {
serviceRequestService.rejectRequest(requestId, applicationId);
redirectAttributes.addFlashAttribute("success", "Aplicación rechazada correctamente.");
return "redirect:/requests/applications/" + requestId;
} catch (RuntimeException error) {
redirectAttributes.addFlashAttribute("error", error.getMessage());
return "redirect:/requests/applications/" + requestId;
}
}
Managing Active Jobs
Once you accept an application, a ServiceJob is created. Jobs can have these statuses:
public enum Status {
CREATED, IN_PROGRESS, COMPLETED, CANCELLED, PAUSED
}
Completing a Job
When the work is finished, mark the job as complete:
MyRequestsController.java:190-206
@PostMapping("/complete/{jobId}")
public String completeJob(@PathVariable Long jobId, Authentication auth) {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Find and validate the job
ServiceJob trabajoEncontrado = buscarYValidarTrabajo(jobId, usuarioLogueado);
if (trabajoEncontrado == null) {
return "redirect:/requests/my-requests";
}
// Complete the job
completarTrabajoEspecifico(trabajoEncontrado);
// Redirect to ratings
return "redirect:/shared/ratings?jobId=" + jobId;
}
Completing a job:
- Sets the job status to
COMPLETED
- Records the end date
- Redirects you to rate the professional
Pausing a Job
Temporarily pause work in progress:
MyRequestsController.java:212-226
@PostMapping("/pause/{jobId}")
public String pauseJob(@PathVariable Long jobId, Authentication auth) {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Find and validate the job
ServiceJob trabajoEncontrado = buscarYValidarTrabajo(jobId, usuarioLogueado);
if (trabajoEncontrado == null) {
return "redirect:/requests/my-requests";
}
// Pause the job
pausarTrabajoEspecifico(trabajoEncontrado);
return "redirect:/requests/my-requests";
}
Cancelling a Job
Cancel a job that’s no longer needed:
MyRequestsController.java:232-246
@PostMapping("/cancel-job/{jobId}")
public String cancelJob(@PathVariable Long jobId, Authentication auth) {
// Get logged in user
AppUser usuarioLogueado = authService.getAuthenticatedUser(auth);
// Find and validate the job
ServiceJob trabajoEncontrado = buscarYValidarTrabajo(jobId, usuarioLogueado);
if (trabajoEncontrado == null) {
return "redirect:/requests/my-requests";
}
// Cancel the job
cancelarTrabajoEspecifico(trabajoEncontrado);
return "redirect:/requests/my-requests";
}
Job Lifecycle
Understand the complete job workflow:
Job Created
When you accept an application, a job is created with status CREATED. The service request becomes IN_PROGRESS.
Work Begins
The professional starts working. You can update the job status to IN_PROGRESS to track active work.
Work Completed
When finished, mark the job as COMPLETED. This records the end date and prompts you to rate the professional.
Rating
After completion, you can rate the professional and leave a review.
Alternative Outcomes
- Paused: Work is temporarily stopped but may resume later
- Cancelled: Job cancelled before completion (by client or professional)
Best Practices
Review all applications carefullyCompare proposed prices, professional ratings, and messages before making a decision.
Communicate with professionalsIf you have questions about an application, reach out to the professional before accepting.
Complete jobs promptlyMark jobs as complete as soon as work finishes so you can rate the professional while the experience is fresh.
Only you can manage your jobsThe system validates that you’re the client who created the request before allowing job management actions.
Application Status Transitions
Applications move through these states:
PENDING → ACCEPTED (creates ServiceJob)
→ REJECTED (by client)
→ WITHDRAWN (by professional)
- PENDING: Professional has applied, waiting for client response
- ACCEPTED: Client selected this professional (other applications auto-rejected)
- REJECTED: Client declined this application
- WITHDRAWN: Professional cancelled their own application