Documentation
¶
Index ¶
- type AccountRef
- type AccountResponse
- type Address
- type Client
- func (c *Client) CreateCustomer(ctx context.Context, req *CustomerCreateRequest) (*CustomerResponse, error)
- func (c *Client) CreateInvoice(ctx context.Context, req *InvoiceCreateRequest) (*InvoiceResponse, error)
- func (c *Client) CreateItem(ctx context.Context, req *ItemCreateRequest) (*ItemResponse, error)
- func (c *Client) EnsureValidAccessToken(ctx context.Context) error
- func (c *Client) ExchangeAuthCodeForTokens(ctx context.Context) error
- func (c *Client) GetBaseURL(environment string) string
- func (c *Client) GetConnection(ctx context.Context) (*connection.Connection, error)
- func (c *Client) GetDecryptedQuickBooksConfig(conn *connection.Connection) (*QuickBooksConfig, error)
- func (c *Client) GetInvoice(ctx context.Context, invoiceID string) (*InvoiceResponse, error)
- func (c *Client) GetItem(ctx context.Context, itemID string) (*ItemResponse, error)
- func (c *Client) GetPayment(ctx context.Context, paymentID string) (*PaymentResponse, error)
- func (c *Client) GetQuickBooksConfig(ctx context.Context) (*QuickBooksConfig, error)
- func (c *Client) HasQuickBooksConnection(ctx context.Context) bool
- func (c *Client) QueryCustomerByEmail(ctx context.Context, email string) (*CustomerResponse, error)
- func (c *Client) QueryCustomerByName(ctx context.Context, name string) (*CustomerResponse, error)
- func (c *Client) QueryItemByName(ctx context.Context, name string) (*ItemResponse, error)
- func (c *Client) RefreshAccessToken(ctx context.Context) error
- type CustomerCreateRequest
- type CustomerResponse
- type CustomerService
- func (s *CustomerService) GetOrCreateQuickBooksCustomer(ctx context.Context, flexpriceCustomer *customerDomain.Customer) (string, error)
- func (s *CustomerService) GetQuickBooksCustomerID(ctx context.Context, flexpriceCustomerID string) (string, error)
- func (s *CustomerService) SyncCustomerToQuickBooks(ctx context.Context, flexpriceCustomer *customerDomain.Customer) (*CustomerResponse, error)
- type CustomerServiceParams
- type EmailAddress
- type InvoiceCreateRequest
- type InvoiceLineItem
- type InvoiceResponse
- type InvoiceService
- type InvoiceServiceParams
- type ItemCreateRequest
- type ItemResponse
- type ItemSyncService
- type ItemSyncServiceParams
- type LinkedTxn
- type PaymentLine
- type PaymentResponse
- type PaymentService
- type PaymentServiceParams
- type QueryResponse
- type QuickBooksClient
- type QuickBooksConfig
- type QuickBooksCustomerService
- type QuickBooksInvoiceService
- type QuickBooksInvoiceSyncRequest
- type QuickBooksInvoiceSyncResponse
- type QuickBooksItemSyncService
- type QuickBooksItemType
- type QuickBooksPaymentService
- type SalesItemLineDetail
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AccountRef ¶
AccountRef represents a reference to an account
type AccountResponse ¶
type AccountResponse struct {
ID string `json:"Id"`
Name string `json:"Name"`
AccountType string `json:"AccountType"`
Active bool `json:"Active"`
AccountSubType string `json:"AccountSubType,omitempty"`
}
AccountResponse represents an account response from QuickBooks Used in QueryResponse for querying accounts
type Address ¶
type Address struct {
Line1 string `json:"Line1,omitempty"`
Line2 string `json:"Line2,omitempty"`
City string `json:"City,omitempty"`
CountrySubDivisionCode string `json:"CountrySubDivisionCode,omitempty"` // State/Province
PostalCode string `json:"PostalCode,omitempty"`
Country string `json:"Country,omitempty"`
}
Address represents an address in QuickBooks
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client handles QuickBooks API client setup and configuration
func (*Client) CreateCustomer ¶
func (c *Client) CreateCustomer(ctx context.Context, req *CustomerCreateRequest) (*CustomerResponse, error)
CreateCustomer creates a customer in QuickBooks
func (*Client) CreateInvoice ¶
func (c *Client) CreateInvoice(ctx context.Context, req *InvoiceCreateRequest) (*InvoiceResponse, error)
CreateInvoice creates an invoice in QuickBooks
func (*Client) CreateItem ¶
func (c *Client) CreateItem(ctx context.Context, req *ItemCreateRequest) (*ItemResponse, error)
CreateItem creates an item in QuickBooks
func (*Client) EnsureValidAccessToken ¶
EnsureValidAccessToken ensures that a valid access token is available. This method should be called before every API operation: 1. If no access token exists, tries to refresh using refresh_token 2. If access token exists, uses it (no proactive expiration check - relies on reactive refresh on 3200 error) This is the main entry point for token management before API calls.
func (*Client) ExchangeAuthCodeForTokens ¶
ExchangeAuthCodeForTokens exchanges an authorization code for access and refresh tokens. This is called during initial connection setup OR when user re-authenticates after refresh token expiry: 1. Exchanges auth_code (from OAuth redirect) for access_token and refresh_token 2. Encrypts tokens before saving 3. Updates connection in database with encrypted tokens and clears auth_code
func (*Client) GetBaseURL ¶
GetBaseURL returns the QuickBooks API base URL based on environment
func (*Client) GetConnection ¶
func (c *Client) GetConnection(ctx context.Context) (*connection.Connection, error)
GetConnection retrieves the QuickBooks connection for the current context
func (*Client) GetDecryptedQuickBooksConfig ¶
func (c *Client) GetDecryptedQuickBooksConfig(conn *connection.Connection) (*QuickBooksConfig, error)
GetDecryptedQuickBooksConfig decrypts and returns QuickBooks configuration from connection. Decrypts encrypted fields (ClientID, ClientSecret, AccessToken, RefreshToken) using encryption service. RealmID and Environment are stored unencrypted. Defaults to "production" environment if not specified.
func (*Client) GetInvoice ¶
GetInvoice retrieves an invoice by ID from QuickBooks
func (*Client) GetPayment ¶
GetPayment retrieves a payment by ID from QuickBooks
func (*Client) GetQuickBooksConfig ¶
func (c *Client) GetQuickBooksConfig(ctx context.Context) (*QuickBooksConfig, error)
GetQuickBooksConfig retrieves and decrypts QuickBooks configuration for the current environment. Validates that required fields (RealmID and AccessToken) are present. Returns decrypted configuration ready for API calls.
func (*Client) HasQuickBooksConnection ¶
HasQuickBooksConnection checks if QuickBooks connection exists for the current environment
func (*Client) QueryCustomerByEmail ¶
QueryCustomerByEmail queries a customer by email Note: QuickBooks Query API requires backslash escaping for single quotes (e.g., \' )
func (*Client) QueryCustomerByName ¶
QueryCustomerByName queries a customer by display name Note: QuickBooks Query API requires backslash escaping for single quotes (e.g., \' )
func (*Client) QueryItemByName ¶
QueryItemByName queries an item by name Note: QuickBooks Query API requires backslash escaping for single quotes (e.g., \' )
func (*Client) RefreshAccessToken ¶
RefreshAccessToken refreshes the QuickBooks access token using the refresh token. This method implements OAuth 2.0 token refresh flow: 1. Uses refresh_token to get new access_token and refresh_token from QuickBooks OAuth endpoint 2. Encrypts new tokens before saving 3. Updates connection in database with new encrypted tokens 4. Clears auth_code if present This is called automatically when API calls detect token expiration (error code 3200) or by EnsureValidAccessToken.
type CustomerCreateRequest ¶
type CustomerCreateRequest struct {
DisplayName string `json:"DisplayName"`
PrimaryEmailAddr *EmailAddress `json:"PrimaryEmailAddr,omitempty"`
BillAddr *Address `json:"BillAddr,omitempty"`
}
CustomerCreateRequest represents the request to create a customer
type CustomerResponse ¶
type CustomerResponse struct {
ID string `json:"Id"`
SyncToken string `json:"SyncToken,omitempty"`
DisplayName string `json:"DisplayName"`
PrimaryEmailAddr *EmailAddress `json:"PrimaryEmailAddr,omitempty"`
BillAddr *Address `json:"BillAddr,omitempty"`
MetaData struct {
CreateTime string `json:"CreateTime,omitempty"`
LastUpdatedTime string `json:"LastUpdatedTime,omitempty"`
} `json:"MetaData,omitempty"`
}
CustomerResponse represents a customer response from QuickBooks
type CustomerService ¶
type CustomerService struct {
CustomerServiceParams
}
CustomerService handles QuickBooks customer synchronization
func (*CustomerService) GetOrCreateQuickBooksCustomer ¶
func (s *CustomerService) GetOrCreateQuickBooksCustomer(ctx context.Context, flexpriceCustomer *customerDomain.Customer) (string, error)
GetOrCreateQuickBooksCustomer gets existing or creates a new customer in QuickBooks. This method implements the customer sync strategy: 1. First checks if customer is already mapped in entity_integration_mapping 2. If not mapped, tries to find existing customer in QuickBooks by email 3. If not found, creates a new customer in QuickBooks Returns the QuickBooks customer ID for use in invoice creation.
func (*CustomerService) GetQuickBooksCustomerID ¶
func (s *CustomerService) GetQuickBooksCustomerID(ctx context.Context, flexpriceCustomerID string) (string, error)
GetQuickBooksCustomerID retrieves the QuickBooks customer ID from entity mapping
func (*CustomerService) SyncCustomerToQuickBooks ¶
func (s *CustomerService) SyncCustomerToQuickBooks(ctx context.Context, flexpriceCustomer *customerDomain.Customer) (*CustomerResponse, error)
SyncCustomerToQuickBooks syncs Flexprice customer to QuickBooks. Creates a customer in QuickBooks with DisplayName, email, and billing address. If customer creation fails (e.g., name already exists), attempts to find existing customer by name and creates a mapping for it to avoid duplicate creation attempts.
type CustomerServiceParams ¶
type CustomerServiceParams struct {
Client QuickBooksClient
CustomerRepo customerDomain.Repository
EntityIntegrationMappingRepo entityintegrationmapping.Repository
Logger *logger.Logger
}
CustomerServiceParams holds dependencies for CustomerService
type EmailAddress ¶
type EmailAddress struct {
Address string `json:"Address"`
}
EmailAddress represents an email address in QuickBooks
type InvoiceCreateRequest ¶
type InvoiceCreateRequest struct {
CustomerRef AccountRef `json:"CustomerRef"`
Line []InvoiceLineItem `json:"Line"`
DueDate *string `json:"DueDate,omitempty"` // Format: YYYY-MM-DD
}
InvoiceCreateRequest represents the request to create an invoice
type InvoiceLineItem ¶
type InvoiceLineItem struct {
LineNum int `json:"LineNum,omitempty"`
Description string `json:"Description,omitempty"`
Amount decimal.Decimal `json:"Amount"`
DetailType string `json:"DetailType"` // "SalesItemLineDetail"
SalesItemLineDetail *SalesItemLineDetail `json:"SalesItemLineDetail"`
}
InvoiceLineItem represents a line item in invoice request
type InvoiceResponse ¶
type InvoiceResponse struct {
ID string `json:"Id"`
SyncToken string `json:"SyncToken,omitempty"`
DocNumber string `json:"DocNumber,omitempty"`
TxnDate string `json:"TxnDate"`
DueDate string `json:"DueDate,omitempty"`
CustomerRef AccountRef `json:"CustomerRef"`
Line []InvoiceLineItem `json:"Line,omitempty"`
SubTotalAmt decimal.Decimal `json:"SubTotalAmt,omitempty"`
TotalAmt decimal.Decimal `json:"TotalAmt,omitempty"`
Balance decimal.Decimal `json:"Balance,omitempty"`
MetaData struct {
CreateTime string `json:"CreateTime,omitempty"`
LastUpdatedTime string `json:"LastUpdatedTime,omitempty"`
} `json:"MetaData,omitempty"`
}
InvoiceResponse represents an invoice response from QuickBooks
type InvoiceService ¶
type InvoiceService struct {
InvoiceServiceParams
}
InvoiceService handles QuickBooks invoice operations
func (*InvoiceService) SyncInvoiceToQuickBooks ¶
func (s *InvoiceService) SyncInvoiceToQuickBooks( ctx context.Context, req QuickBooksInvoiceSyncRequest, ) (*QuickBooksInvoiceSyncResponse, error)
SyncInvoiceToQuickBooks syncs a Flexprice invoice to QuickBooks. Simple workflow: 1. Check if invoice mapping already exists - if yes, return it 2. Get or create customer in QuickBooks 3. Create invoice in QuickBooks 4. Create mapping
type InvoiceServiceParams ¶
type InvoiceServiceParams struct {
Client QuickBooksClient
CustomerSvc QuickBooksCustomerService
CustomerRepo customer.Repository
InvoiceRepo invoice.Repository
EntityIntegrationMappingRepo entityintegrationmapping.Repository
Logger *logger.Logger
}
InvoiceServiceParams holds dependencies for InvoiceService
type ItemCreateRequest ¶
type ItemCreateRequest struct {
Name string `json:"Name"`
Type string `json:"Type"` // "Service"
Description string `json:"Description,omitempty"`
Active bool `json:"Active,omitempty"`
IncomeAccountRef *AccountRef `json:"IncomeAccountRef"`
UnitPrice *decimal.Decimal `json:"UnitPrice,omitempty"` // Default sales price/rate for the item
}
ItemCreateRequest represents the request to create an item
type ItemResponse ¶
type ItemResponse struct {
ID string `json:"Id"`
SyncToken string `json:"SyncToken,omitempty"`
Name string `json:"Name"`
Type string `json:"Type"`
Description string `json:"Description,omitempty"`
Active bool `json:"Active,omitempty"`
UnitPrice *decimal.Decimal `json:"UnitPrice,omitempty"` // Default sales price/rate
IncomeAccountRef *AccountRef `json:"IncomeAccountRef,omitempty"`
MetaData struct {
CreateTime string `json:"CreateTime,omitempty"`
LastUpdatedTime string `json:"LastUpdatedTime,omitempty"`
} `json:"MetaData,omitempty"`
}
ItemResponse represents an item response from QuickBooks
type ItemSyncService ¶
type ItemSyncService struct {
ItemSyncServiceParams
}
ItemSyncService handles synchronization of Flexprice plans/prices to QuickBooks items
func (*ItemSyncService) SyncPriceToQuickBooks ¶
func (s *ItemSyncService) SyncPriceToQuickBooks(ctx context.Context, plan *plan.Plan, priceToSync *price.Price) error
SyncPriceToQuickBooks syncs a single Flexprice price to QuickBooks as a Service Item. This method is called when a price is created/updated. Item naming logic: - Usage charge (with meter): "{plan_name}-{meter_name}" - Recurring charge (without meter): "{plan_name}-Recurring"
type ItemSyncServiceParams ¶
type ItemSyncServiceParams struct {
Client QuickBooksClient
EntityIntegrationMappingRepo entityintegrationmapping.Repository
MeterRepo meter.Repository
Logger *logger.Logger
}
ItemSyncServiceParams holds dependencies for ItemSyncService
type LinkedTxn ¶
type LinkedTxn struct {
TxnId string `json:"TxnId"` // REQUIRED: Invoice ID in QuickBooks
TxnType string `json:"TxnType"` // REQUIRED: Always "Invoice" for payments
}
LinkedTxn represents a linked transaction (invoice) in a payment
type PaymentLine ¶
type PaymentLine struct {
Amount float64 `json:"Amount"` // REQUIRED: Amount applied to this invoice
LinkedTxn []LinkedTxn `json:"LinkedTxn"` // REQUIRED: Invoice reference (always single invoice)
}
PaymentLine represents a line item in a payment linking to an invoice We always link to exactly ONE invoice (1:1 relationship)
type PaymentResponse ¶
type PaymentResponse struct {
ID string `json:"Id"` // QuickBooks Payment ID
SyncToken string `json:"SyncToken,omitempty"` // Version control for updates (we don't use)
TxnDate string `json:"TxnDate"` // Payment date (YYYY-MM-DD)
TotalAmt float64 `json:"TotalAmt"` // Total payment amount
CustomerRef AccountRef `json:"CustomerRef"` // Customer who made payment
Line []PaymentLine `json:"Line,omitempty"` // CRITICAL: Contains which invoices were paid
PrivateNote string `json:"PrivateNote,omitempty"` // Our memo: "Payment recorded by: flexprice"
}
PaymentResponse represents a payment response from QuickBooks Returned when we GET a payment or CREATE a payment
type PaymentService ¶
type PaymentService struct {
// contains filtered or unexported fields
}
PaymentService handles QuickBooks payment operations
func (*PaymentService) HandleExternalPaymentFromWebhook ¶
func (s *PaymentService) HandleExternalPaymentFromWebhook(ctx context.Context, qbPaymentID string, paymentService interfaces.PaymentService, invoiceService interfaces.InvoiceService) error
HandleExternalPaymentFromWebhook processes a QuickBooks payment webhook (INBOUND SYNC)
FLOW: QuickBooks → Flexprice TRIGGER: When a payment is recorded in QuickBooks (via webhook notification)
WHAT IT DOES: 1. Receives webhook notification (minimal data: just payment ID) 2. Calls QuickBooks API to get full payment details (amount, linked invoice, date) 3. Finds the Flexprice invoice via entity mapping 4. Creates a payment record in Flexprice with QuickBooks details in metadata 5. Uses ReconcilePaymentStatus() to update invoice (supports partial payments!)
IMPORTANT: Now creates payment records, supports partial payments!
type PaymentServiceParams ¶
type PaymentServiceParams struct {
Client QuickBooksClient
InvoiceRepo invoice.Repository
EntityIntegrationMappingRepo entityintegrationmapping.Repository
Logger *logger.Logger
}
PaymentServiceParams contains parameters for creating a PaymentService
type QueryResponse ¶
type QueryResponse struct {
QueryResponse struct {
MaxResults int `json:"maxResults"`
StartPosition int `json:"startPosition"`
TotalCount int `json:"totalCount"`
Customer []CustomerResponse `json:"Customer,omitempty"`
Item []ItemResponse `json:"Item,omitempty"`
Account []AccountResponse `json:"Account,omitempty"`
Payment []PaymentResponse `json:"Payment,omitempty"`
} `json:"QueryResponse"`
}
QueryResponse represents a QuickBooks query API response
type QuickBooksClient ¶
type QuickBooksClient interface {
// Configuration and initialization
GetQuickBooksConfig(ctx context.Context) (*QuickBooksConfig, error)
GetDecryptedQuickBooksConfig(conn *connection.Connection) (*QuickBooksConfig, error)
HasQuickBooksConnection(ctx context.Context) bool
GetConnection(ctx context.Context) (*connection.Connection, error)
// Customer API wrappers
CreateCustomer(ctx context.Context, req *CustomerCreateRequest) (*CustomerResponse, error)
QueryCustomerByEmail(ctx context.Context, email string) (*CustomerResponse, error)
QueryCustomerByName(ctx context.Context, name string) (*CustomerResponse, error)
// Item API wrappers
CreateItem(ctx context.Context, req *ItemCreateRequest) (*ItemResponse, error)
GetItem(ctx context.Context, itemID string) (*ItemResponse, error)
QueryItemByName(ctx context.Context, name string) (*ItemResponse, error)
// Invoice API wrappers
CreateInvoice(ctx context.Context, req *InvoiceCreateRequest) (*InvoiceResponse, error)
GetInvoice(ctx context.Context, invoiceID string) (*InvoiceResponse, error)
// Payment API wrappers (inbound only)
GetPayment(ctx context.Context, paymentID string) (*PaymentResponse, error)
// Token management
ExchangeAuthCodeForTokens(ctx context.Context) error
EnsureValidAccessToken(ctx context.Context) error
RefreshAccessToken(ctx context.Context) error
}
QuickBooksClient defines the interface for QuickBooks API operations
func NewClient ¶
func NewClient( connectionRepo connection.Repository, encryptionService security.EncryptionService, logger *logger.Logger, ) QuickBooksClient
NewClient creates a new QuickBooks client
type QuickBooksConfig ¶
type QuickBooksConfig struct {
ClientID string
ClientSecret string
AccessToken string
RefreshToken string
RealmID string
Environment string // "sandbox" or "production"
AuthCode string // Temporary, for initial token exchange
RedirectURI string // Temporary, for initial token exchange
IncomeAccountID string // Optional: Custom income account ID for items (defaults to "79")
WebhookVerifierToken string // Optional: Webhook verifier token from QuickBooks for webhook signature verification
}
QuickBooksConfig holds decrypted QuickBooks configuration
type QuickBooksCustomerService ¶
type QuickBooksCustomerService interface {
GetOrCreateQuickBooksCustomer(ctx context.Context, flexpriceCustomer *customerDomain.Customer) (string, error)
GetQuickBooksCustomerID(ctx context.Context, flexpriceCustomerID string) (string, error)
}
QuickBooksCustomerService defines the interface for QuickBooks customer operations
func NewCustomerService ¶
func NewCustomerService(params CustomerServiceParams) QuickBooksCustomerService
NewCustomerService creates a new QuickBooks customer service
type QuickBooksInvoiceService ¶
type QuickBooksInvoiceService interface {
SyncInvoiceToQuickBooks(ctx context.Context, req QuickBooksInvoiceSyncRequest) (*QuickBooksInvoiceSyncResponse, error)
}
QuickBooksInvoiceService defines the interface for QuickBooks invoice operations
func NewInvoiceService ¶
func NewInvoiceService(params InvoiceServiceParams) QuickBooksInvoiceService
NewInvoiceService creates a new QuickBooks invoice service
type QuickBooksInvoiceSyncRequest ¶
type QuickBooksInvoiceSyncRequest struct {
InvoiceID string `json:"invoice_id" validate:"required"`
}
QuickBooksInvoiceSyncRequest represents a request to sync an invoice to QuickBooks
type QuickBooksInvoiceSyncResponse ¶
type QuickBooksInvoiceSyncResponse struct {
QuickBooksInvoiceID string `json:"quickbooks_invoice_id"`
Total decimal.Decimal `json:"total"`
Currency string `json:"currency"`
}
QuickBooksInvoiceSyncResponse represents the response from syncing an invoice to QuickBooks
type QuickBooksItemSyncService ¶
type QuickBooksItemSyncService interface {
SyncPriceToQuickBooks(ctx context.Context, plan *plan.Plan, priceToSync *price.Price) error
}
QuickBooksItemSyncService defines the interface for QuickBooks item synchronization
func NewItemSyncService ¶
func NewItemSyncService(params ItemSyncServiceParams) QuickBooksItemSyncService
NewItemSyncService creates a new QuickBooks item sync service
type QuickBooksItemType ¶
type QuickBooksItemType string
QuickBooksItemType represents the type of item in QuickBooks
const ( // ItemTypeService represents a service item in QuickBooks ItemTypeService QuickBooksItemType = "Service" )
type QuickBooksPaymentService ¶
type QuickBooksPaymentService interface {
// HandleExternalPaymentFromWebhook processes a QuickBooks payment webhook (INBOUND ONLY)
HandleExternalPaymentFromWebhook(ctx context.Context, qbPaymentID string, paymentService interfaces.PaymentService, invoiceService interfaces.InvoiceService) error
}
QuickBooksPaymentService defines the interface for QuickBooks payment operations
func NewPaymentService ¶
func NewPaymentService(params PaymentServiceParams) QuickBooksPaymentService
NewPaymentService creates a new QuickBooks payment service
type SalesItemLineDetail ¶
type SalesItemLineDetail struct {
ItemRef AccountRef `json:"ItemRef"`
Qty *decimal.Decimal `json:"Qty,omitempty"`
UnitPrice *decimal.Decimal `json:"UnitPrice,omitempty"`
}
SalesItemLineDetail represents sales item line detail