diff --git a/app/controllers/api/v1/billable_metrics/groups_controller.rb b/app/controllers/api/v1/billable_metrics/groups_controller.rb deleted file mode 100644 index 47467d54c2c8..000000000000 --- a/app/controllers/api/v1/billable_metrics/groups_controller.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module Api - module V1 - module BillableMetrics - class GroupsController < Api::BaseController - def index - metric = current_organization.billable_metrics.find_by(code: params[:code]) - return not_found_error(resource: 'billable_metric') unless metric - - groups = metric.selectable_groups - .page(params[:page]).per(params[:per_page] || PER_PAGE) - - render( - json: ::CollectionSerializer.new( - groups, - ::V1::GroupSerializer, - collection_name: 'groups', - meta: pagination_metadata(groups) - ) - ) - end - end - end - end -end diff --git a/app/controllers/api/v1/billable_metrics_controller.rb b/app/controllers/api/v1/billable_metrics_controller.rb index b2060f110ca7..8fb537a49183 100644 --- a/app/controllers/api/v1/billable_metrics_controller.rb +++ b/app/controllers/api/v1/billable_metrics_controller.rb @@ -6,10 +6,7 @@ class BillableMetricsController < Api::BaseController def create service = ::BillableMetrics::CreateService.new result = service.create( - BillableMetricInput.new( - current_organization, - input_params.merge(organization_id: current_organization.id).to_h.deep_symbolize_keys - ).create_input + input_params.merge(organization_id: current_organization.id).to_h.deep_symbolize_keys ) if result.success? @@ -32,10 +29,7 @@ def update result = ::BillableMetrics::UpdateService.call( billable_metric:, - params: BillableMetricInput.new( - current_organization, - input_params.to_h.deep_symbolize_keys - ).update_input + params: input_params.to_h.deep_symbolize_keys ) if result.success? @@ -84,7 +78,7 @@ def show def index metrics = current_organization.billable_metrics - .includes(:filters, :groups) + .includes(:filters) .order(created_at: :desc) .page(params[:page]) .per(params[:per_page] || PER_PAGE) @@ -110,8 +104,7 @@ def input_params :weighted_interval, :recurring, :field_name, - filters: [:key, {values: []}], - group: {} + filters: [:key, {values: []}] ) end end diff --git a/app/controllers/api/v1/plans_controller.rb b/app/controllers/api/v1/plans_controller.rb index 8027bc288009..c50bbdea83f8 100644 --- a/app/controllers/api/v1/plans_controller.rb +++ b/app/controllers/api/v1/plans_controller.rb @@ -6,13 +6,7 @@ class PlansController < Api::BaseController def create service = ::Plans::CreateService.new result = service.create( - PlanLegacyInput.new( - current_organization, - input_params - .merge(organization_id: current_organization.id) - .to_h - .deep_symbolize_keys - ).create_input + input_params.merge(organization_id: current_organization.id).to_h.deep_symbolize_keys ) if result.success? @@ -24,13 +18,7 @@ def create def update plan = current_organization.plans.parents.find_by(code: params[:code]) - result = ::Plans::UpdateService.call( - plan:, - params: PlanLegacyInput.new( - current_organization, - input_params.to_h.deep_symbolize_keys - ).update_input - ) + result = ::Plans::UpdateService.call(plan:, params: input_params.to_h.deep_symbolize_keys) if result.success? render_plan(result.plan) @@ -119,13 +107,6 @@ def input_params } ] }, - { - group_properties: [ - :group_id, - :invoice_display_name, - {values: {}} - ] - }, {tax_codes: []} ] ) diff --git a/app/controllers/api/v1/subscriptions_controller.rb b/app/controllers/api/v1/subscriptions_controller.rb index 654ec28cc006..e4d44469a96f 100644 --- a/app/controllers/api/v1/subscriptions_controller.rb +++ b/app/controllers/api/v1/subscriptions_controller.rb @@ -170,13 +170,6 @@ def plan_overrides } ] }, - { - group_properties: [ - :group_id, - {values: {}}, - :invoice_display_name - ] - }, {tax_codes: []} ] } diff --git a/app/graphql/types/billable_metrics/create_input.rb b/app/graphql/types/billable_metrics/create_input.rb index 53b06f77cff4..8ebbb3cc142b 100644 --- a/app/graphql/types/billable_metrics/create_input.rb +++ b/app/graphql/types/billable_metrics/create_input.rb @@ -14,7 +14,6 @@ class CreateInput < BaseInputObject argument :weighted_interval, Types::BillableMetrics::WeightedIntervalEnum, required: false argument :filters, [Types::BillableMetricFilters::Input], required: false - argument :group, GraphQL::Types::JSON, required: false end end end diff --git a/app/graphql/types/billable_metrics/update_input.rb b/app/graphql/types/billable_metrics/update_input.rb index fa5164b74d90..728cb03a92c9 100644 --- a/app/graphql/types/billable_metrics/update_input.rb +++ b/app/graphql/types/billable_metrics/update_input.rb @@ -16,7 +16,6 @@ class UpdateInput < BaseInputObject argument :weighted_interval, Types::BillableMetrics::WeightedIntervalEnum, required: false argument :filters, [Types::BillableMetricFilters::Input], required: false - argument :group, GraphQL::Types::JSON, required: false end end end diff --git a/app/graphql/types/charges/group_properties.rb b/app/graphql/types/charges/group_properties.rb deleted file mode 100644 index d933ee335034..000000000000 --- a/app/graphql/types/charges/group_properties.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module Types - module Charges - class GroupProperties < Types::BaseObject - field :group_id, ID, null: false - field :invoice_display_name, String, null: true - field :values, Types::Charges::Properties, null: false - - field :deleted_at, GraphQL::Types::ISO8601DateTime, null: true - end - end -end diff --git a/app/graphql/types/charges/group_properties_input.rb b/app/graphql/types/charges/group_properties_input.rb deleted file mode 100644 index 0580e336b7ba..000000000000 --- a/app/graphql/types/charges/group_properties_input.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module Types - module Charges - class GroupPropertiesInput < Types::BaseInputObject - argument :group_id, ID, required: true - argument :invoice_display_name, String, required: false - argument :values, Types::Charges::PropertiesInput, required: true - end - end -end diff --git a/app/graphql/types/groups/object.rb b/app/graphql/types/groups/object.rb deleted file mode 100644 index fc24618784b2..000000000000 --- a/app/graphql/types/groups/object.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Types - module Groups - class Object < Types::BaseObject - graphql_name 'Group' - - field :id, ID, null: false - field :key, String, null: true - field :value, String, null: false - - field :deleted_at, GraphQL::Types::ISO8601DateTime, null: true - - def key - object.parent&.value - end - end - end -end diff --git a/app/graphql/types/groups/usage.rb b/app/graphql/types/groups/usage.rb deleted file mode 100644 index ccd0d983efff..000000000000 --- a/app/graphql/types/groups/usage.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module Types - module Groups - class Usage < Types::BaseObject - graphql_name 'GroupUsage' - - field :amount_cents, GraphQL::Types::BigInt, null: false - field :id, ID, null: false - field :invoice_display_name, String, null: true - field :key, String, null: true - field :units, GraphQL::Types::Float, null: false - field :value, String, null: false - end - end -end diff --git a/app/graphql/types/invoices/invoice_item.rb b/app/graphql/types/invoices/invoice_item.rb index ddc5e3511d4d..96f9c2d58775 100644 --- a/app/graphql/types/invoices/invoice_item.rb +++ b/app/graphql/types/invoices/invoice_item.rb @@ -7,7 +7,6 @@ module InvoiceItem description 'Invoice Item' field :id, ID, null: false - field :group, Types::Groups::Object field :amount_cents, GraphQL::Types::BigInt, null: false field :amount_currency, Types::CurrencyEnum, null: false diff --git a/app/legacy_inputs/billable_metric_input.rb b/app/legacy_inputs/billable_metric_input.rb deleted file mode 100644 index b39183284b33..000000000000 --- a/app/legacy_inputs/billable_metric_input.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -class BillableMetricInput < BaseLegacyInput - def create_input - if args[:group].present? && args[:filters].blank? - return args unless group_args[:key].present? && group_args[:values].present? - - if one_dimension? - args[:filters] = [ - { - key: group_args[:key], - values: group_args[:values] - } - ] - else - args[:filters] = [ - { - key: group_args[:key], - values: group_args[:values].map { |v| v[:name] } - } - ] - - group_args[:values].each do |group| - existing_result = args[:filters].find { |r| r[:key] == group[:key] } - - if existing_result - existing_result[:values] = (existing_result[:values] + group[:values]).uniq - else - args[:filters] << { - key: group[:key], - values: group[:values] - } - end - end - end - elsif args[:filters].present? - args[:group] = {} - end - - args - end - - alias_method :update_input, :create_input - - private - - def group_args - @group_args ||= args[:group] - end - - def one_dimension? - # ie: { key: "region", values: ["USA", "EUROPE"] } - group_args[:key].is_a?(String) && group_args[:values]&.all?(String) - end -end diff --git a/app/legacy_inputs/plan_legacy_input.rb b/app/legacy_inputs/plan_legacy_input.rb deleted file mode 100644 index d7dc4078bffa..000000000000 --- a/app/legacy_inputs/plan_legacy_input.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -class PlanLegacyInput < BaseLegacyInput - def create_input - return args unless args[:charges].is_a?(Array) - return args unless args[:charges].any? { |c| c[:group_properties].present? } - - args[:charges].each do |charge| - next if charge[:group_properties].blank? - next charge[:group] = [] if charge[:filters].present? - - billable_metric = organization.billable_metrics.find_by(id: charge[:billable_metric_id]) - next unless billable_metric - - charge[:filters] = charge[:group_properties].map do |properties| - group = billable_metric.groups.find_by(id: properties[:group_id]) - next unless group - - values = {group.key => [group.value]} - values[group.parent.key] = [group.parent.value] if group.parent - - { - invoice_display_name: properties[:invoice_display_name], - properties: properties[:values], - values: - } - end - - # NOTE: create default filter to keep compatibility with old charges - group_ids = charge[:group_properties].map { |p| p[:group_id] } - - billable_metric.groups.where.not(id: group_ids).includes(:children).find_each do |group| - next if group.children.any? - - values = {group.key => [group.value]} - values[group.parent.key] = [group.parent.value] if group.parent - - charge[:filters] << { - properties: charge[:properties], - values: - } - end - end - - args - end - - alias_method :update_input, :create_input -end diff --git a/app/legacy_inputs/subscription_legacy_input.rb b/app/legacy_inputs/subscription_legacy_input.rb index 20473c57f892..3944ed05ea5f 100644 --- a/app/legacy_inputs/subscription_legacy_input.rb +++ b/app/legacy_inputs/subscription_legacy_input.rb @@ -6,9 +6,6 @@ def create_input args[:subscription_at] ||= date_in_organization_timezone(args[:subscription_date], end_of_day: false) end - return args if args[:plan_overrides].blank? - - args[:plan_overrides] = PlanLegacyInput.new(organization, args[:plan_overrides]).create_input args end alias_method :update_input, :create_input diff --git a/app/models/billable_metric.rb b/app/models/billable_metric.rb index e74ed927cca9..47fc46169663 100644 --- a/app/models/billable_metric.rb +++ b/app/models/billable_metric.rb @@ -59,40 +59,6 @@ def aggregation_type=(value) AGGREGATION_TYPES.key?(value&.to_sym) ? super : nil end - def active_groups - scope = groups - scope = scope.with_discarded if discarded? - scope - end - - # NOTE: 1 dimension: all groups, 2 dimensions: all children. - def selectable_groups - groups = active_groups.children.exists? ? active_groups.children : active_groups - groups.includes(:parent).reorder('parent.value', 'groups.value') - end - - def active_groups_as_tree - return {} if active_groups.blank? - - unless active_groups.children.exists? - return { - key: active_groups.pluck(:key).uniq.first, - values: active_groups.pluck(:value) - } - end - - { - key: active_groups.parents.pluck(:key).uniq.first, - values: active_groups.parents.map do |p| - { - name: p.value, - key: p.children.first.key, - values: p.children.pluck(:value) - } - end - } - end - def payable_in_advance? AGGREGATION_TYPES_PAYABLE_IN_ADVANCE.include?(aggregation_type.to_sym) end diff --git a/app/models/charge.rb b/app/models/charge.rb index 65fc163ae39c..a45dfd75b19a 100644 --- a/app/models/charge.rb +++ b/app/models/charge.rb @@ -46,7 +46,6 @@ class Charge < ApplicationRecord validate :validate_regroup_paid_fees validate :validate_prorated validate :validate_min_amount_cents - validate :validate_uniqueness_group_properties validate :validate_custom_model monetize :min_amount_cents, with_currency: ->(charge) { charge.plan.amount_currency } @@ -55,10 +54,6 @@ class Charge < ApplicationRecord scope :pay_in_advance, -> { where(pay_in_advance: true) } - def properties(group_id: nil) - group_properties.find_by(group_id:)&.values || read_attribute(:properties) - end - private def validate_amount @@ -131,11 +126,6 @@ def validate_prorated errors.add(:prorated, :invalid_billable_metric_or_charge_model) end - def validate_uniqueness_group_properties - group_ids = group_properties.map(&:group_id) - errors.add(:group_properties, :taken) if group_ids.size > group_ids.uniq.size - end - def validate_custom_model return unless custom? return if billable_metric.custom_agg? diff --git a/app/serializers/v1/billable_metric_serializer.rb b/app/serializers/v1/billable_metric_serializer.rb index c3aa5e6a37f8..b058c977f512 100644 --- a/app/serializers/v1/billable_metric_serializer.rb +++ b/app/serializers/v1/billable_metric_serializer.rb @@ -16,7 +16,7 @@ def serialize active_subscriptions_count:, draft_invoices_count:, plans_count: - }.merge(legacy_values) + } payload.merge!(filters) @@ -49,9 +49,5 @@ def filters collection_name: 'filters' ).serialize end - - def legacy_values - V1::Legacy::BillableMetricSerializer.new(model).serialize - end end end diff --git a/app/serializers/v1/charge_serializer.rb b/app/serializers/v1/charge_serializer.rb index 4322e1882992..68db21a7ab31 100644 --- a/app/serializers/v1/charge_serializer.rb +++ b/app/serializers/v1/charge_serializer.rb @@ -16,7 +16,7 @@ def serialize prorated: model.prorated, min_amount_cents: model.min_amount_cents, properties: model.properties - }.merge(legacy_values) + } payload.merge!(charge_filters) @@ -42,9 +42,5 @@ def charge_filters collection_name: 'filters' ).serialize end - - def legacy_values - V1::Legacy::ChargeSerializer.new(model).serialize - end end end diff --git a/app/serializers/v1/group_serializer.rb b/app/serializers/v1/group_serializer.rb deleted file mode 100644 index 7ec0f32477ff..000000000000 --- a/app/serializers/v1/group_serializer.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module V1 - class GroupSerializer < ModelSerializer - def serialize - { - lago_id: model.id, - key: model.parent&.value || model.key, - value: model.value - } - end - end -end diff --git a/app/serializers/v1/legacy/billable_metric_serializer.rb b/app/serializers/v1/legacy/billable_metric_serializer.rb deleted file mode 100644 index ddd4a7f2715c..000000000000 --- a/app/serializers/v1/legacy/billable_metric_serializer.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module V1 - module Legacy - class BillableMetricSerializer < ModelSerializer - def serialize - { - group: model.active_groups_as_tree - } - end - end - end -end diff --git a/app/serializers/v1/legacy/charge_serializer.rb b/app/serializers/v1/legacy/charge_serializer.rb deleted file mode 100644 index eb0a18e6460e..000000000000 --- a/app/serializers/v1/legacy/charge_serializer.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module V1 - module Legacy - class ChargeSerializer < ModelSerializer - def serialize - ::CollectionSerializer.new( - model.group_properties, - ::V1::Legacy::GroupPropertiesSerializer, - collection_name: 'group_properties' - ).serialize - end - end - end -end diff --git a/app/serializers/v1/legacy/group_properties_serializer.rb b/app/serializers/v1/legacy/group_properties_serializer.rb deleted file mode 100644 index f0e7636cad83..000000000000 --- a/app/serializers/v1/legacy/group_properties_serializer.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module V1 - module Legacy - class GroupPropertiesSerializer < ModelSerializer - def serialize - { - group_id: model.group_id, - values: model.values, - invoice_display_name: model.invoice_display_name - } - end - end - end -end diff --git a/app/services/billable_metric_filters/create_or_update_batch_service.rb b/app/services/billable_metric_filters/create_or_update_batch_service.rb index d082c9c24263..10ba905f7760 100644 --- a/app/services/billable_metric_filters/create_or_update_batch_service.rb +++ b/app/services/billable_metric_filters/create_or_update_batch_service.rb @@ -2,10 +2,9 @@ module BillableMetricFilters class CreateOrUpdateBatchService < BaseService - def initialize(billable_metric:, filters_params:, legacy_group_params: nil) + def initialize(billable_metric:, filters_params:) @billable_metric = billable_metric @filters_params = filters_params - @legacy_group_params = legacy_group_params super end @@ -48,9 +47,6 @@ def call billable_metric.filters.where.not(id: result.filters.map(&:id)).find_each do discard_filter(_1) end - - # NOTE: keep compatibility with old group structure by creating the default group properties (as filters) - handle_charge_group_properties if legacy_group_params.present? end refresh_draft_invoices @@ -60,7 +56,7 @@ def call private - attr_reader :billable_metric, :filters_params, :legacy_group_params + attr_reader :billable_metric, :filters_params def discard_all ActiveRecord::Base.transaction do @@ -98,51 +94,5 @@ def refresh_draft_invoices draft_invoices.update_all(ready_to_be_refreshed: true) # rubocop:disable Rails/SkipsModelValidations end - - def handle_charge_group_properties - billable_metric.groups.find_each do |group| - next if group.children.any? - - group_values = group_values(group) - - charges_missing_group(group_values).each do |charge| - filter = charge.filters.create!( - invoice_display_name: nil, - properties: charge[:properties] - ) - - group_values.each do |key, filter_values| - billable_metric_filter = billable_metric.filters.find_by(key:) - - filter.values.create!( - billable_metric_filter_id: billable_metric_filter&.id, - values: filter_values - ) - end - end - end - end - - def group_values(group) - values = {group.key => [group.value]} - values[group.parent.key] = [group.parent.value] if group.parent - values - end - - def charges_missing_group(group_values) - billable_metric.charges.all.select do |charge| - filters = charge.filters.includes(values: :billable_metric_filter) - - filter = filters.find do |f| - next unless f.to_h.sort == group_values.sort - - f.values.all? do |value| - group_values[value.key].sort == value.values.sort - end - end - - filter.nil? - end - end end end diff --git a/app/services/billable_metrics/create_service.rb b/app/services/billable_metrics/create_service.rb index 4f6aa947f937..2d920a88bccb 100644 --- a/app/services/billable_metrics/create_service.rb +++ b/app/services/billable_metrics/create_service.rb @@ -21,14 +21,6 @@ def create(args) weighted_interval: args[:weighted_interval]&.to_sym ) - if args[:group].present? - group_result = Groups::CreateOrUpdateBatchService.call( - billable_metric: metric, - group_params: args[:group].with_indifferent_access - ) - group_result.raise_if_error! - end - if args[:filters].present? BillableMetricFilters::CreateOrUpdateBatchService.call( billable_metric: metric, diff --git a/app/services/billable_metrics/destroy_service.rb b/app/services/billable_metrics/destroy_service.rb index 0e9a17237ba0..29e09d30adf7 100644 --- a/app/services/billable_metrics/destroy_service.rb +++ b/app/services/billable_metrics/destroy_service.rb @@ -16,10 +16,6 @@ def call ActiveRecord::Base.transaction do metric.discard! metric.charges.discard_all - metric.groups.each do |group| - group.properties.discard_all - group.discard! - end discard_filters diff --git a/app/services/billable_metrics/update_service.rb b/app/services/billable_metrics/update_service.rb index 63fe7941fd17..fd5ee645617d 100644 --- a/app/services/billable_metrics/update_service.rb +++ b/app/services/billable_metrics/update_service.rb @@ -22,16 +22,10 @@ def call billable_metric.description = params[:description] if params.key?(:description) ActiveRecord::Base.transaction do - if params.key?(:group) - group_result = update_groups(billable_metric, params[:group]) - group_result.raise_if_error! - end - if params.key?(:filters) BillableMetricFilters::CreateOrUpdateBatchService.call( billable_metric:, - filters_params: params[:filters].map { |f| f.to_h.with_indifferent_access }, - legacy_group_params: params[:group] + filters_params: params[:filters].map { |f| f.to_h.with_indifferent_access } ).raise_if_error! end end @@ -62,12 +56,5 @@ def call attr_reader :billable_metric, :params delegate :organization, to: :billable_metric - - def update_groups(metric, group_params) - Groups::CreateOrUpdateBatchService.call( - billable_metric: metric, - group_params: group_params.with_indifferent_access - ) - end end end diff --git a/app/services/events/post_validation_service.rb b/app/services/events/post_validation_service.rb index 0218a0f15c03..916575248144 100644 --- a/app/services/events/post_validation_service.rb +++ b/app/services/events/post_validation_service.rb @@ -12,13 +12,11 @@ def call errors = { invalid_code: process_query(invalid_code_query), missing_aggregation_property: process_query(missing_aggregation_property_query), - missing_group_key: process_query(missing_group_key_query), invalid_filter_values: process_query(invalid_filter_values_query) } if errors[:invalid_code].present? || errors[:missing_aggregation_property].present? || - errors[:missing_group_key].present? || errors[:invalid_filter_values].present? deliver_webhook(errors) end @@ -58,24 +56,6 @@ def missing_aggregation_property_query SQL end - def missing_group_key_query - <<-SQL - SELECT DISTINCT transaction_id - FROM last_hour_events_mv - WHERE organization_id = '#{organization.id}' - AND ( - ( - parent_group_mandatory = 't' - AND has_parent_group_key = 'f' - ) - OR ( - child_group_mandatory = 't' - AND has_child_group_key = 'f' - ) - ) - SQL - end - def invalid_filter_values_query <<-SQL SELECT DISTINCT transaction_id diff --git a/app/services/group_properties/create_or_update_batch_service.rb b/app/services/group_properties/create_or_update_batch_service.rb deleted file mode 100644 index 71a3203b34ef..000000000000 --- a/app/services/group_properties/create_or_update_batch_service.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -module GroupProperties - class CreateOrUpdateBatchService < BaseService - def initialize(charge:, properties_params:) - @charge = charge - @properties_params = properties_params - - super - end - - def call - if properties_params.empty? - charge.group_properties.discard_all - return result - end - - charge.group_properties.where.not(group_id: properties_params.map { |gp| gp[:group_id] }).discard_all - properties_params.each do |params| - property = charge.group_properties.find_by(group_id: params[:group_id]) - - if property - property.update!(values: params[:values], invoice_display_name: params[:invoice_display_name]) - else - charge.group_properties.create!( - group_id: params[:group_id], - values: params[:values], - invoice_display_name: params[:invoice_display_name] - ) - end - end - - charge.plan.invoices.draft.update_all(ready_to_be_refreshed: true) # rubocop:disable Rails/SkipsModelValidations - - result - end - - private - - attr_reader :charge, :properties_params - end -end diff --git a/app/services/groups/create_or_update_batch_service.rb b/app/services/groups/create_or_update_batch_service.rb deleted file mode 100644 index 303338fbdcaa..000000000000 --- a/app/services/groups/create_or_update_batch_service.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -module Groups - class CreateOrUpdateBatchService < BaseService - def initialize(billable_metric:, group_params:) - @billable_metric = billable_metric - @group_params = group_params - - super - end - - def call - if group_params.empty? - billable_metric.groups.each(&:discard_with_properties!) - return result - end - - return result.validation_failure!(errors: {group: %w[value_is_invalid]}) unless valid_format? - - ActiveRecord::Base.transaction do - if one_dimension? - billable_metric.groups.each(&:discard_with_properties!) if billable_metric.groups.children.any? - assign_groups(group_params[:key], group_params[:values].uniq) - else - billable_metric.groups.parents.where.not( - value: group_params[:values].map { |v| v[:name] }, - key: group_params[:key] - ).find_each(&:discard_with_properties!) - - billable_metric.groups.parents.each { |g| g.properties.discard_all } - - group_params[:values].each do |value| - parent_group = billable_metric.groups.find_or_create_by!(key: group_params[:key], value: value[:name]) - assign_groups(value[:key], value[:values].uniq, parent_group.id) - end - end - end - - draft_invoices = Invoice.draft.joins(plans: [:billable_metrics]) - .where(billable_metrics: {id: billable_metric.id}) - .distinct - draft_invoices.update_all(ready_to_be_refreshed: true) # rubocop:disable Rails/SkipsModelValidations - - result - end - - private - - attr_reader :billable_metric, :group_params - - # One dimension: - # { key: "region", values: ["USA", "EUROPE"] } - # - # Two dimensions: - # { - # key: "region", - # values: [{ - # name: "Africa", - # key: "cloud", - # values: ["Google cloud", "AWS", "Qovery", "Cloudfare"] - # }, { - # name: "America", - # key: "cloud", - # values: ["Google cloud", "AWS"] - # }] - # } - def valid_format? - return false unless group_params[:key].is_a?(String) && group_params[:values].is_a?(Array) - return false if group_params[:values].empty? - return true if one_dimension? - return false unless group_params[:values].all?(Hash) - return false if group_params[:values].any? { |v| v[:values].blank? } - - group_params[:values].map { |e| [e[:name], e[:key], e[:values]] }.flatten.all?(String) - end - - def assign_groups(key, values, parent_group_id = nil) - groups_to_discard = billable_metric.groups.where.not(key:, value: values) - groups_to_discard = groups_to_discard.where(parent_group_id:).children if parent_group_id - groups_to_discard.each(&:discard_with_properties!) - - values.each do |value| - next if billable_metric.groups.find_by(key:, value:, parent_group_id:) - - billable_metric.groups.create!(key:, value:, parent_group_id:) - end - end - - def one_dimension? - # ie: { key: "region", values: ["USA", "EUROPE"] } - group_params[:key].is_a?(String) && group_params[:values]&.all?(String) - end - end -end diff --git a/app/services/plans/create_service.rb b/app/services/plans/create_service.rb index 723e1f756da4..4f1b20e4376e 100644 --- a/app/services/plans/create_service.rb +++ b/app/services/plans/create_service.rb @@ -83,8 +83,7 @@ def create_charge(plan, args) invoice_display_name: args[:invoice_display_name], charge_model: charge_model(args), pay_in_advance: args[:pay_in_advance] || false, - prorated: args[:prorated] || false, - group_properties: (args[:group_properties] || []).map { |gp| GroupProperty.new(gp) } + prorated: args[:prorated] || false ) properties = args[:properties].presence || Charges::BuildDefaultPropertiesService.call(charge_model(args)) diff --git a/app/services/plans/override_service.rb b/app/services/plans/override_service.rb index c63bca5749c1..0e2f0a7bee50 100644 --- a/app/services/plans/override_service.rb +++ b/app/services/plans/override_service.rb @@ -29,7 +29,7 @@ def call taxes_result.raise_if_error! end - plan.charges.includes(:group_properties).find_each do |charge| + plan.charges.find_each do |charge| charge_params = ( params[:charges]&.find { |p| p[:id] == charge.id } || {} ).merge(plan_id: new_plan.id) diff --git a/app/services/plans/update_service.rb b/app/services/plans/update_service.rb index ecf7234bb7d9..a0b762744c52 100644 --- a/app/services/plans/update_service.rb +++ b/app/services/plans/update_service.rb @@ -79,8 +79,7 @@ def create_charge(plan, params) amount_currency: params[:amount_currency], charge_model: charge_model(params), pay_in_advance: params[:pay_in_advance] || false, - prorated: params[:prorated] || false, - group_properties: (params[:group_properties] || []).map { |gp| GroupProperty.new(gp) } + prorated: params[:prorated] || false ) properties = params[:properties].presence || Charges::BuildDefaultPropertiesService.call(charge.charge_model) @@ -151,15 +150,6 @@ def process_charges(plan, params_charges) if charge charge.charge_model = payload_charge[:charge_model] unless plan.attached_to_subscriptions? - group_properties = payload_charge.delete(:group_properties) - if group_properties.present? - group_result = GroupProperties::CreateOrUpdateBatchService.call( - charge:, - properties_params: group_properties - ) - return group_result if group_result.error - end - properties = payload_charge.delete(:properties).presence || Charges::BuildDefaultPropertiesService.call( payload_charge[:charge_model] ) @@ -220,7 +210,6 @@ def discard_charge!(charge) .where(charges: {id: charge.id}).distinct.pluck(:id) charge.discard! - charge.group_properties.discard_all charge.filter_values.discard_all charge.filters.discard_all diff --git a/config/routes.rb b/config/routes.rb index 6b7c2b9be448..283f99147fe4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -39,7 +39,6 @@ resources :add_ons, param: :code resources :billable_metrics, param: :code - get '/billable_metrics/:code/groups', to: 'billable_metrics/groups#index', as: 'billable_metric_groups' resources :coupons, param: :code resources :credit_notes, only: %i[create update show index] do diff --git a/db/migrate/20240708081356_update_last_hour_events_mv_v04.rb b/db/migrate/20240708081356_update_last_hour_events_mv_v04.rb new file mode 100644 index 000000000000..6b6a3294124a --- /dev/null +++ b/db/migrate/20240708081356_update_last_hour_events_mv_v04.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class UpdateLastHourEventsMvV04 < ActiveRecord::Migration[7.1] + def change + drop_view :last_hour_events_mv, materialized: true + create_view :last_hour_events_mv, materialized: true, version: 4 + end +end diff --git a/db/schema.rb b/db/schema.rb index 3fa568fa97e7..b49efc966d68 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_07_06_204557) do +ActiveRecord::Schema[7.1].define(version: 2024_07_08_081356) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -1169,52 +1169,6 @@ add_foreign_key "webhook_endpoints", "organizations" add_foreign_key "webhooks", "webhook_endpoints" - create_view "last_hour_events_mv", materialized: true, sql_definition: <<-SQL - WITH billable_metric_groups AS ( - SELECT billable_metrics_1.organization_id AS bm_organization_id, - billable_metrics_1.id AS bm_id, - billable_metrics_1.code AS bm_code, - count(parent_groups.id) AS parent_group_count, - array_agg(parent_groups.key) AS parent_group_keys, - count(child_groups.id) AS child_group_count, - array_agg(child_groups.key) AS child_group_keys - FROM ((billable_metrics billable_metrics_1 - LEFT JOIN groups parent_groups ON (((parent_groups.billable_metric_id = billable_metrics_1.id) AND (parent_groups.parent_group_id IS NULL) AND (parent_groups.deleted_at IS NULL)))) - LEFT JOIN groups child_groups ON (((child_groups.billable_metric_id = billable_metrics_1.id) AND (child_groups.parent_group_id IS NOT NULL) AND (child_groups.deleted_at IS NULL)))) - WHERE (billable_metrics_1.deleted_at IS NULL) - GROUP BY billable_metrics_1.id, billable_metrics_1.code - ), billable_metric_filters AS ( - SELECT billable_metrics_1.organization_id AS bm_organization_id, - billable_metrics_1.id AS bm_id, - billable_metrics_1.code AS bm_code, - filters.key AS filter_key, - filters."values" AS filter_values - FROM (billable_metrics billable_metrics_1 - JOIN public.billable_metric_filters filters ON ((filters.billable_metric_id = billable_metrics_1.id))) - WHERE ((billable_metrics_1.deleted_at IS NULL) AND (filters.deleted_at IS NULL)) - ) - SELECT events.organization_id, - events.transaction_id, - events.properties, - billable_metrics.code AS billable_metric_code, - (billable_metrics.aggregation_type <> 0) AS field_name_mandatory, - (billable_metrics.aggregation_type = ANY (ARRAY[1, 2, 5, 6])) AS numeric_field_mandatory, - (events.properties ->> (billable_metrics.field_name)::text) AS field_value, - ((events.properties ->> (billable_metrics.field_name)::text) ~ '^-?\\d+(\\.\\d+)?$'::text) AS is_numeric_field_value, - (COALESCE(billable_metric_groups.parent_group_count, (0)::bigint) > 0) AS parent_group_mandatory, - (events.properties ?| (billable_metric_groups.parent_group_keys)::text[]) AS has_parent_group_key, - (COALESCE(billable_metric_groups.child_group_count, (0)::bigint) > 0) AS child_group_mandatory, - (events.properties ?| (billable_metric_groups.child_group_keys)::text[]) AS has_child_group_key, - (events.properties ? (billable_metric_filters.filter_key)::text) AS has_filter_keys, - ((events.properties ->> (billable_metric_filters.filter_key)::text) = ANY ((billable_metric_filters.filter_values)::text[])) AS has_valid_filter_values - FROM (((events - LEFT JOIN billable_metrics ON ((((billable_metrics.code)::text = (events.code)::text) AND (events.organization_id = billable_metrics.organization_id)))) - LEFT JOIN billable_metric_groups ON ((billable_metrics.id = billable_metric_groups.bm_id))) - LEFT JOIN billable_metric_filters ON ((billable_metrics.id = billable_metric_filters.bm_id))) - WHERE ((events.deleted_at IS NULL) AND (events.created_at >= (date_trunc('hour'::text, now()) - 'PT1H'::interval)) AND (events.created_at < date_trunc('hour'::text, now())) AND (billable_metrics.deleted_at IS NULL)); - SQL - add_index "last_hour_events_mv", ["organization_id"], name: "index_last_hour_events_mv_on_organization_id" - create_view "billable_metrics_grouped_charges", sql_definition: <<-SQL SELECT billable_metrics.organization_id, billable_metrics.code, @@ -1240,4 +1194,30 @@ WHERE ((billable_metrics.deleted_at IS NULL) AND (charges.deleted_at IS NULL) AND (charges.pay_in_advance = false) AND (charge_filters.deleted_at IS NULL) AND (charge_filter_values.deleted_at IS NULL) AND (billable_metric_filters.deleted_at IS NULL)) GROUP BY billable_metrics.organization_id, billable_metrics.code, billable_metrics.aggregation_type, billable_metrics.field_name, charges.plan_id, charges.id, charge_filters.id; SQL + create_view "last_hour_events_mv", materialized: true, sql_definition: <<-SQL + WITH billable_metric_filters AS ( + SELECT billable_metrics_1.organization_id AS bm_organization_id, + billable_metrics_1.id AS bm_id, + billable_metrics_1.code AS bm_code, + filters.key AS filter_key, + filters."values" AS filter_values + FROM (billable_metrics billable_metrics_1 + JOIN public.billable_metric_filters filters ON ((filters.billable_metric_id = billable_metrics_1.id))) + WHERE ((billable_metrics_1.deleted_at IS NULL) AND (filters.deleted_at IS NULL)) + ) + SELECT events.organization_id, + events.transaction_id, + events.properties, + billable_metrics.code AS billable_metric_code, + (billable_metrics.aggregation_type <> 0) AS field_name_mandatory, + (billable_metrics.aggregation_type = ANY (ARRAY[1, 2, 5, 6])) AS numeric_field_mandatory, + (events.properties ->> (billable_metrics.field_name)::text) AS field_value, + ((events.properties ->> (billable_metrics.field_name)::text) ~ '^-?\\d+(\\.\\d+)?$'::text) AS is_numeric_field_value, + (events.properties ? (billable_metric_filters.filter_key)::text) AS has_filter_keys, + ((events.properties ->> (billable_metric_filters.filter_key)::text) = ANY ((billable_metric_filters.filter_values)::text[])) AS has_valid_filter_values + FROM ((events + LEFT JOIN billable_metrics ON ((((billable_metrics.code)::text = (events.code)::text) AND (events.organization_id = billable_metrics.organization_id)))) + LEFT JOIN billable_metric_filters ON ((billable_metrics.id = billable_metric_filters.bm_id))) + WHERE ((events.deleted_at IS NULL) AND (events.created_at >= (date_trunc('hour'::text, now()) - 'PT1H'::interval)) AND (events.created_at < date_trunc('hour'::text, now())) AND (billable_metrics.deleted_at IS NULL)); + SQL end diff --git a/db/views/last_hour_events_mv_v04.sql b/db/views/last_hour_events_mv_v04.sql new file mode 100644 index 000000000000..f5710950ca99 --- /dev/null +++ b/db/views/last_hour_events_mv_v04.sql @@ -0,0 +1,37 @@ +WITH billable_metric_filters as ( + SELECT + billable_metrics.organization_id as bm_organization_id, + billable_metrics.id AS bm_id, + billable_metrics.code AS bm_code, + filters.key AS filter_key, + filters.values AS filter_values + FROM billable_metrics + INNER JOIN billable_metric_filters filters + ON filters.billable_metric_id = billable_metrics.id + WHERE + billable_metrics.deleted_at IS NULL + AND filters.deleted_at IS NULL +) + + +SELECT + events.organization_id, + events.transaction_id, + events.properties, + billable_metrics.code AS billable_metric_code, + billable_metrics.aggregation_type != 0 AS field_name_mandatory, + billable_metrics.aggregation_type IN (1,2,5,6) AS numeric_field_mandatory, + events.properties ->> billable_metrics.field_name::text AS field_value, + events.properties ->> billable_metrics.field_name::text ~ '^-?\d+(\.\d+)?$' AS is_numeric_field_value, + events.properties ? billable_metric_filters.filter_key as has_filter_keys, + (events.properties ->> billable_metric_filters.filter_key) = ANY (billable_metric_filters.filter_values) as has_valid_filter_values +FROM + events + LEFT JOIN billable_metrics ON billable_metrics.code = events.code + AND events.organization_id = billable_metrics.organization_id + LEFT JOIN billable_metric_filters ON billable_metrics.id = billable_metric_filters.bm_id +WHERE + events.deleted_at IS NULL + AND events.created_at >= date_trunc('hour', NOW()) - INTERVAL '1 hour' + AND events.created_at < date_trunc('hour', NOW()) + AND billable_metrics.deleted_at IS NULL diff --git a/schema.graphql b/schema.graphql index b2518944b4cd..1435e1d9b44a 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1783,7 +1783,6 @@ input CreateBillableMetricInput { description: String! fieldName: String filters: [BillableMetricFiltersInput!] - group: JSON name: String! recurring: Boolean weightedInterval: WeightedIntervalEnum @@ -3486,7 +3485,6 @@ type Fee implements InvoiceItem { description: String eventsCount: BigInt feeType: FeeTypesEnum! - group: Group groupedBy: JSON! id: ID! invoiceDisplayName: String @@ -3762,13 +3760,6 @@ type GrossRevenueCollection { metadata: CollectionMetadata! } -type Group { - deletedAt: ISO8601DateTime - id: ID! - key: String - value: String! -} - type GroupedChargeUsage { amountCents: BigInt! eventsCount: Int! @@ -3923,7 +3914,6 @@ Invoice Item interface InvoiceItem { amountCents: BigInt! amountCurrency: CurrencyEnum! - group: Group id: ID! itemCode: String! itemName: String! @@ -6946,7 +6936,6 @@ input UpdateBillableMetricInput { description: String! fieldName: String filters: [BillableMetricFiltersInput!] - group: JSON id: String! name: String! recurring: Boolean diff --git a/schema.json b/schema.json index 6c202814959a..9a6fb5cf5088 100644 --- a/schema.json +++ b/schema.json @@ -6732,18 +6732,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "group", - "description": null, - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", @@ -15143,20 +15131,6 @@ ] }, - { - "name": "group", - "description": null, - "type": { - "kind": "OBJECT", - "name": "Group", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - }, { "name": "groupedBy", "description": null, @@ -17509,83 +17483,6 @@ "inputFields": null, "enumValues": null }, - { - "kind": "OBJECT", - "name": "Group", - "description": null, - "interfaces": [ - - ], - "possibleTypes": null, - "fields": [ - { - "name": "deletedAt", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ISO8601DateTime", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - }, - { - "name": "key", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - }, - { - "name": "value", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - } - ], - "inputFields": null, - "enumValues": null - }, { "kind": "OBJECT", "name": "GroupedChargeUsage", @@ -19443,20 +19340,6 @@ ] }, - { - "name": "group", - "description": null, - "type": { - "kind": "OBJECT", - "name": "Group", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - - ] - }, { "name": "id", "description": null, @@ -33782,18 +33665,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "group", - "description": null, - "type": { - "kind": "SCALAR", - "name": "JSON", - "ofType": null - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", diff --git a/spec/factories/group_properties.rb b/spec/factories/group_properties.rb deleted file mode 100644 index d593d5b2978d..000000000000 --- a/spec/factories/group_properties.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :group_property do - association :charge, factory: :standard_charge - group - values do - {amount: Faker::Number.between(from: 100, to: 500).to_s} - end - invoice_display_name { Faker::Fantasy::Tolkien.character } - end -end diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb deleted file mode 100644 index b4930f7db771..000000000000 --- a/spec/factories/groups.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :group do - billable_metric - key { 'region' } - value { 'europe' } - end -end diff --git a/spec/graphql/types/billable_metrics/create_input_spec.rb b/spec/graphql/types/billable_metrics/create_input_spec.rb index b69bc3528571..33a108130e57 100644 --- a/spec/graphql/types/billable_metrics/create_input_spec.rb +++ b/spec/graphql/types/billable_metrics/create_input_spec.rb @@ -13,5 +13,4 @@ it { is_expected.to accept_argument(:recurring).of_type('Boolean') } it { is_expected.to accept_argument(:weighted_interval).of_type('WeightedIntervalEnum') } it { is_expected.to accept_argument(:filters).of_type('[BillableMetricFiltersInput!]') } - it { is_expected.to accept_argument(:group).of_type('JSON') } end diff --git a/spec/graphql/types/billable_metrics/update_input_spec.rb b/spec/graphql/types/billable_metrics/update_input_spec.rb index 31711c90a42d..6a64dbd81d65 100644 --- a/spec/graphql/types/billable_metrics/update_input_spec.rb +++ b/spec/graphql/types/billable_metrics/update_input_spec.rb @@ -14,5 +14,4 @@ it { is_expected.to accept_argument(:recurring).of_type('Boolean') } it { is_expected.to accept_argument(:weighted_interval).of_type('WeightedIntervalEnum') } it { is_expected.to accept_argument(:filters).of_type('[BillableMetricFiltersInput!]') } - it { is_expected.to accept_argument(:group).of_type('JSON') } end diff --git a/spec/graphql/types/charges/group_properties_spec.rb b/spec/graphql/types/charges/group_properties_spec.rb deleted file mode 100644 index 7cbae497a813..000000000000 --- a/spec/graphql/types/charges/group_properties_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Types::Charges::GroupProperties do - subject { described_class } - - it { is_expected.to have_field(:group_id).of_type('ID!') } - it { is_expected.to have_field(:invoice_display_name).of_type('String') } - it { is_expected.to have_field(:values).of_type('Properties!') } - it { is_expected.to have_field(:deleted_at).of_type('ISO8601DateTime') } -end diff --git a/spec/graphql/types/groups/object_spec.rb b/spec/graphql/types/groups/object_spec.rb deleted file mode 100644 index eecb9fb0ae5c..000000000000 --- a/spec/graphql/types/groups/object_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Types::Groups::Object do - subject { described_class } - - it { is_expected.to have_field(:id).of_type('ID!') } - it { is_expected.to have_field(:key).of_type('String') } - it { is_expected.to have_field(:value).of_type('String!') } - - it { is_expected.to have_field(:deleted_at).of_type('ISO8601DateTime') } -end diff --git a/spec/models/billable_metric_spec.rb b/spec/models/billable_metric_spec.rb index 95b2796b4648..e3480e5eef8e 100644 --- a/spec/models/billable_metric_spec.rb +++ b/spec/models/billable_metric_spec.rb @@ -71,99 +71,6 @@ end end - describe '#selectable_groups' do - context 'without active groups' do - it 'returns an empty collection' do - expect(billable_metric.selectable_groups).to be_empty - end - end - - context 'when groups contain one dimension' do - it 'returns all groups' do - one = create(:group, billable_metric:, key: 'country', value: 'france') - second = create(:group, billable_metric:, key: 'country', value: 'italy') - - expect(billable_metric.selectable_groups).to contain_exactly(one, second) - end - end - - context 'when groups contain two dimensions' do - it 'returns only children groups' do - france = create(:group, billable_metric:, key: 'country', value: 'france') - italy = create(:group, billable_metric:, key: 'country', value: 'italy') - one = create(:group, billable_metric:, key: 'cloud', value: 'aws', parent_group_id: france.id) - second = create(:group, billable_metric:, key: 'cloud', value: 'google', parent_group_id: france.id) - third = create(:group, billable_metric:, key: 'cloud', value: 'google', parent_group_id: italy.id) - - expect(billable_metric.selectable_groups).to contain_exactly(one, second, third) - end - end - - context 'when billable metric and group are deleted' do - it 'returns all groups' do - billable_metric.discard! - one = create(:group, :deleted, billable_metric:, key: 'country', value: 'france') - second = create(:group, :deleted, billable_metric:, key: 'country', value: 'italy') - - expect(billable_metric.selectable_groups).to contain_exactly(one, second) - end - end - end - - describe '#active_groups_as_tree' do - context 'without active groups' do - it 'returns {}' do - expect(billable_metric.active_groups_as_tree).to eq({}) - end - end - - context 'when groups contain one dimension' do - before do - create(:group, billable_metric:, key: 'country', value: 'france') - create(:group, billable_metric:, key: 'country', value: 'italy') - end - - it 'returns a tree with one dimension' do - expect(billable_metric.active_groups_as_tree).to eq( - { - key: 'country', - values: %w[france italy] - } - ) - end - end - - context 'when groups contain two dimensions' do - before do - france = create(:group, billable_metric:, key: 'country', value: 'france') - italy = create(:group, billable_metric:, key: 'country', value: 'italy') - create(:group, billable_metric:, key: 'cloud', value: 'aws', parent_group_id: france.id) - create(:group, billable_metric:, key: 'cloud', value: 'google', parent_group_id: france.id) - create(:group, billable_metric:, key: 'cloud', value: 'google', parent_group_id: italy.id) - end - - it 'returns a tree with two dimensions' do - expect(billable_metric.active_groups_as_tree).to eq( - { - key: 'country', - values: [ - { - name: 'france', - key: 'cloud', - values: %w[aws google] - }, - { - name: 'italy', - key: 'cloud', - values: %w[google] - } - ] - } - ) - end - end - end - describe '#payable_in_advance?' do it do described_class::AGGREGATION_TYPES_PAYABLE_IN_ADVANCE.each do |agg| diff --git a/spec/models/charge_spec.rb b/spec/models/charge_spec.rb index 7a59e7a1d090..2c0691a666d0 100644 --- a/spec/models/charge_spec.rb +++ b/spec/models/charge_spec.rb @@ -9,21 +9,6 @@ it { is_expected.to have_many(:filters).dependent(:destroy) } - describe '#properties' do - context 'with group properties' do - it 'returns the group properties' do - property = create(:group_property, charge:, values: {foo: 'bar'}) - expect(charge.properties(group_id: property.group_id)).to eq(property.values) - end - end - - context 'without group properties' do - it 'returns the charge properties' do - expect(charge.properties).to eq(charge.properties) - end - end - end - describe '#validate_graduated' do subject(:charge) do build(:graduated_charge, properties: charge_properties) @@ -527,21 +512,6 @@ end end - describe '#validate_uniqueness_group_properties' do - subject(:charge) do - build(:standard_charge, group_properties: [build(:group_property, group:), build(:group_property, group:)]) - end - - let(:group) { create(:group) } - - it 'returns an error for a duplicate' do - aggregate_failures do - expect(charge).not_to be_valid - expect(charge.errors.messages[:group_properties]).to include('is duplicated') - end - end - end - describe '#validate_custom_model' do subject(:charge) { build(:charge, billable_metric:, charge_model: 'custom') } diff --git a/spec/requests/api/v1/billable_metrics/groups_controller_spec.rb b/spec/requests/api/v1/billable_metrics/groups_controller_spec.rb deleted file mode 100644 index 092617556882..000000000000 --- a/spec/requests/api/v1/billable_metrics/groups_controller_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Api::V1::BillableMetrics::GroupsController, type: :request do - let(:organization) { create(:organization) } - let(:billable_metric) { create(:billable_metric, organization:) } - - describe 'GET /groups' do - before { billable_metric } - - context 'when billable_metric_id does not exist' do - it 'returns a not found error' do - get_with_token(organization, '/api/v1/billable_metrics/unknown/groups') - - expect(response).to have_http_status(:not_found) - end - end - - context 'when billable_metric_id is deleted' do - it 'returns a not found error' do - billable_metric.discard - get_with_token(organization, "/api/v1/billable_metrics/#{billable_metric.code}/groups") - - expect(response).to have_http_status(:not_found) - end - end - - context 'when billable_metric_id does not belong to the current organization' do - it 'returns a not found error' do - metric = create(:billable_metric) - get_with_token(organization, "/api/v1/billable_metrics/#{metric.code}/groups") - - expect(response).to have_http_status(:not_found) - end - end - - context 'when billable metric has no groups' do - it 'returns an empty array' do - get_with_token(organization, "/api/v1/billable_metrics/#{billable_metric.code}/groups") - - expect(response).to have_http_status(:success) - expect(json[:groups]).to eq([]) - end - end - - context 'when groups contain one dimension' do - it 'returns all billable metric\'s active groups' do - one = create(:group, billable_metric:) - second = create(:group, billable_metric:) - create(:group, billable_metric:, deleted_at: Time.current) - - get_with_token(organization, "/api/v1/billable_metrics/#{billable_metric.code}/groups") - - expect(response).to have_http_status(:success) - expect(json[:groups]).to contain_exactly( - {lago_id: one.id, key: one.key, value: one.value}, - {lago_id: second.id, key: one.key, value: second.value} - ) - end - end - - context 'when groups contain two dimensions' do - it 'returns billable metric\'s active children groups' do - parent = create(:group, billable_metric:) - children1 = create(:group, billable_metric:, parent_group_id: parent.id) - children2 = create(:group, billable_metric:, parent_group_id: parent.id) - create(:group, billable_metric:, parent_group_id: parent.id, deleted_at: Time.current) - - get_with_token(organization, "/api/v1/billable_metrics/#{billable_metric.code}/groups") - - expect(response).to have_http_status(:success) - expect(json[:groups]).to contain_exactly( - {lago_id: children1.id, key: parent.value, value: children1.value}, - {lago_id: children2.id, key: parent.value, value: children2.value} - ) - end - end - - context 'with pagination' do - it 'returns invoices with correct meta data' do - parent = create(:group, billable_metric:) - create_list(:group, 2, billable_metric:, parent_group_id: parent.id) - - get_with_token(organization, "/api/v1/billable_metrics/#{billable_metric.code}/groups?page=1&per_page=1") - - expect(response).to have_http_status(:success) - - expect(json[:groups].count).to eq(1) - expect(json[:meta][:current_page]).to eq(1) - expect(json[:meta][:next_page]).to eq(2) - expect(json[:meta][:prev_page]).to eq(nil) - expect(json[:meta][:total_pages]).to eq(2) - expect(json[:meta][:total_count]).to eq(2) - end - end - end -end diff --git a/spec/requests/api/v1/billable_metrics_controller_spec.rb b/spec/requests/api/v1/billable_metrics_controller_spec.rb index ec780de0589b..2fce73e36305 100644 --- a/spec/requests/api/v1/billable_metrics_controller_spec.rb +++ b/spec/requests/api/v1/billable_metrics_controller_spec.rb @@ -5,16 +5,6 @@ RSpec.describe Api::V1::BillableMetricsController, type: :request do let(:organization) { create(:organization) } - let(:group) do - { - key: 'cloud', - values: [ - {name: 'AWS', key: 'region', values: %w[usa europe]}, - {name: 'Google', key: 'region', values: ['usa']} - ] - } - end - describe 'create' do let(:create_params) do { @@ -36,38 +26,9 @@ expect(json[:billable_metric][:name]).to eq(create_params[:name]) expect(json[:billable_metric][:created_at]).to be_present expect(json[:billable_metric][:recurring]).to eq(create_params[:recurring]) - expect(json[:billable_metric][:group]).to eq({}) expect(json[:billable_metric][:filters]).to eq([]) end - context 'with group parameter' do - it 'creates billable metric\'s group' do - post_with_token( - organization, - '/api/v1/billable_metrics', - {billable_metric: create_params.merge(group:)} - ) - - expect(json[:billable_metric][:group]).to eq(group) - expect(json[:billable_metric][:filters].count).to eq(2) - end - end - - context 'with invalid group parameter' do - it 'returns an error' do - post_with_token( - organization, - '/api/v1/billable_metrics', - {billable_metric: create_params.merge(group: {foo: 'bar'})} - ) - - aggregate_failures do - expect(response).to have_http_status(:unprocessable_entity) - expect(json[:error_details]).to eq({group: %w[value_is_invalid]}) - end - end - end - context 'with weighted sum aggregation' do let(:create_params) do { @@ -122,36 +83,6 @@ expect(json[:billable_metric][:filters]).to eq([]) end - context 'with group parameter' do - it 'updates billable metric\'s group' do - create(:group, billable_metric:) - - put_with_token( - organization, - "/api/v1/billable_metrics/#{billable_metric.code}", - {billable_metric: update_params.merge(group:)} - ) - - expect(json[:billable_metric][:group]).to eq(group) - expect(json[:billable_metric][:filters].count).to eq(2) - end - end - - context 'with invalid group parameter' do - it 'returns an error' do - put_with_token( - organization, - "/api/v1/billable_metrics/#{billable_metric.code}", - {billable_metric: update_params.merge(group: {foo: 'bar'})} - ) - - aggregate_failures do - expect(response).to have_http_status(:unprocessable_entity) - expect(json[:error_details]).to eq({group: %w[value_is_invalid]}) - end - end - end - context 'when billable metric does not exist' do it 'returns not_found error' do put_with_token(organization, '/api/v1/billable_metrics/invalid', {billable_metric: update_params}) diff --git a/spec/requests/api/v1/plans_controller_spec.rb b/spec/requests/api/v1/plans_controller_spec.rb index aab6df559685..590c8ca51e40 100644 --- a/spec/requests/api/v1/plans_controller_spec.rb +++ b/spec/requests/api/v1/plans_controller_spec.rb @@ -149,68 +149,6 @@ end end - context 'with group properties on charges' do - let(:group) { create(:group, billable_metric:) } - let(:billable_metric_filter) do - create(:billable_metric_filter, billable_metric:, key: group.key, values: [group.value]) - end - let(:create_params) do - { - name: 'P1', - code: 'plan_code', - interval: 'weekly', - description: 'description', - amount_cents: 100, - amount_currency: 'EUR', - trial_period: 1, - pay_in_advance: false, - charges: [ - { - billable_metric_id: billable_metric.id, - charge_model: 'standard', - group_properties: [ - { - group_id: group.id, - invoice_display_name: 'Europe', - values: {amount: '0.22'} - } - ] - } - ] - } - end - - before { billable_metric_filter } - - it 'creates a plan' do - post_with_token(organization, '/api/v1/plans', {plan: create_params}) - - expect(response).to have_http_status(:success) - - expect(json[:plan][:lago_id]).to be_present - expect(json[:plan][:code]).to eq(create_params[:code]) - expect(json[:plan][:charges].first[:group_properties]).to eq( - [ - { - group_id: group.id, - invoice_display_name: 'Europe', - values: {amount: '0.22'} - } - ] - ) - - expect(json[:plan][:charges].first[:filters]).to eq( - [ - { - invoice_display_name: 'Europe', - properties: {amount: '0.22'}, - values: {group.key.to_sym => [group.value]} - } - ] - ) - end - end - context 'without charges' do let(:create_params) do { @@ -514,68 +452,6 @@ end end end - - context 'with group properties on charges' do - let(:group) { create(:group, billable_metric:) } - let(:billable_metric_filter) do - create(:billable_metric_filter, billable_metric:, key: group.key, values: [group.value]) - end - let(:update_params) do - { - name: 'P1', - code: 'plan_code', - interval: 'weekly', - description: 'description', - amount_cents: 100, - amount_currency: 'EUR', - trial_period: 1, - pay_in_advance: false, - charges: [ - { - billable_metric_id: billable_metric.id, - charge_model: 'standard', - group_properties: [ - { - group_id: group.id, - invoice_display_name: 'Europe', - values: {amount: '0.22'} - } - ] - } - ] - } - end - - before { billable_metric_filter } - - it 'creates a plan' do - put_with_token(organization, "/api/v1/plans/#{plan.code}", {plan: update_params}) - - expect(response).to have_http_status(:success) - - expect(json[:plan][:lago_id]).to be_present - expect(json[:plan][:code]).to eq(update_params[:code]) - expect(json[:plan][:charges].first[:group_properties]).to eq( - [ - { - group_id: group.id, - invoice_display_name: 'Europe', - values: {amount: '0.22'} - } - ] - ) - - expect(json[:plan][:charges].first[:filters]).to eq( - [ - { - invoice_display_name: 'Europe', - properties: {amount: '0.22'}, - values: {group.key.to_sym => [group.value]} - } - ] - ) - end - end end describe 'show' do diff --git a/spec/serializers/v1/billable_metric_serializer_spec.rb b/spec/serializers/v1/billable_metric_serializer_spec.rb index d9949e81177f..9f8708a9a286 100644 --- a/spec/serializers/v1/billable_metric_serializer_spec.rb +++ b/spec/serializers/v1/billable_metric_serializer_spec.rb @@ -23,7 +23,6 @@ expect(result['billable_metric']['plans_count']).to eq(0) expect(result['billable_metric']['filters']).to eq([]) - expect(result['billable_metric']['group']).to eq({}) end end diff --git a/spec/serializers/v1/group_serializer_spec.rb b/spec/serializers/v1/group_serializer_spec.rb deleted file mode 100644 index 20f395f1f0ec..000000000000 --- a/spec/serializers/v1/group_serializer_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ::V1::GroupSerializer do - subject(:serializer) { described_class.new(group, root_name: 'group') } - - let(:group) { create(:group) } - - it 'serializes the object' do - result = JSON.parse(serializer.to_json) - - aggregate_failures do - expect(result['group']['lago_id']).to eq(group.id) - expect(result['group']['key']).to eq(group.key) - expect(result['group']['value']).to eq(group.value) - end - end -end diff --git a/spec/serializers/v1/legacy/group_properties_serializer_spec.rb b/spec/serializers/v1/legacy/group_properties_serializer_spec.rb deleted file mode 100644 index dcaab09ae2e6..000000000000 --- a/spec/serializers/v1/legacy/group_properties_serializer_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ::V1::Legacy::GroupPropertiesSerializer do - subject(:serializer) { described_class.new(group_properties, root_name: 'group_properties') } - - let(:group_properties) { create(:group_property) } - - it 'serializes the object' do - result = JSON.parse(serializer.to_json) - - aggregate_failures do - expect(result['group_properties']['group_id']).to eq(group_properties.group.id) - expect(result['group_properties']['invoice_display_name']).to eq(group_properties.invoice_display_name) - end - end -end diff --git a/spec/serializers/v1/plan_serializer_spec.rb b/spec/serializers/v1/plan_serializer_spec.rb index 43d2a49dddf0..f97c6bec5f87 100644 --- a/spec/serializers/v1/plan_serializer_spec.rb +++ b/spec/serializers/v1/plan_serializer_spec.rb @@ -45,8 +45,7 @@ ) expect(result['plan']['charges'].first).to include( - 'lago_id' => charge.id, - 'group_properties' => [] + 'lago_id' => charge.id ) expect(result['plan']['minimum_commitment']).to include( @@ -94,8 +93,7 @@ ) expect(result['plan']['charges'].first).to include( - 'lago_id' => charge.id, - 'group_properties' => [] + 'lago_id' => charge.id ) expect(result['plan']['minimum_commitment']).to be_nil diff --git a/spec/services/billable_metrics/create_service_spec.rb b/spec/services/billable_metrics/create_service_spec.rb index d0e1a1e7c12b..178d7d55f494 100644 --- a/spec/services/billable_metrics/create_service_spec.rb +++ b/spec/services/billable_metrics/create_service_spec.rb @@ -42,34 +42,6 @@ end end - context 'with group parameter' do - let(:group) do - { - key: 'cloud', - values: [ - {name: 'AWS', key: 'region', values: %w[usa europe]}, - {name: 'Google', key: 'region', values: ['usa']} - ] - } - end - - it 'creates billable metric\'s groups' do - expect do - create_service.create(**create_args.merge(group:)) - end.to change(Group, :count).by(5) - end - - it 'returns an error if group is invalid' do - result = create_service.create(**create_args.merge(group: {key: 'foo'})) - - aggregate_failures do - expect(result).not_to be_success - expect(result.error).to be_a(BaseService::ValidationFailure) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - end - end - end - context 'with filters arguments' do let(:filters) do [ diff --git a/spec/services/billable_metrics/destroy_service_spec.rb b/spec/services/billable_metrics/destroy_service_spec.rb index 814566ab937d..738ea9aaefc6 100644 --- a/spec/services/billable_metrics/destroy_service_spec.rb +++ b/spec/services/billable_metrics/destroy_service_spec.rb @@ -10,8 +10,6 @@ let(:billable_metric) { create(:billable_metric, organization:) } let(:subscription) { create(:subscription) } let(:charge) { create(:standard_charge, plan: subscription.plan, billable_metric:) } - let(:group) { create(:group, billable_metric:) } - let(:group_property) { create(:group_property, group:, charge:) } let(:filters) { create_list(:billable_metric_filter, 2, billable_metric:) } let(:charge_filter) { create(:charge_filter, charge:) } @@ -21,7 +19,6 @@ before do charge - group_property filter_value @@ -44,13 +41,6 @@ end end - it 'soft deletes all the related groups' do - freeze_time do - expect { destroy_service.call }.to change { group.reload.deleted_at }.from(nil).to(Time.current) - .and change { group_property.reload.deleted_at }.from(nil).to(Time.current) - end - end - it 'soft deletes all related filters' do freeze_time do expect { destroy_service.call }.to change { billable_metric.filters.reload.kept.count }.from(2).to(0) diff --git a/spec/services/billable_metrics/update_service_spec.rb b/spec/services/billable_metrics/update_service_spec.rb index 6c2659353ec5..c3ef434a8c40 100644 --- a/spec/services/billable_metrics/update_service_spec.rb +++ b/spec/services/billable_metrics/update_service_spec.rb @@ -17,11 +17,9 @@ aggregation_type: 'sum_agg', field_name: 'field_value' }.tap do |p| - p[:group] = group unless group.nil? p[:filters] = filters unless filters.nil? end end - let(:group) { nil } let(:filters) { nil } describe '#call' do @@ -39,46 +37,6 @@ end end - context 'with group parameter' do - let(:group) do - { - key: 'cloud', - values: [ - {name: 'AWS', key: 'region', values: %w[usa europe]}, - {name: 'Google', key: 'region', values: ['usa']} - ] - } - end - - it 'updates billable metric\'s group' do - expect { update_service.call }.to change { billable_metric.active_groups.reload.count }.from(0).to(5) - end - - context 'with empty group' do - let(:group) { {} } - - before { create(:group, billable_metric:) } - - it 'updates billable metric\'s group' do - expect { update_service.call }.to change { billable_metric.active_groups.reload.count }.from(1).to(0) - end - end - - context 'with invalid group' do - let(:group) { {key: 1} } - - it 'returns an error if group is invalid' do - result = update_service.call - - aggregate_failures do - expect(result).not_to be_success - expect(result.error).to be_a(BaseService::ValidationFailure) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - end - end - end - end - context 'with filters arguments' do let(:filters) do [ diff --git a/spec/services/charges/override_service_spec.rb b/spec/services/charges/override_service_spec.rb index 32b81d9d90e8..025271880d65 100644 --- a/spec/services/charges/override_service_spec.rb +++ b/spec/services/charges/override_service_spec.rb @@ -10,30 +10,15 @@ describe '#call' do let(:billable_metric) { create(:billable_metric, organization:) } - let(:group) { create(:group, billable_metric:) } - let(:group2) { create(:group, billable_metric:) } let(:tax) { create(:tax, organization:) } let(:charge) do create( :standard_charge, billable_metric:, - properties: {amount: '300'}, - group_properties: [ - build( - :group_property, - group:, - values: {amount: '10', amount_currency: 'EUR'} - ), - build( - :group_property, - group: group2, - values: {amount: '20', amount_currency: 'EUR'} - ) - ] + properties: {amount: '300'} ) end - let(:plan) { create(:plan, organization:) } let(:params) do { @@ -42,13 +27,7 @@ # invoice_display_name: 'invoice display name', min_amount_cents: 1000, properties: {amount: '200'}, - tax_codes: [tax.code], - group_properties: [ - { - group_id: group.id, - values: {amount: '100'} - } - ] + tax_codes: [tax.code] } end @@ -66,7 +45,6 @@ it 'creates a charge based on the given charge', :aggregate_failures do applied_tax = create(:charge_applied_tax, charge:) - expect(charge.group_properties.count).to eq(2) expect(charge.taxes).to contain_exactly(applied_tax.tax) expect { override_service.call }.to change(Charge, :count).by(1) @@ -85,14 +63,6 @@ min_amount_cents: 1000, properties: {'amount' => '200'} ) - expect(charge.group_properties.count).to eq(1) - expect(charge.group_properties.with_discarded.discarded.count).to eq(1) - expect(charge.group_properties.first).to have_attributes( - { - group_id: group.id, - values: {'amount' => '100'} - } - ) expect(charge.taxes).to contain_exactly(tax) end diff --git a/spec/services/events/post_validation_service_spec.rb b/spec/services/events/post_validation_service_spec.rb index 637e63daea75..8feb7cfb67b6 100644 --- a/spec/services/events/post_validation_service_spec.rb +++ b/spec/services/events/post_validation_service_spec.rb @@ -43,27 +43,6 @@ ) end - let(:billable_metric_with_group) do - create( - :sum_billable_metric, - organization: - ) - end - - let(:parent_group) do - create(:group, billable_metric: billable_metric_with_group) - end - - let(:child_group) do - create( - :group, - billable_metric: billable_metric_with_group, - parent: parent_group, - key: 'provider', - value: 'aws' - ) - end - let(:billable_metric_with_filter) do create( :billable_metric, @@ -80,29 +59,6 @@ ) end - let(:missing_parent_group_key_event) do - create( - :event, - organization:, - code: billable_metric_with_group.code, - properties: {billable_metric_with_group.field_name => 12}, - created_at: Time.current.beginning_of_hour - 25.minutes - ) - end - - let(:missing_child_group_key_event) do - create( - :event, - organization:, - code: billable_metric_with_group.code, - properties: { - parent_group.key => parent_group.value, - billable_metric_with_group.field_name => 12 - }, - created_at: Time.current.beginning_of_hour - 25.minutes - ) - end - let(:invalid_filter_values_event) do create( :event, @@ -114,13 +70,9 @@ end before do - child_group - invalid_code_event missing_aggregation_property_event negative_aggregation_property_event - missing_parent_group_key_event - missing_child_group_key_event invalid_filter_values_event Scenic.database.refresh_materialized_view( @@ -150,11 +102,6 @@ .to include(missing_aggregation_property_event.transaction_id) expect(result.errors[:missing_aggregation_property]) .not_to include(negative_aggregation_property_event.transaction_id) - expect(result.errors[:missing_group_key]) - .to include( - missing_parent_group_key_event.transaction_id, - missing_child_group_key_event.transaction_id - ) expect(result.errors[:invalid_filter_values]).to include(invalid_filter_values_event.transaction_id) end @@ -168,7 +115,6 @@ errors: { invalid_code: [invalid_code_event.transaction_id], missing_aggregation_property: [missing_aggregation_property_event.transaction_id], - missing_group_key: Array, invalid_filter_values: [invalid_filter_values_event.transaction_id] } ) diff --git a/spec/services/group_properties/create_or_update_batch_service_spec.rb b/spec/services/group_properties/create_or_update_batch_service_spec.rb deleted file mode 100644 index f8c228104815..000000000000 --- a/spec/services/group_properties/create_or_update_batch_service_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe GroupProperties::CreateOrUpdateBatchService, type: :service do - subject(:service) do - described_class.call(charge:, properties_params:) - end - - let(:charge) { create(:standard_charge) } - - context 'when group properties params is empty' do - let(:properties_params) { {} } - - it 'does not create any group properties' do - expect { service }.not_to change(GroupProperty, :count) - end - end - - context 'when group properties are already assigned' do - let(:group1) { create(:group, billable_metric: charge.billable_metric) } - let(:group2) { create(:group, billable_metric: charge.billable_metric) } - let(:group_property1) { create(:group_property, group: group1, charge:) } - let(:group_property2) { create(:group_property, group: group2, charge:) } - let(:properties_params) do - [{group_id: group1.id, invoice_display_name: 'Invoice Name', values: {amount: '1'}}] - end - - before { group_property1 && group_property2 } - - it 'assigns expected group properties' do - aggregate_failures do - expect { service }.to change(GroupProperty, :count).by(-1) - expect(group_property2.reload).to be_discarded - expect(group_property1.reload.values).to eq({'amount' => '1'}) - expect(group_property1.reload.invoice_display_name).to eq('Invoice Name') - expect(charge.reload.group_properties).to eq([group_property1]) - end - end - - it 'marks invoices as ready to be refreshed' do - invoice = create(:invoice, :draft) - subscription = create(:subscription) - charge = create(:standard_charge, plan: subscription.plan) - create(:invoice_subscription, subscription:, invoice:) - - expect do - described_class.call(charge:, properties_params:) - end.to change { invoice.reload.ready_to_be_refreshed }.to(true) - end - end -end diff --git a/spec/services/groups/create_or_update_batch_service_spec.rb b/spec/services/groups/create_or_update_batch_service_spec.rb deleted file mode 100644 index f5cd481bd8c6..000000000000 --- a/spec/services/groups/create_or_update_batch_service_spec.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Groups::CreateOrUpdateBatchService, type: :service do - subject(:service) do - described_class.call(billable_metric:, group_params:) - end - - let(:billable_metric) { create(:billable_metric) } - - context 'when group params is empty' do - let(:group_params) { {} } - - it 'does not create any groups' do - expect { service }.not_to change(Group, :count) - end - end - - context 'when format is not valid' do - it 'returns an error' do - result = create_groups({key: 0, values: 1}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo'}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({invalid: 'foo', values: ['bar']}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo', values: 'bar'}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo', values: [1, 2]}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo', values: [{name: 1}]}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo', values: [{name: 'bar', key: 1, values: ['baz']}]}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - - result = create_groups({key: 'foo', values: [{name: 'bar', key: 'baz', values: [1]}]}) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - end - - def create_groups(group_params) - described_class.call(billable_metric:, group_params:) - end - end - - context 'when three dimensions' do - let(:group_params) do - { - key: 'region', - values: [ - { - name: 'Europe', - key: 'cloud', - values: [ - { - name: 'AWS', - key: 'country', - values: %w[France] - } - ] - } - ] - } - end - - it 'returns an error' do - result = service - - aggregate_failures do - expect(result).not_to be_success - expect(result.error).to be_a(BaseService::ValidationFailure) - expect(result.error.messages[:group]).to eq(['value_is_invalid']) - end - end - end - - context 'with one dimension' do - let(:group_params) do - {key: 'region', values: %w[usa europe usa]} - end - let(:group1) { create(:group, billable_metric:, key: 'region', value: 'europe', deleted_at: Time.current) } - let(:group2) { create(:group, billable_metric:, key: 'region', value: 'africa') } - - before { group1 && group2 } - - it 'assigns expected groups' do - expect { service }.to change(Group, :count).by(1) - - expect(billable_metric.groups.pluck(:key, :value)) - .to contain_exactly(%w[region usa], %w[region europe]) - end - - it 'marks invoices as ready to be refreshed' do - invoice = create(:invoice, :draft) - subscription = create(:subscription) - create(:standard_charge, plan: subscription.plan, billable_metric:) - create(:invoice_subscription, subscription:, invoice:) - - expect { service }.to change { invoice.reload.ready_to_be_refreshed }.to(true) - end - end - - context 'with two dimensions' do - let(:group_params) do - { - key: 'cloud', - values: [ - { - name: 'AWS', - invoice_display_name: "AWS Invoice name", - key: 'region', - values: %w[usa europe] - }, - { - name: 'Google', - key: 'region', - values: %w[usa usa] - } - ] - } - end - - let(:parent_group1) { create(:group, billable_metric:, key: 'cloud', value: 'AWS') } - let(:parent_group2) { create(:group, billable_metric:, key: 'cloud', value: 'Microsoft') } - let(:group1) { create(:group, billable_metric:, key: 'region', value: 'europe', parent_group_id: parent_group1.id) } - let(:group2) { create(:group, billable_metric:, key: 'region', value: 'africa', parent_group_id: parent_group1.id) } - let(:group3) { create(:group, billable_metric:, key: 'region', value: 'europe', parent_group_id: parent_group2.id) } - - before { group1 && group2 && group3 } - - it 'assigns expected groups' do - expect { service }.not_to change { billable_metric.reload.groups.count } - - groups = billable_metric.reload.groups - aws = groups.find_by(key: 'cloud', value: 'AWS') - expect(aws.children).to include(group1) - expect(aws.children.pluck(:key, :value)).to contain_exactly(%w[region usa], %w[region europe]) - - google = groups.find_by(key: 'cloud', value: 'Google') - expect(google.children.pluck(:key, :value)).to eq([%w[region usa]]) - end - - it 'marks invoices as ready to be refreshed' do - invoice = create(:invoice, :draft) - subscription = create(:subscription) - create(:standard_charge, plan: subscription.plan, billable_metric:) - create(:invoice_subscription, subscription:, invoice:) - - expect { service }.to change { invoice.reload.ready_to_be_refreshed }.to(true) - end - end -end diff --git a/spec/services/plans/create_service_spec.rb b/spec/services/plans/create_service_spec.rb index 60f602317242..22a994cedb9d 100644 --- a/spec/services/plans/create_service_spec.rb +++ b/spec/services/plans/create_service_spec.rb @@ -16,7 +16,6 @@ let(:billable_metric_filter) do create(:billable_metric_filter, billable_metric:, key: 'payment_method', values: %w[card physical]) end - let(:group) { create(:group, billable_metric:) } let(:plan_tax) { create(:tax, organization:) } let(:charge_tax) { create(:tax, organization:) } let(:create_args) do @@ -53,12 +52,6 @@ charge_model: 'standard', min_amount_cents: 100, tax_codes: [charge_tax.code], - group_properties: [ - { - group_id: group.id, - values: {amount: '100'} - } - ], filters: [ { values: {billable_metric_filter.key => ['card']}, @@ -130,12 +123,6 @@ properties: {'amount' => '0'} ) expect(standard_charge.taxes.pluck(:code)).to eq([charge_tax.code]) - expect(standard_charge.group_properties.first).to have_attributes( - { - group_id: group.id, - values: {'amount' => '100'} - } - ) expect(standard_charge.filters.first).to have_attributes( invoice_display_name: 'Card filter', properties: {'amount' => '90'} @@ -183,13 +170,7 @@ billable_metric_id: billable_metric.id, charge_model: 'standard', min_amount_cents: 100, - tax_codes: [charge_tax.code], - group_properties: [ - { - group_id: group.id, - values: {amount: '100'} - } - ] + tax_codes: [charge_tax.code] }, { billable_metric_id: sum_billable_metric.id, diff --git a/spec/services/plans/override_service_spec.rb b/spec/services/plans/override_service_spec.rb index 83a7f214bba5..4ff54ad1cdb5 100644 --- a/spec/services/plans/override_service_spec.rb +++ b/spec/services/plans/override_service_spec.rb @@ -11,7 +11,7 @@ describe '#call' do let(:parent_plan) { create(:plan, organization:) } let(:billable_metric) { create(:billable_metric, organization:) } - let(:group) { create(:group, billable_metric:) } + let(:billable_metric_filter) { create(:billable_metric_filter, billable_metric:) } let(:tax) { create(:tax, organization:) } let(:charge) do @@ -19,14 +19,24 @@ :standard_charge, plan: parent_plan, billable_metric:, - properties: {amount: '300'}, - group_properties: [ - build( - :group_property, - group:, - values: {amount: '10', amount_currency: 'EUR'} - ) - ] + properties: {amount: '300'} + ) + end + + let(:filter) do + create( + :charge_filter, + charge:, + properties: {amount: '10'} + ) + end + + let(:filter_value) do + create( + :charge_filter_value, + charge_filter: filter, + billable_metric_filter:, + values: [billable_metric_filter.values.first] ) end @@ -69,6 +79,7 @@ before do charge allow(SegmentTrackJob).to receive(:perform_later) + filter_value end it 'creates a plan based from the parent plan', :aggregate_failures do diff --git a/spec/services/plans/update_service_spec.rb b/spec/services/plans/update_service_spec.rb index 7617263e6af9..984a23672032 100644 --- a/spec/services/plans/update_service_spec.rb +++ b/spec/services/plans/update_service_spec.rb @@ -10,7 +10,6 @@ let(:plan) { create(:plan, organization:) } let(:plan_name) { 'Updated plan name' } let(:plan_invoice_display_name) { 'Updated plan invoice display name' } - let(:group) { create(:group, billable_metric: sum_billable_metric) } let(:sum_billable_metric) { create(:sum_billable_metric, organization:, recurring: true) } let(:billable_metric) { create(:billable_metric, organization:) } let(:tax1) { create(:tax, organization:) } @@ -49,12 +48,6 @@ charge_model: 'standard', invoice_display_name: 'charge1', min_amount_cents: 100, - group_properties: [ - { - group_id: group.id, - values: {amount: '100'} - } - ], tax_codes: [tax1.code] }, { @@ -534,12 +527,6 @@ pay_in_advance: true, prorated: true, invoiceable: false, - group_properties: [ - { - group_id: group.id, - values: {amount: '100'} - } - ], filters: [ { invoice_display_name: 'Card filter', @@ -569,17 +556,12 @@ end it 'updates existing charge' do - expect { plans_service.call } - .to change(GroupProperty, :count).by(1) + plans_service.call expect(existing_charge.reload).to have_attributes( prorated: true, properties: {'amount' => '0'} ) - expect(existing_charge.group_properties.first).to have_attributes( - group_id: group.id, - values: {'amount' => '100'} - ) expect(existing_charge.filters.first).to have_attributes( invoice_display_name: 'Card filter', @@ -677,13 +659,10 @@ end let(:billable_metric) { sum_billable_metric } - let(:group_property) { create(:group_property, group:, charge:) } - let(:group) { create(:group, billable_metric:) } before do subscription charge - group_property end it 'discards the charge' do @@ -693,13 +672,6 @@ end end - it 'discards group properties related to the charge' do - freeze_time do - expect { plans_service.call } - .to change { group_property.reload.deleted_at }.from(nil).to(Time.current) - end - end - it 'marks invoices as ready to be refreshed' do invoice = create(:invoice, :draft) create(:invoice_subscription, subscription:, invoice:)