diff --git a/delivery/http_server/admin/kind_box/route.go b/delivery/http_server/admin/kind_box/route.go index 146fc0a..627bf10 100644 --- a/delivery/http_server/admin/kind_box/route.go +++ b/delivery/http_server/admin/kind_box/route.go @@ -15,4 +15,5 @@ func (h Handler) SetRoutes(e *echo.Echo) { r.PATCH("/:id/assign-receiver-agent", h.AssignReceiverAgent, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxAssignReceiverAgentPermission)) r.GET("", h.GetAll, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxGetAllPermission)) r.PATCH("/:id/enumerate", h.Enumerate, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxEnumeratePermission)) + r.PUT("/update/:id", h.Update, middleware.AdminAuthorization(h.adminAuthorizeSvc, entity.AdminKindBoxUpdatePermission)) } diff --git a/delivery/http_server/admin/kind_box/update.go b/delivery/http_server/admin/kind_box/update.go new file mode 100644 index 0000000..ecf4cbb --- /dev/null +++ b/delivery/http_server/admin/kind_box/update.go @@ -0,0 +1,50 @@ +package adminkindboxhandler + +import ( + "net/http" + + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box" + httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg" + "github.com/labstack/echo/v4" +) + +// Update godoc +// @Summary Update kind Box by admin +// @Tags Admins KindBoxes +// @Accept json +// @Produce json +// @Param id path int true "Kind Box ID" +// @Param Request body param.KindBoxUpdateRequest true "Update KindBox Request Body" +// @Success 204 +// @Failure 400 {string} "Bad Request" +// @Failure 401 {string} "invalid or expired jwt" +// @Failure 403 {string} "user not allowed" +// @Failure 422 {object} httpmsg.ErrorResponse +// @Failure 500 {string} "something went wrong" +// @Security AuthBearerAdmin +// @Router /admins/kindboxes/update/{id} [put]. +func (h Handler) Update(c echo.Context) error { + + var req param.KindBoxUpdateRequest + + if bErr := c.Bind(&req); bErr != nil { + return c.JSON(http.StatusBadRequest, httpmsg.ErrorResponse{ + Message: "Invalid request body", + }) + } + + resp, sErr := h.adminKindBoxSvc.Update(c.Request().Context(), req) + if sErr != nil { + msg, code := httpmsg.Error(sErr) + if resp.FieldErrors != nil { + return c.JSON(code, echo.Map{ + "message": msg, + "errors": resp.FieldErrors, + }) + } + + return echo.NewHTTPError(code, msg) + } + + return c.JSON(http.StatusNoContent, nil) +} diff --git a/docs/docs.go b/docs/docs.go index f045a18..4ca78a4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -249,6 +249,78 @@ const docTemplate = `{ } } }, + "/admins/kindboxes/update/{id}": { + "put": { + "security": [ + { + "AuthBearerAdmin": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admins KindBoxes" + ], + "summary": "Update kind Box by admin", + "parameters": [ + { + "type": "integer", + "description": "Kind Box ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update KindBox Request Body", + "name": "Request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/adminkindboxparam.KindBoxUpdateRequest" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "invalid or expired jwt", + "schema": { + "type": "string" + } + }, + "403": { + "description": "user not allowed", + "schema": { + "type": "string" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/httpmsg.ErrorResponse" + } + }, + "500": { + "description": "something went wrong", + "schema": { + "type": "string" + } + } + } + } + }, "/admins/kindboxes/{id}": { "get": { "security": [ @@ -2746,6 +2818,35 @@ const docTemplate = `{ } } }, + "adminkindboxparam.KindBoxUpdateRequest": { + "type": "object", + "properties": { + "amount": { + "type": "integer", + "example": 3 + }, + "benefactor_id": { + "type": "integer", + "example": 1 + }, + "receiver_agent_id": { + "type": "integer", + "example": 23 + }, + "return_address_id": { + "type": "integer", + "example": 1 + }, + "return_refer_date": { + "type": "string", + "example": "2025-01-02T15:04:05Z" + }, + "return_refere_time_id": { + "type": "integer", + "example": 3 + } + } + }, "adminkindboxreqparam.AssignSenderRequest": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 9a05883..b1559fd 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -238,6 +238,78 @@ } } }, + "/admins/kindboxes/update/{id}": { + "put": { + "security": [ + { + "AuthBearerAdmin": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admins KindBoxes" + ], + "summary": "Update kind Box by admin", + "parameters": [ + { + "type": "integer", + "description": "Kind Box ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Update KindBox Request Body", + "name": "Request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/adminkindboxparam.KindBoxUpdateRequest" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "401": { + "description": "invalid or expired jwt", + "schema": { + "type": "string" + } + }, + "403": { + "description": "user not allowed", + "schema": { + "type": "string" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "$ref": "#/definitions/httpmsg.ErrorResponse" + } + }, + "500": { + "description": "something went wrong", + "schema": { + "type": "string" + } + } + } + } + }, "/admins/kindboxes/{id}": { "get": { "security": [ @@ -2735,6 +2807,35 @@ } } }, + "adminkindboxparam.KindBoxUpdateRequest": { + "type": "object", + "properties": { + "amount": { + "type": "integer", + "example": 3 + }, + "benefactor_id": { + "type": "integer", + "example": 1 + }, + "receiver_agent_id": { + "type": "integer", + "example": 23 + }, + "return_address_id": { + "type": "integer", + "example": 1 + }, + "return_refer_date": { + "type": "string", + "example": "2025-01-02T15:04:05Z" + }, + "return_refere_time_id": { + "type": "integer", + "example": 3 + } + } + }, "adminkindboxreqparam.AssignSenderRequest": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 9e06187..98c9827 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -192,6 +192,27 @@ definitions: type: string type: object type: object + adminkindboxparam.KindBoxUpdateRequest: + properties: + amount: + example: 3 + type: integer + benefactor_id: + example: 1 + type: integer + receiver_agent_id: + example: 23 + type: integer + return_address_id: + example: 1 + type: integer + return_refer_date: + example: "2025-01-02T15:04:05Z" + type: string + return_refere_time_id: + example: 3 + type: integer + type: object adminkindboxreqparam.AssignSenderRequest: properties: sender_agent_id: @@ -1158,6 +1179,52 @@ paths: summary: Admin enumerate kindbox tags: - Admins KindBoxes + /admins/kindboxes/update/{id}: + put: + consumes: + - application/json + parameters: + - description: Kind Box ID + in: path + name: id + required: true + type: integer + - description: Update KindBox Request Body + in: body + name: Request + required: true + schema: + $ref: '#/definitions/adminkindboxparam.KindBoxUpdateRequest' + produces: + - application/json + responses: + "204": + description: No Content + "400": + description: Bad Request + schema: + type: string + "401": + description: invalid or expired jwt + schema: + type: string + "403": + description: user not allowed + schema: + type: string + "422": + description: Unprocessable Entity + schema: + $ref: '#/definitions/httpmsg.ErrorResponse' + "500": + description: something went wrong + schema: + type: string + security: + - AuthBearerAdmin: [] + summary: Update kind Box by admin + tags: + - Admins KindBoxes /admins/kindboxreqs: get: consumes: diff --git a/entity/admin_permission.go b/entity/admin_permission.go index f7c8142..da55036 100644 --- a/entity/admin_permission.go +++ b/entity/admin_permission.go @@ -20,4 +20,5 @@ const ( AdminKindBoxGetAwaitingReturnPermission = AdminPermission("kindbox-get_awaiting_return") AdminKindBoxReturnPermission = AdminPermission("kindbox-return") AdminKindBoxEnumeratePermission = AdminPermission("kindbox-enumerate") + AdminKindBoxUpdatePermission = AdminPermission("kindbox-update") ) diff --git a/param/admin/kind_box/update.go b/param/admin/kind_box/update.go index 10e9792..0bfae24 100644 --- a/param/admin/kind_box/update.go +++ b/param/admin/kind_box/update.go @@ -1,17 +1,20 @@ package adminkindboxparam -import entity "git.gocasts.ir/ebhomengo/niki/entity" +import ( + "time" +) +//when kindbox creates, which fields are type KindBoxUpdateRequest struct { - BenefactorID uint - KindBoxID uint - Amount uint - ReceiverAgentID uint - SenderAgentID uint - SerialNumber string - Status entity.KindBoxStatus + KindBoxID uint `json:"-" param:"id" example:"1"` // ID is passed in the URL path + BenefactorID uint `json:"benefactor_id" example:"1"` + ReturnReferTimeID uint `json:"return_refere_time_id" example:"3"` + ReturnReferDate time.Time `json:"return_refer_date" example:"2025-01-02T15:04:05Z"` + ReturnAddressID uint `json:"return_address_id" example:"1"` + ReceiverAgentID uint `json:"receiver_agent_id" example:"23"` + Amount uint `json:"amount" example:"3"` } type KindBoxUpdateResponse struct { - KindBox entity.KindBox + FieldErrors map[string]string `json:"field_errors,omitempty"` } diff --git a/repository/mysql/kind_box/update.go b/repository/mysql/kind_box/update.go new file mode 100644 index 0000000..fb051fb --- /dev/null +++ b/repository/mysql/kind_box/update.go @@ -0,0 +1,94 @@ +package mysqlkindbox + +import ( + "context" + "database/sql" + "time" + + + "git.gocasts.ir/ebhomengo/niki/entity" + errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" + "git.gocasts.ir/ebhomengo/niki/repository/mysql" +) + +func (d *DB) UpdateKindBox(ctx context.Context, kindBox entity.KindBox) error { + const op = "mysqlkindbox.UpdateKindBox" + + // Handle nullable fields + var ( + returnReferTimeID sql.NullInt64 + returnReferDate sql.NullTime + returnAddressID sql.NullInt64 + receiverAgentID sql.NullInt64 + returnedAt sql.NullTime + ) + + if kindBox.ReturnReferTimeID != 0 { + returnReferTimeID = sql.NullInt64{Int64: int64(kindBox.ReturnReferTimeID), Valid: true} + } else { + returnReferTimeID = sql.NullInt64{Int64: 0, Valid: false} + } + + if !kindBox.ReturnReferDate.IsZero() { + returnReferDate = sql.NullTime{Time: kindBox.ReturnReferDate, Valid: true} + } else { + returnReferDate = sql.NullTime{Time: time.Time{}, Valid: false} + } + + if kindBox.ReturnAddressID != 0 { + returnAddressID = sql.NullInt64{Int64: int64(kindBox.ReturnAddressID), Valid: true} + } else { + returnAddressID = sql.NullInt64{Int64: 0, Valid: false} + } + + if kindBox.ReceiverAgentID != 0 { + receiverAgentID = sql.NullInt64{Int64: int64(kindBox.ReceiverAgentID), Valid: true} + } else { + receiverAgentID = sql.NullInt64{Int64: 0, Valid: false} + } + + if !kindBox.ReturnedAt.IsZero() { + returnedAt = sql.NullTime{Time: kindBox.ReturnedAt, Valid: true} + } else { + returnedAt = sql.NullTime{Time: time.Time{}, Valid: false} + } + + query:= `UPDATE kind_boxes SET + benefactor_id = ?, type = ?, amount = ?, serial_number = ?, status = ?, deliver_refer_time_id = ?, deliver_refer_date = ?, deliver_address_id = ?, + sender_agent_id = ?, delivered_at = ?, return_refer_time_id = ?, return_refer_date = ?, return_address_id = ?, receiver_agent_id = ?, returned_at = ? + WHERE + id = ? AND deleted_at IS NULL` + + stmt, err := d.conn.PrepareStatement(ctx, mysql.StatementKeyKindBoxUpdate, query) + if err != nil { + return richerror.New(op).WithErr(err). + WithMessage(errmsg.ErrorMsgCantPrepareStatement).WithKind(richerror.KindUnexpected) + } + + _, uErr := stmt.ExecContext(ctx, + kindBox.BenefactorID, + kindBox.KindBoxType, + kindBox.Amount, + kindBox.SerialNumber, + kindBox.Status, + kindBox.DeliverReferTimeID, + kindBox.DeliverReferDate, + kindBox.DeliverAddressID, + kindBox.SenderAgentID, + kindBox.DeliveredAt, + returnReferTimeID, + returnReferDate, + returnAddressID, + receiverAgentID, + returnedAt, + kindBox.ID, + ) + + if uErr != nil { + return richerror.New(op).WithErr(uErr).WithMessage(errmsg.ErrorMsgCantUpdateRecord). + WithKind(richerror.KindUnexpected) + } + + return nil +} diff --git a/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql b/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql index baa74c3..69424e2 100644 --- a/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql +++ b/repository/mysql/migration/1708712564_alter_admin_access_controls_table_permission_enum_field.sql @@ -17,7 +17,8 @@ ALTER TABLE `admin_access_controls` MODIFY COLUMN `permission` 'kindboxreq-get', 'kindbox-get_awaiting_return', 'kindbox-return', - 'kindbox-enumerate' + 'kindbox-enumerate', + 'kindbox-update' ) NOT NULL; -- +migrate Down \ No newline at end of file diff --git a/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql b/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql index e321d7c..9e6f3d0 100644 --- a/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql +++ b/repository/mysql/migration/1708712565_insert_admin_access_controls_table.sql @@ -37,7 +37,8 @@ VALUES (1 , 'role','kindbox-return'), (3 , 'role','kindbox-return'), (1 , 'role','kindbox-enumerate'), - (2 , 'role','kindbox-enumerate'); + (2 , 'role','kindbox-enumerate'), + (1 , 'role','kindbox-update'); diff --git a/repository/mysql/prepared_statement.go b/repository/mysql/prepared_statement.go index f10d898..9500522 100644 --- a/repository/mysql/prepared_statement.go +++ b/repository/mysql/prepared_statement.go @@ -42,5 +42,6 @@ const ( StatementKeyKindBoxReqRollbackToPendingStatus StatementKeyKindBoxReqReject StatementKeyKindBoxReqUpdate + StatementKeyKindBoxUpdate StatementKeyReferTimeGetByID ) diff --git a/service/admin/kind_box/service.go b/service/admin/kind_box/service.go index 6e9dba0..1476abd 100644 --- a/service/admin/kind_box/service.go +++ b/service/admin/kind_box/service.go @@ -15,6 +15,7 @@ type Repository interface { AssignReceiverAgent(ctx context.Context, kindBox entity.KindBox) error GetAllKindBox(ctx context.Context, filter params.FilterRequest, pagination params.PaginationRequest, sort params.SortRequest) ([]entity.KindBox, uint, error) EnumerateKindBox(ctx context.Context, kindBoxID uint, amount uint) error + UpdateKindBox(ctx context.Context, KindBox entity.KindBox) error } type Service struct { diff --git a/service/admin/kind_box/update.go b/service/admin/kind_box/update.go new file mode 100644 index 0000000..3d01b0b --- /dev/null +++ b/service/admin/kind_box/update.go @@ -0,0 +1,48 @@ +package adminkindboxservice + +import ( + "context" + + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" +) + +func (s Service) Update(ctx context.Context, req param.KindBoxUpdateRequest) (param.KindBoxUpdateResponse, error) { + const op = "adminkindboxservice.Update" + + // Validate the request using a validation service + if fieldErrors, vErr := s.vld.ValidateUpdateRequest(ctx, req); vErr != nil { + return param.KindBoxUpdateResponse{FieldErrors: fieldErrors}, richerror.New(op).WithErr(vErr) + } + + // Fetch the current kind box data from the repository + kindBox, err := s.repo.GetKindBox(ctx, req.KindBoxID) + if err != nil { + return param.KindBoxUpdateResponse{}, richerror.New(op).WithErr(err) + } + + // Update the fields that are non-zero or non-default values + if req.Amount != 0 { + kindBox.Amount = req.Amount + } + if req.ReturnReferTimeID != 0 { + kindBox.ReturnReferTimeID = req.ReturnReferTimeID + } + if !req.ReturnReferDate.IsZero() { + kindBox.ReturnReferDate = req.ReturnReferDate + } + if req.ReturnAddressID != 0 { + kindBox.ReturnAddressID = req.ReturnAddressID + } + if req.ReceiverAgentID != 0 { + kindBox.ReceiverAgentID = req.ReceiverAgentID + } + + // Update the kind box in the repository + if uErr := s.repo.UpdateKindBox(ctx, kindBox); uErr != nil { + return param.KindBoxUpdateResponse{}, richerror.New(op).WithErr(uErr) + } + + // Return a successful response + return param.KindBoxUpdateResponse{}, nil +} diff --git a/service/service.go b/service/service.go index 97821ca..f00ae19 100644 --- a/service/service.go +++ b/service/service.go @@ -76,7 +76,7 @@ func New(cfg config.Config, db *mysql.DB, rds *redis.Adapter, smsAdapter smscont AdminVld = adminvalidator.New(adminRepo) AdminSvc = adminservice.New(adminRepo, AdminAuthSvc, AdminVld) - AdminKindBoxVld = adminkindboxvalidator.New(kindBoxRepo, AdminAgentSvc) + AdminKindBoxVld = adminkindboxvalidator.New(kindBoxRepo, AdminAgentSvc, AdminBenefactorSvc, AdminReferTimeSvc, AdminAddressSvc) AdminKindBoxSvc = adminkindboxservice.New(kindBoxRepo, AdminKindBoxVld) AdminKindBoxReqVld = adminkindboxreqvalidator.New(kindBoxReqRepo, AdminSvc, AdminAgentSvc, AdminBenefactorSvc, AdminReferTimeSvc, AdminAddressSvc) AdminKindBoxReqSvc = adminkindboxreqservice.New(kindBoxReqRepo, AdminKindBoxSvc, AdminKindBoxReqVld) diff --git a/validator/admin/kind_box/mock_AddressSvc_test.go b/validator/admin/kind_box/mock_AddressSvc_test.go new file mode 100644 index 0000000..f83fd35 --- /dev/null +++ b/validator/admin/kind_box/mock_AddressSvc_test.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package adminkindboxvalidator + +import ( + context "context" + + adminaddressparam "git.gocasts.ir/ebhomengo/niki/param/admin/address" + + mock "github.com/stretchr/testify/mock" +) + +// MockAddressSvc is an autogenerated mock type for the AddressSvc type +type MockAddressSvc struct { + mock.Mock +} + +type MockAddressSvc_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAddressSvc) EXPECT() *MockAddressSvc_Expecter { + return &MockAddressSvc_Expecter{mock: &_m.Mock} +} + +// GetAddressByID provides a mock function with given fields: ctx, request +func (_m *MockAddressSvc) GetAddressByID(ctx context.Context, request adminaddressparam.AddressGetRequest) (adminaddressparam.AddressGetResponse, error) { + ret := _m.Called(ctx, request) + + if len(ret) == 0 { + panic("no return value specified for GetAddressByID") + } + + var r0 adminaddressparam.AddressGetResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, adminaddressparam.AddressGetRequest) (adminaddressparam.AddressGetResponse, error)); ok { + return rf(ctx, request) + } + if rf, ok := ret.Get(0).(func(context.Context, adminaddressparam.AddressGetRequest) adminaddressparam.AddressGetResponse); ok { + r0 = rf(ctx, request) + } else { + r0 = ret.Get(0).(adminaddressparam.AddressGetResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, adminaddressparam.AddressGetRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAddressSvc_GetAddressByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAddressByID' +type MockAddressSvc_GetAddressByID_Call struct { + *mock.Call +} + +// GetAddressByID is a helper method to define mock.On call +// - ctx context.Context +// - request adminaddressparam.AddressGetRequest +func (_e *MockAddressSvc_Expecter) GetAddressByID(ctx interface{}, request interface{}) *MockAddressSvc_GetAddressByID_Call { + return &MockAddressSvc_GetAddressByID_Call{Call: _e.mock.On("GetAddressByID", ctx, request)} +} + +func (_c *MockAddressSvc_GetAddressByID_Call) Run(run func(ctx context.Context, request adminaddressparam.AddressGetRequest)) *MockAddressSvc_GetAddressByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(adminaddressparam.AddressGetRequest)) + }) + return _c +} + +func (_c *MockAddressSvc_GetAddressByID_Call) Return(_a0 adminaddressparam.AddressGetResponse, _a1 error) *MockAddressSvc_GetAddressByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAddressSvc_GetAddressByID_Call) RunAndReturn(run func(context.Context, adminaddressparam.AddressGetRequest) (adminaddressparam.AddressGetResponse, error)) *MockAddressSvc_GetAddressByID_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAddressSvc creates a new instance of MockAddressSvc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockAddressSvc(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAddressSvc { + mock := &MockAddressSvc{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/validator/admin/kind_box/mock_AgentSvc_test.go b/validator/admin/kind_box/mock_AgentSvc_test.go new file mode 100644 index 0000000..81b3eb2 --- /dev/null +++ b/validator/admin/kind_box/mock_AgentSvc_test.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package adminkindboxvalidator + +import ( + context "context" + + adminagentparam "git.gocasts.ir/ebhomengo/niki/param/admin/agent" + + mock "github.com/stretchr/testify/mock" +) + +// MockAgentSvc is an autogenerated mock type for the AgentSvc type +type MockAgentSvc struct { + mock.Mock +} + +type MockAgentSvc_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAgentSvc) EXPECT() *MockAgentSvc_Expecter { + return &MockAgentSvc_Expecter{mock: &_m.Mock} +} + +// AgentExistByID provides a mock function with given fields: ctx, req +func (_m *MockAgentSvc) AgentExistByID(ctx context.Context, req adminagentparam.AdminAgentExistByIDRequest) (adminagentparam.AdminAgentExistByIDResponse, error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for AgentExistByID") + } + + var r0 adminagentparam.AdminAgentExistByIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, adminagentparam.AdminAgentExistByIDRequest) (adminagentparam.AdminAgentExistByIDResponse, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, adminagentparam.AdminAgentExistByIDRequest) adminagentparam.AdminAgentExistByIDResponse); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Get(0).(adminagentparam.AdminAgentExistByIDResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, adminagentparam.AdminAgentExistByIDRequest) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAgentSvc_AgentExistByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AgentExistByID' +type MockAgentSvc_AgentExistByID_Call struct { + *mock.Call +} + +// AgentExistByID is a helper method to define mock.On call +// - ctx context.Context +// - req adminagentparam.AdminAgentExistByIDRequest +func (_e *MockAgentSvc_Expecter) AgentExistByID(ctx interface{}, req interface{}) *MockAgentSvc_AgentExistByID_Call { + return &MockAgentSvc_AgentExistByID_Call{Call: _e.mock.On("AgentExistByID", ctx, req)} +} + +func (_c *MockAgentSvc_AgentExistByID_Call) Run(run func(ctx context.Context, req adminagentparam.AdminAgentExistByIDRequest)) *MockAgentSvc_AgentExistByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(adminagentparam.AdminAgentExistByIDRequest)) + }) + return _c +} + +func (_c *MockAgentSvc_AgentExistByID_Call) Return(_a0 adminagentparam.AdminAgentExistByIDResponse, _a1 error) *MockAgentSvc_AgentExistByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAgentSvc_AgentExistByID_Call) RunAndReturn(run func(context.Context, adminagentparam.AdminAgentExistByIDRequest) (adminagentparam.AdminAgentExistByIDResponse, error)) *MockAgentSvc_AgentExistByID_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAgentSvc creates a new instance of MockAgentSvc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockAgentSvc(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAgentSvc { + mock := &MockAgentSvc{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/validator/admin/kind_box/mock_BenefactorSvc_test.go b/validator/admin/kind_box/mock_BenefactorSvc_test.go new file mode 100644 index 0000000..f9419a0 --- /dev/null +++ b/validator/admin/kind_box/mock_BenefactorSvc_test.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package adminkindboxvalidator + +import ( + context "context" + + adminbenefactoreparam "git.gocasts.ir/ebhomengo/niki/param/admin/benefactor" + + mock "github.com/stretchr/testify/mock" +) + +// MockBenefactorSvc is an autogenerated mock type for the BenefactorSvc type +type MockBenefactorSvc struct { + mock.Mock +} + +type MockBenefactorSvc_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBenefactorSvc) EXPECT() *MockBenefactorSvc_Expecter { + return &MockBenefactorSvc_Expecter{mock: &_m.Mock} +} + +// BenefactorExistByID provides a mock function with given fields: ctx, request +func (_m *MockBenefactorSvc) BenefactorExistByID(ctx context.Context, request adminbenefactoreparam.BenefactorExistByIDRequest) (adminbenefactoreparam.BenefactorExistByIDResponse, error) { + ret := _m.Called(ctx, request) + + if len(ret) == 0 { + panic("no return value specified for BenefactorExistByID") + } + + var r0 adminbenefactoreparam.BenefactorExistByIDResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, adminbenefactoreparam.BenefactorExistByIDRequest) (adminbenefactoreparam.BenefactorExistByIDResponse, error)); ok { + return rf(ctx, request) + } + if rf, ok := ret.Get(0).(func(context.Context, adminbenefactoreparam.BenefactorExistByIDRequest) adminbenefactoreparam.BenefactorExistByIDResponse); ok { + r0 = rf(ctx, request) + } else { + r0 = ret.Get(0).(adminbenefactoreparam.BenefactorExistByIDResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, adminbenefactoreparam.BenefactorExistByIDRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBenefactorSvc_BenefactorExistByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BenefactorExistByID' +type MockBenefactorSvc_BenefactorExistByID_Call struct { + *mock.Call +} + +// BenefactorExistByID is a helper method to define mock.On call +// - ctx context.Context +// - request adminbenefactoreparam.BenefactorExistByIDRequest +func (_e *MockBenefactorSvc_Expecter) BenefactorExistByID(ctx interface{}, request interface{}) *MockBenefactorSvc_BenefactorExistByID_Call { + return &MockBenefactorSvc_BenefactorExistByID_Call{Call: _e.mock.On("BenefactorExistByID", ctx, request)} +} + +func (_c *MockBenefactorSvc_BenefactorExistByID_Call) Run(run func(ctx context.Context, request adminbenefactoreparam.BenefactorExistByIDRequest)) *MockBenefactorSvc_BenefactorExistByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(adminbenefactoreparam.BenefactorExistByIDRequest)) + }) + return _c +} + +func (_c *MockBenefactorSvc_BenefactorExistByID_Call) Return(_a0 adminbenefactoreparam.BenefactorExistByIDResponse, _a1 error) *MockBenefactorSvc_BenefactorExistByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBenefactorSvc_BenefactorExistByID_Call) RunAndReturn(run func(context.Context, adminbenefactoreparam.BenefactorExistByIDRequest) (adminbenefactoreparam.BenefactorExistByIDResponse, error)) *MockBenefactorSvc_BenefactorExistByID_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBenefactorSvc creates a new instance of MockBenefactorSvc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBenefactorSvc(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBenefactorSvc { + mock := &MockBenefactorSvc{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/validator/admin/kind_box/mock_ReferTimeSvc_test.go b/validator/admin/kind_box/mock_ReferTimeSvc_test.go new file mode 100644 index 0000000..4ef06a9 --- /dev/null +++ b/validator/admin/kind_box/mock_ReferTimeSvc_test.go @@ -0,0 +1,94 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package adminkindboxvalidator + +import ( + context "context" + + param "git.gocasts.ir/ebhomengo/niki/param/admin/refer_time" + mock "github.com/stretchr/testify/mock" +) + +// MockReferTimeSvc is an autogenerated mock type for the ReferTimeSvc type +type MockReferTimeSvc struct { + mock.Mock +} + +type MockReferTimeSvc_Expecter struct { + mock *mock.Mock +} + +func (_m *MockReferTimeSvc) EXPECT() *MockReferTimeSvc_Expecter { + return &MockReferTimeSvc_Expecter{mock: &_m.Mock} +} + +// GetReferTimeByID provides a mock function with given fields: ctx, req +func (_m *MockReferTimeSvc) GetReferTimeByID(ctx context.Context, req param.GetReferTimeRequest) (param.GetReferTimeResponse, error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for GetReferTimeByID") + } + + var r0 param.GetReferTimeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, param.GetReferTimeRequest) (param.GetReferTimeResponse, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, param.GetReferTimeRequest) param.GetReferTimeResponse); ok { + r0 = rf(ctx, req) + } else { + r0 = ret.Get(0).(param.GetReferTimeResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, param.GetReferTimeRequest) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockReferTimeSvc_GetReferTimeByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReferTimeByID' +type MockReferTimeSvc_GetReferTimeByID_Call struct { + *mock.Call +} + +// GetReferTimeByID is a helper method to define mock.On call +// - ctx context.Context +// - req param.GetReferTimeRequest +func (_e *MockReferTimeSvc_Expecter) GetReferTimeByID(ctx interface{}, req interface{}) *MockReferTimeSvc_GetReferTimeByID_Call { + return &MockReferTimeSvc_GetReferTimeByID_Call{Call: _e.mock.On("GetReferTimeByID", ctx, req)} +} + +func (_c *MockReferTimeSvc_GetReferTimeByID_Call) Run(run func(ctx context.Context, req param.GetReferTimeRequest)) *MockReferTimeSvc_GetReferTimeByID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(param.GetReferTimeRequest)) + }) + return _c +} + +func (_c *MockReferTimeSvc_GetReferTimeByID_Call) Return(_a0 param.GetReferTimeResponse, _a1 error) *MockReferTimeSvc_GetReferTimeByID_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockReferTimeSvc_GetReferTimeByID_Call) RunAndReturn(run func(context.Context, param.GetReferTimeRequest) (param.GetReferTimeResponse, error)) *MockReferTimeSvc_GetReferTimeByID_Call { + _c.Call.Return(run) + return _c +} + +// NewMockReferTimeSvc creates a new instance of MockReferTimeSvc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReferTimeSvc(t interface { + mock.TestingT + Cleanup(func()) +}) *MockReferTimeSvc { + mock := &MockReferTimeSvc{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/validator/admin/kind_box/mock_Repository_test.go b/validator/admin/kind_box/mock_Repository_test.go new file mode 100644 index 0000000..6715b17 --- /dev/null +++ b/validator/admin/kind_box/mock_Repository_test.go @@ -0,0 +1,151 @@ +// Code generated by mockery v2.45.0. DO NOT EDIT. + +package adminkindboxvalidator + +import ( + context "context" + + entity "git.gocasts.ir/ebhomengo/niki/entity" + mock "github.com/stretchr/testify/mock" +) + +// MockRepository is an autogenerated mock type for the Repository type +type MockRepository struct { + mock.Mock +} + +type MockRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *MockRepository) EXPECT() *MockRepository_Expecter { + return &MockRepository_Expecter{mock: &_m.Mock} +} + +// GetKindBox provides a mock function with given fields: ctx, kindBoxID +func (_m *MockRepository) GetKindBox(ctx context.Context, kindBoxID uint) (entity.KindBox, error) { + ret := _m.Called(ctx, kindBoxID) + + if len(ret) == 0 { + panic("no return value specified for GetKindBox") + } + + var r0 entity.KindBox + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint) (entity.KindBox, error)); ok { + return rf(ctx, kindBoxID) + } + if rf, ok := ret.Get(0).(func(context.Context, uint) entity.KindBox); ok { + r0 = rf(ctx, kindBoxID) + } else { + r0 = ret.Get(0).(entity.KindBox) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint) error); ok { + r1 = rf(ctx, kindBoxID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRepository_GetKindBox_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKindBox' +type MockRepository_GetKindBox_Call struct { + *mock.Call +} + +// GetKindBox is a helper method to define mock.On call +// - ctx context.Context +// - kindBoxID uint +func (_e *MockRepository_Expecter) GetKindBox(ctx interface{}, kindBoxID interface{}) *MockRepository_GetKindBox_Call { + return &MockRepository_GetKindBox_Call{Call: _e.mock.On("GetKindBox", ctx, kindBoxID)} +} + +func (_c *MockRepository_GetKindBox_Call) Run(run func(ctx context.Context, kindBoxID uint)) *MockRepository_GetKindBox_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint)) + }) + return _c +} + +func (_c *MockRepository_GetKindBox_Call) Return(_a0 entity.KindBox, _a1 error) *MockRepository_GetKindBox_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRepository_GetKindBox_Call) RunAndReturn(run func(context.Context, uint) (entity.KindBox, error)) *MockRepository_GetKindBox_Call { + _c.Call.Return(run) + return _c +} + +// KindBoxExist provides a mock function with given fields: ctx, kindBoxID +func (_m *MockRepository) KindBoxExist(ctx context.Context, kindBoxID uint) (bool, error) { + ret := _m.Called(ctx, kindBoxID) + + if len(ret) == 0 { + panic("no return value specified for KindBoxExist") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, uint) (bool, error)); ok { + return rf(ctx, kindBoxID) + } + if rf, ok := ret.Get(0).(func(context.Context, uint) bool); ok { + r0 = rf(ctx, kindBoxID) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, uint) error); ok { + r1 = rf(ctx, kindBoxID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockRepository_KindBoxExist_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'KindBoxExist' +type MockRepository_KindBoxExist_Call struct { + *mock.Call +} + +// KindBoxExist is a helper method to define mock.On call +// - ctx context.Context +// - kindBoxID uint +func (_e *MockRepository_Expecter) KindBoxExist(ctx interface{}, kindBoxID interface{}) *MockRepository_KindBoxExist_Call { + return &MockRepository_KindBoxExist_Call{Call: _e.mock.On("KindBoxExist", ctx, kindBoxID)} +} + +func (_c *MockRepository_KindBoxExist_Call) Run(run func(ctx context.Context, kindBoxID uint)) *MockRepository_KindBoxExist_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint)) + }) + return _c +} + +func (_c *MockRepository_KindBoxExist_Call) Return(_a0 bool, _a1 error) *MockRepository_KindBoxExist_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockRepository_KindBoxExist_Call) RunAndReturn(run func(context.Context, uint) (bool, error)) *MockRepository_KindBoxExist_Call { + _c.Call.Return(run) + return _c +} + +// NewMockRepository creates a new instance of MockRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *MockRepository { + mock := &MockRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/validator/admin/kind_box/update.go b/validator/admin/kind_box/update.go new file mode 100644 index 0000000..c0bbd42 --- /dev/null +++ b/validator/admin/kind_box/update.go @@ -0,0 +1,131 @@ +package adminkindboxvalidator + +import ( + "context" + + entity "git.gocasts.ir/ebhomengo/niki/entity" + param "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box" + errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" + validation "github.com/go-ozzo/ozzo-validation/v4" +) + +func (v Validator) ValidateUpdateRequest(ctx context.Context, req param.KindBoxUpdateRequest) (map[string]string, error) { + const op = "adminkindboxvalidator.ValidateUpdateRequest" + + err := validation.ValidateStruct(&req, + validation.Field(&req.KindBoxID, + validation.Required, + validation.By(v.doesKindBoxExist(ctx))), + validation.Field(&req.BenefactorID, + validation.Required, + validation.By(v.doesBenefactorExist(ctx)), + validation.By(v.doesBenefactorHaveKindBox(ctx, req.KindBoxID, req.BenefactorID))), + ) + + if err != nil { + fieldErrors := make(map[string]string) + v.processValidationErrors(err, fieldErrors) + return fieldErrors, richerror.New(op). + WithMessage(errmsg.ErrorMsgInvalidInput). + WithKind(richerror.KindInvalid). + WithMeta(map[string]interface{}{"req": req}). + WithErr(err) + } + + kindBox, err := v.repo.GetKindBox(ctx, req.KindBoxID) + if err != nil { + return nil, richerror.New(op). + WithMessage(errmsg.ErrorMsgSomethingWentWrong). + WithKind(richerror.KindUnexpected). + WithMeta(map[string]interface{}{"req": req}). + WithErr(err) + } + + var sErr error + fieldErrors := make(map[string]string) + + switch kindBox.Status { + case entity.KindBoxDeliveredStatus, entity.KindBoxReturnedStatus: + fieldErrors["KindBoxID"] = errmsg.ErrorMsgCantUpdateRecord + + case entity.KindBoxReadyToReturnStatus: + if req.Amount != 0 { + fieldErrors["Amount"] = errmsg.ErrorMsgInvalidInput + } + if req.ReceiverAgentID != 0 { + fieldErrors["Receiver Agent Id"] = errmsg.ErrorMsgInvalidInput + } else { + sErr = validation.ValidateStruct(&req, + validation.Field(&req.ReturnAddressID, + validation.Required, + validation.By(v.doesBenefactorAddressExist(ctx, req.KindBoxID, req.BenefactorID, req.ReturnAddressID)), + ), + validation.Field(&req.ReturnReferDate, + validation.Required, + validation.By(v.isDateValid), + ), + validation.Field(&req.ReturnReferTimeID, + validation.Required, + validation.By(v.isReturnReferTimeIDValid(ctx)), + ), + ) + } + + case entity.KindBoxAssignedReceiverAgentStatus: + if req.Amount != 0 { + fieldErrors["Amount"] = errmsg.ErrorMsgInvalidInput + } + if req.ReturnReferTimeID != 0 { + fieldErrors["Return Refer Time Id"] = errmsg.ErrorMsgInvalidInput + } + if !req.ReturnReferDate.IsZero() { + fieldErrors["Return Refer Date"] = errmsg.ErrorMsgInvalidInput + } + if req.ReturnAddressID != 0 { + fieldErrors["Return Address ID"] = errmsg.ErrorMsgInvalidInput + } else { + sErr = validation.ValidateStruct(&req, + validation.Field(&req.ReceiverAgentID, validation.Required, + validation.By(v.doesAgentExist(ctx))), + ) + } + + case entity.KindBoxEnumeratedStatus: + if req.ReceiverAgentID != 0 { + fieldErrors["Receiver Agent ID"] = errmsg.ErrorMsgInvalidInput + } + if req.ReturnReferTimeID != 0 { + fieldErrors["Return Refer Time Id"] = errmsg.ErrorMsgInvalidInput + } + if !req.ReturnReferDate.IsZero() { + fieldErrors["Return Refer Date"] = errmsg.ErrorMsgInvalidInput + } + if req.ReturnAddressID != 0 { + fieldErrors["Return Address ID"] = errmsg.ErrorMsgInvalidInput + } else { + sErr = validation.ValidateStruct(&req, + validation.Field(&req.Amount, validation.Required, + validation.By(v.isAmountValid(ctx))), + ) + } + } + + if sErr != nil { + v.processValidationErrors(sErr, fieldErrors) + return fieldErrors, richerror.New(op). + WithMessage(errmsg.ErrorMsgInvalidInput). + WithKind(richerror.KindInvalid). + WithMeta(map[string]interface{}{"req": req}). + WithErr(sErr) + } + + if len(fieldErrors) > 0 { + return fieldErrors, richerror.New(op). + WithMessage(errmsg.ErrorMsgInvalidInput). + WithKind(richerror.KindInvalid). + WithMeta(map[string]interface{}{"req": req}) + } + + return nil, nil +} diff --git a/validator/admin/kind_box/update_test.go b/validator/admin/kind_box/update_test.go new file mode 100644 index 0000000..8ddc187 --- /dev/null +++ b/validator/admin/kind_box/update_test.go @@ -0,0 +1,453 @@ +package adminkindboxvalidator + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "git.gocasts.ir/ebhomengo/niki/entity" + adminupdateparam "git.gocasts.ir/ebhomengo/niki/param/admin/kind_box" + benefactorserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/benefactor" + agentserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/agent" + addressserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/address" + refertimeserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/refer_time" +) + + + +func TestValidator_ValidateUpdateRequest(t *testing.T) { + + now := time.Now() + twoDaysLater := now.Add(48 * time.Hour) + threeDaysLater := now.Add(52 * time.Hour) + + mockRepository := NewMockRepository(t) + mockAgentSvc := NewMockAgentSvc(t) + mockBenefactorSvc := NewMockBenefactorSvc(t) + mockReferTimeSvc := NewMockReferTimeSvc(t) + mockAddressSvc := NewMockAddressSvc(t) + + validator := New(mockRepository, mockAgentSvc, mockBenefactorSvc, mockReferTimeSvc, mockAddressSvc) + ctx := context.Background() + + + t.Run("KindBox Delivered And Benefactor Does Not Exist", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: false}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxDeliveredStatus}, nil).Once() + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "benefactor_id") + + }) + + t.Run("KindBox Does Not Exist", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(false, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{}, nil).Once() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "KindBoxID") + }) + + + t.Run("KindBox Delivered And Does Not Belong to Benefactor", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxDeliveredStatus, BenefactorID: 2}, nil).Once() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "benefactor_id") + }) + + t.Run("KindBoxID is Null", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 0, + BenefactorID: 1, + } + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{}, nil).Once() + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "KindBoxID") + + + }) + + t.Run("BenefactorID is Null", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 0, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxDeliveredStatus, BenefactorID: 1}, nil).Once() // Note the different BenefactorID + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "benefactor_id") + }) + + + t.Run("Valid KindBox Delivered Request", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID). + Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxDeliveredStatus}, nil).Once() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + }) + + t.Run("KindBox Ready to Return Status and Address Does Not Belong", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReturnReferDate: twoDaysLater, + ReturnReferTimeID: 1, + ReturnAddressID: 23, + } + + validReferTime := entity.ReferTime{ + ID: 1, + Duration: "30m", + Status: entity.ReferTimeActiveStatus, + } + + addressExm := entity.Address{ + ID: 23, + PostalCode: "1231231231", + Address : "Tehran", + Name : "Home", + CityID : 1, + ProvinceID: 1, + BenefactorID: 2, + } + + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID). + Return(true, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockAddressSvc.EXPECT().GetAddressByID(ctx, addressserviceparam.AddressGetRequest{AddressID: req.ReturnAddressID}). + Return(addressserviceparam.AddressGetResponse{Address: addressExm}, nil).Once() + + mockReferTimeSvc.EXPECT().GetReferTimeByID(ctx, refertimeserviceparam.GetReferTimeRequest{ReferTimeID: 1}). + Return(refertimeserviceparam.GetReferTimeResponse{ReferTime: validReferTime}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, uint(req.KindBoxID)). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "return_address_id") + }) + + t.Run("KindBox Ready to Return Status and ReturnReferTimeID Invalid", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReturnReferDate: twoDaysLater, + ReturnReferTimeID: 14, + ReturnAddressID: 1, + } + + validAddress := entity.Address{ + ID: 1, + PostalCode: "1234567890", + Address: "tehran", + Name: "home", + CityID: 1, + ProvinceID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID). + Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + mockAddressSvc.EXPECT().GetAddressByID(ctx, addressserviceparam.AddressGetRequest{AddressID: req.ReturnAddressID}). + Return(addressserviceparam.AddressGetResponse{Address: validAddress}, nil).Once() + + mockReferTimeSvc.EXPECT().GetReferTimeByID(ctx, refertimeserviceparam.GetReferTimeRequest{ReferTimeID: req.ReturnReferTimeID}). + Return(refertimeserviceparam.GetReferTimeResponse{}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "return_refere_time_id") + }) + + + t.Run("Valid KindBox Ready to Return Status Request", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReturnReferDate: twoDaysLater, + ReturnReferTimeID: 1, + ReturnAddressID: 1, + } + + validAddress := entity.Address{ + ID: 1, + PostalCode: "1234567890", + Address: "tehran", + Name: "home", + CityID: 1, + ProvinceID: 1, + BenefactorID: 1, + } + + validReferTime := entity.ReferTime{ + ID: 1, + Duration: "30m", + Status: entity.ReferTimeActiveStatus, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID). + Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + + mockAddressSvc.EXPECT().GetAddressByID(ctx, addressserviceparam.AddressGetRequest{AddressID: req.ReturnAddressID}). + Return(addressserviceparam.AddressGetResponse{Address: validAddress}, nil).Once() + + mockReferTimeSvc.EXPECT().GetReferTimeByID(ctx, refertimeserviceparam.GetReferTimeRequest{ReferTimeID: req.ReturnReferTimeID}). + Return(refertimeserviceparam.GetReferTimeResponse{ReferTime: validReferTime}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, uint(1)). + Return(entity.KindBox{Status: entity.KindBoxReadyToReturnStatus, BenefactorID: req.BenefactorID}, nil).Once() + + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.NoError(t, err) + assert.Nil(t, fieldErrors) + }) + + t.Run("Assigned Receiver Agent Status And ReturnReferDate Not Null", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReturnReferDate: threeDaysLater, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID).Return(entity.KindBox{Status: entity.KindBoxAssignedReceiverAgentStatus, BenefactorID: req.BenefactorID}, nil).Twice() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "Return Refer Date" ) + }) + + t.Run("Assigned Receiver Agent Status And ReturnAddressID Not Null", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReturnAddressID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID).Return(entity.KindBox{Status: entity.KindBoxAssignedReceiverAgentStatus, BenefactorID: req.BenefactorID}, nil).Twice() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "Return Address ID" ) + }) + + t.Run("Valid KindBox Assigned Receiver Agent Status Request", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + ReceiverAgentID: 1, + } + + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID).Return(entity.KindBox{ + Status: entity.KindBoxAssignedReceiverAgentStatus, + BenefactorID: 1, + }, nil).Once() + + mockAgentSvc.EXPECT().AgentExistByID(ctx, agentserviceparam.AdminAgentExistByIDRequest{AgentID: 1}).Return(agentserviceparam.AdminAgentExistByIDResponse{Exist: true}, nil).Once() + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID).Return(entity.KindBox{ + Status: entity.KindBoxAssignedReceiverAgentStatus, + BenefactorID: req.BenefactorID, + }, nil).Once() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.NoError(t, err) + assert.Nil(t, fieldErrors) + }) + + t.Run("Valid Kindbox Returned Status Request", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + } + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID).Return(entity.KindBox{Status: entity.KindBoxReturnedStatus}, nil).Once() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + + }) + + t.Run("Invalid KindBox Enumerate Status Amount", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + Amount: 0, + } + + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{ + Status: entity.KindBoxEnumeratedStatus, + BenefactorID: req.BenefactorID, + }, nil).Twice() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.Error(t, err) + assert.NotNil(t, fieldErrors) + assert.Contains(t, fieldErrors, "amount" ) + }) + + + t.Run("Valid KindBox Enumerated Status Request", func(t *testing.T) { + req := adminupdateparam.KindBoxUpdateRequest{ + KindBoxID: 1, + BenefactorID: 1, + Amount: 100, + } + + + mockRepository.EXPECT().KindBoxExist(ctx, req.KindBoxID).Return(true, nil).Once() + + mockBenefactorSvc.EXPECT().BenefactorExistByID(ctx, benefactorserviceparam.BenefactorExistByIDRequest{ID: req.BenefactorID}). + Return(benefactorserviceparam.BenefactorExistByIDResponse{Existed: true}, nil).Once() + + + mockRepository.EXPECT().GetKindBox(ctx, req.KindBoxID). + Return(entity.KindBox{ + Status: entity.KindBoxEnumeratedStatus, + BenefactorID: 1, + }, nil).Twice() + + fieldErrors, err := validator.ValidateUpdateRequest(ctx, req) + + assert.NoError(t, err) + assert.Nil(t, fieldErrors) + }) +} diff --git a/validator/admin/kind_box/validator.go b/validator/admin/kind_box/validator.go index 25405cd..030e56d 100644 --- a/validator/admin/kind_box/validator.go +++ b/validator/admin/kind_box/validator.go @@ -2,62 +2,133 @@ package adminkindboxvalidator import ( "context" + "errors" "fmt" + "time" - "git.gocasts.ir/ebhomengo/niki/entity" + entity "git.gocasts.ir/ebhomengo/niki/entity" + adminaddressparam "git.gocasts.ir/ebhomengo/niki/param/admin/address" agentparam "git.gocasts.ir/ebhomengo/niki/param/admin/agent" + param "git.gocasts.ir/ebhomengo/niki/param/admin/benefactor" + refertimeparam "git.gocasts.ir/ebhomengo/niki/param/admin/refer_time" errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg" + richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error" validation "github.com/go-ozzo/ozzo-validation/v4" ) +//go:generate mockery --name Repository type Repository interface { KindBoxExist(ctx context.Context, kindBoxID uint) (bool, error) GetKindBox(ctx context.Context, kindBoxID uint) (entity.KindBox, error) } +//go:generate mockery --name AgentSvc type AgentSvc interface { AgentExistByID(ctx context.Context, req agentparam.AdminAgentExistByIDRequest) (agentparam.AdminAgentExistByIDResponse, error) } -type Validator struct { - repo Repository - AgentSvc AgentSvc +//go:generate mockery --name AddressSvc +type AddressSvc interface { + GetAddressByID(ctx context.Context, request adminaddressparam.AddressGetRequest) (adminaddressparam.AddressGetResponse, error) } -func New(repo Repository, adminSvc AgentSvc) Validator { - return Validator{repo: repo, AgentSvc: adminSvc} +//go:generate mockery --name ReferTimeSvc +type ReferTimeSvc interface { + GetReferTimeByID(ctx context.Context, req refertimeparam.GetReferTimeRequest) (refertimeparam.GetReferTimeResponse, error) +} + +//go:generate mockery --name BenefactorSvc +type BenefactorSvc interface { + BenefactorExistByID(ctx context.Context, request param.BenefactorExistByIDRequest) (param.BenefactorExistByIDResponse, error) +} + +type Validator struct { + repo Repository + agentSvc AgentSvc + benefactorSvc BenefactorSvc + referTimeSvc ReferTimeSvc + addressSvc AddressSvc +} + +func New(repo Repository, agentSvc AgentSvc, benefactorSvc BenefactorSvc, referTimeSvc ReferTimeSvc, addressSvc AddressSvc) Validator { + return Validator{repo: repo, agentSvc: agentSvc, benefactorSvc: benefactorSvc, referTimeSvc: referTimeSvc, addressSvc: addressSvc} } func (v Validator) doesKindBoxExist(ctx context.Context) validation.RuleFunc { return func(value interface{}) error { + const op = "Validator.doesKindBoxExist" kindBoxID, ok := value.(uint) if !ok { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindInvalid) + } + if kindBoxID == 0 { + return richerror.New(op).WithMessage(errmsg.ErrorMsgInvalidInput).WithKind(richerror.KindInvalid) } exists, err := v.repo.KindBoxExist(ctx, kindBoxID) if err != nil { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithErr(err).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected) } if !exists { - return fmt.Errorf(errmsg.ErrorMsgNotFound) + return richerror.New(op).WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound) + } + return nil + } +} + +func (v Validator) doesBenefactorExist(ctx context.Context) validation.RuleFunc { + return func(value interface{}) error { + const op = "Validator.doesBenefactorExist" + + benefactorID, ok := value.(uint) + if !ok { + return richerror.New(op). + WithMessage("invalid type for benefactorID"). + WithKind(richerror.KindInvalid) + } + + _, err := v.benefactorSvc.BenefactorExistByID(ctx, param.BenefactorExistByIDRequest{ID: benefactorID}) + if err != nil { + return richerror.New(op). + WithErr(err). + WithMessage("could not check if benefactor exists"). + WithKind(richerror.KindUnexpected) } return nil } } + +func (v Validator) doesBenefactorHaveKindBox(ctx context.Context, kindBoxID uint, benefactorID uint) validation.RuleFunc { + return func(value interface{}) error { + const op = "Validator.doesBenefactorHaveKindBox" + + fetchedKindBox, err := v.repo.GetKindBox(ctx, kindBoxID) + if err != nil { + + return richerror.New(op).WithErr(err).WithMessage("could not fetch KindBox").WithKind(richerror.KindUnexpected) + } + + if fetchedKindBox.BenefactorID != benefactorID { + return richerror.New(op).WithMessage("benefactor does not have the specified kind box").WithKind(richerror.KindInvalid) + } + return nil + } +} + func (v Validator) checkKindBoxStatusForAssigningReceiverAgent(ctx context.Context) validation.RuleFunc { return func(value interface{}) error { + const op = "Validator.checkKindBoxStatusForAssigningReceiverAgent" kindboxID, ok := value.(uint) if !ok { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindInvalid) } kindBox, err := v.repo.GetKindBox(ctx, kindboxID) if err != nil { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithErr(err).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected) } if kindBox.Status != entity.KindBoxReadyToReturnStatus { - return fmt.Errorf(errmsg.ErrorMsgAssignReceiverAgentKindBoxStatus) + return richerror.New(op).WithMessage(errmsg.ErrorMsgAssignReceiverAgentKindBoxStatus).WithKind(richerror.KindInvalid) } return nil @@ -66,18 +137,38 @@ func (v Validator) checkKindBoxStatusForAssigningReceiverAgent(ctx context.Conte func (v Validator) doesAgentExist(ctx context.Context) validation.RuleFunc { return func(value interface{}) error { + const op = "Validator.doesAgentExist" agentID, ok := value.(uint) if !ok { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindInvalid) } - resp, err := v.AgentSvc.AgentExistByID(ctx, agentparam.AdminAgentExistByIDRequest{AgentID: agentID}) + resp, err := v.agentSvc.AgentExistByID(ctx, agentparam.AdminAgentExistByIDRequest{AgentID: agentID}) if err != nil { - return fmt.Errorf(errmsg.ErrorMsgSomethingWentWrong) + return richerror.New(op).WithErr(err).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected) } if !resp.Exist { - return fmt.Errorf(errmsg.ErrorMsgNotFound) + return richerror.New(op).WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound) } + return nil + } +} +func (v Validator) isReturnReferTimeIDValid(ctx context.Context) validation.RuleFunc { + return func(value interface{}) error { + const op = "Validator.isReturnTimeIDValid" + referTimeID, ok := value.(uint) + if !ok { + return richerror.New(op).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindInvalid) + } + resp, err := v.referTimeSvc.GetReferTimeByID(ctx, refertimeparam.GetReferTimeRequest{ + ReferTimeID: referTimeID, + }) + if err != nil { + return richerror.New(op).WithErr(err).WithMessage(errmsg.ErrorMsgReferTimeNotFound).WithKind(richerror.KindNotFound) + } + if resp.ReferTime.Status != entity.ReferTimeActiveStatus { + return richerror.New(op).WithMessage(errmsg.ErrorMsgReferTimeIsNotActive).WithKind(richerror.KindInvalid) + } return nil } } @@ -98,4 +189,57 @@ func (v Validator) CheckKindBoxStatusForEnumeration(ctx context.Context) validat return nil } -} \ No newline at end of file +} +func (v Validator) doesBenefactorAddressExist(ctx context.Context, kindBoxID uint, benefactorID uint, addressID uint) validation.RuleFunc { + return func(value interface{}) error { + const op = "Validator.doesBenefactorAddressExist" + addressRequest := adminaddressparam.AddressGetRequest{ + AddressID: addressID, + } + addressResponse, err := v.addressSvc.GetAddressByID(ctx, addressRequest) + if err != nil { + return richerror.New(op).WithErr(err).WithMessage("failed to retrieve address").WithKind(richerror.KindUnexpected) + } + + if addressResponse.Address.BenefactorID != benefactorID { + return richerror.New(op).WithMessage("the specified address does not belong to the benefactor").WithKind(richerror.KindInvalid) + } + return nil + } +} + +func (v Validator) isDateValid(value interface{}) error { + const op = "Validator.isDateValid" + date, ok := value.(time.Time) + if !ok { + return richerror.New(op).WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindInvalid) + } + if date.Before(time.Now()) { + return richerror.New(op).WithMessage(errmsg.ErrorMsgInvalidInput).WithKind(richerror.KindInvalid) + } + return nil +} + + +func (v Validator) isAmountValid(ctx context.Context) validation.RuleFunc { + return func(value interface{}) error { + const op = "Validator.isAmountValid" + amount, ok := value.(uint) + if !ok || amount == 0 { + return richerror.New(op).WithMessage("amount is required").WithKind(richerror.KindInvalid) + } + return nil + } +} + +//processing errors +func (v Validator) processValidationErrors(err error, fieldErrors map[string]string) { + var errV validation.Errors + if errors.As(err, &errV) { + for key, value := range errV { + if value != nil { + fieldErrors[key] = value.Error() + } + } + } +}