feat: enhance tariff processing with error handling and category filtering
This commit is contained in:
@@ -3,9 +3,13 @@ package products
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/pkg/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
pb "sipro-mps/api/generated/v1/yandexmarket/products"
|
||||
@@ -15,6 +19,7 @@ import (
|
||||
|
||||
"git.denco.store/fakz9/yandex-go-client"
|
||||
"github.com/samber/lo"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -246,46 +251,90 @@ func (r *apiRepository) CalculateProductTariffs(ctx context.Context, marketplace
|
||||
func (r *apiRepository) setTariffsRateLimit() {
|
||||
ym.SetPathLimit("/tariffs/calculate", rateLimitWindow, tariffsRateLimit)
|
||||
}
|
||||
func getCategoriesError(bodyData string) []int64 {
|
||||
var result []int64
|
||||
for _, v := range gjson.Get(bodyData, "errors.#.message").Array() {
|
||||
errorMessage := v.String()
|
||||
split := strings.Split(errorMessage, "categories: ")
|
||||
if len(split) < 2 {
|
||||
continue
|
||||
}
|
||||
categories := strings.Split(strings.TrimSpace(split[1]), ",")
|
||||
for _, category := range categories {
|
||||
category = strings.TrimSpace(category)
|
||||
if category == "" {
|
||||
continue
|
||||
}
|
||||
isDigit, categoryId := utils.IsDigit(category)
|
||||
if !isDigit || categoryId == nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, *categoryId)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// processTariffChunk processes a single chunk of offers for tariff calculation
|
||||
func (r *apiRepository) processTariffChunk(ctx context.Context, client *ymclient.APIClient, ymParameters *ymclient.CalculateTariffsParametersDTO, offerChunk []*pb.CalculateProductTariffsRequest_Offer, chunkIndex int) (*pb.CalculateProductTariffsResponse, error) {
|
||||
func filterOffersByCategories(offers []*pb.CalculateProductTariffsRequest_Offer, categories []int64) []*pb.CalculateProductTariffsRequest_Offer {
|
||||
return lo.Filter(offers, func(offer *pb.CalculateProductTariffsRequest_Offer, _ int) bool {
|
||||
return lo.Contains(categories, offer.CategoryId)
|
||||
})
|
||||
}
|
||||
|
||||
func (r *apiRepository) makeTariffRequest(context context.Context, client *ymclient.APIClient, ymParameters *ymclient.CalculateTariffsParametersDTO, offerChunk []*pb.CalculateProductTariffsRequest_Offer) (*ymclient.CalculateTariffsResponse, *http.Response, error) {
|
||||
ymOffers := r.convertOffersToYM(offerChunk)
|
||||
if len(ymOffers) == 0 {
|
||||
fmt.Printf("Skipping chunk %d: no valid offers\n", chunkIndex+1)
|
||||
return nil, nil
|
||||
return nil, nil, fmt.Errorf("no valid offers in chunk")
|
||||
}
|
||||
|
||||
if ymParameters.CampaignId != nil && *ymParameters.CampaignId > 0 {
|
||||
ymParameters.SellingProgram = nil
|
||||
ymParameters.Frequency = nil
|
||||
ymParameters.Currency = nil
|
||||
|
||||
} else {
|
||||
ymParameters.CampaignId = nil
|
||||
}
|
||||
|
||||
ymRequest := ymclient.NewCalculateTariffsRequest(*ymParameters, ymOffers)
|
||||
response, httpResp, err := client.TariffsAPI.CalculateTariffs(ctx).
|
||||
response, httpResp, err := client.TariffsAPI.CalculateTariffs(context).
|
||||
CalculateTariffsRequest(*ymRequest).
|
||||
Execute()
|
||||
return response, httpResp, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if httpResp != nil && httpResp.Body != nil {
|
||||
bodyData := make([]byte, 2048)
|
||||
_, httpErr := httpResp.Body.Read(bodyData)
|
||||
if httpErr == nil {
|
||||
fmt.Printf("Error response for chunk %d: %s\n", chunkIndex+1, string(bodyData))
|
||||
// processTariffChunk processes a single chunk of offers for tariff calculation
|
||||
func (r *apiRepository) processTariffChunk(ctx context.Context, client *ymclient.APIClient, ymParameters *ymclient.CalculateTariffsParametersDTO, offerChunk []*pb.CalculateProductTariffsRequest_Offer, chunkIndex int) (*pb.CalculateProductTariffsResponse, error) {
|
||||
globalError := fmt.Errorf("failed to process chunk %d", chunkIndex+1)
|
||||
for range 2 {
|
||||
response, httpResp, err := r.makeTariffRequest(ctx, client, ymParameters, offerChunk)
|
||||
|
||||
if err != nil {
|
||||
globalError = err
|
||||
if httpResp == nil || httpResp.Body == nil {
|
||||
return nil, fmt.Errorf("failed to call Yandex Market API for chunk %d: %w", chunkIndex+1, err)
|
||||
}
|
||||
bodyData, httpErr := io.ReadAll(httpResp.Body)
|
||||
if httpErr != nil {
|
||||
return nil, fmt.Errorf("failed to read response body for chunk %d: %w", chunkIndex+1, httpErr)
|
||||
}
|
||||
fmt.Printf("Error response for chunk %d: %s\n", chunkIndex+1, string(bodyData))
|
||||
categoriesErrors := getCategoriesError(string(bodyData))
|
||||
if len(categoriesErrors) == 0 {
|
||||
return nil, fmt.Errorf("failed to call Yandex Market API for chunk %d: %w", chunkIndex+1, err)
|
||||
}
|
||||
|
||||
offerChunk = filterOffersByCategories(offerChunk, categoriesErrors)
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("failed to call Yandex Market API for chunk %d: %w", chunkIndex+1, err)
|
||||
|
||||
if response == nil || response.Result == nil {
|
||||
|
||||
return nil, fmt.Errorf("Warning: received empty response for chunk %d\n", chunkIndex+1)
|
||||
}
|
||||
|
||||
return r.convertResponseToProto(response), nil
|
||||
}
|
||||
|
||||
if response == nil || response.Result == nil {
|
||||
fmt.Printf("Warning: received empty response for chunk %d\n", chunkIndex+1)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return r.convertResponseToProto(response), nil
|
||||
return nil, globalError
|
||||
}
|
||||
|
||||
// convertOffersToYM converts protobuf offers to Yandex Market format
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
@@ -123,3 +124,10 @@ func HashArray[T Hashable](arr []T) (string, error) {
|
||||
|
||||
return fmt.Sprintf("%x", h.Sum64()), nil
|
||||
}
|
||||
|
||||
func IsDigit(v string) (bool, *int64) {
|
||||
if val, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
return true, &val
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user