610 lines
19 KiB
Go
610 lines
19 KiB
Go
package handlers
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// =====================
|
|
// Subscription Plan Types
|
|
// =====================
|
|
|
|
type createPlanReq struct {
|
|
Name string `json:"name" validate:"required"`
|
|
Description *string `json:"description"`
|
|
DurationValue int32 `json:"duration_value" validate:"required,min=1"`
|
|
DurationUnit string `json:"duration_unit" validate:"required,oneof=DAY WEEK MONTH YEAR"`
|
|
Price float64 `json:"price" validate:"required,min=0"`
|
|
Currency string `json:"currency" validate:"required"`
|
|
IsActive *bool `json:"is_active"`
|
|
}
|
|
|
|
type updatePlanReq struct {
|
|
Name *string `json:"name"`
|
|
Description *string `json:"description"`
|
|
DurationValue *int32 `json:"duration_value"`
|
|
DurationUnit *string `json:"duration_unit"`
|
|
Price *float64 `json:"price"`
|
|
Currency *string `json:"currency"`
|
|
IsActive *bool `json:"is_active"`
|
|
}
|
|
|
|
type planRes struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Description *string `json:"description,omitempty"`
|
|
DurationValue int32 `json:"duration_value"`
|
|
DurationUnit string `json:"duration_unit"`
|
|
Price float64 `json:"price"`
|
|
Currency string `json:"currency"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
// =====================
|
|
// User Subscription Types
|
|
// =====================
|
|
|
|
type subscribeReq struct {
|
|
PlanID int64 `json:"plan_id" validate:"required"`
|
|
PaymentReference *string `json:"payment_reference"`
|
|
PaymentMethod *string `json:"payment_method"`
|
|
}
|
|
|
|
type subscribeWithPaymentReq struct {
|
|
PlanID int64 `json:"plan_id" validate:"required"`
|
|
Phone string `json:"phone" validate:"required"`
|
|
Email string `json:"email" validate:"required,email"`
|
|
}
|
|
|
|
type subscriptionRes struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
PlanID int64 `json:"plan_id"`
|
|
PlanName *string `json:"plan_name,omitempty"`
|
|
StartsAt string `json:"starts_at"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
Status string `json:"status"`
|
|
PaymentReference *string `json:"payment_reference,omitempty"`
|
|
PaymentMethod *string `json:"payment_method,omitempty"`
|
|
AutoRenew bool `json:"auto_renew"`
|
|
DurationValue *int32 `json:"duration_value,omitempty"`
|
|
DurationUnit *string `json:"duration_unit,omitempty"`
|
|
Price *float64 `json:"price,omitempty"`
|
|
Currency *string `json:"currency,omitempty"`
|
|
CreatedAt string `json:"created_at"`
|
|
}
|
|
|
|
type autoRenewReq struct {
|
|
AutoRenew bool `json:"auto_renew"`
|
|
}
|
|
|
|
// =====================
|
|
// Subscription Plan Handlers
|
|
// =====================
|
|
|
|
// CreateSubscriptionPlan godoc
|
|
// @Summary Create a subscription plan
|
|
// @Description Creates a new subscription plan (admin only)
|
|
// @Tags subscriptions
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body createPlanReq true "Create plan payload"
|
|
// @Success 201 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscription-plans [post]
|
|
func (h *Handler) CreateSubscriptionPlan(c *fiber.Ctx) error {
|
|
var req createPlanReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
plan, err := h.subscriptionsSvc.CreatePlan(c.Context(), domain.CreateSubscriptionPlanInput{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
DurationValue: req.DurationValue,
|
|
DurationUnit: req.DurationUnit,
|
|
Price: req.Price,
|
|
Currency: req.Currency,
|
|
IsActive: req.IsActive,
|
|
})
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to create subscription plan",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
actorID := c.Locals("user_id").(int64)
|
|
actorRole := string(c.Locals("role").(domain.Role))
|
|
ip := c.IP()
|
|
ua := c.Get("User-Agent")
|
|
meta, _ := json.Marshal(map[string]interface{}{"name": plan.Name, "price": plan.Price})
|
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionSubscriptionPlanCreated, domain.ResourceSubscriptionPlan, &plan.ID, "Created subscription plan: "+plan.Name, meta, &ip, &ua)
|
|
|
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
|
Message: "Subscription plan created successfully",
|
|
Data: planToRes(plan),
|
|
})
|
|
}
|
|
|
|
// ListSubscriptionPlans godoc
|
|
// @Summary List subscription plans
|
|
// @Description Returns all subscription plans
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Param active_only query bool false "Return only active plans"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscription-plans [get]
|
|
func (h *Handler) ListSubscriptionPlans(c *fiber.Ctx) error {
|
|
activeOnly := c.Query("active_only", "true") == "true"
|
|
|
|
plans, err := h.subscriptionsSvc.ListPlans(c.Context(), activeOnly)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to list subscription plans",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
result := make([]planRes, len(plans))
|
|
for i, p := range plans {
|
|
result[i] = *planToRes(&p)
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription plans retrieved successfully",
|
|
Data: result,
|
|
})
|
|
}
|
|
|
|
// GetSubscriptionPlan godoc
|
|
// @Summary Get a subscription plan
|
|
// @Description Returns a single subscription plan by ID
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Param id path int true "Plan ID"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 404 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscription-plans/{id} [get]
|
|
func (h *Handler) GetSubscriptionPlan(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseInt(c.Params("id"), 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid plan ID",
|
|
})
|
|
}
|
|
|
|
plan, err := h.subscriptionsSvc.GetPlanByID(c.Context(), id)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
|
|
Message: "Subscription plan not found",
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription plan retrieved successfully",
|
|
Data: planToRes(plan),
|
|
})
|
|
}
|
|
|
|
// UpdateSubscriptionPlan godoc
|
|
// @Summary Update a subscription plan
|
|
// @Description Updates a subscription plan (admin only)
|
|
// @Tags subscriptions
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "Plan ID"
|
|
// @Param body body updatePlanReq true "Update plan payload"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscription-plans/{id} [put]
|
|
func (h *Handler) UpdateSubscriptionPlan(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseInt(c.Params("id"), 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid plan ID",
|
|
})
|
|
}
|
|
|
|
var req updatePlanReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
err = h.subscriptionsSvc.UpdatePlan(c.Context(), id, domain.UpdateSubscriptionPlanInput{
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
DurationValue: req.DurationValue,
|
|
DurationUnit: req.DurationUnit,
|
|
Price: req.Price,
|
|
Currency: req.Currency,
|
|
IsActive: req.IsActive,
|
|
})
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to update subscription plan",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
actorID := c.Locals("user_id").(int64)
|
|
actorRole := string(c.Locals("role").(domain.Role))
|
|
ip := c.IP()
|
|
ua := c.Get("User-Agent")
|
|
meta, _ := json.Marshal(map[string]interface{}{"plan_id": id})
|
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionSubscriptionPlanUpdated, domain.ResourceSubscriptionPlan, &id, fmt.Sprintf("Updated subscription plan ID: %d", id), meta, &ip, &ua)
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription plan updated successfully",
|
|
})
|
|
}
|
|
|
|
// DeleteSubscriptionPlan godoc
|
|
// @Summary Delete a subscription plan
|
|
// @Description Deletes a subscription plan (admin only)
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Param id path int true "Plan ID"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscription-plans/{id} [delete]
|
|
func (h *Handler) DeleteSubscriptionPlan(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseInt(c.Params("id"), 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid plan ID",
|
|
})
|
|
}
|
|
|
|
err = h.subscriptionsSvc.DeletePlan(c.Context(), id)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to delete subscription plan",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
actorID := c.Locals("user_id").(int64)
|
|
actorRole := string(c.Locals("role").(domain.Role))
|
|
ip := c.IP()
|
|
ua := c.Get("User-Agent")
|
|
meta, _ := json.Marshal(map[string]interface{}{"plan_id": id})
|
|
go h.activityLogSvc.RecordAction(context.Background(), &actorID, &actorRole, domain.ActionSubscriptionPlanDeleted, domain.ResourceSubscriptionPlan, &id, fmt.Sprintf("Deleted subscription plan ID: %d", id), meta, &ip, &ua)
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription plan deleted successfully",
|
|
})
|
|
}
|
|
|
|
// =====================
|
|
// User Subscription Handlers
|
|
// =====================
|
|
|
|
// Subscribe godoc
|
|
// @Summary Subscribe to a plan (Admin only - bypasses payment)
|
|
// @Description Creates a new subscription for the authenticated user. For regular users, use /payments/subscribe instead.
|
|
// @Tags subscriptions
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body subscribeReq true "Subscribe payload"
|
|
// @Success 201 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscriptions [post]
|
|
// @deprecated Use POST /api/v1/payments/subscribe for user subscriptions with payment
|
|
func (h *Handler) Subscribe(c *fiber.Ctx) error {
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
// Check role - only admins can create subscriptions without payment
|
|
role, ok := c.Locals("role").(domain.Role)
|
|
if !ok || (role != domain.RoleAdmin && role != domain.RoleSuperAdmin) {
|
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
|
Message: "Use /api/v1/payments/subscribe to subscribe with payment",
|
|
Error: "Direct subscription creation requires admin privileges",
|
|
})
|
|
}
|
|
|
|
var req subscribeReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
sub, err := h.subscriptionsSvc.Subscribe(c.Context(), userID, req.PlanID, req.PaymentReference, req.PaymentMethod)
|
|
if err != nil {
|
|
status := fiber.StatusInternalServerError
|
|
if err.Error() == "user already has an active subscription" {
|
|
status = fiber.StatusConflict
|
|
}
|
|
return c.Status(status).JSON(domain.ErrorResponse{
|
|
Message: "Failed to create subscription",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
|
Message: "Subscription created successfully",
|
|
Data: subscriptionToRes(sub),
|
|
})
|
|
}
|
|
|
|
// SubscribeWithPayment godoc
|
|
// @Summary Subscribe to a plan with payment
|
|
// @Description Initiates payment for a subscription plan. Returns payment URL for checkout.
|
|
// @Tags subscriptions
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body subscribeWithPaymentReq true "Subscribe with payment payload"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 409 {object} domain.ErrorResponse "User already has active subscription"
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscriptions/checkout [post]
|
|
func (h *Handler) SubscribeWithPayment(c *fiber.Ctx) error {
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
var req subscribeWithPaymentReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Use ArifPay service to initiate payment
|
|
result, err := h.arifpaySvc.InitiateSubscriptionPayment(c.Context(), userID, domain.InitiateSubscriptionPaymentRequest{
|
|
PlanID: req.PlanID,
|
|
Phone: req.Phone,
|
|
Email: req.Email,
|
|
})
|
|
if err != nil {
|
|
status := fiber.StatusInternalServerError
|
|
if err.Error() == "user already has an active subscription" {
|
|
status = fiber.StatusConflict
|
|
} else if err.Error() == "subscription plan is not active" {
|
|
status = fiber.StatusBadRequest
|
|
}
|
|
return c.Status(status).JSON(domain.ErrorResponse{
|
|
Message: "Failed to initiate subscription payment",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Payment initiated. Complete payment to activate subscription.",
|
|
Data: result,
|
|
})
|
|
}
|
|
|
|
// GetMySubscription godoc
|
|
// @Summary Get current subscription
|
|
// @Description Returns the authenticated user's active subscription
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 404 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscriptions/me [get]
|
|
func (h *Handler) GetMySubscription(c *fiber.Ctx) error {
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
sub, err := h.subscriptionsSvc.GetActiveSubscription(c.Context(), userID)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
|
|
Message: "No active subscription found",
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription retrieved successfully",
|
|
Data: subscriptionToRes(sub),
|
|
})
|
|
}
|
|
|
|
// GetMySubscriptionHistory godoc
|
|
// @Summary Get subscription history
|
|
// @Description Returns the authenticated user's subscription history
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Param limit query int false "Limit" default(20)
|
|
// @Param offset query int false "Offset" default(0)
|
|
// @Success 200 {object} domain.Response
|
|
// @Router /api/v1/subscriptions/history [get]
|
|
func (h *Handler) GetMySubscriptionHistory(c *fiber.Ctx) error {
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
limit, _ := strconv.Atoi(c.Query("limit", "20"))
|
|
offset, _ := strconv.Atoi(c.Query("offset", "0"))
|
|
|
|
subs, err := h.subscriptionsSvc.GetSubscriptionHistory(c.Context(), userID, int32(limit), int32(offset))
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to get subscription history",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
result := make([]subscriptionRes, len(subs))
|
|
for i, s := range subs {
|
|
result[i] = *subscriptionToRes(&s)
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription history retrieved successfully",
|
|
Data: result,
|
|
})
|
|
}
|
|
|
|
// CheckSubscriptionStatus godoc
|
|
// @Summary Check subscription status
|
|
// @Description Returns whether the authenticated user has an active subscription
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Success 200 {object} domain.Response
|
|
// @Router /api/v1/subscriptions/status [get]
|
|
func (h *Handler) CheckSubscriptionStatus(c *fiber.Ctx) error {
|
|
userID, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
hasActive, err := h.subscriptionsSvc.HasActiveSubscription(c.Context(), userID)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to check subscription status",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription status retrieved",
|
|
Data: fiber.Map{
|
|
"has_active_subscription": hasActive,
|
|
},
|
|
})
|
|
}
|
|
|
|
// CancelSubscription godoc
|
|
// @Summary Cancel subscription
|
|
// @Description Cancels the user's subscription
|
|
// @Tags subscriptions
|
|
// @Produce json
|
|
// @Param id path int true "Subscription ID"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscriptions/{id}/cancel [post]
|
|
func (h *Handler) CancelSubscription(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseInt(c.Params("id"), 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid subscription ID",
|
|
})
|
|
}
|
|
|
|
err = h.subscriptionsSvc.CancelSubscription(c.Context(), id)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to cancel subscription",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Subscription cancelled successfully",
|
|
})
|
|
}
|
|
|
|
// SetAutoRenew godoc
|
|
// @Summary Set auto-renew
|
|
// @Description Enables or disables auto-renewal for a subscription
|
|
// @Tags subscriptions
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "Subscription ID"
|
|
// @Param body body autoRenewReq true "Auto-renew payload"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/subscriptions/{id}/auto-renew [put]
|
|
func (h *Handler) SetAutoRenew(c *fiber.Ctx) error {
|
|
id, err := strconv.ParseInt(c.Params("id"), 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid subscription ID",
|
|
})
|
|
}
|
|
|
|
var req autoRenewReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
err = h.subscriptionsSvc.SetAutoRenew(c.Context(), id, req.AutoRenew)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to update auto-renew setting",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Auto-renew setting updated successfully",
|
|
})
|
|
}
|
|
|
|
// Helper functions
|
|
|
|
func planToRes(p *domain.SubscriptionPlan) *planRes {
|
|
return &planRes{
|
|
ID: p.ID,
|
|
Name: p.Name,
|
|
Description: p.Description,
|
|
DurationValue: p.DurationValue,
|
|
DurationUnit: p.DurationUnit,
|
|
Price: p.Price,
|
|
Currency: p.Currency,
|
|
IsActive: p.IsActive,
|
|
CreatedAt: p.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
}
|
|
}
|
|
|
|
func subscriptionToRes(s *domain.UserSubscription) *subscriptionRes {
|
|
return &subscriptionRes{
|
|
ID: s.ID,
|
|
UserID: s.UserID,
|
|
PlanID: s.PlanID,
|
|
PlanName: s.PlanName,
|
|
StartsAt: s.StartsAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
ExpiresAt: s.ExpiresAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
Status: s.Status,
|
|
PaymentReference: s.PaymentReference,
|
|
PaymentMethod: s.PaymentMethod,
|
|
AutoRenew: s.AutoRenew,
|
|
DurationValue: s.DurationValue,
|
|
DurationUnit: s.DurationUnit,
|
|
Price: s.Price,
|
|
Currency: s.Currency,
|
|
CreatedAt: s.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
}
|
|
}
|