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

Remove currency from line items #1507

Merged
merged 8 commits into from
Oct 13, 2016

Conversation

kennyadsl
Copy link
Member

@kennyadsl kennyadsl commented Oct 7, 2016

This PR removes currency from line items. That field is no more useful since all order contents will have the same currency (the order one).

ref: #1399

TODO:

  • Understand what happens when the order currency is changed. Can this happen? Shouldn't we recalculate prices for all line items with the new currency? Is this already handled by the order merger? Handled with a separate Issue
  • Remove currency from spree_line_items database table. I'm a bit concerned about this. What happens if there are users that rely on this field has custom logic related to line item currency (like statistics)? They could loose them. Can we proceed anyway or it's better to leave the field in the database and mark it for a future removal?
  • Update changelog

@kennyadsl kennyadsl force-pushed the remove-currency-from-line-items branch from 5c0c145 to f2d2dde Compare October 7, 2016 16:07
There's no need to compare currency on all line items since they
all have the same currency, same as their order.
@kennyadsl kennyadsl force-pushed the remove-currency-from-line-items branch 2 times, most recently from f4dc323 to 571b3d7 Compare October 8, 2016 10:28
Copy link
Contributor

@mamhoff mamhoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really, really good work. I have a couple of more nits, but I think the general direction is great. 👍

end

def currency
order.currency if order
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written shorter as a delegate:

delegate :currency, to: :order

#
# @param [Spree::Money] money - the money object to obtain price and currency from
# @param [Spree::Money] money - the money object to obtain price from
def money_price=(money)
Copy link
Contributor

@mamhoff mamhoff Oct 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should have a Safeguard: It should raise a good error when trying to assign a price with a currency different to the order currency. Otherwise the information would just be lost. So something along these lines:

class CurrencyMismatch < StandardError; end

def money_price=(money)
   return unless money
   raise CurrencyMismatch, "Line item price currency must match order currency!" if money.currency.iso_code != currency
   self.price = money.to_d
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is good. I have a feeling one could golf around in this method a bit more, but I'm fine leaving it as is because it does the right things.

end
end

def pricing_options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like removing things from the public interface, but I'm not sure about moving this method to the private section.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted this change for now. I'm probably missing something but at the moment I cannot see any scenario when something else then the line item itself could need to be aware of these specific line item pricing options. That's why I'd move it to the private section, but I'm ok leaving it in the public one as well.

self.cost_price ||= variant.cost_price
self.money_price = variant.price_for(pricing_options) if price.nil?
self.money_price = price_from_options if price.nil?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for extracting this method? I wouldn't do that. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reading the code again, I think you are right. There's no reason to extract this method. Going to revert this change.

@@ -33,7 +33,7 @@ def self.default_price_attributes
def self.from_line_item(line_item)
tax_address = line_item.order.try!(:tax_address)
new(
currency: line_item.order.try(:currency) || line_item.currency || Spree::Config.currency,
currency: line_item.order.try(:currency) || Spree::Config.currency,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the delegate, this can actually be written shorter as line_item.currency :)

it needs `allow_nil` set to true because the variant pricing
options should work even when the line item has no order
associated.
Previously if a price with a currency different from the
order currency was set on a line item, it was just taking
the wrong price amount without explictily rasing an error.
@kennyadsl kennyadsl force-pushed the remove-currency-from-line-items branch from 571b3d7 to d47b62c Compare October 8, 2016 22:13
Copy link
Member Author

@kennyadsl kennyadsl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mamhoff thanks a lot for the hints! Please let me know if you see anything else that can be improved.

end
end

def pricing_options
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted this change for now. I'm probably missing something but at the moment I cannot see any scenario when something else then the line item itself could need to be aware of these specific line item pricing options. That's why I'd move it to the private section, but I'm ok leaving it in the public one as well.

It's no more allowed to have line item with a currency
different from the order currency. The line item currency
will be taken from the order directly so this field is no
more needed.
@kennyadsl
Copy link
Member Author

@mamhoff please check again when you have time, thanks a lot!

@kennyadsl kennyadsl changed the title WIP: Remove currency from line items Remove currency from line items Oct 11, 2016
Copy link
Contributor

@mamhoff mamhoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, @kennyadsl - I think this is good to go now!

#
# @param [Spree::Money] money - the money object to obtain price and currency from
# @param [Spree::Money] money - the money object to obtain price from
def money_price=(money)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is good. I have a feeling one could golf around in this method a bit more, but I'm fine leaving it as is because it does the right things.

# When price is part of the options we are not going to fetch
# it from the variant. Please note that this always allows to set
# a price for this line item, even if there is no existing price
# for the associated line item in the order currency.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good documentation. I wish I'd had that when first reading this method :)

self.price = nil
return
end
raise CurrencyMismatch, "Line item price currency must match order currency!" if money.currency.iso_code != currency
self.price = money.to_d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little tough to parse with the early return inside the unless (which has me thinking about the rest of the method like the double negative unless...else).

I think it would read better as an if/elseif/else

  if !money
    self.price = nil
  elsif money.currency.iso_code != currency
    raise CurrencyMismatch, "Line item price currency must match order currency!"
  else
    self.price = money.to_d
  end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jhawthorn thanks for your review. Agree on the better readability of suggested version. Changed!

Copy link
Contributor

@jhawthorn jhawthorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than one suggestion this is great.

Thank you @kennyadsl

This prevents to keep storing the old price (valid) when
passing a new nil money object (invalid) to the `money_price`
setter method.

Previously:

line_item.price               => #<BigDecimal: 33.22>
line_item.money_price = nil
line_item.price               => #<BigDecimal: 33.22>

Now:

line_item.price               => #<BigDecimal: 33.22>
line_item.money_price = nil
line_item.price               => nil
@kennyadsl kennyadsl force-pushed the remove-currency-from-line-items branch from 73660fa to 1d92f39 Compare October 12, 2016 18:39
@jhawthorn jhawthorn merged commit 20fc1b0 into solidusio:master Oct 13, 2016
@kennyadsl kennyadsl deleted the remove-currency-from-line-items branch October 14, 2016 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants