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"
)
type Api struct {
Client *client.Client
}
type (
Api struct {
Client *client.Client
}
Credentials struct {
Username string
Password string
}
type Method interface {
GetParentCategories() ([]model.Category, error)
GetCategories() ([]model.Category, error)
GetTreeCategories() ([]model.TreeCategories, error)
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) // Возвращает массив, в котором содержатся актуальные цены и остатки товаров.
}
)
GetProducts() ([]model.Product, error)
GetProductByArticle(article string) (model.Product, error)
GetRemainsAndPlanresidues() ([]model.ShortProduct, error)
}
func NewApi(credentials client.Credentials) Method {
func NewApi(credentials Credentials) Method {
return &Api{
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)
}
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) {
@ -77,7 +82,7 @@ func (a *Api) GetRemainsAndPlanresidues() ([]model.ShortProduct, error) {
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 {
remainsAndPlanresidues = append(remainsAndPlanresidues, result.Products...)

View File

@ -1,15 +1,13 @@
package client
import "github.com/go-resty/resty/v2"
// import (
// "net/http"
// "net/url"
// )
import (
"gitea.24example.ru/spavelit/bpiek/api"
"github.com/go-resty/resty/v2"
)
const (
AUTH_API_URL = "https://bp.iek.ru/oauth/login"
BASE_API_URL = "https://bp.iek.ru/api/catalog/v1/"
AuthApiUrl = "https://bp.iek.ru/oauth/login"
BaseApiUrl = "https://bp.iek.ru/api/catalog/v1/"
)
type (
@ -27,18 +25,18 @@ type (
}
)
func NewClient(credentials Credentials) *Client {
func NewClient(credentials api.Credentials) *Client {
authSuccess := &AuthSuccess{}
client := resty.New()
client.SetBaseURL(BASE_API_URL)
client.SetBaseURL(BaseApiUrl)
response, err := client.R().
SetFormData(map[string]string{
"username": credentials.GetUsername(),
"password": credentials.GetPassword(),
"username": credentials.Username,
"password": credentials.Password,
}).
SetResult(&authSuccess).
Post(AUTH_API_URL)
Post(AuthApiUrl)
if err != nil {
panic(err)
@ -49,7 +47,7 @@ func NewClient(credentials Credentials) *Client {
}
client.SetHeader("Content-Type", "application/json")
client.SetHeader("Authorization", "Bearer "+authSuccess.AccessToken)
client.SetHeader("Authorization", authSuccess.TokenType+" "+authSuccess.AccessToken)
return &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
type Category struct {
Slug string `json:"slug"`
Name string `json:"name"`
Url string `json:"url"`
ApiUrl string `json:"apiUrl"`
Slug string `json:"slug"` // Слаг категории
Name string `json:"name"` // Название категории
Url string `json:"url"` // Ссылка на скачивание файла с содержимым категории
ApiUrl string `json:"apiUrl"` // Относительный адрес категории
}
type TreeCategories struct {
Slug string `json:"slug"`
Name string `json:"name"`
Url string `json:"url"`
Children []TreeCategories `json:"children"`
Slug string `json:"slug"` // Слаг категории
Name string `json:"name"` // Название категории
Url string `json:"url"` // Относительный адрес категории
Children []TreeCategories `json:"children"` // Children nested categories in TreeCategories
}

View File

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