-
-
Notifications
You must be signed in to change notification settings - Fork 572
fix(kit_creation): update item visibility and value during kit creation #5411
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
base: main
Are you sure you want to change the base?
Changes from 4 commits
9e41917
a96b468
984aea5
46287db
56a553e
b9d607b
4182295
12936cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class ItemUpdateService | ||
| attr_reader :item, :params, :request_unit_ids | ||
| def initialize(item:, params:, request_unit_ids: []) | ||
| @item = item | ||
| @request_unit_ids = request_unit_ids | ||
| @params = params | ||
| end | ||
|
|
||
| def call | ||
| ActiveRecord::Base.transaction do | ||
| item.update!(params) | ||
| update_kit_value | ||
| if Flipper.enabled?(:enable_packs) | ||
| item.sync_request_units!(request_unit_ids) | ||
| end | ||
| end | ||
| Result.new(value: item) | ||
| rescue => e | ||
| Result.new(error: e) | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def update_kit_value | ||
| return unless item.kit | ||
|
|
||
| kit_value_in_cents = item.kit.items.reduce(0) do |sum, i| | ||
| sum + i.value_in_cents.to_i * item.kit.line_items.find_by(item_id: i.id).quantity.to_i | ||
| end | ||
| item.kit.update!(value_in_cents: kit_value_in_cents) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,11 @@ def call | |
| unless item_creation_result.success? | ||
| raise item_creation_result.error | ||
| end | ||
| kit.items.update_all(visible_to_partners: kit.visible_to_partners) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This definitely shouldn't happen - the items' visibility shouldn't be affected by a kit's visibility. The ticket was asking for the kit item (i.e. kit.item, not kit.items) to have its visibility updated. |
||
| kit_value_in_cents = kit.items.reduce(0) do |sum, i| | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This probably should be moved into a method on |
||
| sum + i.value_in_cents.to_i * kit.line_items.find_by(item_id: i.id).quantity.to_i | ||
| end | ||
| kit.update!(value_in_cents: kit_value_in_cents) | ||
| rescue StandardError => e | ||
| errors.add(:base, e.message) | ||
| raise ActiveRecord::Rollback | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require "rspec" | ||
|
|
||
| RSpec.describe ItemUpdateService, type: :service do | ||
| describe ".call" do | ||
| subject { described_class.new(item: item, params: params, request_unit_ids: request_unit_ids).call } | ||
|
|
||
| let(:kit) { create(:kit) } | ||
| let(:item) { create(:item, kit: kit) } | ||
| let(:item2) { create(:item, kit: kit) } | ||
| let(:params) do | ||
| { | ||
| name: "Updated Item Name", | ||
| reporting_category: "pads", | ||
| value_in_cents: 2000 | ||
| } | ||
| end | ||
| let(:request_unit_ids) { [] } | ||
| let(:kit_value_in_cents) do | ||
| kit.line_items.reduce(0) do |sum, li| | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use actual values in the spec rather than calculating them from the factory. It's better to create explicit records with known values and use those values during checks. |
||
| item = Item.find(li.item_id) | ||
| sum + item.value_in_cents.to_i * li.quantity.to_i | ||
| end | ||
| end | ||
|
|
||
| context "params are ok" do | ||
| it "returns a Result with success? true and the item" do | ||
| result = subject | ||
| expect(result).to be_a_kind_of(Result) | ||
| expect(result.success?).to eq(true) | ||
| expect(result.value).to eq(item) | ||
| end | ||
|
|
||
| it "updates the item attributes" do | ||
| subject | ||
| item.reload | ||
| expect(item.name).to eq("Updated Item Name") | ||
| expect(item.value_in_cents).to eq(2000) | ||
| end | ||
|
|
||
| it "updates the kit value_in_cents" do | ||
| subject | ||
| kit.reload | ||
| expect(kit.value_in_cents).to eq(kit_value_in_cents) | ||
| end | ||
| end | ||
|
|
||
| context "params are invalid" do | ||
| let(:params) do | ||
| { | ||
| name: "" # Invalid as name can't be blank | ||
| } | ||
| end | ||
|
|
||
| it "returns a Result with success? false and an error" do | ||
| result = subject | ||
| expect(result).to be_a_kind_of(Result) | ||
| expect(result.success?).to eq(false) | ||
| expect(result.error).to be_a(ActiveRecord::RecordInvalid) | ||
| expect(result.error.message).to include("Validation failed: Name can't be blank") | ||
| end | ||
|
|
||
| it "does not update the item attributes" do | ||
| original_name = item.name | ||
| subject | ||
| item.reload | ||
| expect(item.name).to eq(original_name) | ||
| end | ||
|
|
||
| it "does not update the kit value_in_cents" do | ||
| original_kit_value = kit.value_in_cents | ||
| subject | ||
| kit.reload | ||
| expect(kit.value_in_cents).to eq(original_kit_value) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,22 +24,25 @@ | |
| } | ||
| end | ||
| end | ||
| let(:kit_value_in_cents) do | ||
| line_items_attr.sum do |li| | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto here. |
||
| item = Item.find(li[:item_id]) | ||
| item.value_in_cents.to_i * li[:quantity].to_i | ||
| end | ||
| end | ||
|
|
||
| it 'should return an the instance' do | ||
| expect(subject).to be_a_kind_of(described_class) | ||
| end | ||
|
|
||
| context 'when the parameters are valid' do | ||
| it 'should create a new Kit' do | ||
| expect { subject }.to change { Kit.all.count }.by(1) | ||
| expect { subject }.to change { Kit.count }.by(1) | ||
| expect(Kit.last.value_in_cents).to eq(kit_value_in_cents) | ||
| end | ||
|
|
||
| it 'should create a new Item' do | ||
| expect { subject }.to change { Item.all.count }.by(1) | ||
| end | ||
|
|
||
| it 'should create the new Item associated with the Kit' do | ||
| expect { subject }.to change { Kit.all.count }.by(1) | ||
| expect { subject }.to change { Item.count }.by(1) | ||
| end | ||
|
|
||
| context 'but an unexpected error gets raised' do | ||
|
|
@@ -92,6 +95,14 @@ | |
| end | ||
| end | ||
|
|
||
| context 'line_items_attributes is empty' do | ||
| let(:line_items_attr) { [] } | ||
|
|
||
| it 'should have an error At least one item is required' do | ||
| expect(subject.errors.full_messages).to include("At least one item is required") | ||
| end | ||
| end | ||
|
|
||
| context 'because the kit_params is invalid for kit creation' do | ||
| let(:kit_params) { { organization_id: organization_id } } | ||
| let(:kit_validation_errors) do | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're doing a lot of extra queries this way... I'd recommend instead looping over the line items, so you have access to the quantity, and then looking at the item. E.g.