This commit is contained in:
@@ -81,7 +81,7 @@ func main() {
|
|||||||
|
|
||||||
boot.Bootstrap(ctx)
|
boot.Bootstrap(ctx)
|
||||||
|
|
||||||
log.Println("gRPC server started via rk-boot on port 9091")
|
log.Println("gRPC server started via rk-boot")
|
||||||
|
|
||||||
boot.WaitForShutdownSig(ctx)
|
boot.WaitForShutdownSig(ctx)
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,5 @@ security:
|
|||||||
jwt_secret: ${JWT_SECRET:xM8KhJVkk28cIJeBo0306O2e6Ifni6tNVlcCMxDFAEc=}
|
jwt_secret: ${JWT_SECRET:xM8KhJVkk28cIJeBo0306O2e6Ifni6tNVlcCMxDFAEc=}
|
||||||
crypto_secret: ${CRYPTO_SECRET:xM8KhJVkk28cIJeBo0306O2e6Ifni6tNVlcCMxDFAEc=}
|
crypto_secret: ${CRYPTO_SECRET:xM8KhJVkk28cIJeBo0306O2e6Ifni6tNVlcCMxDFAEc=}
|
||||||
|
|
||||||
grpc:
|
|
||||||
port: ${GRPC_PORT:9091}
|
|
||||||
max_connections: ${GRPC_MAX_CONNS:100}
|
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level: ${LOG_LEVEL:info}
|
level: ${LOG_LEVEL:info}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ type Config struct {
|
|||||||
Database DatabaseConfig `yaml:"database"`
|
Database DatabaseConfig `yaml:"database"`
|
||||||
AI AIConfig `yaml:"ai"`
|
AI AIConfig `yaml:"ai"`
|
||||||
Security SecurityConfig `yaml:"security"`
|
Security SecurityConfig `yaml:"security"`
|
||||||
GRPC GRPCConfig `yaml:"grpc"`
|
|
||||||
Logging LoggingConfig `yaml:"logging"`
|
Logging LoggingConfig `yaml:"logging"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,11 +36,6 @@ type SecurityConfig struct {
|
|||||||
CryptoSecret string `yaml:"crypto_secret"`
|
CryptoSecret string `yaml:"crypto_secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GRPCConfig struct {
|
|
||||||
Port int `yaml:"port"`
|
|
||||||
MaxConnections int `yaml:"max_connections"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoggingConfig struct {
|
type LoggingConfig struct {
|
||||||
Level string `yaml:"level"`
|
Level string `yaml:"level"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (h *RequestHandler) GetMailingListByID(ctx context.Context, req *pb.GetMail
|
|||||||
return nil, errors.ToGRPCError(err, h.logger, "RequestService.GetMailingListByID")
|
return nil, errors.ToGRPCError(err, h.logger, "RequestService.GetMailingListByID")
|
||||||
}
|
}
|
||||||
|
|
||||||
detail, err := h.requestService.GetMailingListByID(ctx, requestID)
|
detail, err := h.requestService.GetMailingListByID(ctx, requestID, int(req.UserId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ToGRPCError(err, h.logger, "RequestService.GetMailingListByID")
|
return nil, errors.ToGRPCError(err, h.logger, "RequestService.GetMailingListByID")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func NewHandlers(pool *pgxpool.Pool, jwtSecret, cryptoSecret, openAIKey, perplex
|
|||||||
userService := service.NewUserService(userRepo, requestRepo, cryptoSecret)
|
userService := service.NewUserService(userRepo, requestRepo, cryptoSecret)
|
||||||
inviteService := service.NewInviteService(inviteRepo, userRepo, txManager)
|
inviteService := service.NewInviteService(inviteRepo, userRepo, txManager)
|
||||||
requestService := service.NewRequestService(requestRepo, supplierRepo, tokenUsageRepo, userRepo, openAIClient, perplexityClient, txManager)
|
requestService := service.NewRequestService(requestRepo, supplierRepo, tokenUsageRepo, userRepo, openAIClient, perplexityClient, txManager)
|
||||||
supplierService := service.NewSupplierService(supplierRepo)
|
supplierService := service.NewSupplierService(supplierRepo, requestRepo)
|
||||||
|
|
||||||
return &AuthHandler{authService: authService, logger: logger},
|
return &AuthHandler{authService: authService, logger: logger},
|
||||||
&UserHandler{userService: userService, logger: logger},
|
&UserHandler{userService: userService, logger: logger},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func (h *SupplierHandler) ExportExcel(ctx context.Context, req *pb.ExportExcelRe
|
|||||||
return nil, errors.ToGRPCError(err, h.logger, "SupplierService.ExportExcel")
|
return nil, errors.ToGRPCError(err, h.logger, "SupplierService.ExportExcel")
|
||||||
}
|
}
|
||||||
|
|
||||||
fileData, err := h.supplierService.ExportExcel(ctx, requestID)
|
fileData, err := h.supplierService.ExportExcel(ctx, requestID, int(req.UserId))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ToGRPCError(err, h.logger, "SupplierService.ExportExcel")
|
return nil, errors.ToGRPCError(err, h.logger, "SupplierService.ExportExcel")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ type RequestRepository interface {
|
|||||||
GetByID(ctx context.Context, id uuid.UUID) (*model.Request, error)
|
GetByID(ctx context.Context, id uuid.UUID) (*model.Request, error)
|
||||||
GetDetailByID(ctx context.Context, id uuid.UUID) (*model.RequestDetail, error)
|
GetDetailByID(ctx context.Context, id uuid.UUID) (*model.RequestDetail, error)
|
||||||
GetUserStatistics(ctx context.Context, userID int) (requestsCount, suppliersCount, createdTZ int, err error)
|
GetUserStatistics(ctx context.Context, userID int) (requestsCount, suppliersCount, createdTZ int, err error)
|
||||||
|
CheckOwnership(ctx context.Context, requestID uuid.UUID, userID int) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupplierRepository interface {
|
type SupplierRepository interface {
|
||||||
|
|||||||
@@ -214,3 +214,24 @@ func (r *requestRepository) GetUserStatistics(ctx context.Context, userID int) (
|
|||||||
|
|
||||||
return requestsCount, suppliersCount, createdTZ, nil
|
return requestsCount, suppliersCount, createdTZ, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *requestRepository) CheckOwnership(ctx context.Context, requestID uuid.UUID, userID int) (bool, error) {
|
||||||
|
query := r.qb.Select("1").From("requests_for_suppliers").
|
||||||
|
Where(sq.Eq{"id": requestID, "user_id": userID})
|
||||||
|
|
||||||
|
sqlQuery, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return false, errs.NewInternalError(errs.DatabaseError, "failed to build query", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var exists int
|
||||||
|
err = r.pool.QueryRow(ctx, sqlQuery, args...).Scan(&exists)
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, errs.NewInternalError(errs.DatabaseError, "failed to check ownership", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ type RequestService interface {
|
|||||||
CreateTZ(ctx context.Context, userID int, requestTxt string) (uuid.UUID, string, error)
|
CreateTZ(ctx context.Context, userID int, requestTxt string) (uuid.UUID, string, error)
|
||||||
ApproveTZ(ctx context.Context, requestID uuid.UUID, tzText string, userID int) ([]*model.Supplier, error)
|
ApproveTZ(ctx context.Context, requestID uuid.UUID, tzText string, userID int) ([]*model.Supplier, error)
|
||||||
GetMailingList(ctx context.Context, userID int) ([]*model.Request, error)
|
GetMailingList(ctx context.Context, userID int) ([]*model.Request, error)
|
||||||
GetMailingListByID(ctx context.Context, requestID uuid.UUID) (*model.RequestDetail, error)
|
GetMailingListByID(ctx context.Context, requestID uuid.UUID, userID int) (*model.RequestDetail, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SupplierService interface {
|
type SupplierService interface {
|
||||||
ExportExcel(ctx context.Context, requestID uuid.UUID) ([]byte, error)
|
ExportExcel(ctx context.Context, requestID uuid.UUID, userID int) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,13 +107,20 @@ func (s *requestService) CreateTZ(ctx context.Context, userID int, requestTxt st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *requestService) ApproveTZ(ctx context.Context, requestID uuid.UUID, tzText string, userID int) ([]*model.Supplier, error) {
|
func (s *requestService) ApproveTZ(ctx context.Context, requestID uuid.UUID, tzText string, userID int) ([]*model.Supplier, error) {
|
||||||
if err := s.requestRepo.UpdateFinalTZ(ctx, requestID, tzText); err != nil {
|
isOwner, err := s.requestRepo.CheckOwnership(ctx, requestID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isOwner {
|
||||||
|
return nil, errors.NewBusinessError(errors.PermissionDenied, "access denied to this request")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.requestRepo.UpdateFinalTZ(ctx, requestID, tzText); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var suppliers []*model.Supplier
|
var suppliers []*model.Supplier
|
||||||
var promptTokens, responseTokens int
|
var promptTokens, responseTokens int
|
||||||
var err error
|
|
||||||
|
|
||||||
for attempt := 0; attempt < 3; attempt++ {
|
for attempt := 0; attempt < 3; attempt++ {
|
||||||
suppliers, promptTokens, responseTokens, err = s.perplexity.FindSuppliers(tzText)
|
suppliers, promptTokens, responseTokens, err = s.perplexity.FindSuppliers(tzText)
|
||||||
@@ -169,6 +176,14 @@ func (s *requestService) GetMailingList(ctx context.Context, userID int) ([]*mod
|
|||||||
return s.requestRepo.GetByUserID(ctx, userID)
|
return s.requestRepo.GetByUserID(ctx, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *requestService) GetMailingListByID(ctx context.Context, requestID uuid.UUID) (*model.RequestDetail, error) {
|
func (s *requestService) GetMailingListByID(ctx context.Context, requestID uuid.UUID, userID int) (*model.RequestDetail, error) {
|
||||||
|
isOwner, err := s.requestRepo.CheckOwnership(ctx, requestID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isOwner {
|
||||||
|
return nil, errors.NewBusinessError(errors.PermissionDenied, "access denied to this request")
|
||||||
|
}
|
||||||
|
|
||||||
return s.requestRepo.GetDetailByID(ctx, requestID)
|
return s.requestRepo.GetDetailByID(ctx, requestID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,21 +5,32 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.techease.ru/Smart-search/smart-search-back/internal/repository"
|
"git.techease.ru/Smart-search/smart-search-back/internal/repository"
|
||||||
|
"git.techease.ru/Smart-search/smart-search-back/pkg/errors"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/xuri/excelize/v2"
|
"github.com/xuri/excelize/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type supplierService struct {
|
type supplierService struct {
|
||||||
supplierRepo repository.SupplierRepository
|
supplierRepo repository.SupplierRepository
|
||||||
|
requestRepo repository.RequestRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSupplierService(supplierRepo repository.SupplierRepository) SupplierService {
|
func NewSupplierService(supplierRepo repository.SupplierRepository, requestRepo repository.RequestRepository) SupplierService {
|
||||||
return &supplierService{
|
return &supplierService{
|
||||||
supplierRepo: supplierRepo,
|
supplierRepo: supplierRepo,
|
||||||
|
requestRepo: requestRepo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *supplierService) ExportExcel(ctx context.Context, requestID uuid.UUID) ([]byte, error) {
|
func (s *supplierService) ExportExcel(ctx context.Context, requestID uuid.UUID, userID int) ([]byte, error) {
|
||||||
|
isOwner, err := s.requestRepo.CheckOwnership(ctx, requestID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !isOwner {
|
||||||
|
return nil, errors.NewBusinessError(errors.PermissionDenied, "access denied to this request")
|
||||||
|
}
|
||||||
|
|
||||||
suppliers, err := s.supplierRepo.GetByRequestID(ctx, requestID)
|
suppliers, err := s.supplierRepo.GetByRequestID(ctx, requestID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const (
|
|||||||
InsufficientBalance = "INSUFFICIENT_BALANCE"
|
InsufficientBalance = "INSUFFICIENT_BALANCE"
|
||||||
UserNotFound = "USER_NOT_FOUND"
|
UserNotFound = "USER_NOT_FOUND"
|
||||||
RequestNotFound = "REQUEST_NOT_FOUND"
|
RequestNotFound = "REQUEST_NOT_FOUND"
|
||||||
|
PermissionDenied = "PERMISSION_DENIED"
|
||||||
|
|
||||||
DatabaseError = "DATABASE_ERROR"
|
DatabaseError = "DATABASE_ERROR"
|
||||||
EncryptionError = "ENCRYPTION_ERROR"
|
EncryptionError = "ENCRYPTION_ERROR"
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ func ToGRPCError(err error, zapLogger *zap.Logger, method string) error {
|
|||||||
switch appErr.Code {
|
switch appErr.Code {
|
||||||
case AuthInvalidCredentials, AuthMissing, AuthInvalidToken, RefreshInvalid:
|
case AuthInvalidCredentials, AuthMissing, AuthInvalidToken, RefreshInvalid:
|
||||||
return status.Error(codes.Unauthenticated, appErr.Message)
|
return status.Error(codes.Unauthenticated, appErr.Message)
|
||||||
|
case PermissionDenied:
|
||||||
|
return status.Error(codes.PermissionDenied, appErr.Message)
|
||||||
case InviteLimitReached:
|
case InviteLimitReached:
|
||||||
return status.Error(codes.ResourceExhausted, appErr.Message)
|
return status.Error(codes.ResourceExhausted, appErr.Message)
|
||||||
case InsufficientBalance, InviteInvalidOrExpired:
|
case InsufficientBalance, InviteInvalidOrExpired:
|
||||||
|
|||||||
@@ -283,3 +283,140 @@ func (s *IntegrationSuite) TestEdgeCase_LoginWithWrongPassword() {
|
|||||||
s.True(ok)
|
s.True(ok)
|
||||||
s.Equal(codes.Unauthenticated, st.Code())
|
s.Equal(codes.Unauthenticated, st.Code())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestEdgeCase_ApproveTZTwice() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Тест двойного approve",
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||||
|
s.NoError(err)
|
||||||
|
requestID := createResp.RequestId
|
||||||
|
|
||||||
|
approveReq1 := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Первое утверждение",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveResp1, err := s.requestClient.ApproveTZ(ctx, approveReq1)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(approveResp1.Success)
|
||||||
|
|
||||||
|
approveReq2 := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Второе утверждение",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveResp2, err := s.requestClient.ApproveTZ(ctx, approveReq2)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(approveResp2.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestEdgeCase_CreateTZWithVeryLongText() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
_, err = s.pool.Exec(ctx, "UPDATE users SET balance = 10000 WHERE id = $1", validateResp.UserId)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
longText := "Нужны поставщики. "
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
longText += "Дополнительные требования к качеству и срокам поставки материалов. "
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &requestpb.CreateTZRequest{
|
||||||
|
UserId: validateResp.UserId,
|
||||||
|
RequestTxt: longText,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.requestClient.CreateTZ(ctx, req)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(resp)
|
||||||
|
s.NotEmpty(resp.RequestId)
|
||||||
|
s.NotEmpty(resp.TzText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestEdgeCase_ApproveTZWithVeryLongFinalTZ() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Тест длинного ТЗ",
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||||
|
s.NoError(err)
|
||||||
|
requestID := createResp.RequestId
|
||||||
|
|
||||||
|
longFinalTZ := "ТЕХНИЧЕСКОЕ ЗАДАНИЕ\n\n"
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
longFinalTZ += "Пункт требований с детальным описанием спецификации и условий поставки. "
|
||||||
|
}
|
||||||
|
|
||||||
|
approveReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: longFinalTZ,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveResp, err := s.requestClient.ApproveTZ(ctx, approveReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(approveResp.Success)
|
||||||
|
}
|
||||||
|
|||||||
@@ -184,6 +184,83 @@ func (s *IntegrationSuite) TestFullFlow_InviteCodeLifecycle() {
|
|||||||
s.True(logoutResp.Success)
|
s.True(logoutResp.Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestFullFlow_CreateTZ_ApproveTZ_GetMailingListByID_ExportExcel() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(loginResp.AccessToken)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(validateResp.Valid)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createTZReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Нужны поставщики офисной мебели: столы 20 шт, стулья 50 шт",
|
||||||
|
}
|
||||||
|
|
||||||
|
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createTZResp.RequestId)
|
||||||
|
s.NotEmpty(createTZResp.TzText)
|
||||||
|
requestID := createTZResp.RequestId
|
||||||
|
|
||||||
|
approveTZReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: createTZResp.TzText,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveTZResp, err := s.requestClient.ApproveTZ(ctx, approveTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(approveTZResp.Success)
|
||||||
|
|
||||||
|
getMailingListByIDReq := &requestpb.GetMailingListByIDRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
mailingListByIDResp, err := s.requestClient.GetMailingListByID(ctx, getMailingListByIDReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(mailingListByIDResp.Item)
|
||||||
|
s.Equal(requestID, mailingListByIDResp.Item.RequestId)
|
||||||
|
s.Greater(mailingListByIDResp.Item.SuppliersFound, int32(0))
|
||||||
|
|
||||||
|
exportExcelReq := &supplierpb.ExportExcelRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
exportExcelResp, err := s.supplierClient.ExportExcel(ctx, exportExcelReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(exportExcelResp)
|
||||||
|
s.NotEmpty(exportExcelResp.FileName)
|
||||||
|
s.NotEmpty(exportExcelResp.FileData)
|
||||||
|
s.Equal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", exportExcelResp.MimeType)
|
||||||
|
s.Greater(len(exportExcelResp.FileData), 0)
|
||||||
|
|
||||||
|
logoutReq := &authpb.LogoutRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
logoutResp, err := s.authClient.Logout(ctx, logoutReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(logoutResp.Success)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *IntegrationSuite) TestFullFlow_MultipleRefresh() {
|
func (s *IntegrationSuite) TestFullFlow_MultipleRefresh() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|||||||
@@ -233,3 +233,45 @@ func (s *IntegrationSuite) TearDownTest() {
|
|||||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM suppliers")
|
_, _ = s.pool.Exec(s.ctx, "DELETE FROM suppliers")
|
||||||
_, _ = s.pool.Exec(s.ctx, "DELETE FROM requests_for_suppliers")
|
_, _ = s.pool.Exec(s.ctx, "DELETE FROM requests_for_suppliers")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) createSecondTestUser() (email string, password string, userID int64) {
|
||||||
|
email = "second_user@example.com"
|
||||||
|
password = "secondpassword"
|
||||||
|
|
||||||
|
cryptoHelper := crypto.NewCrypto(testCryptoSecret)
|
||||||
|
|
||||||
|
encryptedEmail, err := cryptoHelper.Encrypt(email)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
encryptedPhone, err := cryptoHelper.Encrypt("+9876543210")
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
encryptedUserName, err := cryptoHelper.Encrypt("Second User")
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
emailHash := cryptoHelper.EmailHash(email)
|
||||||
|
passwordHash := crypto.PasswordHash(password)
|
||||||
|
|
||||||
|
query := `
|
||||||
|
INSERT INTO users (email, email_hash, password_hash, phone, user_name, company_name, balance, payment_status, invites_issued, invites_limit)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||||
|
ON CONFLICT (email_hash) DO UPDATE SET balance = $7
|
||||||
|
RETURNING id
|
||||||
|
`
|
||||||
|
|
||||||
|
err = s.pool.QueryRow(s.ctx, query,
|
||||||
|
encryptedEmail,
|
||||||
|
emailHash,
|
||||||
|
passwordHash,
|
||||||
|
encryptedPhone,
|
||||||
|
encryptedUserName,
|
||||||
|
"Second Company",
|
||||||
|
1000.0,
|
||||||
|
"active",
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
).Scan(&userID)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
return email, password, userID
|
||||||
|
}
|
||||||
|
|||||||
214
tests/ownership_test.go
Normal file
214
tests/ownership_test.go
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
authpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/auth"
|
||||||
|
requestpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/request"
|
||||||
|
supplierpb "git.techease.ru/Smart-search/smart-search-back/pkg/pb/supplier"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestOwnership_GetMailingListByID_AnotherUsersRequest() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
user1ID := validateResp.UserId
|
||||||
|
|
||||||
|
createTZReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: user1ID,
|
||||||
|
RequestTxt: "Нужны поставщики для теста ownership",
|
||||||
|
}
|
||||||
|
|
||||||
|
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createTZResp.RequestId)
|
||||||
|
requestID := createTZResp.RequestId
|
||||||
|
|
||||||
|
_, _, user2ID := s.createSecondTestUser()
|
||||||
|
|
||||||
|
getMailingByIDReq := &requestpb.GetMailingListByIDRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: user2ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.requestClient.GetMailingListByID(ctx, getMailingByIDReq)
|
||||||
|
s.Error(err)
|
||||||
|
s.Nil(resp)
|
||||||
|
|
||||||
|
st, ok := status.FromError(err)
|
||||||
|
s.True(ok)
|
||||||
|
s.Equal(codes.PermissionDenied, st.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestOwnership_ApproveTZ_AnotherUsersRequest() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
user1ID := validateResp.UserId
|
||||||
|
|
||||||
|
createTZReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: user1ID,
|
||||||
|
RequestTxt: "Нужны поставщики для теста ownership approve",
|
||||||
|
}
|
||||||
|
|
||||||
|
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createTZResp.RequestId)
|
||||||
|
requestID := createTZResp.RequestId
|
||||||
|
|
||||||
|
_, _, user2ID := s.createSecondTestUser()
|
||||||
|
|
||||||
|
approveTZReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Утвержденное ТЗ от чужого пользователя",
|
||||||
|
UserId: user2ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.requestClient.ApproveTZ(ctx, approveTZReq)
|
||||||
|
s.Error(err)
|
||||||
|
s.Nil(resp)
|
||||||
|
|
||||||
|
st, ok := status.FromError(err)
|
||||||
|
s.True(ok)
|
||||||
|
s.Equal(codes.PermissionDenied, st.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestOwnership_ExportExcel_AnotherUsersRequest() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
user1ID := validateResp.UserId
|
||||||
|
|
||||||
|
createTZReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: user1ID,
|
||||||
|
RequestTxt: "Нужны поставщики для теста ownership export",
|
||||||
|
}
|
||||||
|
|
||||||
|
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createTZResp.RequestId)
|
||||||
|
requestID := createTZResp.RequestId
|
||||||
|
|
||||||
|
approveTZReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Утвержденное ТЗ для экспорта",
|
||||||
|
UserId: user1ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.requestClient.ApproveTZ(ctx, approveTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
_, _, user2ID := s.createSecondTestUser()
|
||||||
|
|
||||||
|
exportReq := &supplierpb.ExportExcelRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: user2ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.supplierClient.ExportExcel(ctx, exportReq)
|
||||||
|
s.Error(err)
|
||||||
|
s.Nil(resp)
|
||||||
|
|
||||||
|
st, ok := status.FromError(err)
|
||||||
|
s.True(ok)
|
||||||
|
s.Equal(codes.PermissionDenied, st.Code())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestOwnership_GetMailingListByID_OwnRequest_Success() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createTZReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Нужны поставщики для теста ownership success",
|
||||||
|
}
|
||||||
|
|
||||||
|
createTZResp, err := s.requestClient.CreateTZ(ctx, createTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createTZResp.RequestId)
|
||||||
|
requestID := createTZResp.RequestId
|
||||||
|
|
||||||
|
approveTZReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Утвержденное ТЗ",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.requestClient.ApproveTZ(ctx, approveTZReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
getMailingByIDReq := &requestpb.GetMailingListByIDRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.requestClient.GetMailingListByID(ctx, getMailingByIDReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(resp)
|
||||||
|
s.NotNil(resp.Item)
|
||||||
|
s.Equal(requestID, resp.Item.RequestId)
|
||||||
|
}
|
||||||
@@ -136,3 +136,133 @@ func (s *IntegrationSuite) TestRequestHandler_GetMailingListWithValidUser() {
|
|||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.NotNil(resp)
|
s.NotNil(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestRequestHandler_CreateTZWithFile() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
req := &requestpb.CreateTZRequest{
|
||||||
|
UserId: validateResp.UserId,
|
||||||
|
RequestTxt: "Нужны поставщики металлоконструкций",
|
||||||
|
FileData: []byte("Содержимое файла с дополнительными требованиями"),
|
||||||
|
FileName: "requirements.txt",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.requestClient.CreateTZ(ctx, req)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(resp)
|
||||||
|
s.NotEmpty(resp.RequestId)
|
||||||
|
s.NotEmpty(resp.TzText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestRequestHandler_ApproveTZSuccess() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Нужны поставщики кирпича для строительства",
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createResp.RequestId)
|
||||||
|
|
||||||
|
approveReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: createResp.RequestId,
|
||||||
|
FinalTz: "Утвержденное техническое задание на поставку кирпича",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveResp, err := s.requestClient.ApproveTZ(ctx, approveReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(approveResp)
|
||||||
|
s.True(approveResp.Success)
|
||||||
|
s.Equal("sent", approveResp.MailingStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestRequestHandler_GetMailingListByIDSuccess() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Нужны поставщики бетона",
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createResp.RequestId)
|
||||||
|
requestID := createResp.RequestId
|
||||||
|
|
||||||
|
approveReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Утвержденное ТЗ на поставку бетона",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.requestClient.ApproveTZ(ctx, approveReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
getByIDReq := &requestpb.GetMailingListByIDRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
getByIDResp, err := s.requestClient.GetMailingListByID(ctx, getByIDReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(getByIDResp)
|
||||||
|
s.NotNil(getByIDResp.Item)
|
||||||
|
s.Equal(requestID, getByIDResp.Item.RequestId)
|
||||||
|
s.Greater(getByIDResp.Item.SuppliersFound, int32(0))
|
||||||
|
}
|
||||||
|
|||||||
@@ -93,3 +93,58 @@ func (s *IntegrationSuite) TestSupplierHandler_ExportExcelWithValidRequest() {
|
|||||||
s.NotEmpty(exportResp.FileName)
|
s.NotEmpty(exportResp.FileName)
|
||||||
s.Equal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", exportResp.MimeType)
|
s.Equal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", exportResp.MimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *IntegrationSuite) TestSupplierHandler_ExportExcelWithSuppliers() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
loginReq := &authpb.LoginRequest{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "testpassword",
|
||||||
|
Ip: "127.0.0.1",
|
||||||
|
UserAgent: "integration-test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginResp, err := s.authClient.Login(ctx, loginReq)
|
||||||
|
s.NoError(err)
|
||||||
|
|
||||||
|
validateReq := &authpb.ValidateRequest{
|
||||||
|
AccessToken: loginResp.AccessToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
validateResp, err := s.authClient.Validate(ctx, validateReq)
|
||||||
|
s.NoError(err)
|
||||||
|
userID := validateResp.UserId
|
||||||
|
|
||||||
|
createReq := &requestpb.CreateTZRequest{
|
||||||
|
UserId: userID,
|
||||||
|
RequestTxt: "Нужны поставщики офисной мебели для большого офиса",
|
||||||
|
}
|
||||||
|
|
||||||
|
createResp, err := s.requestClient.CreateTZ(ctx, createReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotEmpty(createResp.RequestId)
|
||||||
|
requestID := createResp.RequestId
|
||||||
|
|
||||||
|
approveReq := &requestpb.ApproveTZRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
FinalTz: "Техническое задание на поставку офисной мебели",
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
approveResp, err := s.requestClient.ApproveTZ(ctx, approveReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.True(approveResp.Success)
|
||||||
|
|
||||||
|
exportReq := &supplierpb.ExportExcelRequest{
|
||||||
|
RequestId: requestID,
|
||||||
|
UserId: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
exportResp, err := s.supplierClient.ExportExcel(ctx, exportReq)
|
||||||
|
s.NoError(err)
|
||||||
|
s.NotNil(exportResp)
|
||||||
|
s.NotEmpty(exportResp.FileName)
|
||||||
|
s.NotEmpty(exportResp.FileData)
|
||||||
|
s.Equal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", exportResp.MimeType)
|
||||||
|
s.Greater(len(exportResp.FileData), 1000)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user