Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat (invoice_custom_sections): customer update service #2960

Merged
merged 29 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
681222c
Add InvoiceCustomSections::UpdateService
annvelents Dec 6, 2024
28e5ac5
add destroy service to invoice_custom_sections family
annvelents Dec 9, 2024
829172a
WIP adding destroy mutation
annvelents Dec 10, 2024
b0708ca
add single invoice_custom_section resolver
annvelents Dec 11, 2024
42c36af
fix the tests
annvelents Dec 11, 2024
3ccaf94
fix linter
annvelents Dec 11, 2024
0c144cb
fix rebase conflict
annvelents Dec 20, 2024
9a21b3f
Add InvoiceCustomSections::UpdateService
annvelents Dec 6, 2024
591dd5f
add destroy service to invoice_custom_sections family
annvelents Dec 9, 2024
f2a1463
WIP adding destroy mutation
annvelents Dec 10, 2024
84ab0d7
add single invoice_custom_section resolver
annvelents Dec 11, 2024
096962e
fix the tests
annvelents Dec 11, 2024
1a0b6f4
fix linter
annvelents Dec 11, 2024
b5ba87b
WIP update customer with invoice_custom sections service
annvelents Dec 13, 2024
e684f5e
refactoring of the select and deselect services
annvelents Dec 13, 2024
04c8aeb
fix rebase conflict
annvelents Dec 20, 2024
ec0ca77
finish refactoring
annvelents Dec 20, 2024
893f2fe
fix and add tests
annvelents Dec 23, 2024
a66f17b
fix linter
annvelents Dec 23, 2024
d6d59bd
remove not needed organization call
annvelents Dec 23, 2024
e56152a
fix tests
annvelents Dec 23, 2024
0828386
fix test
annvelents Dec 23, 2024
7d716b1
refactor managing invoice_custom_sections
annvelents Dec 30, 2024
cbf47f2
fix tests and a little bit more refactoring
annvelents Dec 30, 2024
59f5aca
fix linter
annvelents Dec 30, 2024
20472d8
fix last test
annvelents Dec 30, 2024
fd33738
update grapql schema
annvelents Dec 30, 2024
3455e51
cr comments
annvelents Jan 9, 2025
aed1f2c
more fixes around tests
annvelents Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
annvelents marked this conversation as resolved.
Show resolved Hide resolved
).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
8 changes: 2 additions & 6 deletions schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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
Loading