| package addondiff |
|
|
| import ( |
| "fmt" |
| "reflect" |
|
|
| "github.com/samber/lo" |
|
|
| "github.com/openmeterio/openmeter/openmeter/subscription" |
| subscriptionaddon "github.com/openmeterio/openmeter/openmeter/subscription/addon" |
| "github.com/openmeterio/openmeter/pkg/datetime" |
| "github.com/openmeterio/openmeter/pkg/models" |
| ) |
|
|
| func (d *diffable) restore() subscription.AppliesToSpec { |
| return subscription.NewAppliesToSpec(func(spec *subscription.SubscriptionSpec, _ subscription.ApplyContext) error { |
| for _, p := range spec.GetSortedPhases() { |
| pCad, err := spec.GetPhaseCadence(p.PhaseKey) |
| if err != nil { |
| return fmt.Errorf("failed to get phase cadence for phase %s: %w", p.PhaseKey, err) |
| } |
|
|
| for itemsKey := range p.ItemsByKey { |
| aPer := d.addon.CadencedModel.AsPeriod() |
|
|
| affectingAddonRateCard, ok := lo.Find(d.addon.RateCards, func(rc subscriptionaddon.SubscriptionAddonRateCard) bool { |
| return rc.AddonRateCard.Key() == itemsKey |
| }) |
|
|
| |
| if !ok { |
| continue |
| } |
|
|
| |
| rmIdxs := []int{} |
| for idx, item := range p.ItemsByKey[itemsKey] { |
| itemPer := item.GetCadence(pCad).AsPeriod() |
|
|
| if !aPer.IsSupersetOf(itemPer) { |
| continue |
| } |
|
|
| |
| target := item.RateCard.Clone() |
|
|
| if item.Annotations == nil { |
| item.Annotations = models.Annotations{} |
| } |
|
|
| for range d.addon.Quantity { |
| if err := affectingAddonRateCard.Restore(target, item.Annotations, d.addon.Addon.InstanceType); err != nil { |
| return fmt.Errorf("failed to restore addon rate card %s: %w", affectingAddonRateCard.AddonRateCard.Key(), err) |
| } |
| } |
|
|
| item.RateCard = target |
|
|
| |
| chk := zeroRateCardCheck{ |
| itemAnnotations: item.Annotations, |
| rc: target, |
| } |
|
|
| if chk.CanDelete() { |
| rmIdxs = append(rmIdxs, idx) |
| } |
| } |
|
|
| filteredItems := make([]*subscription.SubscriptionItemSpec, 0, len(p.ItemsByKey[itemsKey])-len(rmIdxs)) |
| for idx, item := range p.ItemsByKey[itemsKey] { |
| if lo.Contains(rmIdxs, idx) { |
| continue |
| } |
| filteredItems = append(filteredItems, item) |
| } |
|
|
| |
| |
| |
| mergedItems := make([]*subscription.SubscriptionItemSpec, 0, len(filteredItems)) |
|
|
| var targetItem *subscription.SubscriptionItemSpec |
| for idx := range filteredItems { |
| if targetItem == nil { |
| targetItem = filteredItems[idx] |
| } |
|
|
| if idx+1 >= len(filteredItems) { |
| break |
| } |
|
|
| targetCadence := targetItem.GetCadence(pCad) |
|
|
| testItem := filteredItems[idx+1] |
| testCadence := testItem.GetCadence(pCad) |
|
|
| canMerge := func() bool { |
| |
| if !targetItem.RateCard.Equal(testItem.RateCard) { |
| return false |
| } |
|
|
| if (targetItem.Annotations == nil) != (testItem.Annotations == nil) { |
| return false |
| } |
|
|
| if targetItem.Annotations != nil && !reflect.DeepEqual(targetItem.Annotations, testItem.Annotations) { |
| return false |
| } |
|
|
| if !reflect.DeepEqual(targetItem.BillingBehaviorOverride, testItem.BillingBehaviorOverride) { |
| return false |
| } |
|
|
| |
| if targetCadence.ActiveTo == nil || !targetCadence.ActiveTo.Equal(testCadence.ActiveFrom) { |
| return false |
| } |
|
|
| return true |
| }() |
|
|
| if canMerge { |
| combinedPer := targetCadence.AsPeriod().Union(testCadence.AsPeriod()) |
|
|
| if combinedPer.From != nil && !combinedPer.From.Equal(pCad.ActiveFrom) { |
| targetItem.ActiveFromOverrideRelativeToPhaseStart = lo.ToPtr(datetime.ISODurationBetween(pCad.ActiveFrom, *combinedPer.From)) |
| } |
|
|
| if combinedPer.To == nil { |
| targetItem.ActiveToOverrideRelativeToPhaseStart = nil |
| } |
|
|
| if combinedPer.To != nil && !combinedPer.To.Equal(pCad.ActiveFrom) { |
| targetItem.ActiveToOverrideRelativeToPhaseStart = lo.ToPtr(datetime.ISODurationBetween(pCad.ActiveFrom, *combinedPer.To)) |
| } |
| } else { |
| mergedItems = append(mergedItems, targetItem) |
| targetItem = testItem |
| } |
| } |
|
|
| if targetItem != nil { |
| mergedItems = append(mergedItems, targetItem) |
| } |
|
|
| p.ItemsByKey[itemsKey] = mergedItems |
|
|
| if len(p.ItemsByKey[itemsKey]) == 0 { |
| delete(p.ItemsByKey, itemsKey) |
| } |
| } |
| } |
|
|
| return nil |
| }) |
| } |
|
|