Bernd: Welcome to episode 47 of the TM Podcast.
Bernd: Has been a while, you know why, it's corona times.
Bernd: Still what COVID-19 and 2021.
Bernd: That let's say didn't stop us from developing but it did stop us a bit from recording new episodes. But this is over. We now also have a remote setup, so
Bernd: here we are again and today we talk about something that we developed quite recently.
Bernd: Something that we call the error handling.
Bernd: And basically what it is, some of the technical backgrounds will be discussed in today's episode. And we have a nice group of guests today. Or guests, hosts,
Bernd: participants, whatever you would like to call it.
Bernd: We have Patrick, Balazs and Kevin with us and maybe as always Patrick. Can you maybe start introducing yourself, you as a veteran. You may know Patrick from
Bernd: the very first episode of the TM Podcast. So that's. But still
Bernd: for those of you don't remember Patrick too well, maybe you can introduce yourself.
Patrick: Halo, my name is Patrick. I'm working at the consulting organization in the area of transportation management and currently supporting the development team in various areas.
Bernd: And Patrick has been working as a development architect also before here so he is more than qualified,
Bernd: to answer the questions. No answer questions but actually Patrick will ask the questions today and we will answer. Balazs can you maybe also add some words about you?
Balazs: Sure, I'm Balazs and I joined TM development team only in March last year so I'm quite new here but I have some, I have almost ten years of ABAP experiance already, so
Balazs: technical part in a way is not new to me but I'm new to the TM. Nevertheless I had the chance to work amongst other topics on this error handling and I'm very excited to record my first
Balazs: TM Podcast episode.
Bernd: We're really happy to have you on board. On board of this podcasts episode but of course also in development. And Kevin can you also say some words about you?
Kevin: Sure. Also very warm welcome from my side. My name is Kevin and I am now since May 2020 developer in the TM community.
Kevin: I am quite new to the ABAP language and to the TM processes, so I'm looking forward to this episode today about error handling.
Bernd: Thank you and a very good position to ask questions right, if you don't have been involved. Today our roles. I wasn't introduced myself, I am Bernd
Bernd: from the Order Management Team, one of the architects it that area and has been working in TM for a while and you may have heard me in previous TM Podcast episodes already.
Bernd: And today our setup is a bit different so, Patrick and Kevin
Bernd: will ask the questions and Balazs and myself will try to answer them.
Bernd: So that's that. I will hand over to Kevin, Patrick, to the two of you. What do you want to know about error handling?
Patrick: What is error handling? No, just kidding.
Patrick: When I work for some customers, I sometimes have the problem that when for example messages arrive in the system that they fail and
Patrick: basically I cannot correct the actual error in that area. I wonder if there's some news in this area.
Patrick: Maybe some improvements in the standard system that helped me here to improve the overall handling?
Bernd: What a coincidence, Patrick, exactly for the problem
Bernd: we developed this error handling. So what is the overall idea of that error handling?
Bernd: I mean all kinds of errors but this what we call error handling here it has at least the starting point in exactly the process you described.
Bernd: So you have received a message, electronic message, so not a fax or something, an electronic message and
Bernd: unfortunately there are errors in that message. For example there's a typo in the ID
Bernd: of the product that's referred or it refers to a purchase order
Bernd: that you don't have or that you don't detect. And what so far happens is that goes back into the queue and to forward error handling
Bernd: and that's it. And the technical user can then basically go and try to solve the problem.
Bernd: In the process of the coinovation project that we had,
Bernd: we had to find a solution for exactly that problem. In the project what we heard is that,
Bernd: 10-15% of the messages do have some errors and if now 10-15% of the messages go into forward error handling a technical user has to solve them. That's quite a job,
Bernd: quite a challenge. And also I mean this classic behavior that goes into
Bernd: the queue, that means in the end if you have an order with hundreds of items if there's one
Bernd: tiny little bit wrong for one of the items,
Bernd: product ID or something, the complete message is rejected. Which is also a problem because a possible workaround of course is that you record this
Bernd: document then manually, but then you also have to enter the 99 or 999 items manually which are actually completely correct in the message.
Bernd: And to address that issue we introduced error handling. So what it does is
Bernd: you receive a message with a error or with multiple errors and even so it has
Bernd: some errors and we come to that what's supported it and what not, later it is,
Bernd: you have a certain error, you can still save the document so all the other
Bernd: 999 items and all the rest of the document is saved together with that faulty item.
Bernd: Still you have an error. So it is not that we can just store it without any
Bernd: extra caution, so this error is identified and persisted, let's say, as a part of the document as a clear error and the document is blocked,
Bernd: at least for the stops which are affected by that item. So now the new situation is, you receive a error with a message,
Bernd: or message with an error. Is that the same thing? No. You receive a message with an error and you can now store it. It is visible to business users and the document is stored with an error and the end user can now go
Bernd: and can correct the error. Either by enter for example if the product ID is wrong,
Bernd: you can identify that and you can for example correct it. Because you know that the supplier is always sending that message with that wrong product ID. It's always the same error.
Bernd: You can also call your supplier and say "OK, see, here in that item that reference for example, this purchase order, is wrong, can you please check
Bernd: if you don't have the correct number" and then your supplier sends an update for example, and the error would be gone.
Bernd: Or you can also for certain errors where the for example master data is not yet created, you can also do something that we call a retry. But in the end
Bernd: errors which are user solvable,
Bernd: (is that a word?), solvable by a business user are now visible to business users and they can fix them themselves. And once errors are fixed
Bernd: the document is also unblocked automatically and everything goes on,
Bernd: as there was never error before. So that's the idea.
Patrick: So this means instead of, let's say, keeping the message in the queue we try to process
Patrick: the message and create or update the document but only the bits and pieces of the message which can be processed and the bits and pieces which contain errors
Patrick: are however stored as error.
Patrick: So that big difference compared to the former world is that we really create the document in TM instead of letting just the message fail.
Bernd: Exactly, exactly the point. So you see the document, now you have a chance to correct it also without being
Bernd: SMQ2 or whatever Q-monitor transactions you're using. Users, but the business users,
Bernd: can go, can identify an error and can more or less independently resolve them. That's the idea.
Patrick: Does it then completely replace the old logic, the old forward error handling and postprocessing office, or is it something which comes additionally to that.
Bernd: We think we should then also come to the type of errors because that's not a bold statement, right, so we replace forward error handling. That's,
Bernd: unfortunately it's not the case completely, so.
Bernd: We address certain defined errors. We may also come later to what we call error categories. So for every error that we
Bernd: handle there is a clearly defined scope for the error. What is the error, how can it be resolved et cetera?
Bernd: And we have quite a list of error categories. Balazs, how many? Fifty something?
Balazs: Something, something like that, yeah.
Bernd: But still there are more possible errors. For example if we receive a message that refers to a document type that we don't know, that is nothing we can handle here because no business user could solve that.
Bernd: You could not just create a new document type or something as a business user or just pick
Bernd: a different document type. Because we would have issues to create a document in the first place. So there are still errors that would go into forward error handling.
Bernd: Basically that are all the errors that we do not explicitly catch in an our new error handling.
Bernd: However that number of errors that we handle in our error handling is...
Bernd: I think will grow over the years to come, decades maybe even. But we will never, let's say, completely replace forward error handling.
Bernd: Still if you have technical issues, really
Bernd: deep technical configuration that is missing or wrong that's nothing. That's really it focuses also business users. So errors that a business user can solve. It's nothing, not just another UI for the technical user but this is really for business user
Bernd: handleable errors.
Patrick: OK. And everything else is then handled by the old world so to say.
Bernd: Exactly. That sounds now like strict limitation but than again if you look into the 10-15% of the errors that we for example leart
Bernd: from the project partner that we worked with, the vast majority of source errors, at least after a certain setup phase, are master data errors, wrong references to purchase orders
Bernd: or typos whatever in product
Bernd: or business partner IDs. That kind of errors. So I think with that limited number of errors we still
Bernd: expect to catch the majority of the things that today end up in forward error handling.
Patrick: OK. And with which release is this functionality coming.
Bernd: The error handling, Balazs, it comes with S4? So that's a S4 exclusive thing. It comes with 2020.
Bernd: So it's not 2009 anymore. Now it's 2020. Right? Because 2009 sounds
Bernd: eleven years old. That's why it's now 2020. And it comes with feature pack zero already. Right? We have some features coming with feature pack one.
Bernd: FP1 of S/4 2020 there is quite some more features within and the error handling is more or less completely delivered with FP0. Right, Balazs?
Balazs: Yes, that's right. So there are some improvements that we did in FPS1 and most likely there will be some additional improvements in the FPS2 but the core concept is delivered in 2020.
Bernd: Right, right. And the stuff that we, the enhancement that we had is also available as note. However I think anyway for 2020
Bernd: going on FP1, feature pack one, is a good idea because there is massive development that we had to add. So for production I think it's a good idea to
Bernd: go for FPS1 if it comes to error handling. But available, technically available it's already with feature pack zero.
Patrick: OK, so if we would go down one level deeper regarding the different error we can catch or we can handle with this concept. So you said technical errors that's a completely different story but
Patrick: what kind of errors would then be the majority what we currently handle with this concept.
Bernd: Maybe I can start and Balazs you can
Bernd: take over if you like. So basically so far we foresee three main categories of errors. First one
Bernd: beeing the master data errors. So I refer to a non-existing
Bernd: or not yet existing master data object. For example my product that I refer to in my item is not there.
Bernd: The, I don't know, certain business partner that I refer in my freight order or consignment order is not known in my system yet. That kind of errors
Bernd: is called master data errors.
Bernd: Then we have another class of errors. And for that master data errors, I think, we have in itself
Bernd: 30, 40? 30 maybe. It is really a majority of our error categories.
Bernd: So for example. It's a product on the item. It's the business partner or a certain business partner on route level. It's business partner on the business partner tab. It's the business partner on item level et cetera. So, more or less for every single
Bernd: master data object, on every single BO node or what we call data node in this context here,
Bernd: we have master data error category. The second major category as reference errors, and maybe Balazs, you want to add some words on what that is?
Balazs: Sure. So a reference error, as it's name says, is created when the processed message that references a document that does not exist in the system.
Balazs: This might be a TM document or this could be document in the ERP referencing for example a purchase order for
Balazs: which we don't find anything with the given ID and in this case we create a reference error.
Balazs: Maybe we should also note that some master data errors can also trigger reference errors so,
Balazs: we have for example,
Balazs: when we're looking for a purchasing order we also consider some information such as the product IDs.
Balazs: And when the product ID is not found, in addition to the master data error we also create a reference error because if the product. So even if the document ID of the purchase order matches
Balazs: if the products that are included do not match then we still create this reference error.
Bernd: That's a very good point. Yes, it can also be a combination of reference errors.
Bernd: It can also be a list of master data errors. So one item can be, I don't know, could have like ten
Bernd: or maybe not ten but five different master data errors and then also, most likely then also the reference error. Because if I cannot really identify the item I also cannot identify the item of the
Bernd: ERP document and then finally the freight unit as well.
Bernd: OK. That's the reference error. Anything else on the reference error, Balazs? On high level?
Bernd: OK. Maybe we come to this life cycle of how the life, day and the life of a reference error,
Bernd: maybe later anyhow. Exactly.
Bernd: Than we have something maybe like a spare category of what we called an advanced error. So far I'm not even sure if we delivered something in that
Bernd: main category.
Bernd: But that's more for more complex things like. For example now we are, that's future, but that may be a chosen vision, we are curently doing a prototype with some students on if you have geo-distance determination errors
Bernd: that those also end up in the error handling. Again this is nothing that we delivered. That's something that we tried out, but that would go into that advanced error category. It's not a master data error per se, it's definitely not a reference error.
Bernd: And if you don't know what kind of error it is it is an advanced error. So, in the end that's more like an open category for more
Bernd: complex stuff. Maybe also something for enhancement and we'll talk about enhancement definitely later.
Bernd: Yeah so, wraping up once again, so we have master data errors that's any field on any node that refers to master data that we can not find.
Bernd: We have the reference errors and we have the advanced errors. And maybe one more word about the master data errors.
Bernd: What we do. So what happens, if I receive a message with a faulty for example product ID, in the item, then we leave in the actually item field, we leave the product ID empty.
Bernd: Why is that? In most cases leading fields is anyway GUID, the key where we refer to our master data objects and I mean if you don't, determine the
Bernd: ID correctly how, what kind of key could be right there? And that would break up everything. So in the end the product ID is kept empty in the item and you have now an error
Bernd: and then we talk about how I see it a little later. In the document and which exactly states you have an error on this item
Bernd: for a product field.
Bernd: OK, maybe that's enough, high level about the categories or types of errors that we have.
Patrick: But this means, so that the type is actually only a grouping of the individual errors, correct or is it?
Bernd: Yeah, what I refer to, or maybe I was not too precise when I said error category.
Bernd: That's actually maybe a jump a bit ahead but error category in the error handling case here that's really a combination of
Bernd: the field that has issue and the node. For example
Bernd: the product item, our product field on our item level, that is one error category. The shipper field on our item that's another error category.
Bernd: The consignee field on the item or ship-to field on the item that's another error category. So really every combination of node and field
Bernd: that's an own category. If we talk about reference errors we also have, it's not just there is a reference error but we know that's a
Bernd: freight unit reference error or maybe you can mentione some more example here, Balazs?
Balazs: Yes, so we have.
Bernd: Some error categories?
Balazs: For example we have freight orders referencing non-existing consignments. Or freight orders referencing consignments which themselves have an error.
Balazs: Have errors.
Balazs: So yeah.
Bernd: Go ahead sorry.
Balazs: So this, I just wanted to add that this master data error versus reference error this is
Balazs: mostly technical grouping. So from the user point of view it doesn't really matter. There is this tab where we display these error messages and they look the same
Balazs: they have obviously different semantics but it's not really,
Balazs: It's more a way that we technically divided these error categories into master data and reference errors.
Bernd: Exactly. Well you'll see that. I mean. Maybe we can also jump ahead a little bit. So every error category that really identifies a certain error on a certain node has a refering handler class, that.
Bernd: We come to the details of that class later but it's a one to one. So for every single error category there is a error class and most likely,
Bernd: 99% of the cases there is also a specific message ID,
Bernd: So user message with a long text, where the options how to resolve the errors are described and that is of course. For master data it's a little bit similar, but it's not identical.
Bernd: That is what an error category actualy is. A very detailed.
Bernd: It's the field level, node field level the error. What we talked about is
Bernd: master data error, reference error and advanced that's more let's say a logical grouping. You can only find them
Bernd: if you look into the class hierarchies. Because master data errors have a lot in common, that's why the handler classes have a lot in common.
Bernd: Like 99% of the code or 90% of the code is shared for them. However as Balazs said for the end user anyway an error is an error,
Bernd: and there's a certain action set etc. To handle it, that's more a logical categorization of categories. But what's a group of categories? Super category. I don't know.
Bernd: Meta-category. Whatever.
Patrick: OK, so that the actual type of what we just described the master data, the reference and advanced errors is just a kind of as you said logic grouping of the individual error categories, where we will talk about
Patrick: I think in a few minutes a bit more in a detail. OK, now I got it.
Patrick: Good. For me still what's not 100% clear is how do we get these errors? So let's. I receive a message. OK, that's processed by the system and finaly
Patrick: I need. So what is an error and how do we create them basically?
Bernd: OK, so maybe that's a good point, that's a good idea. So maybe we can go to the day in a life of an error. So maybe in start with the creation of course. So let's say we receive a message
Bernd: and by the way,
Bernd: come to that a bit later. It has certain limitations so that does not work for any message in any context. We will come to that in more detail later. So you receive a message and in that message you have for example.
Bernd: In the items you refer to a product which does not exist in your system.
Bernd: So what happens? First of all it goes into the normal message processing. And from there,
Bernd: it goes into an engine which is called the update handler, which is for those messages taking care of creating correct document chain. And in this update handler
Bernd: the check of master data, of existence of master data is performed. Right, Balazs?
Balazs: Yes if you want to be a bit more precise when there is a component called the inbound agent
Balazs: before the update handler so to say. And that's were this jackson on the different reference master data object takes place.
Bernd: OK, thank. I want to be precise but I can't so that's why it's very good to have you here.
Bernd: The inbound agent so it's a master. First of all it's been checked if it detects some master data.
Bernd: And if he recognized that master data and so far if he did not do then we would go to an error and go back into forward error handling. Now I think.
Bernd: Or maybe it's best, Balazs, I mean you wrote that part. Maybe you do describe what comes next.
Balazs: Yeah. The master data errors are detected in this thing called inbound agent. And then...
Balazs: The next step is another component of this update handler called the service first aid, where we
Balazs: do a lots of things. We also do this thing called freight unit matching. Where we do
Balazs: the matching of the reference documents and link them between each other.
Balazs: And this is the place where we check for reference errors for example.
Balazs: And after this, so after we have the inbound agent and this reference errors there's, then we gather everything and
Balazs: we create our document. If errors are detected then we also create them.
Balazs: Because maybe I also jump a bit ahead. These errors are stored in the TOR BO just as everything. All the other information just like items, just like stops and so on.
Balazs: These error information is also part of the business oject. So then we also give this data to the update handler and then we store everything including the errors.
Balazs: So that's how the document with the errors is created.
Bernd: So basically this ID, this faulty ID, is removed from the item in that example, right? And instead or based on that detected error the item field is cleaned up,
Bernd: but also an error node is instantiated. We come to the exact BO modeling a bit later, but
Bernd: that's basically what happens. And then the item is created without a product reference.
Bernd: Plus we create this error instance. That is how it all starts and then you can save.
Bernd: Also important maybe, if you create such an error instance we also create a block,
Bernd: so that because there is no item, or if you have such an incomplete item obviously there is a problem for execution. Maybe not for planning but for execution. That's why we create an execution block.
Bernd: But this block only blocks the stops which are
Bernd: linked to that item. So if I have for example multi drop
Bernd: and that only affects my second drop in the inbound scenario, my first stop is fine but I create a block for the second stop.
Bernd: If that item refers to the second stop. Then the document is saved. Item with an empty product,
Bernd: block entry on stop level, plus the error handling instance in that BO node. And we'll come to the details of that later.
Patrick: But this means that this error must be identified by,
Patrick: so to say, an external caller and not the business objected itself. So the business object does not recognize the error itself?
Patrick: But it is rather as you said the inbound agent for example who creates that error in the business object.
Bernd: Exactly, yeah, clearly, that's as simple as that, so far I mean
Bernd: maybe we'll come later also to an outlook and they might be other sources for errors but so far the concept is the error is detected,
Bernd: outside the core BO model and then the BO model knows how to handle but not how to detect it.
Patrick: OK
Bernd: That's how it starts and maybe if you'd like we can also address it, take that from a user perspective maybe.
Bernd: Continue the journey of that error so what happens now is the document is saved.
Bernd: This item has an empty product, there's an error entry and there's a block and it is solved. Now first thing is how can I recognize or how can I find those documents.
Bernd: And this is basically as I said we have blocks for the document and basically
Bernd: we are using the block categories which, okay, then master data in reference and in advance comes on place again, so not every error category has its own block category but we have only,
Bernd: block categories like master data or reference error. So you can in your POWL, you can as, I mean,
Bernd: already today you can select documents by block category and that now also is used to identify documents with the block category, for example master data or reference error
Bernd: so in POWL business user can check for example all faulty documents or ones with reference errors or ones with master data errors.
Bernd: And then we have a list, then we have first a list of all documents with unresolved document errors.
Bernd: OK, that's a good starting point but it's not solved yet, so then user can go into the, for example, freight order.
Bernd: We identified this master data, product, let's stick to the product example. We can now go into the document and there is a special tab Error handling,
Bernd: Right. And in there.
Bernd: First of all you can go into a document to go into the Error handling tab and there you'll see the list of errors. And maybe, Balazs, do you want to say more words about Error handling tab and what it provides then.
Balazs: Yes. So basically you have a list of all the errors that have been identified for this document and then depending on
Balazs: the error category you have different options to solve this.
Balazs: Let's say, the simplest thing
Balazs: for example a reference error, the document is referenced to the ERP document which for some reason it's not yet available
Balazs: but then it appears in the system.
Balazs: Then we can simply solve this by a retry so that's one option.
Bernd: Maybe one more thing you can start with is for every error you also have a description, right, so you have lists of errors and then you can
Bernd: press on Describe I think it's something like that and then you will get a long text or a message and it's also tries to highlight the affected node data
Bernd: like if you have an Error handling tab opened and the Items tab opened then, and you press Describe that you would also see that the red surrounding on the product item field
Bernd: and would get a message for >?now? says OK,
Bernd: product ID is wrong for that field and it also tells you what was wrong product ID so we also store the faulty data because it might give you a hint to correct the data.
Bernd: and instead faulty
Bernd: With that message a long text that a user gets information how to resolve the error as mentioned. We try to address end users. One of the options that we typically have is a retry.
Bernd: We just take the value as it has been sent and try to,
Bernd: if it works now, so for example the product maybe it's something where that master data is not yet created. It's not a typo but your supplier
Bernd: did send the message so fast that you didn't even have the time to create master data, part of it and that's why you, you just have to wait
Bernd: half an hour later, some master data has been created then you press Retry and everything is fine, in this case. That's one option to solve it.
Bernd: But I thing there are more options typically, right Balazs?
Balazs: Yes, so let's say we really had a typo for a product ID,
Balazs: and then next to the error message you have an input field and then you can actually correct this faulty value and
Balazs: you also have a nice search help which is so smart that depending on the error category
Balazs: you get relevant search help so if you have a wrong product ID then as soon as you start typing you get an search help for an products and the same for example for locations.
Balazs: That's another option but you can also correct this field on the item itself or on the faulty node,
Balazs: so you can actually, you don't have to necessarily do this in the error handling tab,
Balazs: but you can go into the your items or your stops and then correct this data there. That's also an option.
Bernd: Exactly, or you call your supplier and the suppliers sends you a new version.
Bernd: now with corrected errors and also correct product ID Identies? also disappeared so basically the error disappears as soon as the field has been
Bernd: filled with the valid values, so it knows that this item,
Bernd: has a problem and also knows what kind of problem based on the error category.
Bernd: Add now if this problem on this item has been resolved on whatever way that's a valid product ID in the item then the error is resolved,
Bernd: that this error disappears,
Bernd: so far we do not store resolved errors that something for the future. Once all blocks are gone, sorry, when all errors are gone, the underline blocks are also removed.
Bernd: So ones again, when the message comes in
Bernd: the error is detected, the field is cleared in the field, in this what we call data node like: item, stop, route. We create an entry which identifies that error also we have an....
Bernd: but we will comes to BO modeling later, so we create an entry.
Bernd: That is an item product error and once for the affected items it is a valid product.
Bernd: For a affected business partner node once there is a valid business partner ID,
Bernd: key in the end, then the error is resolved.
Bernd: Error is, error handler, error instance is removed and also the block finally goes away and document looks like it never had a problem.
Balazs: Maybe what's still worth mentioning here, so this actions like retrieve and so on, that is quite flexible so we can offer up to five actions, if I'm correct.
Balazs: On the UI that's completely flexible so there we can provide
Balazs: different actions for different error categories for the solution.
Bernd: That's a good point, we'll come to the technical modeling I think in a minute, but more or less every error category has assigned, that we already talked about, messages, so the end user,
Bernd: side of the story, for search help. Something that is more less defined by the error category in the end.
Bernd: And also the actions. Balazs have you mentioned up to five I think so far or maximum is two,
Bernd: or three, right? That's the retries, very popular, we almost there.
Bernd: But what we have one or two example where we have more actions but hopefully we will find other, let's say, actions that help to user to solve the problem and then you could have up to
Bernd: the five actions with the button Description and then of course underlying system behavior if you press that button. And then every, OK, now that's disadvangege for error podcast,
Bernd: but audio podcast, error podcast but audio podcast that what it was. You have the list of errors on the left hand side with the description and you have Describe button and then you have
Bernd: the buttons to solve the error like Retry and then you have input field where you can just enter values where applicable, of course, that is not
Bernd: always possible, but in many, like in master data cases you can just enter corrected master data ID, than those
Bernd: corrected data, by the way I also check so I can not just enter anything and then this is goes through, ones again check if this is a valid value and if not you can get an error message that this is that you failed to correct the field.
Bernd: And then you have to try again.
Patrick: But this means errors are usually corrected so to say manually by a user, except you get an update via message, but then it also, also corrected so
Patrick: You can either change the let's say the faulty value to the correct one.
Patrick: Or in case of reference errors or master data which is not yet there then it can also happen that is if the error is
Patrick: corrected automatically so to say, because you enter for example all the actual fields which, which is
Patrick: not correct, is now maintained correctly in then the error would also be gone.
Bernd: That's a very good point, in the end is there one more option that I forgot to mention, it's mass retry. So in the POWL
Bernd: if I'm not wrong, we introduced also Mass Retry button. So you can also select all your consignments, I don't know, they may be restricted
Bernd: to a certain supplier or something. So you can select documents and then perform retry on all
Bernd: errors of that node and then it resolves as much as possible. Of course if the retry still fails and fails, but instead you can
Bernd: auto mass retry from POWL. I think we even have a report but I forgot
Bernd: it's name. I wrote it myself. So maybe we can check that and also provide that but if you search for reports with error in it
Bernd: that should be possible. So you can also just run a report that can select all documents with errors
Bernd: and would then do a retry automatically in the background. Good that you asked, that I would have forgotten to mention it. In POWL mass retry is also available.
Bernd: Because retry is something that you can just blindly do, I mean, we store the original value, but of course it only makes sense for not yet created data, but for example for the reference errors.
Bernd: If you have that kind of problem frequently that the... because in the end maybe coming to the reference error.
Bernd: It is not enough that you have for example the purchase order but there must be freight units which refers to the that purchase order in the end. Maybe for some reasons the freight units are not yet created.
Bernd: Then retry would work even though ??? a number.
Bernd: Purchase order number did not work before but after freight unit creation it would work. Same if you already receive a freight order and that points to consignment and if this consignment just arrives five minutes later, it can be solved automatically,
Bernd: by automatic retry as well. So that's also very efficient option of course for applicable errors.
Bernd: So that's not.... wouldn't work for everything I guess. Typo is a typo
Bernd: But for everything else which really can be solved by retry, that's a nice way of solving it.
Patrick: And then once you click on Retry or you change the data and say retry, then the message is adapted and you send it again? Or how is this error then also resolved?
Bernd: This retry is... maybe we'll come.
Bernd: We'll come to the details also of BO ??bottling?? a little bit later, but when we store such an error
Bernd: We store also as mentioned we remove the data from the item for example, from the data node, but we store with the error original value that was a part of the message for example.
Bernd: For an example, I don't know. You receive only item product 123.
Bernd: And this is not yet there. We store that. In this error instance we store that product 123, value.
Bernd: If you now press Retry, it will just try to mimic> that you enter produce 123 into the product field.
Bernd: In the end. So there is no new version of the message or something, but it just the way it has been sent originally.
Bernd: It tries to kind of re-enter that the data and check if it's now a valid value. But it does not goes truly complete error handling process, right Balazs? Not to the message processing completely, right Balazs?
Bernd: It more mimics the user entry.
Balazs: Yes, it's depending on the error category, so for some
Balazs: some categories really trigger new processing of the message like reference error for example but for master data, that's right what you said.
Bernd: As way after deep sort now I remember the name of that retry report. It's /SCMTMS/TOR_RETRY_ERRORS. Sometimes it's good to think deep enough then you remember all the report names.
Bernd: That's maybe for the life cycle of an error.
Patrick: So you said that blocks are usually created in case there's a document error. Is that correct? Does it...
Patrick: You have the errors on let's say different levels so you might have an item error and you might have an a business partner error and all are creating then root logs or you mentioned also stop based blocks. So can you maybe just
Patrick: say some words on that? So how all those stops and blocks are basically created.
Bernd: I think we still owe kind of owe audience also maybe a podcast episode about blocks but in the end. Right, we have a block
Bernd: defines sorted certain,
Bernd: document or part of document is blocked for certain activity. Basically we have the planning block that means,
Bernd: that's document or that's part of the document, like a stage should not be planned. We have an execution block so I shouldn't execute that part and we have an invoicing block,
Bernd: to not invoicing that part. We have that on header level so that's means that complete document this locked, right? We introduced that or we had it already earlier on stage level,
Bernd: so like for freight units, if freight unit stage is for example incomplete or so, then this stage is blocked but the other stage which does not have that problem can already be planned and then also executed.
Bernd: And now for the sake of the development, we introduced this block also on stop level because we are..
Bernd: we had discussions with the customers and they said that they have cases where
Bernd: certains locations are find on the same document, they go to inbound scenario for example plants of mine and
Bernd: they don't want to block the complete document just because, for example, you deliver to Berlin and Frankfurt or so. And in Berlin everything is fine and Frankfurt you might have an issue and then you don't want to
Bernd: prevent delivery or execution to Berlin, just because later something wrong in Frankfurt, because that can be fixed while truck is moving from Berlin to Frankfurt. That's why we introduced that,
Bernd: blocks on stop level now and for every error more less we know for every error
Bernd: where it belongs to. For example it belongs to an item and this item is an inbound item them we know the inbound stop needs to be blocked.
Bernd: Same if its refers to stop itself, so master data, this location is unknown or so, then also the stop is blocked. But if this refers to a carrier or something which is a header level then the complete document is blocked.
Bernd: So depends a bit. And as soon as we create such an error,
Bernd: so far we create an execution block that is hardcoded actually. We only differ between master data reference and advance errors but it's also just, let's say, for
Bernd: grouping has no technical difference between them and then you have an execution block on stop level or on route level.
Patrick: So kind of contacts sensitivity when blocking the document. OK, so only the needed parts are really blocked, OK.
Bernd: Yes, as fine as possible, yes. I mean you could still, yeah. But it's bit technically driven to be honest, so for the item we know what's the
Bernd: stop reference, for stop in a stage, we know it. But on the header level, might also be cases where you could say OK but it only affects on the first stop or last stop, something but
Bernd: so far that would be a complete document block. If we have nice ideas or a customers have a nice ideas on how to make that more granular
Bernd: based on clear criteria that we would also be more granular there.
Patrick: OK, so this means actually this new concept you can more less handle all the errors which we
Patrick: might even think of so far. For example same semantic problems we might have the document has, or the weight is too high and then we created an error or
Patrick: this is a concept of blocking the document only or can you only handle certain errors?
Bernd: Yes, of course, if you think long enough maybe you can apply it to more areas but in the end there are certain
Bernd: limitations or maybe we should call it rules for errors that can be handled with error handling.
Bernd: First of all I think we mentioned that already at the begining it should be something that can be used, solved by business user.
Bernd: So that's a one rule. So that's why if it's really technical problem which anyway is something for tech-user then forward error handling is a right place for
Bernd: technical user. So there is one more semantic decision. Then the second one rule is that of course we need a clear indicator,
Bernd: that something is wrong. For example product ID that we do not know that something that we as programmers.
Bernd: Yes we as a developers and actually our programs can detect clearly. We say, OK...
Bernd: Let's say the product ID is very unlikely to be sent by this carrier, by this supplier or something like that. There is nothing you can code against.
Bernd: So either is this an error or not?
Bernd: If we must have a clear rule where we can identify that. This is a error situation. For example product ID does not exist. If it exist but it is for whatever reason not suitable that would be
Bernd: something to think about at least. What is that clear criteria where you say this is right or wrong, so must be a clear separation.
Bernd: and then what holds that faulty creation of the error but also as resolution, so there must be a clear indicator that this error has been solved. If you say the weight problem, if you say, this weight is now OK.
Bernd: You need crystal clear indication what OK means.
Bernd: I don't know we could talk something like capacity check if you say now do error handling for capacity checks then you would need a clear rule, where you say OK, you have such an error.
Bernd: if the capacity is violated then we have an error. If it is not violated then is not an error anymore. Then it would be suitable but you say: Should be OK? But 5% is OK or maybe 7 it's depends. Then it's not a candidate
Bernd: for error handling. So there must be a clear rule.
Patrick: OK, but it somehow sounds also like, let's say, we have a clear definition of what is the error and when is it resolved for master data error or references errors.
Patrick: But when we think about these advanced errors actually we can substitute what not whatever but many additional errors which we I think...
Bernd: Yes if. But again there must be a way that we know now the problem has been solved.
Bernd: Yes of course it can be more complex than yes or no, but there must be a rule
Bernd: so far. I mean, either of course, we also already discussed about manual overwriting kind of errors and as I said this distance error is maybe again not so
Bernd: black and white or weight. So there might be more to come, but for the moment I would say as a guideing principle also if you think about let say your own using it's error category maybe for that fields also.
Bernd: Then you should have a clear understanding on when do I create error and when do I remove the error.
Bernd: Also what is the error that I want to present to my end users. So what do I tell my user how to solve error. If you don't know how to tell it your user most likely it's not a candidate for error handling, because if you don't know how to explain,
Bernd: what to tell the user the user will also be lost on how to solve it.
Bernd: So if you cannot write a long text message that may be also an indication for a error that is not applicable for error handling.
Patrick: Is the error handling actually limited to let's say one field or can I also have a combination of attributes which form the error to say so if i have?
Bernd: Combinations of attributes, I would say it's not a problem. Combination of nodes is maybe more of a challenge. We come to the technical modeling I think.
Bernd: One of the next steps that we should also discuss the technical modeling and maybe from that it becomes clear what is technical
Bernd: surrounding or limitations that we have here.
Patrick: OK, because we also talked about this kind of error category and I think you also mentioned sometimes the kind of handler classes and so and so.
Patrick: There seems to be some error category specific implementations or how? How is that over all concept?
Bernd: Yes, so every error
Bernd: in the end, what. Maybe we can just slightly, slowly moving over to the technical part of the modeling. And maybe also come to
Bernd: handler classes and what they handle. But in the end more or less all,
Bernd: all steps in the life cycle of such an error are handled by error handler methods, class methods. So you have such a handler class for error category and then is for example called to check if the error is resolved.
Bernd: It is also called if you enter a value. That you make sure that a value is appropriate
Bernd: for your handler class or for your error. So I don't know. If your numeric field or so that you then validate the input, that the input is numeric or whatever.
Bernd: If it really fits. The F4 helps are described or defined by the error handler class so more or less everything.
Bernd: In the end the action. The actions, the names, the icons. All that comes from the error handler class. The handling of the actions as well. So you have it more or less in full control. The only thing that you do not do in the handler class itself is the creation of the error.
Bernd: Obviously. Because I mean to create the error
Bernd: and identify the error handler class, that's catch 22, right? If the error handler class
Bernd: which depends on the. Or the category would also be responsible for creating the error, that will be a catch 22. So in the end that is something else so that we come to it later there is some coding that you can
Bernd: create your errors in the message processing in the end.
Patrick: What it means, for every error category. And every error category is really the smallest piece so to say because it really defines unique error.
Patrick: There is a class which actually defines the context of this error and the additional information and characteristics.
Bernd: Everything. Exactly, so for every error category there's a class that has no other job that handling executor errors, but all aspects of that error.
Bernd: We come a little bit around it, maybe
Bernd: let's jump into the BO model and maybe that explains what is done outside the handler classes
Bernd: So, if you create such an error...
Bernd: We already talked about the error categories. This needs to be stored somewhere. If I have like three errors for item 20 and two errors for item 10, there needs to be a place where we store those
Bernd: errors. And that is done in a new BO node,
Bernd: which is called... It's below the ROOT node, and it's called ERROR_HANDLER, right, Balazs?
Balazs: I think so, yeah.
Bernd: Maybe I just think a bit longer, and now, ah. Now I remember that it's called ERROR_HANDLING.
Bernd: After a deep thought. That's the error handling node. And this, in the end, it has as a main indicator,
Bernd: the error category. Because there's so much depending on the error category. I think we discussed that already quite a bit. This is stored in the error handling node.
Bernd: But not only that, also the wrong value. The value that has been set originally,
Bernd: or sent. Product_123 for example. That needs to be stored somewhere. This is stored in that ERROR_HANDLING node.
Bernd: Actually there are two values that we can store. That is for example, for the reference errors relevant, where we have
Bernd: the type code and the ID.
Bernd: That in the end identifies the reference error. And that's already it on that level, but you might ask yourself how do we know which item is affected. And that is a sub node of that ERROR_HANDLING node.
Bernd: So below the ERROR_HANDLING node, the thing long enough, the subnode is called ERROR_INSTANCES. There we have a pointer to the actual
Bernd: for example item keys. Why is that a sub node? The rational behind that is,
Bernd: that we think that have certain errors that affect many nodes. For example after there's wrong
Bernd: consignee, for example for ten items. I don't want to see that error ten times, but I want to see I have this error ten times.
Bernd: As one error, but they also resolve it in one go. That's why we decided that the error with an error category,
Bernd: plus the wrong value and additional wrong value for context. It's stored
Bernd: independent of the error instances. And the instances I mean we are in BOBF so we can just store the keys and the error category will know what is the node I take care about,
Bernd: because item product, it's route, party, route shipper, route consignees, I know the node from the category already.
Bernd: Then I just need to do a safety instance, the GUID of item 10, the GUID of item 20, etc.
Bernd: That's it, in the end.
Bernd: There's one more thing however, and for performance reason on the actual data node, like our item in that case there's also a field that indicated that this item for example has an error.
Bernd: So the field is called NODE_HAS_ERROR, so hmm, that's node an error.
Bernd: And as long as we have it on item level for example, it's at least one error
Bernd: instance pointing to that item. Then this node has error, that is true, x is not initial.
Bernd: That is why is that in the first place - performance. Because now if I'm in the after modify determination for such an item and no, OK.
Bernd: Something changed on the item and the item has an error, so maybe my problem is gone, so it notifies the...
Bernd: I'm on the item.
Bernd: I see I have an error and there's association technically from the item to the error instance node.
Bernd: Because it's all GUIDs and all BOBFs, it's pretty straight forward. So we, from the item we can easily navigate to the respective error handling node in the end.
Bernd: And from there, we have the error handler class, and then we say OK, error handler class can you please check if your problem is solved.
Bernd: As simple as that. And then we said we have five different errors on the item and maybe the user solved three of them, then three of the errors will be gone, but the other two will still remain, and instead with that also this NODE_HAS_ERROR flag remains.
Bernd: After the last error has been resolved then also this NODE_HAS_ERROR flag is also resolved.
Bernd: And then also if that is resolved
Bernd: the error handling class, error handling node is solved and disappears and with that the block disappears. All that is done in the end is after modified determinations.
Bernd: Yes, so we have after modified determination on the item, this then calls the
Bernd: action to say, or calls the error handler class to check if the error has been resolved. If the error has been resolved, then this error handling instances resolved,
Bernd: is deleted, if the error handling instance is deleted, the block
Bernd: is checked, if it's still an error instance there. And if not, the block is also deleted.
Bernd: All that's normal BOPF stuff. I think if you don't know what BOPF is, there are two episodes about that, that you may listen to, and then hear that again and you'll know what we are talking about.
Bernd: If I did not already lose you beforehand.
Bernd: That's in the end of modelling, so you have a node, an error
Bernd: that's also displayed on the UI as dot, and that's really small one, at least for us. So it's only the error category and the references,
Bernd: and the node so the item ??.
Bernd: Then, the actual that pointer to the instances, which is said error instance, and the flag in the actual data node, and the item, and the stop, and the route level, etc.
Bernd: And that's it. From the "BO" perspective, but that also means that coming back, closing the brackets, your question was: Can I
Bernd: listed advanced error, can I resolve or can I model any kind of error?
Bernd: At least if it's kind of cross node, then you have to think about how to, which node is marked with no test error in that case
Bernd: for example. How do i make sure that's removed correctly. That would be a challenge. If I have a
Bernd: combination of fields on different nodes, then the current concept I think would come to it's limitations, but if it's just a
Bernd: custom field on route level, custom field on
Bernd: item level, combination of fields on item level, I think that's all fine. Also the hierarchy is clear, that you say, the field on item level must match something on root level and, but the error is on item level, that's also fine.
Bernd: The only challenge is then if it's possible to change something on root level and that should also trigger reevaluation, that would be a bit tricky in that case.
Bernd: But for I think, there are many use cases where you are, lets say
Bernd: bound to one node and maybe a combination of fields on a node, but in the end you are on one node.
Bernd: Plus you have some context maybe from other nodes,
Bernd: that you have a combination of values of different fields and any change on any level can solve the error then maybe the error handling is not there yet.
Patrick: OK, but this means again,
Patrick: we have basically ann external caller who creates these instances so actual BO node instances in case there is an error,
Patrick: the BO is somehow self containing itself, meaning the BO detects if the error is solved,
Patrick: by calling or by asking so to say the individual error handler classes.
Bernd: Exactly that's a good point, the BO itself doesn't know if it's solved, it asks the handler classes if it's solved. That's a good point.
Patrick: And then once everything's solved to say that error instances are gone and then also the blocks are then removed again, and this is again done more or less by the business objected itself.
Bernd: Exactly, the error instances are gone, once the error instances are gone, the error handling node is grouping the instance is gone, and that is where other blocks are gone.
Bernd: That's the technical sequence, if i'm not wrong, right Balazs?.
Balazs: Yes that's correct.
Bernd: Thank you.
Patrick: OK. This feature is something which we, which we just have activated in standard or is it, is it something which you can call,
Patrick: which you control by the handler classes or how do you control this feature?
Bernd: Balazs, do you want to answer that or I take it?
Balazs: Yes, so there
Balazs: there's some criteria, so as you mentioned this is mostly the context of message processing and there's
Balazs: a limitation here, so this is active in the service which is called transportation order generic request
Balazs: or the TGI.
Balazs: Then in addition there's a customizing where you can enable the
Balazs: this error handling basically.
Bernd: Document type level, right?
Patrick: So it's available for Freight Orders and for Consignment Orders?
Bernd: Exactly, Freight Orders, Consignment Orders, Freight Units not yet, right?
Bernd: Maybe one more comment on the message as Balazs already mentioned is Transportation Order Generic Request In.
Bernd: I think there's one or two more prerequisites. One is that you have that replication indicator, I guess.
Bernd: So also if you're working with messages, will know better than I do what this means. Or if the, what's it called? A delta handling... Wrote it somewhere, wait a second.
Patrick: Complete Transmission Indicator, you mean.
Bernd: Ah, yes, now when you mentioned. If you're using this Complete Transmission Indicator only then it's active for the moment. Maybe we will widen the scope, that's lets say
Bernd: What we use for our 2020 course scenarios, consignment inbound message, freight order inbound message, and
Bernd: focus on that. It might be widened and we also think about
Bernd: message external users, but so far it's actually only was in a message, so let's say if we look at standard, it's only used only in the message handling so far,
Bernd: and for that specific message with that specific prerequisite, and if the customizing is active, that is of course compatibility consideration. We think it should always be active,
Bernd: and we also default it if I'm not wrong, for new document types, but of course if you just upgrade and don't care about that feature, you still want to see the errors in our forward error handing, because this is where you people are used to look for it.
Bernd: That's why you have to activate it in customizing explicitly, because it was a different behavior before and compatibility is key.
Patrick: So basically you control the behavior by other, the type customizing and currently only so to say quotes, activated for the Transportation Order Generic Request In.
Patrick: Which supports processes like the TOR Generic In,
Patrick: so the replication TOR Generic In, ASN, whatsoever, what's coming.
Bernd: Yes, I think, but that's another episode maybe. The Consignment Order might be something
Bernd: let's say, the very prominent user of that one, which is to be discussed in another episode, yes.
Bernd: That is ASN in the end typically end up being consignment on our side, Consignment Order and there is where we typically have that kind of master data errors and all scenarios. But of course also for Freight Orders.
Patrick: So you know i'm from consulting, so usually I also love to use these features in customer project, so is there any option to easily enhance it?
Patrick: So if I have a dedicated error, I want to do my own error category or so.
Bernd: Patrick you never get enough right? So ok. You said one in 50 error categories? Isn't that enough?
Bernd: Yes there's a chance to enhance that. Maybe Balazs you want to spend some words on what needs to be done?
Balazs: Yes I think if you...
Bernd: For greedy Patrick.
Balazs: If you've listened carefully until now and then you ask yourself how could you then create your own category I think you already have the answer. It's quite straightforward.
Balazs: So, yes it's possible. You can define your category.
Balazs: That's you already know, category has it's own handler class, which implements a certain interface. And then
Balazs: you have to implement this class and then there are a set of methods that you have to implement. You can also choose to implement from one of our
Balazs: standard super classes, for example if you just want to create a new like
Balazs: master data error, then you can inherit from the super class for the master data errors.
Balazs: Then you probably only need like a couple of lines of code to specify for which field you want to create this error category and so on.
Balazs: And then, once you have the category and it's handler, then there's a Badi,
Balazs: they can register it and add to the list of the available categories.
Balazs: And then you just need one last step. You also have to identify the situations as we mentioned.
Balazs: This is not done in the BO, but it's done outside. So there's a Badi doing the service processing.
Balazs: For the TGI service. And then it's possible to create an enhancement, a Badi implementation, where you detect this error situation and then you
Balazs: you write this error, that you've defined.
Bernd: Sounds easy, Patrick.
Bernd: More questions. Maybe we can mention some of the names. So first of all, the error categories. They are defined in the domain /SCMTMS/TOR_ERROR_CUT,
Bernd: I think it's the first step that Balazs mentioned, so you have to enhance that domain
Bernd: by your own Z category.
Bernd: It's a character ten, so that should be plenty space for meaningful cat.
Bernd: That's one thing. The interface that you have to implement, it's called
Bernd: /SCMTMS/IF_TOR_ERROR_HANDLE.
Bernd: That's the interface.
Bernd: And then we have the Badi. /SCMTMS/TOR_ERROR_HANDLING_CUT, where you do the mapping. As this error category belongs to the handler class.
Bernd: which then implements the interface that we just mentioned.
Bernd: And the last step is then this Badi where you rewrite error from the message and that's /SCMTMS/TOR_SE_TOR_GN_WRECK.
Bernd: And in there is specific message called DEPT_DATA_, uh, no.
Bernd: I lost my memory. Uh, yeah.
Bernd: TOR_GM_WRECK, that's the name. And then DEBT_DATA_FOR_OMUH. (For Auto Management Update Handler) That is where you then write the actual error.
Bernd: And the structure, which you write there is pretty much what we just described.
Bernd: The structure for the error handling. error handling class and the instances, you referring to.
Patrick: And if I would create an error category, let's say which is
Patrick: where there is a similar error category already in standard, so on the same node and so and then, I think everything would work more less out of the box. And if I would introduce a new node or if I would have an error on a node which doesn't
Patrick: have any errors on standard I would have to do some enhancements in the determinations and so on.
Bernd: Exactly. So you should follow that NODE_HAS_ERROR pattern however, you do have to implement after modified determination and the call yourself, but then you can just follow the pattern that we introduced in orgnization nodes that already have that error handlers.
Patrick: OK, cool. Sounds like a really nice concept and feature and has a bright future I think.
Bernd: Yeah, we hope so too. So we're talking what future may be. So some sorts that we have. Again we typically talk just so.
Bernd: What we talked about so far is mostly there. Subdivisions that we have here is that we also store more, because so far as mentioned, if an error is resolved it's really gone as it was never there. That of course is
Bernd: lean and uh data.
Bernd: Speaks German Oh das ist Datensparsamkeit Speaks German It's a lean usage of data for sure. However for some analytics, or even for
Bernd: improving solving errors for the future we think about storing more information on the error, and how it has been solved, maybe when it has been solved. By which means it has been solved.
Bernd: So for example an error that is typically resolved by retry after ten minutes maybe may even schedule something
Bernd: like ten minutes later. Awesome, yeah?
Bernd: To take example, that is one thing. We already talked about usages and planning like the mentioned geo and distance determination error,
Bernd: that is maybe a candidate. Maybe capacity check errors that we also make so small. Let's say explicit,
Bernd: explicitly handled.
Bernd: I also hope that has a bright future and that we can use it also for other scenarios we
Bernd: didn't even think of so far. So...
Bernd: But so far it turned out nice. Our colleagues from MIPSO, that was the artist formally knowns as custom development. We worked very closely with them on recent project. And they also already introduced their own error categories so.
Bernd: We know that's not only series that we described. And so, and...
Bernd: But that's only available with Feature Pack 1 or some nodes with full extendability.
Bernd: But yeah, I also think that's good feautre and can be, can solve problems and hope you did it well.
Bernd: OK, then it is a no more questions even from Patrick, that I think we...
Patrick: Everything is solved. Everything's solved, everything's answered.
Bernd: OK then, thanks a lot everybody. And we can call it an episode I would say.
Bernd: One hour, twenty minutes. That's solid episode, but it's okay. A lot of details. By the way, there will be...
Bernd: We are currenly preparing another podcast. I think I said that a year ago already right, so what were still preparing is a very deep preparation. Where we go a bit deeper, for example we now just mentioned are there different interface messages, etc. So we...
Bernd: As a podcast, TM Podcast, but Blacked Out Edition so it goes more into technology.
Bernd: We don't stay that much on the surface like today, but we go into some more details.
Bernd: Like the interfaces, etc. Interface messages required. And we also plan to have an episode on
Bernd: more deep, more detailed level, how to create such an error instance in this new podcast to come. But that's just a plan so far. It's not a promise, but a plan at least.
Bernd: And we hope to deliver that as well. And then if you liked this episode and now want to go and create you own error category, it might be worth listening to the other one. We will announce that on our usual channels. On SCN, that's linked in Transportation Management Group.
Bernd: And Twitter. TM Podcast - Twitter account, and then you would find us there.
Bernd: So thanks a lot everybody. Thanks for listening, thanks for asking, thanks for answering. And have a good day. Bye.
Patrick: Bye.
Balazs: Bye bye, thanks.