 Good afternoon everyone. Thanks for joining happy to see you. So today we're going to have a little talk about Drupal commerce first off I Presumably have some basic development knowledge as well as as well as some basic Commerce knowledge by which I mean, you know what orders are order items Products otherwise this session will be hard to follow. I think Also, I will be switching between my slides some example code and The live demo website I prepared so this can get interesting Hello, I'm Robin. I'm Drupal developer for Already, I think eight or nine years and I'm currently employed at entity one, which is a Belgian based Drupal company we Provide Drupal solutions for medium-to-large corporations, which also include e-commerce solutions I bring my crazy IDs into live in a Drupal main Drupal if you have any questions after the session or just want to talk Give me a tap on the shoulder arm or contact me via Drupal.org or the Drupal or Drupal be slack channels alright The session outline for today first we're going to tackle some Basics about commerce then we're going to see some core plugins provided by your commerce core We're going to talk about all the processors price resolvers price resolvers and useful event subscribers If there is any time left, I'll show you how to create custom workflows and transitions as well first off let me show you the Basic structure. I prepared for the demo website So I prepared a demo website where you can buy dinosaurs. This is visible for everyone Reval, okay so pretty basic just a title an image the SKU The price which are two fields added by commerce by default and then I added two custom fields to indicate whether the dinosaur is a Vegetarian and if the dinosaur can fly or not. So that is basically it All right, we're going to start off by some with some Drupal commerce basics So as all as you all know, it's recommended to install Commerce and Drupal with composer because it has quite few dependencies to country modules and external libraries Which are almost all maintained by Commerce guys, so the internationalization library addressing text and zone library The dependent contract is the address module entity API inline entity form entity revisions and spro file And also it requires you to have a lease Drupal core 8.6 and as of version 2.15 currently commerce it is at version 2.14 This will be a Drupal core 8.7. So keep that in mind All right, it has one required PHP extension You should install and it's a VC mat the price module the commerce price module requires you to install that PHP extension For some external payment providers. You also need to install the PHP soap extension, but that's optional For the people who use Drupal VM, you can just install these packages by adding following lines to your config dot yml file For people who use Docker or Orlando. I'm sure it's pretty much the same All right, so commerce and has core module commerce obviously and is separated into separate submodules each Submodule has its own functionality And are dependent to each other. So for example the order module is Dependent to the commerce price module and store module. So most of the time when you install Commerce you will almost always install all of these modules Except for the promotion module if your website doesn't need promotions or the text module if your website doesn't need any Taxes, but I think for the most part all of the other modules will be enabled All right, so I try to map out it's a little small element I'll try I try to map out the structure of commerce. You'll see there are a lot of content entities config entities plugins workflows and if this can be a little bit daunting at first It can be quite complicated But when you when you figure this out all these little separate pieces allow you to as developer really easily to extend Commerce and this makes commerce really really pluggable and that's why we're here today to talk about the extendability of commerce All right first plugins So what are plugins basically plugins are just classes which implements and Interface and which have the same swappable functionality The only special thing about a plugin is the class is all to discover by Drupal So how can you define a plugin? You have to create a class with a specific namespace You have to add an annotation to your class and third you have to extend the your own Plugin class with the base plugin with the base plugin class So always three steps creating a class with a namespace adding the annotation and we extend in the correct class class all right commerce score provides I think five or six maybe seven plugins which you can extend and create the first one we're gonna we're gonna CSD commerce condition Commerce condition is used throughout commerce For now it's only used in promotions and payment gateways where you can set conditions For example, I only want to apply this promotion when the customer has roll VIP or when the order has a total value of let's say $100 so these are the conditions same for the payment gateways But most of the time these conditions suffice, but if you need custom Custom condition you can achieve this by adding Commerce condition plug-in How can you do this? First step you add a class with following namespace. So plug in commerce condition you add An annotation to your class where you provide the ID the label the category of the Condition and the entity type on which the condition will apply this can be a commerce order item or commerce order and Last but not least you implement your class with the evaluate methods where you evaluate true or false is if the condition applies so in our dinosaur Web shop I've added a condition To check at the dinosaur is veggie. So what I did was I created the correct folder structure So source plug-in commerce condition like so In the namespace add it to the commerce condition annotation Where I'm giving it an ID readable a human readable main I'm setting on category product and I want to evaluate against a commerce order item entity and Then I just implement the evaluate methods where I'm checking if the entity is in is a commerce product variation if it has a field field underscore veggie and if so Return if the dino is veggie. Yes or no and this results in the following So I'm going to show this in the promotion UI. I enabled promotion module. I already added a promotion veggie is good and You can see here my custom condition Appears along with the other commerce court court conditions So that's how you can add custom conditions throughout commerce Commerce court commerce course only uses this in promotions and payment gateways But if some contract module also displays this form, it will also pick up your custom condition and you can Select it from the UI. All right The next plug-in. I want to show you is the promotion offer plugin. So if you add a promotion you can choose three types of offers you can The Percentage of fixed amount of or if you buy X you get a this will cover I think 95% or maybe 99% of use cases But it's still possible to add your own offer type true and offer plugin Again saying you just add a clause with the correct namespace this time promotion offer You add the correct annotation give it the ID human readable main and again you want to Indicate on What you're giving the promotion to this can be a commercial order item or a commercial order. So if you Choose for a commercial item the promotion will be applied against each commercial order item that evaluates against the conditions You can figure it and then last but not least you Implement the class For our dyno webshop I couldn't really think of a really good use case. So I cremate create it and a random percentage of Promotion where each time your patreon loads you get a random percentage off So the only thing I did was adding the correct namespace adding my annotation and then applying The promotion how can I apply a promotion? This is the code where I'm just determining how much The promotion will be by giving a random percentage of between five and fifteen percent and then I'm adding an adjustment So I'm adjusting the price of the order item. I'm adding an adjustment of The amount I calculated and I'm multiplied with negative one So to make sure it gets subtracted from the total order price and is not added to the order price I'll Get back to this in a minute. So you can see here. I'm using the promotion adjustment type This is an adjustment type provided by commerce core because yeah, I'm adding adjustments for a promotion, of course This now if you see in the back end You can see your own offer type. So we're going to Save this So now I have a promotion which will apply a random percentage off if your Dinosaur is vegetarian. So let's test this This dinosaur is not a very chip video vegetarian. I'm sorry No to use veggie This one is so I'm going to add two units to my cards I'm going to my card right now And as you can see, I'm getting at 7% discounts two times which results in 1 euro 26 cents if I update my cards because my percentage of this random this Should change to another percentage All right, our custom Promotion offer Works so this is how you can apply conditions and promotion custom promotions to commerce All right next Commerce checkout flow so each order has to go through flow to be completed and Commerce provides you with one checkout flow, which is the default checkout flow and this checkout flow contains I'll show you five or six steps. I'll show you in a minute But for some yeah customers of yours, this isn't enough or it's it is too many You can alter these steps by providing your own commerce checkout flow plug-in again Same three steps adding a closet name space annotation and implementing your class Yeah, I'll just so it show it any code example first checkout flows so By defaults commerce provide this default checkout flow with One two three four five six six steps All right, this is default How can we add our own flow? Okay, we're adding the annotation just an idea and a human readable name and What I did was I extend the multi-step default class, which is the defaults Did the commerce default and I added a negative an extra step to the beginning of the flow Step dino wisdom If you then clear your cash, I haven't pointed this out yet every time you add a new plug-in You have to clear your cash for a droogle to pick it up You can add a new checkout flow of your type you just added I Already did this so the dino flow you can see There's an extra step here before again dino wisdom, but it hasn't any pains yet So we'll provide our own custom pain To display on the step Each step can contain one or multiple pains or even none, but then the step will be skipped And again the same steps adding a class with the commerce checkout pain annotation And providing an ID the default step you want to render the pain on and your wrapper elements This can be container or field sets. I think So I'm choosing for a container just to wrap it in a diff Then I'm determining when the pain should be visible So our pain will contain an image which can be configured which I want to show on a pain So if the image is not empty Our pain will be visible And then I just render the pain to you like so I'm just displaying the configured image So again, if you clear your cash this pain should should show up in your in your flow and You can able it enable it and take safe. All right So we already started an order a few minutes ago And the checkouts flow is determined on order creates. So right now in the database my current order. So check out five has already been tagged with the default checkout flow You can see this because our first step in the dyno flow was dyno wisdom How can I Make sure my order picks up the new checkout flow is just by deleting my order. So I'll delete it and Then I'll have to do one more thing on the order type So there's only the default order type which is added by commerce. I can configure the checkout flow So my dyno flow shows up here. I'm going to save it Going back to my product overview. I'm going to add one item to my cart going to my cart click checkout and Dyno wisdom So this is how you can alter the commerce flow with custom steps and custom paints I've only overridden the get steps um Methods in my class, but there are a lot of So there are a lot of functions which you can override to make sure your flow behaves exactly like you want it so I Recommend not altering the default so because you can also alter plugins. I recommend not altering the Default commercial again. They're just adding your own plugin and extending from whichever clause you want and adding your own functionality All right So at this point we have our custom promotion our custom checkout flow with a checkout pane now we're going to add a Custom commerce tax type. So the tax module already has a lot of functional functionality out of the box again, I think 70 75% of use cases are covered by a commerce score, but if you have a difficult client which has a Complicated tax logics you can add your own tax type plugin which implements those very very complicated rules So again, we do this by adding a Commerce tech that tax type plugin and applying the tax. So again adding a tax is Adjusting the order price We have to do this true and order a jet through an adjustments and I'm choosing to do this on the order item So for each order item, I'm determining the tax and we're going to add an adjustment so it gets added to the order total Pretty simple here. I'm just adding and I'm a VAT of 21 cents next In your configuration of your store go to text types Then you can add a new text type and Your dino V8 or your text type of my dino VAT Text type will show up right here. I already added it But it's disabled. So I'm going to enable it So they are there are no configuration options here on a text type because it's always 21 cents I'm going to my Parts again, I'm going to refresh my cards by updating the quantity and The VAT should show up. All right. We have our custom VAT right here, which is quite simple right now But you can go. Yeah crazy And last but not least may be the most important one and the most difficult one to get right Is the payment gateway plugin? there are already a lot of country modules who provide payment gateways for example paypal or Stripe or some or another payment provider, but and sometimes the clients have their own payments Implementation so then you have to provide a custom payment gateway There are two types of payment gateways on-site payment gateway Which way you don't get redirected to an external payment provider and off-site payment gateway Where you get redirected to an external payment provider and get redirected back to the website after you completed or canceled the payments again To add it is quite simple We just add a payment gateway Annotation add an ID and human readable main the modes are for example, if you install the Paypal payment gateway there are two modes sandbox and life so you can configure the different options on your staging environments and your life environments I Don't need these modes right here You can add you can define forms where you can add a payment manually or receive a payment manually and then you set the payment type So I chose payment manual right here and I just extend just for the sake of the demo the manual payment provider and Yeah, all else is the same. So I don't have any Actual functionality in my class So if we run the first step of our checkouts No, sorry second step So here the payment information Currently you cannot choose between payments provides because there's only one enabled and that's a default commercial one So we're gonna enable our custom payment gate. I'm sorry Our custom payment gateway So if you edit your annotation, you can add a new payment gateway of plug-in type dino check So I provided a dino check I already added it, but it's disabled. I'm just going to enable right now. I added the payment instructions raw This message so if you configure the payments instructions This will show up on the order completed on the checkout completed step So you can configure this here and depending on the payment gateway or the payment type You chose you can configure other Payment instructions, so I'm going to enable this Then refresh and then you should okay. We can choose the manual payments now or they pay by dino check This is pretty basic right now, but if you have like an off-site payments provider Sorry plug-in you'll have to Implement three methods on notify on notifies the method that will be called when the External payment private let's your website know hey this payment was successful or this payment was not successful And then you can do whatever you want and Change the state of the order change the state of the payments So that's a notification callback the on return callback is the callback that gets executed When you get redirected back to the websites after you paid the the order and the uncancel is the Callback when you get redirected back to the website when the user for some reason cancelled the payment So you'll at least have to implement these three methods All right, that's it no of course not there are still Other plug-in types the ones the ones I showed you will be ones that you use most I think but there's also entity threats where you can alter Entity types defined by commerce core inline form which is like an equivalent for inline entity form during checkouts but a lot less code than inline entity form then the payment type again to Provide extra payment types and the same for payment methods to provide extra payment methods So this can all be extended by plugins All right, then order processors order processors What are what are order processors? Those are special services defined by commerce and they allow you to manipulate prices on an order or order item level and It is achieved through price adjustments like we've seen earlier And this is some code from commerce core where Commerce tries to find all order processors. You can see that commerce looks through all services which are tagged with commerce order dot order processor and Which have an attribute adjustment type. So if do those two requirements are fulfilled commerce will Will pick this up as an order processor. I'll show you in a minute how you can define this in your services dot yml file so first off and For my demo, I created a custom adjustment type to add shipping costs So I added an adjustment type shipping. How can I do this just by adding a yml file to my with the following name convention to my module and Adding following code to it a label a singular label a plur plur label if it has to be displayed in UI Yes, or no and you wait and then your custom adjustment type is defined next step This is the price adjustment UI if you chose Has UI to be true Next step is this defining your service in your services dot yml file and tagging it with commerce order dot order pre-sales processor and adding the adjustment type you just defined above which is in this case custom adjustments and Then last but not least implementing your processor. So I'm going to switch to an actual example now So I want to add shipping costs to my dyno web show. How can I do this? So I added an custom adjustment type dyno shipping Like so in my yml file next I had an extra service my order processor I tagged it with order processor and My adjustment type dyno shipping. So now we're all set to Create the order processor class, which is located here. I'm going to remove the return statements So what I'm doing here is I'm checking if the dyno What do you mean? If the dyno can fly whether he can fly or not So if the dyno can fly there are no shipping costs because it can fly to its own destination If it can't fly you have to a shipping costs obviously I'm doing this by adding the adjustments of type dyno shipping to each other item which has to have shipping shipping costs The shipping costs are really low to euros And I'm are multiplied by the order item quantity so I'll show this in my Checkouts in my cards. I don't think all right. We don't have any flying dinosaurs So if we update the quantity right here, we should have six euros Of shipping costs. All right shipping costs six euros We're going to add a flying dinosaur to and the Shipping costs should still be six euros because this dinosaur can fly to its own destination. So This is how you can add custom adjustment types Custom adjustments to your order to manipulate the price after you have added orders products to your cards All right Next Next are price resolvers and what are price resolvers? price resolvers Resolver isn't is a service that provides an answer to potentially complex question So if for example Commerce, what is the price of this product? Which store should I use or what tax rate should I apply these can be but also cannot be but this can be really complicated questions and these are Handled by resolvers the most common resolver which really which you will use I suppose is the price resolver and This allows you to offer different prices for the same product based on conditions For example, if you order more than 50 Items you get a discount or VIP VIP users get a permanent 10% discounts. So this allows you to use Different order item prices for the same products So if you implement price resolvers price results always think some of the conditions can also be achieved through the commerce promotion Module for example a VIP role users have a permanent 10% discount You can just add a promotion with a condition if the user has role VIP at a 10% discounts So it's not always custom code. It can be cheap cheap through the promotion module also all right So what about auto processor because an order processor all also Yeah, adjusts the price the difference is the big difference is that an order processor is always Executed in the context of an order of an order item price resolvers can Exists out of the context of an order. So for example, if you have a product detail page You can show to a VIP user the price of the product with a 10% discount and to a normal user the normal price and at that point the order isn't even created yet. So That's where you should be using price resolvers outside of the context of an order and use all the processors to Alter the prices within the context of the order All right, how can we use a custom price is over a resolver? Actually the same as the order pre-processor just tag it with price resolver I just so added service and tag it with price resolver and then implement your class and implement the resolve methods So for us what I did Was the following I added The price resolver to my services dots YML and tagged it with price resolver and just implemented like so Let's remove the return statement right here Okay, so if you order a quantity between one and fifty just use a default price if you order 50 between 250 get a 10% discount and over 250 get a 50% 50% discount and And else something funky is going on just use the default price We're going to check this in our cart. So to remove this item and at So here we see the unit price of 899. So if I change this to 51 We get a 10% discount. So this should be like around eight point one. I think I hope Yeah, all right so this is our priors price resolver our custom price resolver kicking in and Overriding the default order item unit price by the unit price. We define right here So actually price resolver sets the unit price order adjustments Then later on adjusts the order total price. That's a big difference All right, so I Think though the last Because I don't think I have time enough to explain the workflows and the transition transitions But you can always come up to me and ask as after the session. I'll be happy to explain So last is our event subscribers. So what are event subscribers? They allow different components to interact with each other Where one component dispatches an event and another component can listen to an event So for example, let's say commerce dispatches an event when the order when the cards gets emptied and Your custom code can then listen to that event. Oh the card gets emptied I want to do some custom stuff. Maybe so show a custom message or something like that So those are event subscribers, which also always exists out of one part of dispatcher the other part the listener So these replace a partially hooks the all out dated Drupal 7 hooks I don't think the only hooks and Commerce has are the entity hooks which are provided by Drupal core All the other hooks are now implemented by event subscribers, which is a good thing So a few useful Commerce events are I'm going to show you the order item comparison fields event But there are other useful events also Like I said, if you empty your cards if you add something or update your cards if you assign an order to a user And so on and so on so How can you I'll show you in a minute how you can? Interact with this event and I'll explain what this event is But how can you use an event subscriber again? just add an interviewer services Jammel file and Tag it with event subscriber and then implement your event subscriber Basically, it's always the same just adding a class and then implementing your class All right our event subscriber. So I added The require methods get subscribed events and there I'm saying hey, I want to listen to the event on order item comparison fields What is this event so? Commerce core By default if you add something to your card. So right now we have 51 Dinos, I'm going to add another one That's a card You'll see this just goes up to 52. It's not a new order item Because commerce order checks. Oh, if it's the same product I'll just add one to the to the quantity and not add a new order item. You can alter this behavior by adding Fields which on the commerce to check on To determine if the product added is the same or not. So right now I'm saying hey, I want you to check on the field delivery also To check if the item added is the same or not Which results in I'll just add something to my view to add an extra fields on my Order item type I'm going to alter the add to the card form and I'm going to show the delivery fields So when I'm we add an item to our cards now we can select the delivery option. So I'm going back to my So here This is the delivery. We have already something in our cart with delivery tomorrow I'm going to add. Yeah, I want this dinosaur to be delivered today Go and add it to the cards and it should result in a new order item line So this is how you can manipulate the combining of order line items by using that event All right, I suppose I have two minutes left. I think so I'll skip this one But again, if you want any Elaboration on this subject come to me after the session. I'll explain quick then Commerce country, which I use which I use lots is commerce combined cards To combine cards not other line items, but cards because in some rare Situations users can have multiple cards, which is weird behavior, but it's not fixed by a commerce score It's fixed by a combined cards Then commerce shipping is the shipping module and the commerce currency is over if you have multiple currencies on your webshop Okay Also join us for a contribution of a contribution opportunities on Thursday and thanks for your attention leave some feedback Any questions Payment gateway Price is over Message It it is possible By implementing an event subscriber, I'll show you So the subscriber if you subscribe to the event Parts entity update So when in something in your car changes if you subscribe to that event You can get right some logic if the quantity changes which results in a price change then you can show message Yeah, what you could do is create a custom price for motors Which like shows the original price striped through and then the discounted price. That's what you should do Okay, okay, thank you