forked from ebhomengo/niki
1
0
Fork 0

Merge pull request 'feat(kindbox): add edit kindbox by Admin' (#142) from stage/fatemeh/admin-edit-kindbox into develop

Reviewed-on: ebhomengo/niki#142
This commit is contained in:
hossein 2024-09-11 11:01:54 +00:00
commit 5526088b35
22 changed files with 1757 additions and 29 deletions

View File

@ -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))
}

View File

@ -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)
}

View File

@ -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": {

View File

@ -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": {

View File

@ -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:

View File

@ -20,4 +20,5 @@ const (
AdminKindBoxGetAwaitingReturnPermission = AdminPermission("kindbox-get_awaiting_return")
AdminKindBoxReturnPermission = AdminPermission("kindbox-return")
AdminKindBoxEnumeratePermission = AdminPermission("kindbox-enumerate")
AdminKindBoxUpdatePermission = AdminPermission("kindbox-update")
)

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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

View File

@ -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');

View File

@ -42,5 +42,6 @@ const (
StatementKeyKindBoxReqRollbackToPendingStatus
StatementKeyKindBoxReqReject
StatementKeyKindBoxReqUpdate
StatementKeyKindBoxUpdate
StatementKeyReferTimeGetByID
)

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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
}
}
}
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()
}
}
}
}