Skip to content

Commit

Permalink
misc(export-credit-notes): Refactor services and tests (#2963)
Browse files Browse the repository at this point in the history
## Context

Refactor and preparations to expand existing data export solution with
new export types.

## Description

Extract common logic into a new `BaseCsvService`.
Refactor tests.
  • Loading branch information
floganz authored Dec 17, 2024
1 parent 7bfd4a3 commit f9817fc
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 127 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ruby "3.3.6"
# Core
gem "aasm"
gem "activejob-uniqueness", require: "active_job/uniqueness/sidekiq_patch"
gem "active_storage_validations"
gem "bootsnap", require: false
gem "clockwork", require: false
gem "parallel"
Expand Down
7 changes: 7 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ GEM
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
active_storage_validations (1.3.5)
activejob (>= 6.1.4)
activemodel (>= 6.1.4)
activestorage (>= 6.1.4)
activesupport (>= 6.1.4)
marcel (>= 1.0.3)
activejob (7.1.5.1)
activesupport (= 7.1.5.1)
globalid (>= 0.3.6)
Expand Down Expand Up @@ -922,6 +928,7 @@ PLATFORMS

DEPENDENCIES
aasm
active_storage_validations
activejob-traceable
activejob-uniqueness
adyen-ruby-api-library
Expand Down
1 change: 0 additions & 1 deletion app/mailers/data_export_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ def completed
@resource_type = @data_export.resource_type.humanize.downcase
user = @data_export.user

return if @data_export.file.blank?
return if @data_export.expired?
return unless @data_export.completed?

Expand Down
14 changes: 6 additions & 8 deletions app/models/data_export.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ class DataExport < ApplicationRecord

belongs_to :organization
belongs_to :membership
has_one :user, through: :membership

has_one_attached :file

has_many :data_export_parts

validates :resource_type, presence: true
validates :format, presence: true, inclusion: {in: EXPORT_FORMATS}
validates :status, presence: true, inclusion: {in: STATUSES}

enum format: EXPORT_FORMATS
enum status: STATUSES
enum :format, EXPORT_FORMATS, validate: true
enum :status, STATUSES, validate: true

delegate :user, to: :membership
validates :resource_type, presence: true
validates :file, attached: true, if: :completed?

def processing!
update!(status: 'processing', started_at: Time.zone.now)
Expand Down Expand Up @@ -49,7 +47,7 @@ def file_url
blob_path = Rails.application.routes.url_helpers.rails_blob_path(
file,
host: 'void',
expires_in: 7.days
expires_in: EXPIRATION_PERIOD
)

File.join(ENV['LAGO_API_URL'], blob_path)
Expand Down
32 changes: 32 additions & 0 deletions app/services/data_exports/csv/base_csv_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

require 'csv'
require 'forwardable'

module DataExports
module Csv
class BaseCsvService < ::BaseService
extend Forwardable

def call
result.csv_file = with_csv do |csv|
collection.each do |item|
serialize_item(item, csv)
end
end

result
end

private

def with_csv
tempfile = Tempfile.create([data_export_part.id, ".csv"])
yield CSV.new(tempfile, headers: false)

tempfile.rewind
tempfile
end
end
end
end
113 changes: 58 additions & 55 deletions app/services/data_exports/csv/invoice_fees.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,68 +5,18 @@

module DataExports
module Csv
class InvoiceFees < Invoices
class InvoiceFees < BaseCsvService
extend Forwardable

def initialize(
data_export_part:,
invoice_serializer_klass: V1::InvoiceSerializer,
fee_serializer_klass: V1::FeeSerializer
)
super(data_export_part:, serializer_klass: invoice_serializer_klass)

@data_export_part = data_export_part
@invoice_serializer_klass = invoice_serializer_klass
@fee_serializer_klass = fee_serializer_klass
end

def call
result.csv_file = with_csv do |csv|
invoices.each do |invoice|
serialized_invoice = serializer_klass.new(invoice).serialize

invoice
.fees
.includes(
:invoice,
:subscription,
:charge,
:true_up_fee,
:customer,
:billable_metric,
{charge_filter: {values: :billable_metric_filter}}
)
.find_each
.lazy
.each do |fee|
serialized_fee = fee_serializer_klass.new(fee).serialize

serialized_subscription = fee.subscription ? {external_id: fee.subscription.external_id, plan_code: fee.subscription.plan.code} : {}

csv << [
serialized_invoice[:lago_id],
serialized_invoice[:number],
serialized_invoice[:issuing_date],
serialized_fee[:lago_id],
serialized_fee.dig(:item, :type),
serialized_fee.dig(:item, :code),
serialized_fee.dig(:item, :name),
serialized_fee.dig(:item, :description),
serialized_fee.dig(:item, :invoice_display_name),
serialized_fee.dig(:item, :filter_invoice_display_name),
serialized_fee.dig(:item, :grouped_by),
serialized_subscription[:external_id],
serialized_subscription[:plan_code],
serialized_fee[:from_date],
serialized_fee[:to_date],
serialized_fee[:total_amount_currency],
serialized_fee[:units],
serialized_fee[:precise_unit_amount],
serialized_fee[:taxes_amount_cents],
serialized_fee[:total_amount_cents]
]
end
end
end
result
super
end

def self.headers
Expand Down Expand Up @@ -96,7 +46,60 @@ def self.headers

private

attr_reader :invoice_serializer_klass, :fee_serializer_klass, :subscription_serializer_klass
attr_reader :data_export_part, :invoice_serializer_klass, :fee_serializer_klass

def serialize_item(invoice, csv)
serialized_invoice = invoice_serializer_klass.new(invoice).serialize

invoice
.fees
.includes(
:invoice,
:subscription,
:charge,
:true_up_fee,
:customer,
:billable_metric,
{charge_filter: {values: :billable_metric_filter}}
)
.find_each
.lazy
.each do |fee|
serialized_fee = fee_serializer_klass.new(fee).serialize

serialized_subscription = {
external_id: fee.subscription&.external_id,
plan_code: fee.subscription&.plan&.code
}

csv << [
serialized_invoice[:lago_id],
serialized_invoice[:number],
serialized_invoice[:issuing_date],
serialized_fee[:lago_id],
serialized_fee.dig(:item, :type),
serialized_fee.dig(:item, :code),
serialized_fee.dig(:item, :name),
serialized_fee.dig(:item, :description),
serialized_fee.dig(:item, :invoice_display_name),
serialized_fee.dig(:item, :filter_invoice_display_name),
serialized_fee.dig(:item, :grouped_by),
serialized_subscription[:external_id],
serialized_subscription[:plan_code],
serialized_fee[:from_date],
serialized_fee[:to_date],
serialized_fee[:total_amount_currency],
serialized_fee[:units],
serialized_fee[:precise_unit_amount],
serialized_fee[:taxes_amount_cents],
serialized_fee[:total_amount_cents]
]
end
end

def collection
Invoice.find(data_export_part.object_ids)
end
end
end
end
27 changes: 5 additions & 22 deletions app/services/data_exports/csv/invoices.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

module DataExports
module Csv
class Invoices < BaseService
class Invoices < BaseCsvService
extend Forwardable

def initialize(data_export_part:, serializer_klass: V1::InvoiceSerializer)
Expand All @@ -14,15 +14,6 @@ def initialize(data_export_part:, serializer_klass: V1::InvoiceSerializer)
super
end

def call
result.csv_file = with_csv do |csv|
invoices.each do |invoice|
csv << serialized_invoice(invoice)
end
end
result
end

def self.headers
%w[
lago_id
Expand Down Expand Up @@ -53,22 +44,14 @@ def self.headers

private

def with_csv
tempfile = Tempfile.create([data_export_part.id, ".csv"])
yield CSV.new(tempfile, headers: false)

tempfile.rewind
tempfile
end

attr_reader :data_export_part, :serializer_klass, :output, :batch_size
attr_reader :data_export_part, :serializer_klass

def serialized_invoice(invoice)
def serialize_item(invoice, csv)
serialized_invoice = serializer_klass
.new(invoice, includes: %i[customer])
.serialize

[
csv << [
serialized_invoice[:lago_id],
serialized_invoice[:sequential_id],
serialized_invoice[:issuing_date],
Expand All @@ -95,7 +78,7 @@ def serialized_invoice(invoice)
]
end

def invoices
def collection
Invoice.find(data_export_part.object_ids)
end
end
Expand Down
6 changes: 5 additions & 1 deletion spec/factories/data_exports.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@
end

trait :completed do
with_file
status { 'completed' }
started_at { 2.hours.ago }
completed_at { 30.minutes.ago }
expires_at { 7.days.from_now }
file { Rack::Test::UploadedFile.new(Rails.root.join("spec/fixtures/export.csv")) }
end

trait :expired do
completed
expires_at { 1.day.ago }
end

trait :with_file do
file { Rack::Test::UploadedFile.new(Rails.root.join("spec/fixtures/export.csv")) }
end
end
end
Loading

0 comments on commit f9817fc

Please sign in to comment.