Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.restroly.qrmenu.subscription.controller;

import com.restroly.qrmenu.subscription.dto.RestaurantSubscriptionDto;
import com.restroly.qrmenu.subscription.service.SubscriptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/restaurant/{restId}/subscription")
public class RestaurantSubscriptionController {

@Autowired
private SubscriptionService subscriptionService;

@GetMapping
@PreAuthorize("hasAnyRole('RESTAURANT_OWNER', 'SUPER_ADMIN')")
public ResponseEntity<RestaurantSubscriptionDto> getRestaurantSubscription(@PathVariable Long restId) {
return ResponseEntity.ok(subscriptionService.getRestaurantSubscription(restId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.restroly.qrmenu.subscription.controller;

import com.restroly.qrmenu.subscription.dto.RestaurantSubscriptionDto;
import com.restroly.qrmenu.subscription.dto.RestaurantSubscriptionRequest;
import com.restroly.qrmenu.subscription.dto.SubscriptionPlanDto;
import com.restroly.qrmenu.subscription.dto.SubscriptionPlanRequest;
import com.restroly.qrmenu.subscription.service.SubscriptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/admin/subscriptions")
public class SuperAdminSubscriptionController {

@Autowired
private SubscriptionService subscriptionService;

@PostMapping("/plans")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<SubscriptionPlanDto> createPlan(@RequestBody SubscriptionPlanRequest request) {
return ResponseEntity.ok(subscriptionService.createPlan(request));
}

@PutMapping("/plans/{id}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<SubscriptionPlanDto> updatePlan(@PathVariable Long id, @RequestBody SubscriptionPlanRequest request) {
return ResponseEntity.ok(subscriptionService.updatePlan(id, request));
}

@DeleteMapping("/plans/{id}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<Void> deletePlan(@PathVariable Long id) {
subscriptionService.deletePlan(id);
return ResponseEntity.noContent().build();
}

@GetMapping("/plans")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<List<SubscriptionPlanDto>> getAllPlans() {
return ResponseEntity.ok(subscriptionService.getAllPlans());
}

@GetMapping("/plans/{id}")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<SubscriptionPlanDto> getPlanById(@PathVariable Long id) {
return ResponseEntity.ok(subscriptionService.getPlanById(id));
}

@PostMapping("/restaurants/{restId}/assign")
@PreAuthorize("hasRole('SUPER_ADMIN')")
public ResponseEntity<RestaurantSubscriptionDto> assignPlanToRestaurant(
@PathVariable Long restId,
@RequestBody RestaurantSubscriptionRequest request) {
return ResponseEntity.ok(subscriptionService.assignPlanToRestaurant(restId, request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FeatureMappingRequest {
private Long featureId;
private String featureValue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PlanFeatureMappingDto {
private Long id;
private Long featureId;
private String featureKey;
private String featureValue;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RestaurantSubscriptionDto {
private Long id;
private Long restaurantId;
private SubscriptionPlanDto plan;
private LocalDateTime startDate;
private LocalDateTime endDate;
private String status;
private Boolean isAutoRenew;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RestaurantSubscriptionRequest {
private Long planId;
private Boolean isAutoRenew;
private Integer durationInMonths;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SubscriptionPlanDto {
private Long id;
private String name;
private String description;
private Double price;
private String billingCycle;
private Boolean isActive;
private List<PlanFeatureMappingDto> features;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.restroly.qrmenu.subscription.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SubscriptionPlanRequest {
private String name;
private String description;
private Double price;
private String billingCycle;
private Boolean isActive;
private List<FeatureMappingRequest> features;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.restroly.qrmenu.subscription.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "t_plan_feature_mapping")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class PlanFeatureMapping {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "plan_id", nullable = false)
private SubscriptionPlan plan;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "feature_id", nullable = false)
private SubscriptionFeature feature;

@Column(name = "feature_value", nullable = false)
private String featureValue; // Can be "true", "false", or a number like "3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.restroly.qrmenu.subscription.entity;

import com.restroly.qrmenu.restaurant.entity.Restaurant;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@Table(name = "t_restaurant_subscription")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RestaurantSubscription {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "restaurant_id", nullable = false)
private Restaurant restaurant;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "plan_id", nullable = false)
private SubscriptionPlan plan;

@Column(name = "start_date", nullable = false)
private LocalDateTime startDate;

@Column(name = "end_date", nullable = false)
private LocalDateTime endDate;

@Column(nullable = false)
private String status; // ACTIVE, EXPIRED, CANCELLED

@Column(name = "is_auto_renew")
@Builder.Default
private Boolean isAutoRenew = true;

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

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

@PrePersist
protected void onCreate() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}

@PreUpdate
protected void onUpdate() {
this.updatedAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.restroly.qrmenu.subscription.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Table(name = "t_subscription_feature")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SubscriptionFeature {

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

@Column(name = "feature_key", unique = true, nullable = false)
private String featureKey;

@Column(name = "display_name")
private String displayName;

private String description;

@Column(name = "is_active")
@Builder.Default
private Boolean isActive = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.restroly.qrmenu.subscription.entity;

import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
import java.util.List;

@Entity
@Table(name = "t_subscription_plan")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SubscriptionPlan {

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

@Column(unique = true, nullable = false)
private String name;

private String description;

@Column(nullable = false)
private Double price;

@Column(name = "billing_cycle")
private String billingCycle; // e.g., MONTHLY, YEARLY

@Column(name = "is_active")
@Builder.Default
private Boolean isActive = true;

@OneToMany(mappedBy = "plan", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PlanFeatureMapping> features;

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

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

@PrePersist
protected void onCreate() {
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
}

@PreUpdate
protected void onUpdate() {
this.updatedAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.restroly.qrmenu.subscription.repository;

import com.restroly.qrmenu.subscription.entity.PlanFeatureMapping;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface PlanFeatureMappingRepository extends JpaRepository<PlanFeatureMapping, Long> {
List<PlanFeatureMapping> findByPlanId(Long planId);
Optional<PlanFeatureMapping> findByPlanIdAndFeatureId(Long planId, Long featureId);
void deleteByPlanId(Long planId);
}
Loading
Loading