From eab2aabd60ff5ef1fe263e41ed2035ae2497e93d Mon Sep 17 00:00:00 2001 From: Vincent Pochet Date: Mon, 23 Sep 2024 11:47:19 +0200 Subject: [PATCH] feat(DynamicPricing): Accept precise_total_amount_cents when creating an event (#2610) ## Context AI, CPaaS and Fintech customers can apply a price to a unit that fluctuates over time. Currently Lago does not support this usecase. ## Description This PR updates `POST /api/v1/events` and `POST /api/v1/batch_events` to accept the new `precise_total_amount_cents` field on event model. --- app/controllers/api/v1/events_controller.rb | 2 ++ app/serializers/v1/event_serializer.rb | 1 + app/services/events/create_batch_service.rb | 4 ++- app/services/events/create_service.rb | 2 ++ .../requests/api/v1/events_controller_spec.rb | 4 +++ spec/serializers/v1/event_serializer_spec.rb | 2 ++ .../events/create_batch_service_spec.rb | 4 +++ spec/services/events/create_service_spec.rb | 27 ++++++++++++++++++- 8 files changed, 44 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/v1/events_controller.rb b/app/controllers/api/v1/events_controller.rb index c46f4ca7ce2..352c4dc4868 100644 --- a/app/controllers/api/v1/events_controller.rb +++ b/app/controllers/api/v1/events_controller.rb @@ -90,6 +90,7 @@ def create_params :code, :timestamp, :external_subscription_id, + :precise_total_amount_cents, properties: {} ) end @@ -102,6 +103,7 @@ def batch_params :code, :timestamp, :external_subscription_id, + :precise_total_amount_cents, properties: {} # rubocop:disable Style/HashAsLastArrayItem ] ).to_h.deep_symbolize_keys diff --git a/app/serializers/v1/event_serializer.rb b/app/serializers/v1/event_serializer.rb index 21b74f227f1..270a372eaff 100644 --- a/app/serializers/v1/event_serializer.rb +++ b/app/serializers/v1/event_serializer.rb @@ -9,6 +9,7 @@ def serialize lago_customer_id: model.customer_id, code: model.code, timestamp: model.timestamp.iso8601(3), + precise_total_amount_cents: model.precise_total_amount_cents&.to_s, properties: model.properties, lago_subscription_id: model.subscription_id, external_subscription_id: model.external_subscription_id, diff --git a/app/services/events/create_batch_service.rb b/app/services/events/create_batch_service.rb index cc2a76ee136..fb114333499 100644 --- a/app/services/events/create_batch_service.rb +++ b/app/services/events/create_batch_service.rb @@ -48,6 +48,7 @@ def validate_events event.properties = event_params[:properties] || {} event.metadata = metadata || {} event.timestamp = Time.zone.at(event_params[:timestamp] ? event_params[:timestamp].to_f : timestamp) + event.precise_total_amount_cents = event_params[:precise_total_amount_cents] result.events.push(event) result.errors = result.errors.merge({index => event.errors.messages}) unless event.valid? @@ -80,7 +81,8 @@ def produce_kafka_event(event) timestamp: event.timestamp.to_f, code: event.code, properties: event.properties, - ingested_at: Time.zone.now.iso8601[...-1] + ingested_at: Time.zone.now.iso8601[...-1], + precise_total_amount_cents: event.precise_total_amount_cents }.to_json ) end diff --git a/app/services/events/create_service.rb b/app/services/events/create_service.rb index 4f1d000ad45..985b6ba1114 100644 --- a/app/services/events/create_service.rb +++ b/app/services/events/create_service.rb @@ -19,6 +19,7 @@ def call event.properties = params[:properties] || {} event.metadata = metadata || {} event.timestamp = Time.zone.at(params[:timestamp] ? params[:timestamp].to_f : timestamp) + event.precise_total_amount_cents = params[:precise_total_amount_cents] event.save! unless organization.clickhouse_aggregation? @@ -52,6 +53,7 @@ def produce_kafka_event(event) transaction_id: event.transaction_id, timestamp: event.timestamp.iso8601[...-1], # NOTE: Removes trailing 'Z' to allow clickhouse parsing code: event.code, + precise_total_amount_cents: event.precise_total_amount_cents, properties: event.properties, ingested_at: Time.zone.now.iso8601[...-1] }.to_json diff --git a/spec/requests/api/v1/events_controller_spec.rb b/spec/requests/api/v1/events_controller_spec.rb index 5761748861f..9a86e639ccd 100644 --- a/spec/requests/api/v1/events_controller_spec.rb +++ b/spec/requests/api/v1/events_controller_spec.rb @@ -22,6 +22,7 @@ transaction_id: SecureRandom.uuid, external_subscription_id: subscription.external_id, timestamp: Time.current.to_i, + precise_total_amount_cents: '123.45', properties: { foo: 'bar' } @@ -48,6 +49,7 @@ transaction_id: event.transaction_id, external_subscription_id: subscription.external_id, timestamp: Time.current.to_i, + precise_total_amount_cents: '123.45', properties: { foo: 'bar' } @@ -72,6 +74,7 @@ transaction_id: SecureRandom.uuid, external_subscription_id: subscription.external_id, timestamp: Time.current.to_i, + precise_total_amount_cents: '123.45', properties: { foo: 'bar' } @@ -136,6 +139,7 @@ code: metric.code, external_subscription_id: subscription.external_id, transaction_id: SecureRandom.uuid, + precise_total_amount_cents: '123.45', properties: { foo: 'bar' } diff --git a/spec/serializers/v1/event_serializer_spec.rb b/spec/serializers/v1/event_serializer_spec.rb index 435e5ea8f72..3b86848c030 100644 --- a/spec/serializers/v1/event_serializer_spec.rb +++ b/spec/serializers/v1/event_serializer_spec.rb @@ -10,6 +10,7 @@ :event, customer_id: nil, subscription_id: nil, + precise_total_amount_cents: '123.6', properties: { item_value: '12' } @@ -26,6 +27,7 @@ 'lago_customer_id' => event.customer_id, 'code' => event.code, 'timestamp' => event.timestamp.iso8601(3), + 'precise_total_amount_cents' => '123.6', 'properties' => event.properties, 'lago_subscription_id' => event.subscription_id, 'external_subscription_id' => event.external_subscription_id, diff --git a/spec/services/events/create_batch_service_spec.rb b/spec/services/events/create_batch_service_spec.rb index c2c4c437005..6472519e611 100644 --- a/spec/services/events/create_batch_service_spec.rb +++ b/spec/services/events/create_batch_service_spec.rb @@ -17,6 +17,7 @@ let(:code) { 'sum_agg' } let(:metadata) { {} } let(:creation_timestamp) { Time.current.to_f } + let(:precise_total_amount_cents) { '123.34' } let(:events_params) do events = [] @@ -26,6 +27,7 @@ external_subscription_id: SecureRandom.uuid, code:, transaction_id: SecureRandom.uuid, + precise_total_amount_cents:, properties: {foo: 'bar'}, timestamp: } @@ -178,6 +180,7 @@ external_subscription_id: SecureRandom.uuid, code:, transaction_id: SecureRandom.uuid, + precise_total_amount_cents:, properties: {foo: 'bar'}, timestamp: } @@ -204,6 +207,7 @@ external_subscription_id: SecureRandom.uuid, code:, transaction_id: SecureRandom.uuid, + precise_total_amount_cents:, properties: {foo: 'bar'}, timestamp: } diff --git a/spec/services/events/create_service_spec.rb b/spec/services/events/create_service_spec.rb index a542228c541..db051005238 100644 --- a/spec/services/events/create_service_spec.rb +++ b/spec/services/events/create_service_spec.rb @@ -18,6 +18,7 @@ let(:external_subscription_id) { SecureRandom.uuid } let(:timestamp) { Time.current.to_f } let(:transaction_id) { SecureRandom.uuid } + let(:precise_total_amount_cents) { nil } let(:creation_timestamp) { Time.current.to_f } @@ -26,6 +27,7 @@ external_subscription_id:, code:, transaction_id:, + precise_total_amount_cents:, properties: {foo: 'bar'}, timestamp: } @@ -46,7 +48,8 @@ transaction_id:, code:, timestamp: Time.zone.at(timestamp), - properties: {'foo' => 'bar'} + properties: {'foo' => 'bar'}, + precise_total_amount_cents: nil ) end end @@ -131,5 +134,27 @@ expect(karafka_producer).to have_received(:produce_async) end end + + context 'with a precise_total_amount_cents' do + let(:precise_total_amount_cents) { "123.45" } + + it 'creates an event with the precise_total_amount_cents' do + result = create_service.call + + expect(result).to be_success + expect(result.event.precise_total_amount_cents).to eq(123.45) + end + + context 'when precise_total_amount_cents is not a valid decimal value' do + let(:precise_total_amount_cents) { "asdfa" } + + it 'creates an event' do + result = create_service.call + + expect(result).to be_success + expect(result.event.precise_total_amount_cents).to eq(0) + end + end + end end end