-
Notifications
You must be signed in to change notification settings - Fork 72
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
Allow creating custom vat rates #377
Allow creating custom vat rates #377
Conversation
❌ Deploy Preview for ecommerce-events failed.
|
@@ -81,11 +81,16 @@ def register_customer(name) | |||
end | |||
|
|||
def register_product(name, price, vat_rate) | |||
add_available_vat_rate(vat_rate) |
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.
Do you think this is fine?
If two products will be created with the same vat rate then this will attempt to create two vat rates with the same code. The second attempt will fail and return 422 response. This does not interfere with test logic but I'd like to know if making this call every time when we register product is fine.
The other option is to change every test using register_product
so they also explicitly create vat rates.
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.
I am afraid that having such solution would lead to hacking. Also, it would make the method name invalid.
I'd prefer if the add_available_vat_rate
is called just once. In fact, all we need is to have available rates defined before tests are run.
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.
Thanks 👍 I didn't know how to do it in a way that it is called only once but I added it to each test needing it (inside a setup block).
def to_value | ||
Infra::Types::VatRate.new(code: code, rate: rate) | ||
end |
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.
Other models don't have any methods but this was very useful. I can remove and refactor if we don't want to have any methods in models
|
||
def stream_name(cmd) | ||
"Taxes::AvailableVatRate$#{cmd.vat_rate.code}" |
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.
I'm using code
instead of uuid
in the stream name.
This helps ensure uniqueness of vat rates and simplifies some logic.
Please let me know what you think.
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.
Technically it is a good choice. However I am wondering if the model is correct. But I don't have an answer yet. It is good for first iteration I guess.
refute catalog.vat_rate_available?(vat_rate.code) | ||
end | ||
|
||
def test_returns_false_when_vat_rate_is_not_available_even_when_other_vat_rates_are_available |
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.
I don't quite like this test but mutant complained without it:
@event_store
.read
.stream("Taxes::AvailableVatRate$#{vat_rate_code}")
.to_a
.any?
Mutant indicated that this code passes all the tests without the stream
filter.
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.
I think the test if fine, but the name of it could be improved.
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.
I had to change the functionality of VatRateCatalog so I removed these tests.
ecommerce/taxes/lib/taxes/product.rb
Outdated
def set_vat_rate(vat_rate) | ||
raise VatRateNotApplicable unless vat_rate_applicable?(vat_rate) | ||
def set_vat_rate(vat_rate, catalog) | ||
raise VatRateNotApplicable unless vat_rate_applicable?(vat_rate.code, catalog) |
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.
The validation checking if the vat rate is available should happen outside of the domain model
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.
Thanks @lukaszreszke! Can you help me figure out where to put it? Is command handler a better place for it?
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.
Yes - command handler is better place for checking such a logic.
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.
Done!
attr_reader :code, :rate | ||
|
||
def initialize(params) | ||
@code = params[:code] | ||
@rate = params[:rate] | ||
end |
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.
def set_product_vat_rate(product_id, vat_rate_code) | ||
vat_rate = Taxes::Configuration.available_vat_rates.find{|rate| rate.code == vat_rate_code} | ||
def set_product_vat_rate(product_id, vat_rate) | ||
vat_rate = VatRates::AvailableVatRate.find_by!(code: vat_rate).to_value |
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.
I don't think that the controller should validate if the vat rate exists
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.
Especially as it happens in the domain model (which is also not correct).
Would you move it to the SetVatRateHandler
?
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.
Done 👍
rescue ProductCatalog::AlreadyRegistered | ||
flash[:notice] = "Product was already registered" | ||
render "new" | ||
rescue Taxes::VatRateNotApplicable | ||
flash[:notice] = "Selected VAT rate is not applicable" | ||
render "new" |
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.
I extracted this because it was inside a transaction before.
product_id = SecureRandom.uuid | ||
vat_rate_set = VatRateSet.new(data: { product_id: product_id, vat_rate: available_vat_rate }) | ||
vat_rate_set = VatRateSet.new(data: { product_id: product_id, vat_rate: vat_rate }) |
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.
small tip, you could do
vat_rate_set = VatRateSet.new(data: { product_id:, vat_rate: })
instead :)
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.
I would prefer to leave this as is for now, as it is consistent with the rest of the code in the project. In the future we can add a rubocop rule to enforce style guides :)
class AvailableVatRate < ApplicationRecord | ||
self.table_name = "available_vat_rates" | ||
|
||
def to_value |
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.
It is not used anymore, you can remove this method in next PR :)
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.
I already removed it :)
Issue: #174
This PR lets users create custom VAT rates. Previously, VAT rates were hardcoded in the configuration files, but now users can add their own. It is not possible to add two VAT rates with the same code (it would be very confusing if we had duplicates).
In my changes VAT rate codes can be strings, like "20.0 % S" or "5.0 % R" (source). However, when adding a product, the system still checks if the VAT rate code is a number, which breaks the flow for vat rates with string names. I’ll fix that in a separate PR, along with some confusing naming, to keep this one focused.
Nagranie.z.ekranu.2024-08-13.o.16.52.42.mov