(ctx context.Context, req *adminv1.UpdateBillingSubscriptionRequest)
| 85 | } |
| 86 | |
| 87 | func (s *Server) UpdateBillingSubscription(ctx context.Context, req *adminv1.UpdateBillingSubscriptionRequest) (*adminv1.UpdateBillingSubscriptionResponse, error) { |
| 88 | observability.AddRequestAttributes(ctx, attribute.String("args.org", req.Org)) |
| 89 | observability.AddRequestAttributes(ctx, attribute.String("args.plan_name", req.PlanName)) |
| 90 | |
| 91 | org, err := s.admin.DB.FindOrganizationByName(ctx, req.Org) |
| 92 | if err != nil { |
| 93 | return nil, err |
| 94 | } |
| 95 | |
| 96 | claims := auth.GetClaims(ctx) |
| 97 | forceAccess := claims.Superuser(ctx) && req.SuperuserForceAccess |
| 98 | if !claims.OrganizationPermissions(ctx, org.ID).ManageOrg && !forceAccess { |
| 99 | return nil, status.Error(codes.PermissionDenied, "not allowed to update org billing plan") |
| 100 | } |
| 101 | |
| 102 | if req.PlanName == "" { |
| 103 | return nil, status.Error(codes.InvalidArgument, "plan name must be provided") |
| 104 | } |
| 105 | |
| 106 | if org.BillingCustomerID == "" { |
| 107 | return nil, status.Error(codes.FailedPrecondition, "billing not yet initialized for the organization") |
| 108 | } |
| 109 | |
| 110 | bisc, err := s.admin.DB.FindBillingIssueByTypeForOrg(ctx, org.ID, database.BillingIssueTypeSubscriptionCancelled) |
| 111 | if err != nil { |
| 112 | if !errors.Is(err, database.ErrNotFound) { |
| 113 | return nil, err |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | if bisc != nil { |
| 118 | return nil, status.Errorf(codes.FailedPrecondition, "plan cannot be changed on existing subscription as it was cancelled, please renew the subscription") |
| 119 | } |
| 120 | |
| 121 | plan, err := s.admin.Biller.GetPlanByName(ctx, req.PlanName) |
| 122 | if err != nil { |
| 123 | if errors.Is(err, billing.ErrNotFound) { |
| 124 | return nil, status.Error(codes.NotFound, "plan not found") |
| 125 | } |
| 126 | return nil, err |
| 127 | } |
| 128 | // for the trial plan start the time-based trial, for the free plan start the credit trial |
| 129 | if plan.PlanType == billing.FreePlanType || plan.PlanType == billing.TrailPlanType { |
| 130 | bi, err := s.admin.DB.FindBillingIssueByTypeForOrg(ctx, org.ID, database.BillingIssueTypeNeverSubscribed) |
| 131 | if err != nil { |
| 132 | if errors.Is(err, database.ErrNotFound) { |
| 133 | return nil, status.Errorf(codes.FailedPrecondition, "only new organizations can subscribe to the trial plan %s", plan.Name) |
| 134 | } |
| 135 | return nil, err |
| 136 | } |
| 137 | if bi != nil { |
| 138 | // check against trial orgs quota, skip for superusers |
| 139 | if org.CreatedByUserID != nil && !claims.Superuser(ctx) { |
| 140 | u, err := s.admin.DB.FindUser(ctx, *org.CreatedByUserID) |
| 141 | if err != nil { |
| 142 | return nil, err |
| 143 | } |
| 144 | if u.QuotaTrialOrgs >= 0 && u.CurrentTrialOrgsCount >= u.QuotaTrialOrgs { |
nothing calls this directly
no test coverage detected