Refactoring

Summarized using AI

Spree Adjustments

Ryan Bigg • March 06, 2014 • Earth

In the video 'Spree Adjustments' by Ryan Bigg, presented at Ruby on Ales 2014, the focus is on the refactoring of adjustment handling in the Spree 2.2 release, emphasizing improvements in tax, shipping, and promotional calculations. The talk covers motivations behind the refactoring and practical steps for beginners to engage with the new adjustment code. Key points include:

  • Overview of Spree's Complexity: Bigg humorously touches on Australian stereotypes before diving into the complexities of the existing Spree adjustment system, which he describes as verbose and difficult to navigate due to numerous command regulations.

  • Simplification Goals: Ryan outlines the need for simplified adjustments, pointing out that previous methods could confuse refunds by having different adjustment applications based on scenarios, whether for line items or orders.

  • Detailed Tax Adjustments: He highlights the importance of calculating item-specific taxes accurately. The new system standardizes tax application across line items rather than applying a single tax adjustment for the order, facilitating easier refunds and clearer tax liability understanding.

  • Promotions and Adjustments: The talk explains how the new adjustment framework allows the combination of promotions and discounts, such as free shipping alongside percentage discounts. This flexibility aims to enhance customer experience by applying the most beneficial promotions.

  • Robust Testing and Consistency: Emphasis is placed on having a robust testing environment to maintain accuracy. Bigg mentions the need for avoiding excessive calculations and over-complication, striving for consistency within Spree’s code structure.

  • Conclusion on Functional Changes: Ryan wraps up by affirming that the changes significantly ease the overall tax and adjustment calculations within Spree, allowing users to focus more on operational aspects rather than getting bogged down in complex adjustment rules.

Ultimately, the presentation provides an insightful look at how the Spree 2.2 adjustments can streamline e-commerce operations, especially concerning taxation and promotional activities, making it easier for developers and merchants alike to manage their online sales environments effectively.

Spree Adjustments
Ryan Bigg • March 06, 2014 • Earth

By Ryan Bigg
The brand new Spree 2.2 release contains a complete refactoring of how adjustments are handled. Whether you're interested in taxes, shipping or promotions you'll want to attend Ryan Bigg's comprehensive talk and learn more. The talk will include motivation for refactoring as well as how to get up and running with the new adjustment code.

Help us caption & translate this video!

http://amara.org/v/FG14/

Ruby on Ales 2014

00:00:16.640 Okay, there we go. First of all, some Australian facts. These are some people going to the local shopping center. We have some really strong over-the-counter drugs; they're amazingly potent. I once gave an over-the-counter drug to an American, and when I woke up, he was laying across the bathroom floor.
00:00:24.480 I asked him, 'What are you doing?' and he replied, 'What are you doing?' It was so strange. So yeah, we do have some really big spiders. They aren't five meters tall; they're only about the size of your hand. So, that's fine. They're not actually the most poisonous creatures in Australia. That title belongs to the box jellyfish, which are about an inch big. These guys will really screw up your life.
00:00:43.760 We have a prime minister, and he's not very well-liked. Some people created a Chrome extension called 'Stop Tony Meow.' That guy's name is Tony, and the extension replaces pictures of Tony Abbott with pictures of kittens. It's wonderful; I love it! Now, I want to talk about adjustments within Spree.
00:01:10.640 Who here has ever battled with Spree? I don't think there's going to be anyone who hasn’t. Whoa! Oh, there's like a whole handful of you people. That’s awesome! Sean came down from the mountain and in the book of Spree, it’s written: 'Then Sean turned and went down from the mountain with two tablets of testimony in his hand.' Tablets which were written on both sides.
00:01:31.920 Yes, the book of Spree is quite verbose. On these tablets, there were all these commandments written. Let’s run through them right now. We've got a whole list—looks like that’s crazy. Who wants to read all that? No one does. First of all, we need to retain order-wide adjustments within Spree. We had the concept that you should be able to get a discount in your order if you mess it up.
00:02:04.320 So, if we screw it up, have 20 dollars off, you should also be able to have additional discounts. For example, use this coupon code to get $10 off. We should also have discounts for specific customers. If you have an educational customer, that's $15 off; 5% off for members. Shipping taxation can vary; when shipping from place A to place B, some places require you to tax shipping while other places do not.
00:02:39.680 We should be able to refund specific items easily. In Australia, we have this wonderful tax called the GST. It's literally the best tax in the world, believe me, I have done my research. It's 10%—it's either on, or it's off! That’s it; that’s the complexity of it all. The difficulty though in Spree is that the tax adjustment is applied to the entire order.
00:03:11.680 For example, you could have a $3.63 tax adjustment for this entire order, making it very difficult to calculate how much tax any specific item is incurring. In our adjustments refactoring, we need to figure out how to do that properly. We need to freeze order adjustments if a price changes after the order is completed. The order total shouldn't change; it should just be frozen.
00:03:38.720 We need to be able to refund the value-added tax outside of the EU. If you’re in an EU country—anyone here from the EU? Yes? Awesome! If you're shipping from outside the EU to a country outside of the EU, you need to refund the value-added tax of your country. Additionally, we need to allow multiple discounts per order.
00:04:06.800 A lot of people were asking if we could have a free shipping promotion and a 10% off promotion, and we would always reply, 'No, you cannot.' But we do it really nicely; it’s like, 'Thank you for asking, but no, you can’t. Goodbye!' We need to have a robust test suite, and we already have one of these in Spree.
00:04:38.560 It has about 1500 examples at least, so we’ve already got that. I don’t know why Sean included that in his commandments, but there you go. We needed to scrap events and notifications—we were using the wonderful Active Support notification class and doing it really poorly.
00:05:02.560 So, these needed to go. In the past, we were calling a method called 'fire event.' For instance, when a product was added to the cart, we would call this method, which would find all the instances of the Spree activator class that matched 'Spree cart add,' and it would try to activate them one at a time. This sounds okay so far, but imagine having 500 activator instances all with 'Spree cart add.' You can see how it starts to pile up.
00:05:36.560 We're getting rid of events and notifications because it’s super confusing. Next, we have some ground rules. First of all, we have the nine commandments offered by Sean, and now we have a lettered list. Next, we’ll have a Roman numeral list. The first ground rule is to avoid excessive calculations, of course, because when you're writing code you want it to perform as quickly as possible.
00:06:17.440 Ground rule two is to avoid multiple adjustments per line item. Now, it sounds like a good idea in theory, but later I’ll explain why it’s not okay and why we shouldn't overly complicate things. Spree is already pretty complicated; it has over 86,000 lines of code in just its five components.
00:06:58.000 Then we have all the extensions—with hundreds of thousands of lines in total. So, to say that we're not going to overly complicate things—I don't like that. So, let’s stay with the top two rules. Speaking of overly complex situations, let's talk about Magento. Magento has 484 commits.
00:07:26.480 That’s a lot of stuff happening with a whopping eight million lines of code. I'm not sure if you've ever worked on a codebase this huge. Has anyone ever worked on a codebase this big? Okay, impressive! Magento is made up of wonderful languages such as PHP, XML, and JavaScript. In fact, 17% of Magento's code is XML.
00:08:02.080 Seventeen percent—almost one-fifth of their code base is XML. I love XML; I could talk about XML all day, but I’m going to talk about something way more interesting than that: sales tax. This is the point where you all go into your lunch siesta mode. Sales tax is super complicated—it’s really complicated.
00:08:24.480 Can anyone tell me what the New York sales tax is for these two items? They both cost almost $20 each. New York sales tax? Eight point four percent? Depends on where it’s being shipped, but here’s the kicker. Clothing and footwear under $110 are exempt from the New York City and New York State sales tax!
00:09:04.960 So New York doesn’t have a sales tax for these two items! Purchases above $110 are subject to a 4.5% New York City sales tax and a 4% New York State sales tax. You combine these two tax rates. For these two items, there is no sales tax because they are both under $110.
00:09:40.400 As I was saying before, in Australia we have this wonderful tax code: the Goods and Services Tax (GST). Literally, as I said before, the best tax ever—and I have done my research! So, on these two items costing $20 each, you would have a $3.63 tax included. That’s it! Simple. It’s so simple; it’s either there or it’s not.
00:10:02.720 I'm not going to run through which items are taxed and which are not because that will take literally all this conference and then some more. So let’s move on to the EU. The EU is slightly more complex than Australia. For example, France has a 20% VAT, but on items like newspapers, it has a 2% VAT. I think hotels have a tax between 6% and 8%.
00:10:47.440 Germany has its own rules; France has its reduced VAT rate and a proper VAT rate. So you have Australia, which is this super simple system; it's applied or it's not. Then you have France and Germany with slightly more complex rules concerning their different VAT rates. Then there’s my favorite country in the world: the U.S. of A.
00:11:26.240 America! Where’s the eagle? Somewhere around, trucks and everything. In the U.S., you guys have this weird tax system—like, I just don’t understand what’s up with it! Here’s a map of all the sales taxes in the U.S. as of January 1st, 2012. And by the way, this changes every day.
00:12:03.440 Oregon is one of the really cool states because they don’t have a sales tax. Alaska is also cool because they mostly don’t have a sales tax. Everywhere else is quite complicated! Just taking a little click around a map of D.C., you can see that there are about three different tax rates.
00:12:48.360 There’s 5.3% in the middle of Washington, 5.75% around that area, and then 6% on the outskirts. You can see where you are taxed anywhere in the U.S.-- from zero percent sales tax to about eleven point seven two five percent. That calculates out to about an extra $4.68 just on sales tax.
00:13:21.680 If you have nexus in a state—like if you’re selling products from that state; a friend said he’s based in Oregon but was in Washington. Because he’s selling products out of Washington, they must pay the Washington sales tax—crazy! And you guys call yourselves the United States? You can’t agree on taxes.
00:13:58.480 Taxes have been around for thousands of years. The Romans have written annuals about collecting taxes, and you guys still can’t come to terms with such a simple system. There are two companies that handle tax really well: Tax Cloud and Avatax. Tax Cloud is the map that I clicked around in D.C., and Avatax tracks the eleven thousand different tax rates in the U.S. and updates them whenever they change.
00:14:51.040 With that out of the way, let’s talk about the old adjustments within Spree. It’s fairly interesting, too. In the old adjustment system, we had these four attributes associated with them. You have the source, which is like the thing that's supposed to carry out the adjustment. The originator might be the same as the source, but it could also be the thing that’s being adjusted.
00:15:07.680 The adjustable is, of course, the thing being adjusted, and the amount is self-explanatory. In a tax adjustment, you have the source being the order, the originator being the tax rate, and the adjustable also being the order. The order is the entity being adjusted.
00:15:31.600 What we would do is call that to the tax rate model, which would adjust the calculations. Inside of Spree, there is a tax category for an item and a zone. You can match the tax category with the zone and determine the rate that applies. For example, in Australia, there’s the clothing tax category. When you factor in Australia as the zone, you can work out that it's a 10% sales tax for clothing.
00:15:58.640 Food in New York is 8.875%, and it's exceptionally difficult to do the mental math! The Spree tax system used to be complex. If you purchased items in the same country as the store, like in Australia, and the price was inclusive of tax, then you needed to apply an adjustment to every line item.
00:16:30.720 Let’s say in early versions of Spree, you have a $1.82 tax for this item. The same tax for another item would make the total $3.64 applied to each line item, one at a time. But if the tax was being refunded like shipping from the EU to Australia, we applied one big negative adjustment to the order.
00:16:54.760 This isn’t consistent because in one case we are applying adjustments to the line items while in another case it’s applied to the order. You would have a $1.82 refund for one item and then another $81.82 refund form for the entire order adjustment, leading to confusion. Calculating how much tax any line item incurs during a refund is really difficult.
00:17:36.080 In the new adjustment system, we decided to standardize everything. So whether you’re in the U.S. or Australia, we apply a positive adjustment to the line item. If you are doing a refund, then it's a negative adjustment. It’s quite simple and it makes refunds much easier.
00:18:17.680 For example, you can now calculate how much tax an item has incurred by simply looking at the line item. If a line item incurred $1.82 in tax and there are three of those line items which incur a $4 tax each, you can simply divide and determine the tax applied per item. We have methods like tax total on each line item, the shipment, and the order.
00:19:00.000 Then you can work out the various tax adjustments for that order and ensure you’re in the clear of any audits by the IRS or your local tax authority! We also have this complex situation of included versus additional taxes in our new system.
00:19:26.080 As I touched on earlier, in Australia we have included taxes. If an item on the shelf says $10, you pay that at the register. In the U.S., if you buy an item for $10, the amount you see at the register will be different depending on where you are.
00:19:49.680 So what we have instead is that we have included tax total and an additional tax total. This way, we can accurately calculate total taxes on items as needed. In the new system, for instance, the first line item here might have a tax adjustment of $3.63, while the next could be $1.82. It’s straightforward in the U.S. with one adjustment per line item, like a $1.39 tax.
00:20:18.560 We also introduced a field in the adjustments called 'included' to determine whether or not an adjustment should count towards the final total amount of that particular item being adjusted. In 2.2, we ended up getting rid of 'originator' because it was confusing.
00:20:38.080 Shipment adjustments are varied. We would apply adjustments to the shipment when a shipment was selected. You’d get a list of shipping methods applied to that shipment; for instance, UPS ground shipping costs $5. If you want express shipping, it’s $15; super express is $30. We used to apply the cost as an adjustment, but now we set this directly as an attribute in the shipment model.
00:21:06.800 I have no idea why we didn’t do this earlier, but that’s as simple as it gets. Shipment taxation is a whole different topic. In Spree, shipping methods have specific tax categories. You can view the shipping methods alongside the destination zone and use the tax category and zone to determine what the rate should be taxed.
00:21:45.520 In Spree 2.2, we began taxing both line items and shipments. Previously, we were applying an adjustment based on the shipment cost. In fact, now the only adjustment on the shipment is the tax rate.
00:22:23.920 When it comes to promotions, it’s a whole other ball game. I love the complex promotion rules that people have; they can be highly intricate, like if it’s a Tuesday, and it’s a full moon, and I’m wearing a red shirt, and the customer’s name starts with P, and they’re buying three items, but the total is an odd number, and they happen to be left-handed, then they should get a 10% discount.
00:22:52.080 We had order promotions where the source was the order, the originator was the promotion action (the thing doing the adjusting), and the adjustable would be the order. So you’d have a $10 off promotion, for example, and these items might each receive a $2 reduction.
00:23:32.000 However, the issue arises with working out what promotion applies to a specific item when you’re refunding it. In Spree 2.2, it works where there’s one adjustment per line item. So, for the first line item, you might have a negative adjustment of $2, and for the second line item, you’d also have a negative $2 adjustment. This makes it incredibly easier.
00:24:09.480 More on promotions: we have a concept called promotion handlers. An order calls out to a promotion handler, which checks the eligibility of that promotion on a particular line item. If the promotion applies, you can activate it. For example, if you're using a coupon code, you’ll seek all the matching promotions and validate their eligibility.
00:24:32.560 This can fail if a promotion has already been applied. So if you’ve got free shipping and then apply a coupon code for $10 off shipping, the free shipping promotion is going to take precedence. We only attempt the application of the promotion and report on the success or failure.
00:25:00.080 We’d find all the free shipping promotional actions, check eligibility for that order, and activate them. The next step is to pick a winner out of the different promotions that are applied. Suppose you have a line item with multiple promotions—say one for $10 off and another for $10 off, but both are applied differently.
00:25:21.760 If the total item costs say $10, one will give a $10 discount, while the other is less advantageous. Thus, the one that provides the larger discount prevails.
00:25:33.440 So we're creating a framework for promotions that prioritize the best offerings for the customer. This deal has a large scope of flexibility when it comes to adjustments.
00:25:51.920 In summary, can you combine a free shipping promotion and a 10% off promotion in Spree 2.2? Yes! You absolutely can—so please stop asking! Can you do order-wide adjustments? Yes; you have always been able to do order-wide adjustments.
00:26:11.360 Can you do discounts and credits? Yes, you can do discounts, but no, you can't do credits yet. It gives and then takes away. Can you do group discounts? No, you can't; they're coming soon, but it’s very complex. Shipping taxation? Yes, yes! So you won't get audited by the IRS anymore.
00:26:31.040 Because your shipments aren't taxed and you don’t have a $2,000 shortfall in your tax payment this year! Being audited is not a concern anymore! Refunding items? We’re working on that too! Adjustments freezing? Well, it's always been that way. Once an adjustment is done, once the order is locked—that's it! It'll never change again.
00:27:10.880 That’s refunding! Yes, we do that, and now we apply a negative adjustment to each line item rather than one adjustment for the entire order. Multiple discounts per order? What we can have is one promotion adjustment that wins out, one credit adjustment that wins out, and one taxation adjustment.
00:27:23.680 That’s it! We have a robust test suite, of course! We avoid excessive calculations because we’ve taken it apart and put it back together again. We've got missing pieces—good missing pieces!
00:27:37.440 We can avoid multiple adjustments per line item now, but we will have multiple adjustments, so you’ll see a line that costs $15; then a promotion adjustment reduces the price to $10. If we apply a credit that reduces it to $8, then you’ll need to figure the tax on the $8 item.
00:28:04.640 That makes this straightforward, making adjustments more transparent and easier. Commandments, inheritance, Sean asked that the new adjustment system have some form of inheritance; however, in Spree, we're trying to avoid that. We’re aiming for a simpler, consistent, and flexible adjustment system.
00:28:24.240 So, Steve Klabnik is here, and you’ve been wonderful! Any questions?
00:28:49.680 Yes? Let me bring up the big slide! There you go, enjoy it! That took me about five minutes this morning. But I am legitimately Steve Klabnik—look, I got his badge! How’s he standing like that? Cool! Thank you!
00:29:06.720 No more questions?
00:29:12.720 The Wallabies?
00:29:19.760 It’s okay, thank you everyone! I’ll have that!
00:29:30.080 All right, thanks Ryan! That presentation was very interesting, but I found it sort of taxing.
Explore all talks recorded at Ruby on Ales 2014
+3