package server import ( "fmt" "net/http" "strconv" "time" "github.com/a-h/templ" "github.com/labstack/echo/v4" "github.com/labstack/gommon/log" u "github.com/rjNemo/underscore" "github.com/rjNemo/rentease/constants" "github.com/rjNemo/rentease/internal/domains/booking" "github.com/rjNemo/rentease/internal/pdf" "github.com/rjNemo/rentease/internal/views" myTime "github.com/rjNemo/rentease/pkg/time" ) func (s Server) handleHomePage() echo.HandlerFunc { return func(ctx echo.Context) error { component := views.Index() return s.renderTempl(ctx, http.StatusOK, component) } } func (s Server) handleListBookingPage() echo.HandlerFunc { return func(c echo.Context) error { bookings := make([]*booking.Booking, 0) _ = s.db.Order("id desc").Find(&bookings) bvm := u.Map(bookings, func(b *booking.Booking) *views.ListBookingsViewModel { return &views.ListBookingsViewModel{ Id: strconv.Itoa(b.Id), Url: templ.SafeURL(fmt.Sprintf("%s/%d", constants.RouteBooking, b.Id)), From: b.From.Format("2006-01-02"), To: b.To.Format("2006-01-02"), Platform: b.Platform, Name: b.Name, } }) component := views.ListBookings(bvm) return s.renderTempl(c, http.StatusOK, component) } } func (s Server) handleNewBookingPage() echo.HandlerFunc { return func(c echo.Context) error { component := views.NewBooking(constants.Platforms) return s.renderTempl(c, http.StatusOK, component) } } func (s Server) handleCreateBooking() echo.HandlerFunc { return func(c echo.Context) error { type NewBooking struct { From time.Time `json:"from"` To time.Time `from:"to"` Name string `form:"name"` PhoneNumber string `form:"phone_number"` Email string `form:"email"` Platform string `form:"platform"` CustomerNumber int `form:"customer_number"` PlatformFees float64 `form:"platform_fees"` } nb := new(NewBooking) err := c.Bind(nb) if err != nil { log.Warn(err) return err } ts, _ := myTime.ParseFromForm(c.FormValue("from")) nb.From = ts ts, _ = myTime.ParseFromForm(c.FormValue("to")) nb.To = ts b := &booking.Booking{ Name: nb.Name, PhoneNumber: nb.PhoneNumber, CustomerNumber: nb.CustomerNumber, Email: nb.Email, From: nb.From, To: nb.To, Platform: nb.Platform, PlatformFees: nb.PlatformFees, } _ = s.db.Create(b) return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%s/%d", constants.RouteBooking, b.Id)) } } func (s Server) handleBookingPage() echo.HandlerFunc { return func(c echo.Context) error { idStr := c.Param("id") id, err := strconv.Atoi(idStr) if err != nil { return err } b := &booking.Booking{Id: id} s.db.Preload("Items").First(b) bvm := &views.BookingViewModel{ Id: fmt.Sprintf("%04s", strconv.Itoa(b.Id)), Name: b.Name, PhoneNumber: b.PhoneNumber, CustomerNumber: strconv.Itoa(b.CustomerNumber), Email: b.Email, From: b.From.Format("2006-01-02"), To: b.To.Format("2006-01-02"), Platform: b.Platform, PlatformFees: strconv.FormatFloat(b.PlatformFees, 'f', 2, 64), Url: templ.EscapeString(fmt.Sprintf("%s/%d/items", constants.RouteBooking, b.Id)), Items: u.Map(b.Items, func(i booking.Item) views.ItemViewModel { return views.ItemViewModel{ Item: i.Item, Quantity: strconv.Itoa(i.Quantity), Price: strconv.FormatFloat(i.Price, 'f', 2, 64), SubTotal: strconv.FormatFloat(i.Price*float64(i.Quantity), 'f', 2, 64), PaymentMethod: i.PaymentMethod, PaymentStatus: i.PaymentStatus, } }), Total: strconv.FormatFloat(u.Reduce(b.Items, func(i booking.Item, sum float64) float64 { return sum + i.Price*float64(i.Quantity) }, 0.0), 'f', 2, 64), Platforms: constants.Platforms, ItemList: constants.Items, PaymentMethods: constants.PaymentMethods, } component := views.BookingById(bvm) return s.renderTempl(c, http.StatusOK, component) } } func (s Server) handleCreateItem() echo.HandlerFunc { return func(c echo.Context) error { bookingIdStr := c.Param("id") bid, err := strconv.Atoi(bookingIdStr) if err != nil { return err } type NewItem struct { Item string `form:"item"` Quantity int `form:"quantity"` Price float64 `form:"price"` PaymentMethod string `form:"method"` } ni := new(NewItem) if err := c.Bind(ni); err != nil { log.Warn(err) return err } i := &booking.Item{ BookingId: bid, Item: ni.Item, Quantity: ni.Quantity, Price: ni.Price, PaymentMethod: ni.PaymentMethod, } _ = s.db.Create(i) return s.renderTempl(c, http.StatusCreated, views.LineItem(i)) } } func (s Server) handleReportsPage() echo.HandlerFunc { return func(c echo.Context) error { period := c.QueryParam("period") if !u.Contains([]string{"month", "year"}, period) { period = "month" } monthStr := c.QueryParam("month") month, err := strconv.Atoi(monthStr) if err != nil || month < 1 || month > 12 { month = int(time.Now().Month()) } yearStr := c.QueryParam("year") _, err = strconv.Atoi(yearStr) if err != nil { yearStr = time.Now().Format("2006") } return s.renderTempl(c, http.StatusOK, views.Reports(constants.Months, yearStr)) } } func (s Server) handleComputeReport() echo.HandlerFunc { return func(c echo.Context) error { period := c.FormValue("period") if !u.Contains([]string{"month", "year"}, period) { return &echo.HTTPError{ Code: http.StatusBadRequest, Message: fmt.Sprintf("%q is not a valid period", period), } } monthStr := c.FormValue("month") month, err := strconv.Atoi(monthStr) if err != nil || month < 1 || month > 12 { return &echo.HTTPError{ Code: http.StatusBadRequest, Message: fmt.Sprintf("%q is not a valid month", month), } } yearStr := c.FormValue("year") year, err := strconv.Atoi(yearStr) if err != nil { return &echo.HTTPError{ Code: http.StatusBadRequest, Message: fmt.Sprintf("%q is not a valid year", year), } } type Result struct { From time.Time To time.Time Id string CustomerName string Platform string Total float64 PlatformFees float64 } res := make([]*Result, 0) var startDate time.Time var endDate time.Time if period == "month" { startDate = time.Date(year, time.Month(month), 1, 0, 0, 0, 0, time.UTC) endDate = time.Date(year, time.Month(month), 31, 0, 0, 0, 0, time.UTC) } else { startDate = time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC) endDate = time.Date(year, time.December, 31, 0, 0, 0, 0, time.UTC) } s.db. Raw(` select id, customer_name, "from", "to", platform, total, platform_fees from (select sum(price) as total, booking_id from bookings join items on bookings.id = items.booking_id where "from" between ? and ? group by booking_id) as sbi, (select * from bookings) as b where sbi.booking_id = b.id; `, startDate.Format("2006-01-02"), endDate.Format("2006-01-02")). Scan(&res) reportVm := u.Map(res, func(r *Result) *views.ReportViewModel { return &views.ReportViewModel{ Id: r.Id, Url: templ.SafeURL(fmt.Sprintf("%s/%s", constants.RouteBooking, r.Id)), Total: strconv.FormatFloat(r.Total, 'f', 2, 64), CustomerName: r.CustomerName, From: r.From.Format("2006-01-02"), To: r.To.Format("2006-01-02"), Platform: r.Platform, PlatformFees: strconv.FormatFloat(r.PlatformFees, 'f', 2, 64), } }) return s.renderTempl(c, http.StatusOK, views.ReportSection(reportVm)) } } func handleCreateInvoicePdf(ps *pdf.PdfService) echo.HandlerFunc { return func(c echo.Context) error { err := ps.BuildInvoice() if err != nil { return err } return c.Attachment("tmp.pdf", "tmp.pdf") } }