| package patch |
|
|
| import ( |
| "fmt" |
|
|
| "github.com/openmeterio/openmeter/openmeter/subscription" |
| "github.com/openmeterio/openmeter/pkg/datetime" |
| ) |
|
|
| type PatchRemovePhase struct { |
| PhaseKey string |
| RemoveInput subscription.RemoveSubscriptionPhaseInput |
| } |
|
|
| func (r PatchRemovePhase) Op() subscription.PatchOperation { |
| return subscription.PatchOperationRemove |
| } |
|
|
| func (r PatchRemovePhase) Path() subscription.SpecPath { |
| return subscription.NewPhasePath(r.PhaseKey) |
| } |
|
|
| func (r PatchRemovePhase) Value() subscription.RemoveSubscriptionPhaseInput { |
| return r.RemoveInput |
| } |
|
|
| func (r PatchRemovePhase) ValueAsAny() any { |
| return r.RemoveInput |
| } |
|
|
| func (r PatchRemovePhase) Validate() error { |
| if err := r.Path().Validate(); err != nil { |
| return err |
| } |
|
|
| if err := r.Op().Validate(); err != nil { |
| return err |
| } |
|
|
| return nil |
| } |
|
|
| var _ subscription.ValuePatch[subscription.RemoveSubscriptionPhaseInput] = PatchRemovePhase{} |
|
|
| func (r PatchRemovePhase) ApplyTo(spec *subscription.SubscriptionSpec, actx subscription.ApplyContext) error { |
| phase, exists := spec.Phases[r.PhaseKey] |
| if !exists { |
| return fmt.Errorf("phase %s not found", r.PhaseKey) |
| } |
|
|
| |
| |
| if st, _ := phase.StartAfter.AddTo(spec.ActiveFrom); !st.After(actx.CurrentTime) { |
| return &subscription.PatchForbiddenError{Msg: "cannot remove already started phase"} |
| } |
|
|
| |
| switch r.RemoveInput.Shift { |
| case subscription.RemoveSubscriptionPhaseShiftNext: |
| |
| sortedPhases := spec.GetSortedPhases() |
|
|
| |
| deletedPhaseStart, _ := phase.StartAfter.AddTo(spec.ActiveFrom) |
| var nextPhaseStartAfter datetime.ISODuration |
| for _, p := range spec.GetSortedPhases() { |
| if v, _ := p.StartAfter.AddTo(spec.ActiveFrom); v.After(deletedPhaseStart) { |
| nextPhaseStartAfter = p.StartAfter |
| break |
| } |
| } |
|
|
| if nextPhaseStartAfter.IsZero() { |
| |
| break |
| } |
|
|
| shift, err := nextPhaseStartAfter.Subtract(phase.StartAfter) |
| if err != nil { |
| return fmt.Errorf("failed to calculate shift: %w", err) |
| } |
|
|
| reachedTargetPhase := false |
|
|
| for i, p := range sortedPhases { |
| if v, _ := p.StartAfter.AddTo(spec.ActiveFrom); v.After(deletedPhaseStart) { |
| reachedTargetPhase = true |
| } |
|
|
| if reachedTargetPhase { |
| sa, err := p.StartAfter.Subtract(shift) |
| if err != nil { |
| return fmt.Errorf("failed to shift phase %s: %w", p.PhaseKey, err) |
| } |
| sortedPhases[i].StartAfter = sa |
| } |
| } |
| case subscription.RemoveSubscriptionPhaseShiftPrev: |
| |
| default: |
| return &subscription.PatchValidationError{Msg: fmt.Sprintf("invalid shift behavior: %T", r.RemoveInput.Shift)} |
| } |
|
|
| |
| delete(spec.Phases, r.PhaseKey) |
|
|
| return nil |
| } |
|
|