Documentation
¶
Overview ¶
Package hubspotsync orchestrates pushing OpenMRP sales orders to HubSpot as Closed-Won deals, upserting the associated company and contact along the way.
It is the single source of truth for the HubSpot mapping and is designed to be shared by both the incremental order-created consumer (this step) and the account backfill worker (a later step). Each operation is idempotent on replay: deals are keyed on the augno_sales_order_id property, contacts dedupe on email, and companies are matched by domain/name before creation.
Index ¶
Constants ¶
const ( StatusPreviewing = "previewing" StatusReviewPending = "review_pending" StatusExecuting = "executing" StatusCompleted = "completed" StatusFailed = "failed" )
Job status values (mirror the hubspot_sync_job.status column).
const ( ReviewStatusPending = "pending" ReviewStatusResolved = "resolved" ReviewStatusSkipped = "skipped" // ReviewResolutionLink / ReviewResolutionCreateNew are persisted resolutions; ReviewActionSkip is a user action that maps to ReviewStatusSkipped. ReviewResolutionLink = "link" ReviewResolutionCreateNew = "create_new" ReviewActionSkip = "skip" )
Company-review queue states and the user actions that resolve them.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CompanyCandidate ¶
type CompanyCandidate struct {
HubspotID string `json:"hubspot_id"`
Name string `json:"name"`
Domain string `json:"domain"`
}
CompanyCandidate is one possible HubSpot company match surfaced to a human for an ambiguous customer. It is the JSON shape stored in hubspot_company_review.candidate_matches.
type Config ¶
type Config struct {
// PipelineID (optional; default: "default") is the HubSpot pipeline won deals are created in.
PipelineID string
// ClosedWonStageID (optional; default: "closedwon") is the HubSpot deal stage applied to won deals.
ClosedWonStageID string
}
Config selects where won deals land. Empty fields fall back to HubSpot's default pipeline / closedwon stage.
func (*Config) WithDefaults ¶
WithDefaults fills zero-value optional fields with production defaults and returns the config. It is safe to call with a nil receiver.
type PreviewCounts ¶
type PreviewCounts struct {
CustomersTotal int `json:"customers_total"`
CompaniesConfident int `json:"companies_confident"` // unique domain match → auto-linked
CompaniesAmbiguous int `json:"companies_ambiguous"` // queued for human review
CompaniesToCreate int `json:"companies_to_create"` // no match → created on execute
ContactsWithEmail int `json:"contacts_with_email"` // customers with an email → contact upsert candidates
}
PreviewCounts is the dry-run report stored in hubspot_sync_job.counts. It tallies what the execute phase would do without writing anything to HubSpot.
type Service ¶
type Service interface {
// SyncOrder upserts the order's company + contact and creates/moves its deal to Closed-Won. It is a no-op (returns nil) when the account has no active HubSpot integration.
SyncOrder(ctx context.Context, accountID, salesOrderID string) *apierror.APIError
// RunPreview executes the read-only matching pass for a backfill job: matches customers to HubSpot companies, queues ambiguous ones for review, tallies the dry-run report, and moves the job to review_pending. Writes nothing to HubSpot.
RunPreview(ctx context.Context, accountID, jobID string) *apierror.APIError
// RunExecute applies a reviewed backfill job to HubSpot (companies + contacts, then Closed-Won deals for orders on/after the cutoff). Gated on zero pending reviews; resumable via per-page cursor checkpoints.
RunExecute(ctx context.Context, accountID, jobID string) *apierror.APIError
}
Service syncs OpenMRP sales orders to a connected HubSpot account.
func NewService ¶
func NewService(repos domain.RepoFactory, clientFactory domain.HubspotClientFactory, encryptionKey []byte, cfg Config) Service