Files
MyClub/internal/services/eshop/packeta_service.go
T
Tomas Dvorak dfc079288f hot fix #1
2026-01-26 08:13:18 +01:00

159 lines
4.4 KiB
Go

package eshop
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"net/http"
"time"
"fotbal-club/internal/config"
"fotbal-club/internal/models"
)
type PacketaService struct {
Config *config.Config
}
func NewPacketaService(cfg *config.Config) *PacketaService {
return &PacketaService{Config: cfg}
}
const packetaAPIURL = "https://www.zasilkovna.cz/api/rest"
// CreatePacket creates a new packet in Packeta system
func (s *PacketaService) CreatePacket(order *models.EshopOrder) (string, error) {
type PacketAttributes struct {
Number string `xml:"number"`
Name string `xml:"name"`
Surname string `xml:"surname"`
Email string `xml:"email"`
Phone string `xml:"phone"`
AddressID string `xml:"addressId"`
Value string `xml:"value"`
Currency string `xml:"currency"`
Weight string `xml:"weight"`
Eshop string `xml:"eshop"`
}
type CreatePacketRequest struct {
XMLName xml.Name `xml:"createPacket"`
ApiPassword string `xml:"apiPassword"`
PacketAttributes PacketAttributes `xml:"packetAttributes"`
}
// Extract shipping data
// order.ShippingDataJSON should contain the selected point ID (addressId)
// For now assuming we parse it or it is passed differently.
// In a real scenario, we would parse ShippingDataJSON to get the point ID.
addressID := "1483" // Fallback/Test ID if parsing fails. TODO: Implement proper parsing.
reqBody := CreatePacketRequest{
ApiPassword: s.Config.PacketaAPIPassword,
PacketAttributes: PacketAttributes{
Number: order.OrderNumber,
Name: order.FirstName,
Surname: order.LastName,
Email: order.Email,
Phone: "", // Phone is optional in our model but required for some carriers. TODO: Add phone to checkout.
AddressID: addressID,
Value: fmt.Sprintf("%.2f", float64(order.TotalAmountCents)/100.0),
Currency: order.Currency,
Weight: "1.0", // Default weight 1kg. TODO: Calculate from items.
Eshop: s.Config.PacketaEshopName,
},
}
respBytes, err := s.sendRequest(reqBody)
if err != nil {
return "", err
}
type CreatePacketResponse struct {
PacketId string `xml:"packetId"`
Status string `xml:"status"`
Fault string `xml:"fault"`
}
var resp CreatePacketResponse
if err := xml.Unmarshal(respBytes, &resp); err != nil {
return "", fmt.Errorf("failed to parse response: %w", err)
}
if resp.Status != "ok" && resp.PacketId == "" {
return "", fmt.Errorf("packeta error: %s", resp.Fault)
}
return resp.PacketId, nil
}
// GetPacketLabel downloads the label PDF
func (s *PacketaService) GetPacketLabel(packetID string) ([]byte, error) {
type PacketLabelPdfRequest struct {
XMLName xml.Name `xml:"packetLabelPdf"`
ApiPassword string `xml:"apiPassword"`
PacketId string `xml:"packetId"`
Format string `xml:"format"`
Offset int `xml:"offset"`
}
reqBody := PacketLabelPdfRequest{
ApiPassword: s.Config.PacketaAPIPassword,
PacketId: packetID,
Format: "A6 on A4",
Offset: 0,
}
return s.sendRequest(reqBody)
}
// GetPacketStatus checks the status of a packet
func (s *PacketaService) GetPacketStatus(packetID string) (string, error) {
type PacketStatusRequest struct {
XMLName xml.Name `xml:"packetStatus"`
ApiPassword string `xml:"apiPassword"`
PacketId string `xml:"packetId"`
}
reqBody := PacketStatusRequest{
ApiPassword: s.Config.PacketaAPIPassword,
PacketId: packetID,
}
respBytes, err := s.sendRequest(reqBody)
if err != nil {
return "", err
}
// Simplistic parsing for status text/code
// XML response structure varies slightly but usually contains <status>...</status>
// We might need a more robust struct.
return string(respBytes), nil
}
func (s *PacketaService) sendRequest(payload interface{}) ([]byte, error) {
xmlBytes, err := xml.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Post(packetaAPIURL, "text/xml", bytes.NewReader(xmlBytes))
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(body))
}
return body, nil
}