From c712b487ce8fc8e54c21795440265a42f31b99ae Mon Sep 17 00:00:00 2001 From: Ruidy Date: Tue, 4 Feb 2025 11:26:29 +0100 Subject: [PATCH] create pdf driver --- .air.toml | 2 +- .gitignore | 2 +- internal/driver/pdf/html.go | 40 +++++ .../driver/pdf/{service.go => htmldocs.go} | 2 +- internal/service/booking/mocks_test.go | 117 -------------- internal/service/booking/service.go | 28 +--- internal/service/booking/service_test.go | 148 ------------------ main.go | 7 +- 8 files changed, 46 insertions(+), 300 deletions(-) create mode 100644 internal/driver/pdf/html.go rename internal/driver/pdf/{service.go => htmldocs.go} (97%) delete mode 100644 internal/service/booking/mocks_test.go delete mode 100644 internal/service/booking/service_test.go diff --git a/.air.toml b/.air.toml index 4bdc1e1..1378769 100644 --- a/.air.toml +++ b/.air.toml @@ -7,7 +7,7 @@ tmp_dir = "tmp" delay = 1000 exclude_dir = ["assets", "tmp", "vendor"] exclude_file = [] - exclude_regex = [".*_templ.go"] + exclude_regex = [".*_templ.go", "VFNI*html"] exclude_unchanged = false follow_symlink = false full_bin = "" diff --git a/.gitignore b/.gitignore index 9455f0a..b541175 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,4 @@ tmp.pdf *templ.txt token.json .aider* -output.html \ No newline at end of file +VFNI*.html \ No newline at end of file diff --git a/internal/driver/pdf/html.go b/internal/driver/pdf/html.go new file mode 100644 index 0000000..3ed2dc2 --- /dev/null +++ b/internal/driver/pdf/html.go @@ -0,0 +1,40 @@ +package pdf + +import ( + "bytes" + "fmt" + "os" + "text/template" + + "github.com/rjNemo/rentease/internal/service/booking" +) + +type HtmlPdfClient struct{} + +func NewPdfClient() (*HtmlPdfClient, error) { + return &HtmlPdfClient{}, nil +} + +func (pc *HtmlPdfClient) BuildInvoice(data booking.Invoice) (string, error) { + tmpl, err := template.ParseFiles("assets/html/invoice.html") + if err != nil { + return "", fmt.Errorf("Error parsing template: %v", err) + } + + // Create a buffer to hold the rendered HTML. + var buf bytes.Buffer + if err := tmpl.Execute(&buf, data); err != nil { + return "", fmt.Errorf("error executing template: %v", err) + } + + outputPath := fmt.Sprintf("%s.html", data.ID) + if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil { + return "", fmt.Errorf("error writing HTML file: %v", err) + } + + return outputPath, nil +} + +func (pc *HtmlPdfClient) BuildReport(context map[string]any, period string, month int, year int) error { + panic("unimplemented") +} diff --git a/internal/driver/pdf/service.go b/internal/driver/pdf/htmldocs.go similarity index 97% rename from internal/driver/pdf/service.go rename to internal/driver/pdf/htmldocs.go index b24a230..ce0e4ed 100644 --- a/internal/driver/pdf/service.go +++ b/internal/driver/pdf/htmldocs.go @@ -19,7 +19,7 @@ type PdfClient struct { apiKey string } -func NewPdfClient(pid, rid, url, key string) (*PdfClient, error) { +func NewApiPdfClient(pid, rid, url, key string) (*PdfClient, error) { if pid == "" || rid == "" || url == "" || key == "" { return nil, errors.New("error building Pdf service. Verify your env variables") } diff --git a/internal/service/booking/mocks_test.go b/internal/service/booking/mocks_test.go deleted file mode 100644 index dc16ac8..0000000 --- a/internal/service/booking/mocks_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package booking - -import ( - "time" - - "github.com/stretchr/testify/mock" -) - -// MockStore is a mock implementation of the Store interface -type MockStore struct { - mock.Mock -} - -func (m *MockStore) All() []*Line { - args := m.Called() - return args.Get(0).([]*Line) -} - -func (m *MockStore) Search(value string) []*Line { - args := m.Called(value) - return args.Get(0).([]*Line) -} - -func (m *MockStore) List(from, to time.Time) ([]*Line, error) { - args := m.Called(from, to) - return args.Get(0).([]*Line), args.Error(1) -} - -func (m *MockStore) CardTotal(from, to time.Time) (float64, error) { - args := m.Called(from, to) - return args.Get(0).(float64), args.Error(1) -} - -func (m *MockStore) Get(id int) *Booking { - args := m.Called(id) - return args.Get(0).(*Booking) -} - -func (m *MockStore) Create(b *Booking) error { - args := m.Called(b) - return args.Error(0) -} - -func (m *MockStore) Update(b *Booking) error { - args := m.Called(b) - return args.Error(0) -} - -func (m *MockStore) Cancel(id int) error { - args := m.Called(id) - return args.Error(0) -} - -func (m *MockStore) CreateItem(i *Item) error { - args := m.Called(i) - return args.Error(0) -} - -func (m *MockStore) PayItem(id int) (*Item, error) { - args := m.Called(id) - return args.Get(0).(*Item), args.Error(1) -} - -func (m *MockStore) GetItem(id int) (*Item, error) { - args := m.Called(id) - return args.Get(0).(*Item), args.Error(1) -} - -func (m *MockStore) UpdateItem(id int, item string, paymentMethod string, paymentStatus string, qty int, price float64) (*Item, error) { - args := m.Called(id, item, paymentMethod, paymentStatus, qty, price) - return args.Get(0).(*Item), args.Error(1) -} - -func (m *MockStore) CreatePayment(p *Payment) (*Payment, error) { - args := m.Called(p) - return args.Get(0).(*Payment), args.Error(1) -} - -func (m *MockStore) GetPayment(id int) (*Payment, error) { - args := m.Called(id) - return args.Get(0).(*Payment), args.Error(1) -} - -func (m *MockStore) UpdatePayment(id int, amount float64, paymentMethod string) (*Payment, error) { - args := m.Called(id, amount, paymentMethod) - return args.Get(0).(*Payment), args.Error(1) -} - -// MockParserClient is a mock implementation of the parser.Client interface -type MockParserClient struct { - mock.Mock -} - -// MockCalendarClient is a mock implementation of the calendar.Client interface -type MockCalendarClient struct { - mock.Mock -} - -func (m *MockCalendarClient) Create(calendarId, name, description string, from, to time.Time) error { - args := m.Called(calendarId, name, description, from, to) - return args.Error(0) -} - -// MockPDFClient is a mock implementation of the pdf.Client interface -type MockPDFClient struct { - mock.Mock -} - -func (m *MockPDFClient) BuildInvoice(context map[string]any) error { - args := m.Called(context) - return args.Error(0) -} - -func (m *MockPDFClient) BuildReport(context map[string]any, period string, month, year int) error { - args := m.Called(context, period, month, year) - return args.Error(0) -} diff --git a/internal/service/booking/service.go b/internal/service/booking/service.go index 3006590..3f22020 100644 --- a/internal/service/booking/service.go +++ b/internal/service/booking/service.go @@ -1,11 +1,7 @@ package booking import ( - "bytes" - "fmt" "log" - "os" - "text/template" "time" "github.com/rjNemo/rentease/internal/config" @@ -34,7 +30,7 @@ type Store interface { } type PdfClient interface { - BuildInvoice(context map[string]any) error + BuildInvoice(invoice Invoice) (string, error) BuildReport(context map[string]any, period string, month, year int) error } @@ -105,25 +101,5 @@ func (bs Service) Cancel(id int) { } func (bs Service) BuildInvoice(b *Booking, hc *config.Host) (string, error) { - invoiceData := b.ToInvoice(hc) - - tmpl, err := template.ParseFiles("assets/html/invoice.html") - if err != nil { - return "", fmt.Errorf("Error parsing template: %v", err) - } - - // Create a buffer to hold the rendered HTML. - var buf bytes.Buffer - if err := tmpl.Execute(&buf, invoiceData); err != nil { - return "", fmt.Errorf("error executing template: %v", err) - } - - outputPath := fmt.Sprintf("%s.html", b.InvoiceNumber(hc)) - - if err := os.WriteFile(outputPath, buf.Bytes(), 0644); err != nil { - return "", fmt.Errorf("error writing HTML file: %v", err) - } - - log.Printf("HTML file created successfully: %s", outputPath) - return outputPath, nil + return bs.pdf.BuildInvoice(b.ToInvoice(hc)) } diff --git a/internal/service/booking/service_test.go b/internal/service/booking/service_test.go deleted file mode 100644 index aa7a63b..0000000 --- a/internal/service/booking/service_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package booking - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestService_All(t *testing.T) { - tests := []struct { - name string - mockData []*Line - }{ - { - name: "returns empty list when no bookings", - mockData: []*Line{}, - }, - { - name: "returns list of bookings", - mockData: []*Line{ - { - Id: 1, - CustomerName: "John Doe", - From: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - To: time.Date(2024, 1, 5, 0, 0, 0, 0, time.UTC), - Platform: "Airbnb", - Total: 500.0, - Canceled: false, - }, - { - Id: 2, - CustomerName: "Jane Smith", - From: time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC), - To: time.Date(2024, 2, 3, 0, 0, 0, 0, time.UTC), - Platform: "Booking.com", - Total: 300.0, - Canceled: true, - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create mocks - mockStore := new(MockStore) - mockCalendar := new(MockCalendarClient) - mockPDF := new(MockPDFClient) - - // Set up expectations - mockStore.On("All").Return(tt.mockData) - - // Create service with mocks - service, err := NewService(mockStore, nil, mockCalendar, mockPDF) - assert.NoError(t, err) - - // Call the method - result := service.All() - - // Assert expectations - assert.Equal(t, tt.mockData, result) - mockStore.AssertExpectations(t) - }) - } -} - -func TestService_Search(t *testing.T) { - sampleBookings := []*Line{ - { - Id: 1, - CustomerName: "John Doe", - From: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - To: time.Date(2024, 1, 5, 0, 0, 0, 0, time.UTC), - Platform: "Airbnb", - Total: 500.0, - Canceled: false, - }, - { - Id: 2, - CustomerName: "Jane Smith", - From: time.Date(2024, 2, 1, 0, 0, 0, 0, time.UTC), - To: time.Date(2024, 2, 3, 0, 0, 0, 0, time.UTC), - Platform: "Booking.com", - Total: 300.0, - Canceled: true, - }, - } - - tests := []struct { - name string - searchQuery string - expectedLines []*Line - expectedCalled bool - }{ - { - name: "empty search query returns no results", - searchQuery: "", - expectedLines: []*Line{}, - expectedCalled: false, - }, - { - name: "search for 'John' returns matching booking", - searchQuery: "John", - expectedLines: []*Line{ - sampleBookings[0], - }, - expectedCalled: true, - }, - { - name: "search for 'Smith' returns matching booking", - searchQuery: "Smith", - expectedLines: []*Line{ - sampleBookings[1], - }, - expectedCalled: true, - }, - { - name: "search for non-existent name returns empty list", - searchQuery: "NonExistent", - expectedLines: []*Line{}, - expectedCalled: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create mocks - mockStore := new(MockStore) - mockCalendar := new(MockCalendarClient) - mockPDF := new(MockPDFClient) - - // Set up expectations - mockStore.On("Search", tt.searchQuery).Return(tt.expectedLines) - - // Create service with mocks - service, err := NewService(mockStore, nil, mockCalendar, mockPDF) - assert.NoError(t, err) - - // Call the method - result := service.Search(tt.searchQuery) - - // Assert expectations - assert.Equal(t, tt.expectedLines, result) - mockStore.AssertExpectations(t) - }) - } -} diff --git a/main.go b/main.go index d03ab7c..399174b 100644 --- a/main.go +++ b/main.go @@ -65,12 +65,7 @@ func run(c context.Context, getEnv func(string) string) error { } // build pdf client - pc, err := pdf.NewPdfClient( - getEnv("HTMLDOCS_PROJECT_ID"), - getEnv("HTMLDOCS_REPORT_PROJECT_ID"), - getEnv("HTMLDOCS_URL"), - getEnv("HTMLDOCS_KEY"), - ) + pc, err := pdf.NewPdfClient() if err != nil { return fmt.Errorf("error starting pdf client %w", err) }