Refactor credential handling and improve parsing logic

Deleted client/credential.go and moved the Credentials struct to the api package for better modularity. Enhanced type safety in api by checking type assertions and added detailed comments in model structs.
This commit is contained in:
Павел Синицин 2024-09-08 13:50:05 +03:00
parent 99c8dbd911
commit cea1f96bb4
Signed by: spavelit
GPG Key ID: 2FEC8CEAE5A95DD1
7 changed files with 179 additions and 170 deletions

View File

@ -5,21 +5,26 @@ import (
"gitea.24example.ru/spavelit/bpiek/model" "gitea.24example.ru/spavelit/bpiek/model"
) )
type Api struct { type (
Api struct {
Client *client.Client Client *client.Client
} }
Credentials struct {
type Method interface { Username string
GetParentCategories() ([]model.Category, error) Password string
GetCategories() ([]model.Category, error)
GetTreeCategories() ([]model.TreeCategories, error)
GetProducts() ([]model.Product, error)
GetProductByArticle(article string) (model.Product, error)
GetRemainsAndPlanresidues() ([]model.ShortProduct, error)
} }
func NewApi(credentials client.Credentials) Method { Method interface {
GetParentCategories() ([]model.Category, error) // Возвращает массив категорий каталога 1-ого уровня.
GetCategories() ([]model.Category, error) // Возвращает массив с категориями
GetTreeCategories() ([]model.TreeCategories, error) // Возвращает дерево категорий
GetProducts() ([]model.Product, error) // Возвращает массив с продукцией
GetProductByArticle(article string) (model.Product, error) // Возвращает товар по артикул
GetRemainsAndPlanresidues() ([]model.ShortProduct, error) // Возвращает массив, в котором содержатся актуальные цены и остатки товаров.
}
)
func NewApi(credentials Credentials) Method {
return &Api{ return &Api{
Client: client.NewClient(credentials), Client: client.NewClient(credentials),
} }

View File

@ -49,7 +49,12 @@ func (a *Api) GetProductByArticle(article string) (model.Product, error) {
"error getting product by article: " + article) "error getting product by article: " + article)
} }
return apiResponse.Result().(model.Product), nil product, ok := apiResponse.Result().(*model.Product)
if !ok {
return model.Product{}, errors.New("failed to parse product from response")
}
return *product, nil
} }
func (a *Api) GetRemainsAndPlanresidues() ([]model.ShortProduct, error) { func (a *Api) GetRemainsAndPlanresidues() ([]model.ShortProduct, error) {
@ -77,7 +82,7 @@ func (a *Api) GetRemainsAndPlanresidues() ([]model.ShortProduct, error) {
return nil, errors.New("file remains and planresidues not found") return nil, errors.New("file remains and planresidues not found")
} }
result := apiResponse.Result().(model.RemainsAndPlanresiduesResponse) result := apiResponse.Result().(*model.RemainsAndPlanresiduesResponse)
if len(result.Products) != 0 { if len(result.Products) != 0 {
remainsAndPlanresidues = append(remainsAndPlanresidues, result.Products...) remainsAndPlanresidues = append(remainsAndPlanresidues, result.Products...)

View File

@ -1,15 +1,13 @@
package client package client
import "github.com/go-resty/resty/v2" import (
"gitea.24example.ru/spavelit/bpiek/api"
// import ( "github.com/go-resty/resty/v2"
// "net/http" )
// "net/url"
// )
const ( const (
AUTH_API_URL = "https://bp.iek.ru/oauth/login" AuthApiUrl = "https://bp.iek.ru/oauth/login"
BASE_API_URL = "https://bp.iek.ru/api/catalog/v1/" BaseApiUrl = "https://bp.iek.ru/api/catalog/v1/"
) )
type ( type (
@ -27,18 +25,18 @@ type (
} }
) )
func NewClient(credentials Credentials) *Client { func NewClient(credentials api.Credentials) *Client {
authSuccess := &AuthSuccess{} authSuccess := &AuthSuccess{}
client := resty.New() client := resty.New()
client.SetBaseURL(BASE_API_URL) client.SetBaseURL(BaseApiUrl)
response, err := client.R(). response, err := client.R().
SetFormData(map[string]string{ SetFormData(map[string]string{
"username": credentials.GetUsername(), "username": credentials.Username,
"password": credentials.GetPassword(), "password": credentials.Password,
}). }).
SetResult(&authSuccess). SetResult(&authSuccess).
Post(AUTH_API_URL) Post(AuthApiUrl)
if err != nil { if err != nil {
panic(err) panic(err)
@ -49,7 +47,7 @@ func NewClient(credentials Credentials) *Client {
} }
client.SetHeader("Content-Type", "application/json") client.SetHeader("Content-Type", "application/json")
client.SetHeader("Authorization", "Bearer "+authSuccess.AccessToken) client.SetHeader("Authorization", authSuccess.TokenType+" "+authSuccess.AccessToken)
return &Client{ return &Client{
HTTPClient: client, HTTPClient: client,

View File

@ -1,17 +0,0 @@
package client
type (
// Credentials provides constant credential values.
Credentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
)
func (c *Credentials) GetUsername() string {
return c.Username
}
func (c *Credentials) GetPassword() string {
return c.Password
}

View File

@ -1,15 +1,15 @@
package model package model
type Category struct { type Category struct {
Slug string `json:"slug"` Slug string `json:"slug"` // Слаг категории
Name string `json:"name"` Name string `json:"name"` // Название категории
Url string `json:"url"` Url string `json:"url"` // Ссылка на скачивание файла с содержимым категории
ApiUrl string `json:"apiUrl"` ApiUrl string `json:"apiUrl"` // Относительный адрес категории
} }
type TreeCategories struct { type TreeCategories struct {
Slug string `json:"slug"` Slug string `json:"slug"` // Слаг категории
Name string `json:"name"` Name string `json:"name"` // Название категории
Url string `json:"url"` Url string `json:"url"` // Относительный адрес категории
Children []TreeCategories `json:"children"` Children []TreeCategories `json:"children"` // Children nested categories in TreeCategories
} }

View File

@ -2,150 +2,168 @@ package model
type ( type (
ImageVariant struct { ImageVariant struct {
Url string `json:"url"` Url string `json:"url"` // Ссылка
Ext string `json:"ext"` Ext string `json:"ext"` // Расширение
Width int `json:"width"` Width int `json:"width"` // Ширина
} }
Complects struct { Complects struct {
Article string `json:"article"` Article string `json:"article"` // Артикул
Name string `json:"name"` Name string `json:"name"` // Наименование
Quantity int `json:"quantity"` Quantity int `json:"quantity"` // Количество
} }
LeftPeriod struct { LeftPeriod struct {
Name string `json:"name"` Name string `json:"name"` // Название характеристики
Value string `json:"value"` Value string `json:"value"` // Значение характеристики
} }
LeftPeriodRaw struct { LeftPeriodRaw struct {
Lifespan interface{} `json:"lifespan"` Lifespan struct {
Warranty interface{} `json:"warranty"` Limit string `json:"limit"` // Предельное значение
Value string `json:"value"` // Значение
Units string `json:"units"` // Единицы измерения
} `json:"lifespan"` // Срок службы
Warranty struct {
Value string `json:"value"` // Значение
Units string `json:"units"` // Единицы измерения
} `json:"warranty"` // Гарантийный срок
} }
DesignFeatures struct { DesignFeatures struct {
ImageUrl string `json:"imageUrl"` ImageUrl string `json:"imageUrl"` // Ссылка на изображение
Description string `json:"description"` Description string `json:"description"` // Описание
} }
Video struct { Video struct {
Name string `json:"name"` Name string `json:"name"` // Наименование
Description string `json:"description"` Description string `json:"description"` // Описание
Url string `json:"url"` Url string `json:"url"` // Ссылка
Type string `json:"type"` Type string `json:"type"` // Тип (ссылка на видео-хостинг или прямая ссылка на скачивание); Enum: "url" "file"
} }
Software struct { Software struct {
Name string `json:"name"` Name string `json:"name"` // Наименование
Description string `json:"description"` Description string `json:"description"` // Описание
Url string `json:"url"` Url string `json:"url"` // Ссылка
Size int `json:"size"` Size int `json:"size"` // Размер
} }
Analog struct { Analog struct {
Article string `json:"article"` Article string `json:"article"` // Артикул товара
Name string `json:"name"` Name string `json:"name"` // Полное название товара
ShortName string `json:"shortName"` ShortName string `json:"shortName"` // Краткое название
Description string `json:"description"` Description string `json:"description"` // Описание
ImageUrl string `json:"imageUrl"` ImageUrl string `json:"imageUrl"` // Фото товара (основное)
ImageUrls []string `json:"imageUrls"` ImageUrls []string `json:"imageUrls"` // Все фото товара
ImageVariants []ImageVariant `json:"imageVariants"` ImageVariants []ImageVariant `json:"imageVariants"` // Вариации изображений
IsArchived bool `json:"isArchived"` IsArchived bool `json:"isArchived"` // Архивный или нет
Tm string `json:"tm"` Tm string `json:"tm"` // Торговая марка
} }
WarehouseData struct { WarehouseData struct {
WarehouseId string `json:"warehouseId"` WarehouseId string `json:"warehouseId"` // Идентификатор склада
WarehouseName string `json:"warehouseName"` WarehouseName string `json:"warehouseName"` // Наименование склада
AvailableAmount int `json:"availableAmount"` AvailableAmount int `json:"availableAmount"` // Доступное количество
Incoming []struct { Incoming []struct {
DateBegan string `json:"dateBegan"` DateBegan string `json:"dateBegan"` // Дата начала периода поступления на склад
DateEnd string `json:"dateEnd"` DateEnd string `json:"dateEnd"` // Дата окончания периода поступления на склад
Amount int `json:"amount"` Amount int `json:"amount"` // Ожидаемое количество
Type string `json:"type"` Type string `json:"type"` // Тип поступления, production - поступление после производства, shipping - доставка на склад
} } // Ближайшие поступления
} }
Etim struct { Etim struct {
Features []struct { Features []struct {
Id string `json:"id"` Id string `json:"id"` //
Name string `json:"name"` Name string `json:"name"` // Название свойства
Sort int `json:"sort"` Sort int `json:"sort"` // Порядок сортировки по умолчанию
Unit string `json:"unit"` Unit string `json:"unit"` // Единицы измерения
Value string `json:"value"` Value string `json:"value"` // Значение свойства
} `json:"features"` ValueUnion string `json:"value_union"` // Код значения
} `json:"features"` // Features represents a list of product features with detailed information.
Class struct { Class struct {
Id string `json:"id"` Id string `json:"id"` //
Name string `json:"name"` Name string `json:"name"` // Название класса
} `json:"class"` } `json:"class"` // ETIM-класс товара
} }
LogisticParams struct { LogisticParams struct {
Name string `json:"name"` Name string `json:"name"` // Название параметра
NameOrig string `json:"nameOrig"` NameOrig string `json:"nameOrig"` // Название характеристики (исходное)
Value struct { Value struct {
Group string `json:"group"` Group string `json:"group"` // Значение для группового варианта
Individual string `json:"individual"` Individual string `json:"individual"` // Значение для индивидуального варианта
Transport string `json:"transport"` Transport string `json:"transport"` // Значение для транспортного варианта
} `json:"value"` } `json:"value"` // Value represents group, individual, and transport logistics values in JSON format.
} }
LogisticParamsData struct { LogisticParamsData struct {
SinglePackage struct { SinglePackage struct {
Multiplicity int `json:"multiplicity"` Multiplicity int `json:"multiplicity"` // Кратность
Unit string `json:"unit"` Unit string `json:"unit"` // Единицы измерения
} `json:"singlePackage"` } `json:"singlePackage"` // Для индивидуальной упаковки
} }
ShortProduct struct { ShortProduct struct {
Article string `json:"article"` Article string `json:"article"` // Артикул товара
Name string `json:"name"` Name string `json:"name"` // Полное наименование товара
Multiplicity int `json:"multiplicity"` Multiplicity int `json:"multiplicity"` // Кратность продажи
PriceBase int `json:"priceBase"` PriceBase float64 `json:"priceBase"` // Базовая цена с НДС
PriceRrc int `json:"priceRrc"` PriceRrc float64 `json:"priceRrc"` // Рекомендованная розничная цена (РРЦ) с НДС
Available int `json:"available"` Available float64 `json:"available"` // Значение остатка
Units string `json:"units"` Units string `json:"units"` // Единицы измерения
WarehouseData []WarehouseData `json:"warehouseData"` WarehouseData []WarehouseData `json:"warehouseData"` // Информация по складам
} }
Product struct { Product struct {
ShortName string `json:"shortName"` Article string `json:"article"` // Артикул товара
Description string `json:"description"` Name string `json:"name"` // Полное наименование товара
CategoryName string `json:"categoryName"` ShortName string `json:"shortName"` // Краткое название
Category string `json:"category"` Description string `json:"description"` // Описание
Slug string `json:"slug"` CategoryName string `json:"categoryName"` // Название категории
Tm string `json:"tm"` Category string `json:"category"` // Относительный путь до категории в каталоге
Url string `json:"url"` Slug string `json:"slug"` // Слаг товара
IsArchived bool `json:"isArchived"` Tm string `json:"tm"` // Торговая марка
ImageUrl string `json:"imageUrl"` Url string `json:"url"` // Ссылка на товар
ImageUrls []string `json:"imageUrls"` IsArchived bool `json:"isArchived"` // Архивный или нет
ImageVariants []ImageVariant `json:"imageVariants"` ImageUrl string `json:"imageUrl"` // Фото товара (основное)
Advantages string `json:"advantages"` ImageUrls []string `json:"imageUrls"` // Все фото товара
Etim Etim `json:"etim"` ImageVariants []ImageVariant `json:"imageVariants"` // Вариации изображений
Complects []Complects `json:"complects"` ImageUrlsVariants []interface{} `json:"imageUrlsVariants"` // Все вариации изображений
Complectations string `json:"complectations"` Advantages string `json:"advantages"` // Преимущества
Files []interface{} `json:"files"` Etim Etim `json:"etim"` // ETIM характеристики товара
LeftPeriod []LeftPeriod `json:"leftPeriod"` Complects []Complects `json:"complects"` // Комплектация и сопутствующие товары
LeftPeriodRaw LeftPeriodRaw `json:"leftPeriodRaw"` Complectations string `json:"complectations"` // Комплектация
LogisticParams []LogisticParams `json:"logisticParams"` Files []interface{} `json:"files"` // Список файлов, относящихся к товару (ГЧ, КД, CAD-модели и т.д.)
LogisticParamsData LogisticParamsData `json:"logisticParamsData"` LeftPeriod []LeftPeriod `json:"leftPeriod"` // Характеристики срока службы
Novelty bool `json:"novelty"` LeftPeriodRaw LeftPeriodRaw `json:"leftPeriodRaw"` // Гарантийные показатели
DesignFeatures []DesignFeatures `json:"designFeatures"` LogisticParams []LogisticParams `json:"logisticParams"` // Логистические характеристики
Videos []Video `json:"videos"` LogisticParamsData LogisticParamsData `json:"logisticParamsData"` // Подробные логистические характеристики
Software []Software `json:"software"` Novelty bool `json:"novelty"` // Новинка или нет
Banner string `json:"banner"` DesignFeatures []DesignFeatures `json:"designFeatures"` // Отличительные особенности
LastModified string `json:"lastModified"` Videos []Video `json:"videos"` // Видео по товару
CountryOfProduction string `json:"countryOfProduction"` Software []Software `json:"software"` // ПО по товару
FirstSaleDate string `json:"firstSaleDate"` Banner string `json:"banner"` // Текст баннера
Feacn string `json:"feacn"` LastModified string `json:"lastModified"` // Дата последнего изменения
Family string `json:"family"` CountryOfProduction string `json:"countryOfProduction"` // Страна производства
Series string `json:"series"` FirstSaleDate string `json:"firstSaleDate"` // Дата начала продаж
IndPacking []string `json:"indPacking"` Feacn string `json:"feacn"` // Код ТН ВЭД
Analogs []Analog `json:"analogs"` Multiplicity int `json:"multiplicity"` // Кратность продажи
Related []Analog `json:"related"` PriceBase float64 `json:"priceBase"` // Базовая цена с НДС
QrCode string `json:"qrCode"` PriceRrc float64 `json:"priceRrc"` // Персональная цена с НДС
IsOutOfAssortment bool `json:"isOutOfAssortment"` PricePersonal float64 `json:"pricePersonal"` // Рекомендованная розничная цена (РРЦ) с НДС
IsOutOfProduction bool `json:"isOutOfProduction"` Available int `json:"available"` // Значение остатка
Units string `json:"units"` // Единицы измерения
Family string `json:"family"` // Family specifies the family category of the product.
Series string `json:"series"` // Series is the series of the product.
IndPacking []string `json:"indPacking"` // Ссылки на фото упаковки
Analogs []Analog `json:"analogs"` // Аналоги
Related []Analog `json:"related"` // Совместно применяемые изделия
QrCode string `json:"qrCode"` // QR код со ссылкой на товар в Бизнес платформе
IsOutOfAssortment bool `json:"isOutOfAssortment"` // Выведенный из ассортимента
IsOutOfProduction bool `json:"isOutOfProduction"` // Выводимый из ассортимента
WarehouseData []WarehouseData `json:"warehouseData"` // Информация по складам
} }
) )

View File

@ -1,32 +1,32 @@
package model package model
type CategoryResponse struct { type CategoryResponse struct {
Categories []Category `json:"categories"` Categories []Category `json:"categories"` // Массив категорий 1-го уровня
} }
type CategoriesAndProductsBySlugParentCategoryResponse struct { type CategoriesAndProductsBySlugParentCategoryResponse struct {
Date string `json:"date"` Date string `json:"date"` // Дата формирования файла
Slug string `json:"slug"` Slug string `json:"slug"` // Слаг категории 1-го уровня
Name string `json:"name"` Name string `json:"name"` // Название категории 1-го уровня
Url string `json:"url"` Url string `json:"url"` // Относительный адрес категории 1-го уровня
Categories []Category `json:"categories"` Categories []Category `json:"categories"` // Массив всех входящих категорий
Products []Product `json:"products"` Products []Product `json:"products"` // Массив всех входящих товаров
} }
type NewProductsResponse struct { type NewProductsResponse struct {
Data struct { Data struct {
Products []Product `json:"products"` Products []Product `json:"products"` // Список новинок
} `json:"data"` } `json:"data"` // Список новинок
Meta struct { Meta struct {
Page int `json:"page"` Page int `json:"page"` // Текущая страница
TotalPages int `json:"totalPages"` TotalPages int `json:"totalPages"` // Всего страниц
TotalCount int `json:"totalCount"` TotalCount int `json:"totalCount"` // Всего элементов
PageSize int `json:"pageSize"` PageSize int `json:"pageSize"` // Размер страницы
} `json:"_meta"` } `json:"_meta"` // Параметры пагинации
} }
type RemainsAndPlanresiduesResponse struct { type RemainsAndPlanresiduesResponse struct {
Date string `json:"date"` Date string `json:"date"` // Дата создания файла
Products []ShortProduct `json:"products"` Products []ShortProduct `json:"products"` // Массив остатков по товарам
} }