package ledger import ( "fmt" "github.com/openmeterio/openmeter/pkg/models" ) const ( AnnotationChargeNamespace = "ledger.charge.namespace" AnnotationChargeID = "ledger.charge.id" AnnotationSubscriptionID = "ledger.subscription.id" AnnotationSubscriptionPhaseID = "ledger.subscription.phase.id" AnnotationSubscriptionItemID = "ledger.subscription.item.id" AnnotationFeatureID = "ledger.feature.id" AnnotationTransactionTemplateCode = "ledger.transaction.template_code" AnnotationTransactionDirection = "ledger.transaction.direction" AnnotationCollectionType = "ledger.collection.type" AnnotationCollectionSourceOrder = "ledger.collection.source_order" AnnotationBreakageKind = "ledger.breakage.kind" AnnotationBreakageRecordID = "ledger.breakage.record_id" AnnotationBreakagePlanID = "ledger.breakage.plan_id" ) type ChargeTransactionAnnotationsInput struct { ChargeID models.NamespacedID SubscriptionID *string SubscriptionPhaseID *string SubscriptionItemID *string FeatureID *string } type TransactionDirection string const ( TransactionDirectionForward TransactionDirection = "forward" TransactionDirectionCorrection TransactionDirection = "correction" ) const CollectionTypeBreakage = "breakage" type BreakageKind string const ( BreakageKindPlan BreakageKind = "plan" BreakageKindRelease BreakageKind = "release" BreakageKindReopen BreakageKind = "reopen" ) func (BreakageKind) Values() []string { return []string{ string(BreakageKindPlan), string(BreakageKindRelease), string(BreakageKindReopen), } } type BreakageSourceKind string const ( BreakageSourceKindCreditPurchase BreakageSourceKind = "credit_purchase" BreakageSourceKindUsage BreakageSourceKind = "usage" BreakageSourceKindUsageCorrection BreakageSourceKind = "usage_correction" BreakageSourceKindCreditPurchaseCorrection BreakageSourceKind = "credit_purchase_correction" BreakageSourceKindAdvanceBackfill BreakageSourceKind = "advance_backfill" ) func (BreakageSourceKind) Values() []string { return []string{ string(BreakageSourceKindCreditPurchase), string(BreakageSourceKindUsage), string(BreakageSourceKindUsageCorrection), string(BreakageSourceKindCreditPurchaseCorrection), string(BreakageSourceKindAdvanceBackfill), } } func ChargeAnnotations(chargeID models.NamespacedID) models.Annotations { return models.Annotations{ AnnotationChargeNamespace: chargeID.Namespace, AnnotationChargeID: chargeID.ID, } } func ChargeTransactionAnnotations(input ChargeTransactionAnnotationsInput) models.Annotations { annotations := ChargeAnnotations(input.ChargeID) if input.SubscriptionID != nil && *input.SubscriptionID != "" { annotations[AnnotationSubscriptionID] = *input.SubscriptionID } if input.SubscriptionPhaseID != nil && *input.SubscriptionPhaseID != "" { annotations[AnnotationSubscriptionPhaseID] = *input.SubscriptionPhaseID } if input.SubscriptionItemID != nil && *input.SubscriptionItemID != "" { annotations[AnnotationSubscriptionItemID] = *input.SubscriptionItemID } if input.FeatureID != nil && *input.FeatureID != "" { annotations[AnnotationFeatureID] = *input.FeatureID } return annotations } func TransactionAnnotations(templateCode string, direction TransactionDirection) models.Annotations { return models.Annotations{ AnnotationTransactionTemplateCode: templateCode, AnnotationTransactionDirection: string(direction), } } func BreakageAnnotations(kind BreakageKind, recordID string, planID *string) models.Annotations { annotations := models.Annotations{ AnnotationCollectionType: CollectionTypeBreakage, AnnotationBreakageKind: string(kind), AnnotationBreakageRecordID: recordID, } if planID != nil && *planID != "" { annotations[AnnotationBreakagePlanID] = *planID } return annotations } func TransactionTemplateCodeFromAnnotations(annotations models.Annotations) (string, error) { raw, ok := annotations[AnnotationTransactionTemplateCode] if !ok { return "", fmt.Errorf("transaction template code annotation is required") } code, ok := raw.(string) if !ok || code == "" { return "", fmt.Errorf("transaction template code annotation is invalid") } return code, nil } func TransactionDirectionFromAnnotations(annotations models.Annotations) (TransactionDirection, error) { raw, ok := annotations[AnnotationTransactionDirection] if !ok { return "", fmt.Errorf("transaction direction annotation is required") } value, ok := raw.(string) if !ok || value == "" { return "", fmt.Errorf("transaction direction annotation is invalid") } direction := TransactionDirection(value) switch direction { case TransactionDirectionForward, TransactionDirectionCorrection: return direction, nil default: return "", fmt.Errorf("invalid transaction direction annotation %q", value) } }