package app import ( "bytes" "cake_crm/internal/models/messenger" "cake_crm/internal/models/storage" proto "cake_crm/proto" "context" "errors" "fmt" "strconv" ) type orderItem struct { product *proto.Product count int64 } type Server struct { proto.UnsafeCRMServer storage storage.IStorage messenger messenger.IMessenger } func NewServer( storage storage.IStorage, messenger messenger.IMessenger, ) proto.CRMServer { return &Server{ storage: storage, messenger: messenger, } } func (s *Server) GetCatalog(ctx context.Context, _ *proto.GetCatalogReq) (*proto.CatalogRsp, error) { categories, err := s.storage.GetCatalog(ctx) if err != nil { return nil, err } return &proto.CatalogRsp{Categories: categories}, nil } func (s *Server) GetPositions(ctx context.Context, req *proto.GetPositionsReq) (*proto.PositionsRsp, error) { products, err := s.storage.GetPositions(ctx, req.Id) if err != nil { return nil, err } return &proto.PositionsRsp{Products: products}, nil } func (s *Server) GetProduct(ctx context.Context, req *proto.GetProductReq) (*proto.ProductRsp, error) { product, err := s.storage.GetProduct(ctx, req.Id) if err != nil { return nil, err } return &proto.ProductRsp{Product: product}, nil } func (s *Server) GetBreadcrumbs(ctx context.Context, req *proto.GetBreadcrumbsReq) (*proto.BreadcrumbsRsp, error) { breadcrumbs, err := s.storage.GetBreadcrumbs(ctx, req.Id) if err != nil { return nil, err } return &proto.BreadcrumbsRsp{Categories: breadcrumbs}, nil } func (s *Server) Order(ctx context.Context, req *proto.OrderReq) (*proto.OrderRsp, error) { items := make([]*orderItem, 0, len(req.Order.Items)) for _, item := range req.Order.Items { product, err := s.storage.GetProduct(ctx, item.ProductId) if err != nil { return nil, err } items = append( items, &orderItem{ product: product, count: item.Count, }, ) } text, err := createOrderText(req, items) if err != nil { return nil, err } return &proto.OrderRsp{}, s.messenger.SendMessage(text) } func createOrderText(req *proto.OrderReq, items []*orderItem) (string, error) { buffer := bytes.Buffer{} orderAmount := 0.0 buffer.WriteString(fmt.Sprintf("Заказ от:\n%s\n%s\n", req.Name, req.Phone)) buffer.WriteString("\n") for _, item := range items { buffer.WriteString(item.product.Name) buffer.WriteString("\n") unit, err := unitToText(item.product.Unit) if err != nil { return "", err } buffer.WriteString(fmt.Sprintf("Количество: %d%s\n", item.count, unit)) amount, err := calcItemAmount(item) if err != nil { return "", err } orderAmount += amount buffer.WriteString(fmt.Sprintf("Сумма: %.00fр\n", amount)) buffer.WriteString("\n") } buffer.WriteString("\n") buffer.WriteString(fmt.Sprintf("ИТОГО: %.00fр\n", orderAmount)) return buffer.String(), nil } func calcItemAmount(item *orderItem) (float64, error) { var variant *proto.Variant for _, v := range item.product.Variants { check := true for _, property := range v.Properties { if property.Name == "min" { minBorder, err := strconv.ParseInt(property.Value, 10, 64) if err != nil { return 0, err } if item.count < minBorder { check = false } } if property.Name == "max" { maxBorder, err := strconv.ParseInt(property.Value, 10, 64) if err != nil { return 0, err } if item.count > maxBorder { check = false } } if check { variant = v break } } } if variant == nil { return 0, errors.New("variant not found") } return float64(variant.Price) * float64(item.count) / 100, nil } func unitToText(unit string) (string, error) { switch unit { case "kg": return "кг", nil case "piece": return "шт", nil } return "", errors.New("unit not found") }