package godo import ( "bytes" "context" "fmt" "net/http" "time" ) const invoicesBasePath = "v2/customers/my/invoices" // InvoicesService is an interface for interfacing with the Invoice // endpoints of the DigitalOcean API // See: https://developers.digitalocean.com/documentation/v2/#invoices type InvoicesService interface { Get(context.Context, string, *ListOptions) (*Invoice, *Response, error) GetPDF(context.Context, string) ([]byte, *Response, error) GetCSV(context.Context, string) ([]byte, *Response, error) List(context.Context, *ListOptions) (*InvoiceList, *Response, error) GetSummary(context.Context, string) (*InvoiceSummary, *Response, error) } // InvoicesServiceOp handles communication with the Invoice related methods of // the DigitalOcean API. type InvoicesServiceOp struct { client *Client } var _ InvoicesService = &InvoicesServiceOp{} // Invoice represents a DigitalOcean Invoice type Invoice struct { InvoiceItems []InvoiceItem `json:"invoice_items"` Links *Links `json:"links"` Meta *Meta `json:"meta"` } // InvoiceItem represents a line-item on a DigitalOcean Invoice type InvoiceItem struct { Product string `json:"product"` ResourceID string `json:"resource_id"` ResourceUUID string `json:"resource_uuid"` GroupDescription string `json:"group_description"` Description string `json:"description"` Amount string `json:"amount"` Duration string `json:"duration"` DurationUnit string `json:"duration_unit"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` ProjectName string `json:"project_name"` } // InvoiceList contains a paginated list of all of a customer's invoices. // The InvoicePreview is the month-to-date usage generated by DigitalOcean. type InvoiceList struct { Invoices []InvoiceListItem `json:"invoices"` InvoicePreview InvoiceListItem `json:"invoice_preview"` Links *Links `json:"links"` Meta *Meta `json:"meta"` } // InvoiceListItem contains a small list of information about a customer's invoice. // More information can be found in the Invoice or InvoiceSummary type InvoiceListItem struct { InvoiceUUID string `json:"invoice_uuid"` Amount string `json:"amount"` InvoicePeriod string `json:"invoice_period"` UpdatedAt time.Time `json:"updated_at"` } // InvoiceSummary contains metadata and summarized usage for an invoice generated by DigitalOcean type InvoiceSummary struct { InvoiceUUID string `json:"invoice_uuid"` BillingPeriod string `json:"billing_period"` Amount string `json:"amount"` UserName string `json:"user_name"` UserBillingAddress Address `json:"user_billing_address"` UserCompany string `json:"user_company"` UserEmail string `json:"user_email"` ProductCharges InvoiceSummaryBreakdown `json:"product_charges"` Overages InvoiceSummaryBreakdown `json:"overages"` Taxes InvoiceSummaryBreakdown `json:"taxes"` CreditsAndAdjustments InvoiceSummaryBreakdown `json:"credits_and_adjustments"` } // Address represents the billing address of a customer type Address struct { AddressLine1 string `json:"address_line1"` AddressLine2 string `json:"address_line2"` City string `json:"city"` Region string `json:"region"` PostalCode string `json:"postal_code"` CountryISO2Code string `json:"country_iso2_code"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // InvoiceSummaryBreakdown is a grouped set of InvoiceItems from an invoice type InvoiceSummaryBreakdown struct { Name string `json:"name"` Amount string `json:"amount"` Items []InvoiceSummaryBreakdownItem `json:"items"` } // InvoiceSummaryBreakdownItem further breaks down the InvoiceSummary by product type InvoiceSummaryBreakdownItem struct { Name string `json:"name"` Amount string `json:"amount"` Count string `json:"count"` } func (i Invoice) String() string { return Stringify(i) } // Get detailed invoice items for an Invoice func (s *InvoicesServiceOp) Get(ctx context.Context, invoiceUUID string, opt *ListOptions) (*Invoice, *Response, error) { path := fmt.Sprintf("%s/%s", invoicesBasePath, invoiceUUID) path, err := addOptions(path, opt) if err != nil { return nil, nil, err } req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } root := new(Invoice) resp, err := s.client.Do(ctx, req, root) if err != nil { return nil, resp, err } if l := root.Links; l != nil { resp.Links = l } if m := root.Meta; m != nil { resp.Meta = m } return root, resp, err } // List invoices for a customer func (s *InvoicesServiceOp) List(ctx context.Context, opt *ListOptions) (*InvoiceList, *Response, error) { path := invoicesBasePath path, err := addOptions(path, opt) if err != nil { return nil, nil, err } req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } root := new(InvoiceList) resp, err := s.client.Do(ctx, req, root) if err != nil { return nil, resp, err } if l := root.Links; l != nil { resp.Links = l } if m := root.Meta; m != nil { resp.Meta = m } return root, resp, err } // Get a summary of metadata and summarized usage for an Invoice func (s *InvoicesServiceOp) GetSummary(ctx context.Context, invoiceUUID string) (*InvoiceSummary, *Response, error) { path := fmt.Sprintf("%s/%s/summary", invoicesBasePath, invoiceUUID) req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } root := new(InvoiceSummary) resp, err := s.client.Do(ctx, req, root) if err != nil { return nil, resp, err } return root, resp, err } // Get the pdf for an Invoice func (s *InvoicesServiceOp) GetPDF(ctx context.Context, invoiceUUID string) ([]byte, *Response, error) { path := fmt.Sprintf("%s/%s/pdf", invoicesBasePath, invoiceUUID) req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } var root bytes.Buffer resp, err := s.client.Do(ctx, req, &root) if err != nil { return nil, resp, err } return root.Bytes(), resp, err } // Get the csv for an Invoice func (s *InvoicesServiceOp) GetCSV(ctx context.Context, invoiceUUID string) ([]byte, *Response, error) { path := fmt.Sprintf("%s/%s/csv", invoicesBasePath, invoiceUUID) req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil) if err != nil { return nil, nil, err } var root bytes.Buffer resp, err := s.client.Do(ctx, req, &root) if err != nil { return nil, resp, err } return root.Bytes(), resp, err }