package eshop import ( "encoding/json" "fmt" "net/http" "fotbal-club/internal/config" "fotbal-club/internal/models" "fotbal-club/internal/services" "fotbal-club/pkg/database" "github.com/gin-gonic/gin" "gorm.io/gorm" ) type ShippingController struct { Config *config.Config PacketaService *services.PacketaService } func NewShippingController(cfg *config.Config) *ShippingController { return &ShippingController{ Config: cfg, PacketaService: services.NewPacketaService(cfg), } } // GetPacketaWidgetConfig returns the configuration for the Packeta widget func (c *ShippingController) GetPacketaWidgetConfig(ctx *gin.Context) { ctx.JSON(http.StatusOK, gin.H{ "api_key": c.Config.PacketaWidgetAPIKey, "env": c.Config.PacketaEnv, }) } // DownloadLabel handles the download of a shipping label PDF // GET /api/v1/eshop/shipping/labels/:packet_id func (c *ShippingController) DownloadLabel(ctx *gin.Context) { packetID := ctx.Param("packet_id") if packetID == "" { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Missing packet ID"}) return } // In MVP, we might not have label download implemented in service yet // pdfData, err := c.PacketaService.GetPacketLabel(packetID) // Placeholder pdfData, err := c.PacketaService.GetPacketLabel(packetID) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to download label"}) return } ctx.Header("Content-Type", "application/pdf") ctx.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="label_%s.pdf"`, packetID)) ctx.Data(http.StatusOK, "application/pdf", pdfData) } // CreatePacket creates a shipment in Packeta system from an order func (c *ShippingController) CreatePacket(ctx *gin.Context) { id := ctx.Param("id") // Use a new DB connection or pass it via struct if possible. // For now, InitDB (cached instance) db, _ := database.InitDB() var order models.EshopOrder if err := db.First(&order, id).Error; err != nil { ctx.JSON(http.StatusNotFound, gin.H{"error": "Order not found"}) return } if order.ShippingMethod != "packeta" { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Not a Packeta order"}) return } // Parse shipping address JSON to get point ID // Format: {"id":"123", "name":"Z-Point..."} var pointData struct { ID interface{} `json:"id"` } if err := json.Unmarshal([]byte(order.ShippingAddressJSON), &pointData); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to parse shipping address"}) return } addressID := fmt.Sprintf("%v", pointData.ID) if addressID == "" { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Missing Packeta point ID"}) return } packetID, err := c.PacketaService.CreatePacket(&order, addressID) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Packeta API error: " + err.Error()}) return } // Create Label record label := models.EshopShippingLabel{ OrderID: order.ID, PacketaPacketID: packetID, Carrier: "packeta", Status: "created", } db.Create(&label) // Update order status order.Status = "ready_to_ship" db.Save(&order) ctx.JSON(http.StatusOK, gin.H{ "packet_id": packetID, "status": "created", }) } // Background job func (c *ShippingController) UpdatePacketStatuses(db *gorm.DB) { var labels []models.EshopShippingLabel // Check active shipments if err := db.Where("status NOT IN ?", []string{"delivered", "cancelled", "returned"}).Find(&labels).Error; err != nil { return } for _, label := range labels { status, err := c.PacketaService.GetPacketStatus(label.PacketaPacketID) if err != nil { continue } if label.Status != status { // Update label status label.Status = status if err := db.Save(&label).Error; err != nil { continue } // Update order status based on shipping status c.updateOrderStatusFromShipping(db, label.OrderID, status) } } } // updateOrderStatusFromShipping updates order status based on shipping status func (c *ShippingController) updateOrderStatusFromShipping(db *gorm.DB, orderID uint, shippingStatus string) { var newOrderStatus string switch shippingStatus { case "ready_to_ship", "collected": newOrderStatus = "processing" case "in_transit", "out_for_delivery": newOrderStatus = "shipped" case "delivered": newOrderStatus = "completed" case "cancelled", "returned": newOrderStatus = shippingStatus default: return // No status change needed } if err := db.Model(&models.EshopOrder{}). Where("id = ?", orderID). Update("status", newOrderStatus).Error; err != nil { // Log error but don't fail the entire process return } }