Sobes.tech
Назад к вопросам
Middle+
3

Реализовать метод grpc-сервера AddItemAndOrder: 1. Добавить товары в корзину 2. Обязательно сообщить возможным потребителям о факте оформления корзины через брокер сообщений. 3. При изменении состава корзины надо пересчитывать basket.Total=sum(count*price) 4. Все элементы корзины должны быть уникальны по ключу ProductID 5. Для оформления корзины необходимо сменить ее статус на ordered 6. В оформленные корзины изменения вносить нельзя

Компании, где спрашивали
КуперКупер

Ответ от нейросети

sobes.tech AI

Ниже пример реализации метода AddItemAndOrder для gRPC-сервера на Go с учетом требований:

  • Корзина (Basket) содержит уникальные товары по ProductID.
  • При добавлении товаров пересчитывается сумма Total.
  • При оформлении корзины меняется статус на ordered.
  • После оформления изменения запрещены.
  • После оформления отправляется сообщение через брокер (например, через интерфейс MessageBroker).
package service

import (
    "context"
    "errors"
    "sync"
)

// Пример структур

type BasketStatus string

const (
    StatusOpen    BasketStatus = "open"
    StatusOrdered BasketStatus = "ordered"
)

type BasketItem struct {
    ProductID string
    Count     int
    Price     float64
}

type Basket struct {
    ID     string
    Items  map[string]*BasketItem // ключ - ProductID
    Total  float64
    Status BasketStatus
    mu     sync.Mutex
}

// Интерфейс брокера сообщений

type MessageBroker interface {
    Publish(topic string, message interface{}) error
}

// Сервис с корзинами и брокером

type BasketService struct {
    baskets map[string]*Basket
    broker  MessageBroker
}

func NewBasketService(broker MessageBroker) *BasketService {
    return &BasketService{
        baskets: make(map[string]*Basket),
        broker:  broker,
    }
}

// AddItemAndOrderRequest и Response - protobuf-сгенерированные структуры

func (s *BasketService) AddItemAndOrder(ctx context.Context, req *AddItemAndOrderRequest) (*AddItemAndOrderResponse, error) {
    basket, ok := s.baskets[req.BasketId]
    if !ok {
        return nil, errors.New("basket not found")
    }

    basket.mu.Lock()
    defer basket.mu.Unlock()

    if basket.Status == StatusOrdered {
        return nil, errors.New("cannot modify ordered basket")
    }

    // Добавляем или обновляем товары
    for _, item := range req.Items {
        if existing, exists := basket.Items[item.ProductId]; exists {
            existing.Count += int(item.Count)
            existing.Price = item.Price // обновляем цену, если нужно
        } else {
            basket.Items[item.ProductId] = &BasketItem{
                ProductID: item.ProductId,
                Count:     int(item.Count),
                Price:     item.Price,
            }
        }
    }

    // Пересчет суммы
    var total float64
    for _, item := range basket.Items {
        total += float64(item.Count) * item.Price
    }
    basket.Total = total

    // Если в запросе есть флаг оформления корзины
    if req.Order { // предположим, что есть булево поле Order
        basket.Status = StatusOrdered

        // Отправляем сообщение в брокер
        err := s.broker.Publish("basket_ordered", map[string]interface{}{
            "basket_id": basket.ID,
            "total":     basket.Total,
            "items":     basket.Items,
        })
        if err != nil {
            return nil, err
        }
    }

    return &AddItemAndOrderResponse{
        Total:  basket.Total,
        Status: string(basket.Status),
    }, nil
}

В этом примере:

  • Используется мьютекс для защиты данных корзины от гонок.
  • Товары хранятся в мапе для уникальности по ProductID.
  • При оформлении меняется статус и отправляется событие через брокер.
  • После оформления любые изменения запрещены.

Для реального приложения нужно добавить валидацию, обработку ошибок и интеграцию с реальным брокером сообщений.