diff --git a/domain/campaign/entity/entitty.go b/domain/campaign/entity/entitty.go index 5e79f0b6..463a3af8 100644 --- a/domain/campaign/entity/entitty.go +++ b/domain/campaign/entity/entitty.go @@ -5,41 +5,31 @@ import ( "time" ) -type CampaignStatus string - -const ( - CampaignDraft CampaignStatus = "draft" - CampaignActive CampaignStatus = "active" - CampaignFinished CampaignStatus = "completed" - CampaignPaused CampaignStatus = "paused" - CampaignCanceled CampaignStatus = "cancelled" -) - type Campaign struct { - ID types.ID `json:"id"` - Title string `json:"title"` - Description string `json:"description"` - Link string `json:"link"` - Slogan string `json:"slogan"` // - GoalAmount float64 `json:"goal_amount"` - RaisedAmount float64 `json:"raised_amount"` - Status CampaignStatus `json:"status"` - CreatedAt time.Time `json:"created_at"` - DeadlineAt *time.Time `json:"deadline_at,omitempty"` - AdminID types.ID `json:"creator_id"` + ID types.ID `json:"id"` + Title string `json:"title"` + Description string `json:"description"` + Link string `json:"link"` + Slogan string `json:"slogan"` // + GoalAmount float64 `json:"goal_amount"` + RaisedAmount float64 `json:"raised_amount"` + Status types.CampaignStatus `json:"status"` + CreatedAt time.Time `json:"created_at"` + DeadlineAt *time.Time `json:"deadline_at,omitempty"` + AdminID types.ID `json:"creator_id"` } // Behavior func (c *Campaign) Activate() { - if c.Status == CampaignDraft { - c.Status = CampaignActive + if c.Status == types.CampaignDraft { + c.Status = types.CampaignActive } } func (c *Campaign) AddFunds(amount float64) { c.RaisedAmount += amount if c.RaisedAmount >= c.GoalAmount { - c.Status = CampaignFinished + c.Status = types.CampaignFinished } } diff --git a/domain/campaign/service/create-campaign.go b/domain/campaign/service/create-campaign.go index 372ee293..3d61b93c 100644 --- a/domain/campaign/service/create-campaign.go +++ b/domain/campaign/service/create-campaign.go @@ -3,11 +3,27 @@ package service import ( "context" "fmt" - "git.gocasts.ir/ebhomengo/niki/domain/campaign/service/mapper" + "git.gocasts.ir/ebhomengo/niki/domain/campaign/entity" richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" "git.gocasts.ir/ebhomengo/niki/types" + "time" ) +func ToCampaignEntity(req CreateCampaignRequest) entity.Campaign { + return entity.Campaign{ + Title: req.Title, + Description: req.Description, + Link: req.Link, + Slogan: req.Slogan, + GoalAmount: req.GoalAmount, + RaisedAmount: 0, + Status: types.CampaignStatus(req.Status), + DeadlineAt: req.DeadlineAt, + AdminID: req.AdminID, + CreatedAt: time.Now(), + } +} + // CreateCampaign handles creation of a new campaign. func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) { const op = "service.campaign.create_campaign" @@ -16,7 +32,7 @@ func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaign return 0, richerror.New(op).WithErr(err) } - campaign := mapper.ToCampaignEntity(req) + campaign := ToCampaignEntity(req) id, err := s.repo.Create(ctx, campaign) if err != nil { diff --git a/domain/campaign/service/mapper/main.go b/domain/campaign/service/mapper/main.go deleted file mode 100644 index a03c256f..00000000 --- a/domain/campaign/service/mapper/main.go +++ /dev/null @@ -1,22 +0,0 @@ -package mapper - -import ( - "git.gocasts.ir/ebhomengo/niki/domain/campaign/entity" - param "git.gocasts.ir/ebhomengo/niki/domain/campaign/service" - "time" -) - -func ToCampaignEntity(req param.CreateCampaignRequest) entity.Campaign { - return entity.Campaign{ - Title: req.Title, - Description: req.Description, - Link: req.Link, - Slogan: req.Slogan, - GoalAmount: req.GoalAmount, - RaisedAmount: 0, - Status: entity.CampaignStatus(req.Status), - DeadlineAt: req.DeadlineAt, - AdminID: req.AdminID, - CreatedAt: time.Now(), - } -} diff --git a/domain/campaign/service/services.go b/domain/campaign/service/services.go index 9e027fb9..a34e6256 100644 --- a/domain/campaign/service/services.go +++ b/domain/campaign/service/services.go @@ -14,6 +14,11 @@ type CampaignFilterParam struct { IsArchived *bool } +type CampaignStatus interface { + FindActiveCampaigns(ctx context.Context) ([]entity.Campaign, error) + UpdateStatus(ctx context.Context, id types.ID, status types.CampaignStatus) error +} + type CampaignStorage interface { Create(ctx context.Context, c entity.Campaign) (types.ID, error) Update(ctx context.Context, c entity.Campaign) error @@ -24,10 +29,10 @@ type CampaignStorage interface { } type CampaignService struct { - repo CampaignStorage + repo CampaignStorage + repoStatus CampaignStatus } -// NewCampaignService constructs a new CampaignService. func NewCampaignService(storage CampaignStorage) *CampaignService { return &CampaignService{ repo: storage, diff --git a/domain/campaign/service/update-campaign-status.go b/domain/campaign/service/update-campaign-status.go new file mode 100644 index 00000000..90f54a13 --- /dev/null +++ b/domain/campaign/service/update-campaign-status.go @@ -0,0 +1,63 @@ +package service + +import ( + "context" + "git.gocasts.ir/ebhomengo/niki/types" + "time" +) + +func (s *CampaignService) MonitorCampaignProgress(ctx context.Context) { + + //c := cron.New() + // + //c.AddFunc("@hourly", func() { + // s.checkAndCompleteCampaigns(context.Background()) + //}) + // + //c.Start() + + //ticker := time.NewTicker(1 * time.Hour) // Check every hour + //defer ticker.Stop() + // + //for { + // select { + // case <-ticker.C: + // s.checkAndCompleteCampaigns(ctx) + // case <-ctx.Done(): + // return + // } + //} +} + +func (s *CampaignService) checkAndCompleteCampaigns(ctx context.Context) { + activeCampaigns, err := s.repoStatus.FindActiveCampaigns(ctx) // Method to fetch active campaigns + if err != nil { + // Log the error, but don't stop the monitor + return + } + + for _, campaign := range activeCampaigns { + // Check if deadline has passed + if campaign.DeadlineAt != nil && campaign.DeadlineAt.Before(time.Now()) { + if campaign.Status != types.CampaignFinished { + campaign.Status = types.CampaignFinished + err := s.repoStatus.UpdateStatus(ctx, campaign.ID, types.CampaignFinished) // Method to update status + if err != nil { + // Log error for this specific campaign + } + } + continue // Move to next campaign + } + + // Check if goal is met + if campaign.RaisedAmount >= campaign.GoalAmount { + if campaign.Status != types.CampaignFinished { + campaign.Status = types.CampaignFinished + err := s.repoStatus.UpdateStatus(ctx, campaign.ID, types.CampaignFinished) // Method to update status + if err != nil { + // Log error for this specific campaign + } + } + } + } +} diff --git a/types/status.go b/types/status.go new file mode 100644 index 00000000..6f65d0fb --- /dev/null +++ b/types/status.go @@ -0,0 +1,11 @@ +package types + +type CampaignStatus string + +const ( + CampaignDraft CampaignStatus = "draft" + CampaignActive CampaignStatus = "active" + CampaignFinished CampaignStatus = "completed" + CampaignPaused CampaignStatus = "paused" + CampaignCanceled CampaignStatus = "cancelled" +)