Skip to content

Commit

Permalink
Feat (invoice_custom_sections): customer update service (#2960)
Browse files Browse the repository at this point in the history
## Description

Added service to manage invoice_custom_sections on customer level
  • Loading branch information
annvelents authored Jan 9, 2025
1 parent 58466c8 commit 5437092
Show file tree
Hide file tree
Showing 19 changed files with 382 additions and 113 deletions.
49 changes: 49 additions & 0 deletions app/services/customers/manage_invoice_custom_sections_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Customers
class ManageInvoiceCustomSectionsService < BaseService
def initialize(customer:, skip_invoice_custom_sections:, section_ids:)
@customer = customer
@section_ids = section_ids
@skip_invoice_custom_sections = skip_invoice_custom_sections

super
end

def call
return result.not_found_failure!(resource: "customer") unless customer
raise_invalid_params if skip_invoice_custom_sections && section_ids.present?

ActiveRecord::Base.transaction do
unless skip_invoice_custom_sections.nil?
customer.selected_invoice_custom_sections = [] if !!skip_invoice_custom_sections
customer.skip_invoice_custom_sections = skip_invoice_custom_sections
end

unless section_ids.nil?
customer.skip_invoice_custom_sections = false
return result if customer.applicable_invoice_custom_sections.ids == section_ids

assign_selected_sections
end
customer.save!
end
result
rescue ActiveRecord::RecordInvalid => e
result.record_validation_failure!(record: e.record)
end

private

attr_reader :customer, :section_ids, :skip_invoice_custom_sections

def raise_invalid_params
result.validation_failure!(errors: {invoice_custom_sections: ['skip_sections_and_selected_ids_sent_together']})
end

def assign_selected_sections
# Note: when assigning organization's sections, an empty array will be sent
customer.selected_invoice_custom_sections = customer.organization.invoice_custom_sections.where(id: section_ids)
end
end
end
6 changes: 6 additions & 0 deletions app/services/customers/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ def call
customer.reset_dunning_campaign!
end

Customers::ManageInvoiceCustomSectionsService.call(
customer:,
skip_invoice_custom_sections: args[:skip_invoice_custom_sections],
section_ids: args[:selected_invoice_custom_section_ids]
).raise_if_error!

customer.save!
customer.reload

Expand Down
2 changes: 1 addition & 1 deletion app/services/invoice_custom_sections/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(organization:, create_params:, selected: false)

def call
invoice_custom_section = organization.invoice_custom_sections.create!(create_params)
SelectService.call(section: invoice_custom_section, organization:) if selected
Organizations::SelectInvoiceCustomSectionService.call(section: invoice_custom_section) if selected
result.invoice_custom_section = invoice_custom_section
result
rescue ActiveRecord::RecordInvalid => e
Expand Down

This file was deleted.

This file was deleted.

24 changes: 24 additions & 0 deletions app/services/invoice_custom_sections/deselect_all_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module InvoiceCustomSections
class DeselectAllService < BaseService
def initialize(section:)
@section = section
super
end

def call
deselect_for_all
result
end

private

attr_reader :section

def deselect_for_all
InvoiceCustomSectionSelection.where(invoice_custom_section_id: section.id).destroy_all
result.invoice_custom_section = section
end
end
end
2 changes: 1 addition & 1 deletion app/services/invoice_custom_sections/destroy_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def call

ActiveRecord::Base.transaction do
invoice_custom_section.discard
Deselect::ForAllUsagesService.call(section: invoice_custom_section).raise_if_error!
DeselectAllService.call(section: invoice_custom_section).raise_if_error!
result.invoice_custom_section = invoice_custom_section
result
end
Expand Down
4 changes: 2 additions & 2 deletions app/services/invoice_custom_sections/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ def initialize(invoice_custom_section:, update_params:, selected: false)
def call
invoice_custom_section.update!(update_params)
if selected
SelectService.call(section: invoice_custom_section, organization: invoice_custom_section.organization)
Organizations::SelectInvoiceCustomSectionService.call(section: invoice_custom_section)
else
Deselect::ForOrganizationService.call(section: invoice_custom_section)
Organizations::DeselectInvoiceCustomSectionService.call(section: invoice_custom_section)
end
result.invoice_custom_section = invoice_custom_section
result
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Organizations
class DeselectInvoiceCustomSectionService < BaseService
def initialize(section:)
@section = section
@organization = section.organization
super
end

def call
deselect_for_organization
result.section = section
result
end

private

attr_reader :section, :organization

def deselect_for_organization
return unless organization.selected_invoice_custom_sections.include?(section)

InvoiceCustomSectionSelection.where(
organization_id: organization.id, invoice_custom_section_id: section.id
).destroy_all
end
end
end
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# frozen_string_literal: true

module InvoiceCustomSections
class SelectService < BaseService
def initialize(section:, organization:)
module Organizations
class SelectInvoiceCustomSectionService < BaseService
def initialize(section:)
@section = section
@organization = organization
@organization = section.organization
super
end

def call
select_for_organization if organization
select_for_organization
result
end

Expand Down
123 changes: 123 additions & 0 deletions spec/services/customers/manage_invoice_custom_sections_service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Customers::ManageInvoiceCustomSectionsService do
let(:customer) { create(:customer) }
let(:invoice_custom_sections) { create_list(:invoice_custom_section, 4, organization: customer.organization) }
let(:skip_invoice_custom_sections) { nil }
let(:service) { described_class.new(customer: customer, section_ids:, skip_invoice_custom_sections:) }
let(:section_ids) { nil }

before do
customer.selected_invoice_custom_sections << invoice_custom_sections[0] if customer
customer.organization.selected_invoice_custom_sections = invoice_custom_sections[2..3] if customer
end

describe "#call" do
context "when customer is not found" do
let(:customer) { nil }

it "returns not found failure" do
result = service.call
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::NotFoundFailure)
expect(result.error.message).to eq("customer_not_found")
end
end

context "when sending skip_invoice_custom_sections: true AND selected_ids" do
let(:skip_invoice_custom_sections) { true }
let(:section_ids) { [1, 2, 3] }

it "raises an error" do
result = service.call
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
expect(result.error.message).to include("skip_sections_and_selected_ids_sent_together")
end
end

context "when updating selected_invoice_custom_sections" do
context "when section_ids match customer's applicable sections" do
let(:section_ids) { [invoice_custom_sections.first.id] }

it "returns the result without changes" do
result = service.call
expect(result).to be_success
expect(customer.applicable_invoice_custom_sections.ids).to match_array(section_ids)
end
end

context "when section_ids match organization's selected sections" do
let(:section_ids) { invoice_custom_sections[2..3].map(&:id) }

it "still sets selected invoice_custom_sections as custom" do
service.call
expect(customer.reload.selected_invoice_custom_sections.ids).to match_array(invoice_custom_sections[2..3].map(&:id))
expect(customer.applicable_invoice_custom_sections.ids).to match_array(section_ids)
end
end

context "when section_ids are totally custom" do
let(:section_ids) { invoice_custom_sections[1..2].map(&:id) }

it "assigns customer sections" do
service.call
expect(customer.reload.selected_invoice_custom_sections.ids).to match_array(section_ids)
expect(customer.applicable_invoice_custom_sections.ids).to match_array(section_ids)
end
end

context "when selected_ids are an empty array" do
let(:section_ids) { [] }

it "assigns organization sections" do
service.call
expect(customer.reload.selected_invoice_custom_sections.ids).to match_array([])
expect(customer.applicable_invoice_custom_sections.ids).to match_array(customer.organization.selected_invoice_custom_sections.ids)
end
end

context "when setting invoice_custom_sections_ids when previously customer had skip_invoice_custom_sections" do
let(:section_ids) { [] }

before { customer.update(skip_invoice_custom_sections: true) }

it "sets skip_invoice_custom_sections to false" do
service.call
expect(customer.reload.skip_invoice_custom_sections).to be false
expect(customer.selected_invoice_custom_sections.ids).to match_array([])
expect(customer.applicable_invoice_custom_sections.ids).to match_array(customer.organization.selected_invoice_custom_sections.ids)
end
end
end

context "when updating customer to skip_invoice_custom_sections" do
let(:skip_invoice_custom_sections) { true }

before { customer.selected_invoice_custom_sections << invoice_custom_sections[1] }

it "sets skip_invoice_custom_sections to true" do
service.call
expect(customer.reload.skip_invoice_custom_sections).to be true
expect(customer.selected_invoice_custom_sections).to be_empty
expect(customer.applicable_invoice_custom_sections).to be_empty
end
end

context "when an ActiveRecord::RecordInvalid error is raised" do
let(:section_ids) { invoice_custom_sections[1..2].map(&:id) }

before do
allow(customer).to receive(:selected_invoice_custom_sections=).and_raise(ActiveRecord::RecordInvalid.new(customer))
end

it "returns record validation failure" do
result = service.call
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
end
end
end
end
Loading

0 comments on commit 5437092

Please sign in to comment.