diff --git a/db/db.go b/db/db.go index 415bf5775..fb79a6919 100644 --- a/db/db.go +++ b/db/db.go @@ -1769,9 +1769,34 @@ func (db database) GetPaymentHistoryByCreated(created *time.Time, org_uuid strin func (db database) GetOrganizationBudget(org_uuid string) BountyBudget { ms := BountyBudget{} db.db.Where("org_uuid = ?", org_uuid).Find(&ms) + return ms } +func (db database) GetOrganizationStatusBudget(org_uuid string) StatusBudget { + + orgBudget := db.GetOrganizationBudget(org_uuid) + + var openBudget uint + db.db.Model(&Bounty{}).Where("assignee = '' ").Select("SUM(price)").Row().Scan(&openBudget) + + var assignedBudget uint + db.db.Model(&Bounty{}).Where("assignee != '' ").Select("SUM(price)").Row().Scan(&assignedBudget) + + var completedBudget uint + db.db.Model(&Bounty{}).Where("completed = true ").Select("SUM(price)").Row().Scan(&completedBudget) + + statusBudget := StatusBudget{ + OrgUuid: org_uuid, + CurrentBudget: orgBudget.TotalBudget, + OpenBudget: openBudget, + AssignedBudget: assignedBudget, + CompletedBudget: completedBudget, + } + + return statusBudget +} + func (db database) GetOrganizationBudgetHistory(org_uuid string) []BudgetHistoryData { budgetHistory := []BudgetHistoryData{} diff --git a/db/interface.go b/db/interface.go index 2709abbb1..fc0e08d3b 100644 --- a/db/interface.go +++ b/db/interface.go @@ -103,6 +103,7 @@ type Database interface { UpdateOrganizationBudget(budget BountyBudget) BountyBudget GetPaymentHistoryByCreated(created *time.Time, org_uuid string) PaymentHistory GetOrganizationBudget(org_uuid string) BountyBudget + GetOrganizationStatusBudget(org_uuid string) StatusBudget GetOrganizationBudgetHistory(org_uuid string) []BudgetHistoryData AddAndUpdateBudget(invoice InvoiceList) PaymentHistory WithdrawBudget(sender_pubkey string, org_uuid string, amount uint) diff --git a/db/structs.go b/db/structs.go index 115d557fd..c3a6794de 100644 --- a/db/structs.go +++ b/db/structs.go @@ -361,6 +361,7 @@ type Bounty struct { OwnerID string `json:"owner_id"` Paid bool `json:"paid"` Show bool `gorm:"default:false" json:"show"` + Completed bool `gorm:"default:false" json:"completed"` Type string `json:"type"` Award string `json:"award"` AssignedHours uint8 `json:"assigned_hours"` @@ -496,6 +497,14 @@ type BountyBudget struct { Updated *time.Time `json:"updated"` } +type StatusBudget struct { + OrgUuid string `json:"org_uuid"` + CurrentBudget uint `json:"current_budget"` + OpenBudget uint `json:"open_budget"` + AssignedBudget uint `json:"assigned_budget"` + CompletedBudget uint `json:"completed_budget"` +} + type BudgetInvoiceRequest struct { Amount uint `json:"amount"` SenderPubKey string `json:"sender_pubkey"` diff --git a/handlers/bounty.go b/handlers/bounty.go index 8261ac1a4..5b37aec23 100644 --- a/handlers/bounty.go +++ b/handlers/bounty.go @@ -320,6 +320,7 @@ func UpdatePaymentStatus(w http.ResponseWriter, r *http.Request) { // if setting paid as true by mark as paid // set completion date and mark as paid if bounty.Paid { + bounty.Completed = true bounty.CompletionDate = &now bounty.MarkAsPaidDate = &now if bounty.PaidDate == nil { @@ -525,6 +526,7 @@ func (h *bountyHandler) MakeBountyPayment(w http.ResponseWriter, r *http.Request bounty.Paid = true bounty.PaidDate = &now + bounty.Completed = true bounty.CompletionDate = &now h.db.UpdateBounty(bounty) @@ -781,7 +783,12 @@ func (h *bountyHandler) PollInvoice(w http.ResponseWriter, r *http.Request) { bounty, err := h.db.GetBountyByCreated(uint(invData.Created)) if err == nil { + now := time.Now() + bounty.Paid = true + bounty.PaidDate = &now + bounty.Completed = true + bounty.CompletionDate = &now } h.db.UpdateBounty(bounty) diff --git a/handlers/organization_test.go b/handlers/organization_test.go index 6be18b905..017955cdd 100644 --- a/handlers/organization_test.go +++ b/handlers/organization_test.go @@ -432,16 +432,16 @@ func TestGetOrganizationBudget(t *testing.T) { t.Run("Should test that the right organization budget is returned, if the user is the organization admin or has the ViewReport role", func(t *testing.T) { orgUUID := "valid-uuid" - expectedBudget := db.BountyBudget{ - ID: 1, - OrgUuid: orgUUID, - TotalBudget: 1000, - Created: nil, - Updated: nil, + statusBudget := db.StatusBudget{ + OrgUuid: orgUUID, + CurrentBudget: 10000, + OpenBudget: 1000, + AssignedBudget: 2000, + CompletedBudget: 3000, } oHandler.userHasAccess = mockUserHasAccess - mockDb.On("GetOrganizationBudget", orgUUID).Return(expectedBudget).Once() + mockDb.On("GetOrganizationStatusBudget", orgUUID).Return(statusBudget).Once() rctx := chi.NewRouteContext() rctx.URLParams.Add("uuid", orgUUID) @@ -455,13 +455,13 @@ func TestGetOrganizationBudget(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code) - var responseBudget db.BountyBudget + var responseBudget db.StatusBudget err = json.Unmarshal(rr.Body.Bytes(), &responseBudget) if err != nil { t.Fatal(err) } - assert.Equal(t, expectedBudget, responseBudget) + assert.Equal(t, statusBudget, responseBudget) }) } diff --git a/handlers/organizations.go b/handlers/organizations.go index 2f0544f6c..e91056fa5 100644 --- a/handlers/organizations.go +++ b/handlers/organizations.go @@ -572,7 +572,7 @@ func (oh *organizationHandler) GetOrganizationBudget(w http.ResponseWriter, r *h } // get the organization budget - organizationBudget := oh.db.GetOrganizationBudget(uuid) + organizationBudget := oh.db.GetOrganizationStatusBudget(uuid) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(organizationBudget) diff --git a/mocks/Database.go b/mocks/Database.go index b44f69f67..2332c98fd 100644 --- a/mocks/Database.go +++ b/mocks/Database.go @@ -3648,6 +3648,52 @@ func (_c *Database_GetOrganizationInvoicesCount_Call) RunAndReturn(run func(stri return _c } +// GetOrganizationStatusBudget provides a mock function with given fields: org_uuid +func (_m *Database) GetOrganizationStatusBudget(org_uuid string) db.StatusBudget { + ret := _m.Called(org_uuid) + + if len(ret) == 0 { + panic("no return value specified for GetOrganizationStatusBudget") + } + + var r0 db.StatusBudget + if rf, ok := ret.Get(0).(func(string) db.StatusBudget); ok { + r0 = rf(org_uuid) + } else { + r0 = ret.Get(0).(db.StatusBudget) + } + + return r0 +} + +// Database_GetOrganizationStatusBudget_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrganizationStatusBudget' +type Database_GetOrganizationStatusBudget_Call struct { + *mock.Call +} + +// GetOrganizationStatusBudget is a helper method to define mock.On call +// - org_uuid string +func (_e *Database_Expecter) GetOrganizationStatusBudget(org_uuid interface{}) *Database_GetOrganizationStatusBudget_Call { + return &Database_GetOrganizationStatusBudget_Call{Call: _e.mock.On("GetOrganizationStatusBudget", org_uuid)} +} + +func (_c *Database_GetOrganizationStatusBudget_Call) Run(run func(org_uuid string)) *Database_GetOrganizationStatusBudget_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Database_GetOrganizationStatusBudget_Call) Return(_a0 db.StatusBudget) *Database_GetOrganizationStatusBudget_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Database_GetOrganizationStatusBudget_Call) RunAndReturn(run func(string) db.StatusBudget) *Database_GetOrganizationStatusBudget_Call { + _c.Call.Return(run) + return _c +} + // GetOrganizationUser provides a mock function with given fields: pubkey, org_uuid func (_m *Database) GetOrganizationUser(pubkey string, org_uuid string) db.OrganizationUsers { ret := _m.Called(pubkey, org_uuid)