Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grouped-by): Cleanup and fixes to finalize the feature #1685

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ def customer

def subscription
scope = if external_customer_id && customer
customer.subscriptions
if external_subscription_id
customer.subscriptions.where(external_id: external_subscription_id)
else
customer.subscriptions
end
else
organization.subscriptions.where(external_id: external_subscription_id)
end
Expand Down
6 changes: 5 additions & 1 deletion app/services/billable_metrics/aggregations/base_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ def to_datetime
end

def handle_in_advance_current_usage(total_aggregation, target_result: result)
cached_aggregation = find_cached_aggregation(grouped_by: target_result.grouped_by)
cached_aggregation = find_cached_aggregation(
with_from_datetime: from_datetime,
with_to_datetime: to_datetime,
grouped_by: target_result.grouped_by,
)

if cached_aggregation
aggregation = total_aggregation -
Expand Down
15 changes: 7 additions & 8 deletions app/services/billable_metrics/aggregations/sum_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ def compute_pay_in_advance_aggregation

value = event.properties.fetch(billable_metric.field_name, 0).to_s

cached_aggregation = find_cached_aggregation
cached_aggregation = find_cached_aggregation(
with_from_datetime: from_datetime,
with_to_datetime: to_datetime,
grouped_by: grouped_by_values,
)

unless cached_aggregation
return_value = BigDecimal(value).negative? ? '0' : value
Expand Down Expand Up @@ -129,21 +133,16 @@ def compute_per_event_aggregation
# This method fetches the latest cached aggregation in current period. If such a record exists we know that
# previous aggregation and previous maximum aggregation are stored there. Fetching these values
# would help us in pay in advance value calculation without iterating through all events in current period
def find_cached_aggregation(with_from_datetime: from_datetime, with_to_datetime: to_datetime, grouped_by: nil)
def find_cached_aggregation(with_from_datetime:, with_to_datetime:, grouped_by: nil)
query = CachedAggregation
.where(organization_id: billable_metric.organization_id)
.where(external_subscription_id: subscription.external_id)
.where(charge_id: charge.id)
.from_datetime(with_from_datetime)
.to_datetime(with_to_datetime)
.where(grouped_by: grouped_by.presence || {})
.order(timestamp: :desc)

query = if grouped_by.present?
query.where(grouped_by:)
else
query.where(grouped_by: {})
end

query = query.where.not(event_id: event.id) if event.present?
query = query.where(group_id: group.id) if group

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ def compute_pay_in_advance_aggregation

newly_applied_units = (operation_type == :add) ? 1 : 0

cached_aggregation = find_cached_aggregation(grouped_by: grouped_by_values)
cached_aggregation = find_cached_aggregation(
with_from_datetime: from_datetime,
with_to_datetime: to_datetime,
grouped_by: grouped_by_values,
)

unless cached_aggregation
handle_event_metadata(
Expand Down Expand Up @@ -105,7 +109,7 @@ def compute_per_event_aggregation
# This method fetches the latest cached aggregation in current period. If such a record exists we know that
# previous aggregation and previous maximum aggregation are stored there. Fetching these values
# would help us in pay in advance value calculation without iterating through all events in current period
def find_cached_aggregation(with_from_datetime: from_datetime, with_to_datetime: to_datetime, grouped_by: nil)
def find_cached_aggregation(with_from_datetime:, with_to_datetime:, grouped_by: nil)
query = CachedAggregation
.where(organization_id: billable_metric.organization_id)
.where(external_subscription_id: subscription.external_id)
Expand Down Expand Up @@ -141,7 +145,7 @@ def find_cached_aggregation(with_from_datetime: from_datetime, with_to_datetime:
.where('quantified_events.group_id = cached_aggregations.group_id')
end

@cached_aggregation = query.first
query.first
end

def count_unique_group_scope(events)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
module BillableMetrics
module ProratedAggregations
class BaseService < BillableMetrics::Aggregations::BaseService
def aggregation_without_proration
@aggregation_without_proration ||= base_aggregator.aggregate(options:)
end

def compute_pay_in_advance_aggregation
def compute_pay_in_advance_aggregation(aggregation_without_proration:)
return BigDecimal(0) unless event
return BigDecimal(0) if event.properties.blank?

Expand All @@ -25,14 +21,14 @@ def compute_pay_in_advance_aggregation

value = (result_without_proration * proration_coefficient).ceil(5)

extend_cached_aggregation(value)
extend_cached_aggregation(value, aggregation_without_proration)

value
end

# We need to extend cached aggregation with max_aggregation_with_proration. This attribute will be used
# for current usage in pay_in_advance case
def extend_cached_aggregation(prorated_value)
def extend_cached_aggregation(prorated_value, aggregation_without_proration)
result.max_aggregation = aggregation_without_proration.max_aggregation
result.current_aggregation = aggregation_without_proration.current_aggregation

Expand Down Expand Up @@ -60,11 +56,7 @@ def extend_cached_aggregation(prorated_value)
# In current usage section two main values are presented, number of units in period and amount.
# Proration affects only amount (calculated from aggregation) and number of units shows full number of units
# (calculated from current_usage_units).
def handle_current_usage(
result_with_proration, is_pay_in_advance, target_result: result,
aggregation_without_proration: nil
)
aggregation_without_proration ||= self.aggregation_without_proration
def handle_current_usage(result_with_proration, is_pay_in_advance, aggregation_without_proration:, target_result:)
value_without_proration = aggregation_without_proration.aggregation
cached_aggregation = base_aggregator.find_cached_aggregation(
with_from_datetime: from_datetime,
Expand Down
18 changes: 14 additions & 4 deletions app/services/billable_metrics/prorated_aggregations/sum_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def initialize(**args)
end

def compute_aggregation(options: {})
@options = options
aggregation_without_proration = base_aggregator.aggregate(options:)

# For charges that are pay in advance on billing date we always bill full amount
return aggregation_without_proration if event.nil? && options[:is_pay_in_advance] && !options[:is_current_usage]
Expand All @@ -22,12 +22,17 @@ def compute_aggregation(options: {})
result.full_units_number = aggregation_without_proration.aggregation if event.nil?

if options[:is_current_usage]
handle_current_usage(aggregation, options[:is_pay_in_advance])
handle_current_usage(
aggregation,
options[:is_pay_in_advance],
target_result: result,
aggregation_without_proration:,
)
else
result.aggregation = aggregation
end

result.pay_in_advance_aggregation = compute_pay_in_advance_aggregation
result.pay_in_advance_aggregation = compute_pay_in_advance_aggregation(aggregation_without_proration:)
result.count = aggregation_without_proration.count
result.options = options
result
Expand All @@ -44,7 +49,7 @@ def compute_aggregation(options: {})
# as pay in advance aggregation will be computed on a single group
# with the grouped_by_values filter
def compute_grouped_by_aggregation(options: {})
@options = options
aggregation_without_proration = base_aggregator.aggregate(options:)

# For charges that are pay in advance on billing date we always bill full amount
return aggregation_without_proration if event.nil? && options[:is_pay_in_advance] && !options[:is_current_usage]
Expand All @@ -59,6 +64,11 @@ def compute_grouped_by_aggregation(options: {})
agg.grouped_by == aggregation[:groups]
end

unless group_result_without_proration
group_result_without_proration = empty_results.aggregations.first
group_result_without_proration.grouped_by = aggregation[:groups]
end

group_result = BaseService::Result.new
group_result.grouped_by = aggregation[:groups]
group_result.full_units_number = group_result_without_proration&.aggregation || 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def initialize(**args)
end

def compute_aggregation(options: {})
@options = options
aggregation_without_proration = base_aggregator.aggregate(options:)

# For charges that are pay in advance on billing date we always bill full amount
return aggregation_without_proration if event.nil? && options[:is_pay_in_advance] && !options[:is_current_usage]
Expand All @@ -19,12 +19,17 @@ def compute_aggregation(options: {})
result.full_units_number = aggregation_without_proration.aggregation if event.nil?

if options[:is_current_usage]
handle_current_usage(aggregation, options[:is_pay_in_advance])
handle_current_usage(
aggregation,
options[:is_pay_in_advance],
target_result: result,
aggregation_without_proration:,
)
else
result.aggregation = aggregation
end

result.pay_in_advance_aggregation = compute_pay_in_advance_aggregation
result.pay_in_advance_aggregation = compute_pay_in_advance_aggregation(aggregation_without_proration:)
result.options = options
result.count = result.aggregation
result
Expand All @@ -39,7 +44,7 @@ def compute_aggregation(options: {})
# as pay in advance aggregation will be computed on a single group
# with the grouped_by_values filter
def compute_grouped_by_aggregation(options: {})
@options = options
aggregation_without_proration = base_aggregator.aggregate(options:)

# For charges that are pay in advance on billing date we always bill full amount
return aggregation_without_proration if event.nil? && options[:is_pay_in_advance] && !options[:is_current_usage]
Expand Down
Loading
Loading