Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ build/

### VS Code ###
.vscode/
.claude

### Env ###
.env
61 changes: 61 additions & 0 deletions backend/src/main/java/com/angel/autonow/driver/DriverEntity.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,65 @@
package com.angel.autonow.driver;

import com.angel.autonow.expertise.ExpertiseType;
import com.angel.autonow.vehicle.VehicleEntity;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import org.hibernate.validator.constraints.URL;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Set;

@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "driver")
public class DriverEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotBlank(message = "First name is required")
@Column(name = "first_name", nullable = false)
private String firstName;

@NotBlank(message = "Last name is required")
@Column(name = "last_name", nullable = false)
private String lastName;

@NotBlank(message = "Phone number is required")
@Pattern(regexp = "^\\+?[0-9]{10,15}$", message = "Phone number must be valid")
@Column(name = "phone_number", nullable = false)
private String phoneNumber;

@NotBlank(message = "License number is required")
@Column(name = "license_number", unique = true, nullable = false)
private String licenseNumber;

@NotNull(message = "Expertise type is required")
@Enumerated(EnumType.STRING)
@Column(name = "expertise_type", nullable = false)
private ExpertiseType expertiseType;

@Column(name = "available")
private boolean available;

@URL(message = "Image URL must be valid")
@Column(name = "image_url")
private String imageUrl;

@OneToMany
@JoinTable(
name = "driver_vehicles",
joinColumns = @JoinColumn(name = "driver_id"),
inverseJoinColumns = @JoinColumn(name = "vehicle_id")
)
private Set<VehicleEntity> vehicles;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
package com.angel.autonow.exception;

import com.angel.autonow.user.UserException;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@ControllerAdvice
public class GlobalControllerExceptionHandler {

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ProblemDetail handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.warn(e.getMessage(), HttpStatus.BAD_REQUEST, e);

Map<String, String> errors = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);

ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
problemDetail.setTitle("Validation failed");
problemDetail.setDetail("One or more fields have validation errors");
problemDetail.setProperty("errors", errors);

return problemDetail;
}

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
public ProblemDetail handleConstraintViolationException(ConstraintViolationException e) {
log.warn(e.getMessage(), HttpStatus.BAD_REQUEST, e);

Map<String, String> errors = new HashMap<>();
e.getConstraintViolations().forEach(violation ->
errors.put(violation.getPropertyPath().toString(), violation.getMessage())
);

ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
problemDetail.setTitle("Validation failed");
problemDetail.setDetail("One or more constraints were violated");
problemDetail.setProperty("errors", errors);

return problemDetail;
}

@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UsernameNotFoundException.class)
public ProblemDetail handleUsernameNotFoundException(UsernameNotFoundException e) {
Expand Down
116 changes: 116 additions & 0 deletions backend/src/main/java/com/angel/autonow/order/OrderEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.angel.autonow.order;

import com.angel.autonow.driver.DriverEntity;
import com.angel.autonow.user.UserEntity;
import com.angel.autonow.vehicle.VehicleEntity;
import com.angel.autonow.vehicle.VehicleType;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "orders")
public class OrderEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull(message = "User is required")
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private UserEntity user;

@ManyToOne
@JoinColumn(name = "driver_id")
private DriverEntity driver;

@ManyToOne
@JoinColumn(name = "vehicle_id")
private VehicleEntity vehicle;

@NotNull(message = "Vehicle type is required")
@Enumerated(EnumType.STRING)
@Column(name = "vehicle_type", nullable = false)
private VehicleType vehicleType;

@NotBlank(message = "Pickup address is required")
@Column(name = "pickup_address", nullable = false)
private String pickupAddress;

@NotNull(message = "Pickup latitude is required")
@Column(name = "pickup_latitude", nullable = false)
private Double pickupLatitude;

@NotNull(message = "Pickup longitude is required")
@Column(name = "pickup_longitude", nullable = false)
private Double pickupLongitude;

@NotBlank(message = "Dropoff address is required")
@Column(name = "dropoff_address", nullable = false)
private String dropoffAddress;

@NotNull(message = "Dropoff latitude is required")
@Column(name = "dropoff_latitude", nullable = false)
private Double dropoffLatitude;

@NotNull(message = "Dropoff longitude is required")
@Column(name = "dropoff_longitude", nullable = false)
private Double dropoffLongitude;

@NotNull(message = "Status is required")
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private OrderStatus status;

@Positive(message = "Estimated price must be positive")
@Column(name = "estimated_price")
private Double estimatedPrice;

@Positive(message = "Final price must be positive")
@Column(name = "final_price")
private Double finalPrice;
Comment thread
StoynovAngel marked this conversation as resolved.

@Positive(message = "Distance must be positive")
@Column(name = "distance_km")
private Double distanceKm;

@Positive(message = "Estimated duration must be positive")
@Column(name = "estimated_duration_minutes")
private Integer estimatedDurationMinutes;

@Column(name = "special_requirements")
private String specialRequirements;

@Column(name = "cancellation_reason")
private String cancellationReason;

@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at")
private LocalDateTime updatedAt;

@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
if (status == null) status = OrderStatus.CREATED;
}

@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
74 changes: 74 additions & 0 deletions backend/src/main/java/com/angel/autonow/payment/PaymentEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.angel.autonow.payment;

import com.angel.autonow.order.OrderEntity;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "payments")
public class PaymentEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull(message = "Order is required")
@OneToOne
@JoinColumn(name = "order_id", nullable = false, unique = true)
private OrderEntity order;

@NotNull(message = "Amount is required")
@Positive(message = "Amount must be positive")
@Column(name = "amount", nullable = false)
private Double amount;
Comment thread
StoynovAngel marked this conversation as resolved.

@NotNull(message = "Payment method is required")
@Enumerated(EnumType.STRING)
@Column(name = "payment_method", nullable = false)
private PaymentMethod paymentMethod;

@NotNull(message = "Status is required")
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private PaymentStatus status;

@Column(name = "transaction_id", unique = true)
private String transactionId;

@NotBlank(message = "Currency is required")
@Size(min = 3, max = 3, message = "Currency must be a 3-letter code")
@Column(name = "currency", nullable = false)
private String currency;

@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;

@Column(name = "updated_at")
private LocalDateTime updatedAt;

@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
if (status == null) status = PaymentStatus.PENDING;
if (currency == null) currency = "EUR";
}

@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
}
10 changes: 10 additions & 0 deletions backend/src/main/java/com/angel/autonow/payment/PaymentMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.angel.autonow.payment;

public enum PaymentMethod {
CASH,
CREDIT_CARD,
DEBIT_CARD,
PAYPAL,
GOOGLE_PAY,
APPLE_PAY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.angel.autonow.payment;

public enum PaymentStatus {
PENDING,
COMPLETED,
FAILED,
REFUNDED
}
Loading
Loading