Get product info in promotions applied in Hybris - java

I want to learn which promotions were applied to which products on promotionengine in order to distribute prices on products amongst themselves and send them to ERP.
When we look at the promotionService in Hybris, there is a method called getPromotionResults(order). It returns PromotionOrderResults object. In this object, two methods are related to my case, getAppliedProductPromotions() and getAppliedOrderPromotions().
If I did not miss it, I could not see product info for a promotion in these methods' results. Also, I looked at all attributes via promotion.getAppliedOrderPromotions().get(0).getAllAttributes() but i could not have them.
How can I know product info and discount amount in a promotion?

The method you are looking for is
PromotionOrderResults#getAppliedProductPromotions()
This will return all the promotions applied to order entries / products, you can navigate to the products via PromotionOrderEntryConsumed PromotionResult#getConsumedEntries()

I have a way to get the product that was Added as free gift on a promotion... Usually is something like this
Set promotionResultModels = cart.getAllPromotionResults();
if (!Objects.isNull(promotionResultModels))
{
Iterator resultsIterator = promotionResultModels.iterator();
while (resultsIterator.hasNext())
{
PromotionResultModel promoResultModel = (PromotionResultModel) resultsIterator.next();
Iterator var6 = promoResultModel.getActions().iterator();
while (var6.hasNext())
{
AbstractPromotionActionModel action = (AbstractPromotionActionModel) var6.next();
if (action instanceof RuleBasedOrderAddProductActionModel)
{
String freeGiftProductCode = ((RuleBasedOrderAddProductActionModel) action).getProduct().getCode();
}
}
}
}
However in my scenario, this is Free Gift promotion, not sure if the Bundle Based Promotion might have similar properties. As per the product that actually FIRED the promotion, I'm still looking a way to get it. The closest I've been is with this:
((RuleBasedOrderAddProductActionModel) action).getRule().getRuleContent()
However that's the Hybris Generated Code that has the RAO's and the product codes are buried within that string. So I needed to write an ugly script parser to find the codes.
Let me know if you find out the second part, the Products that triggered the promos, I'm still looking for it too.

Related

How do I make "picklists" or "enums" in bulk from one source system to a destination system using Zapier or Code?

I am by no means experienced in programming, but I can trial and error my way through some basic code. I am currently working on integrating a couple of my business application via Zapier or make (integromat) and I always get stuck on field mapping in bulk.
Right now, I am trying to create a two-way sync between my "loan origination system" and "Monday.com" (project management system) and I am using "AirTable" as a mid point to store/hold the data.
The flow looks like this: Loan Orignation System -> Airtable -> Monday.com.
In reverse, the flow is: Monday.com -> Airtable -> Loan Origination System.
I always get stuck when I have "picklists" or "enums" - basically drop down fields that have different values in both systems.
I know I can use a lookup table in zapier but there are so many fields that it would be nearly impossible and also impracticle to add that many lookup table steps to get transformed values.
Here is an example of what is being passed from the loan origination system -
Field: "propertyType" (Display Name is "Property Type")
Potential Values:
SINGLE_FAMILY_DETACHED,
SINGLE_FAMILY_ATTACHED,
TWO_UNIT,
THREE_UNIT,
FOUR_UNIT,
MANUFACTURED_SINGLE_WIDE,
MANUFACTURED_DOUBLE_WIDE
Now in Monday.com, I have the same field listed as a status field called "Property Type" and the values are the normalized names or display names for these values. So the following:
Monday.com Property Type Status Field Options
"Single Family Detached",
"Single Family Attached",
"Two Unit",
"Three Unit",
"Four Unit",
"Manufactured Single Wide",
"Manufactured Double Wide"
Is there any good way to transform the values for all the possible inputs/outputs for either direction without having to make a million zap steps for all the fields that function this way?
It is a systems integration problem, and I don't have a ton of money to buy a fancy tool. We have zapier, airtable, integromat, etc. And the tools do not have open API's at the moment so I have to work through these tools.
Any help or guidance is super appreciated!
When using Code by Zapier (JavaScript), usually it is a good idea to put some guarantees in your code right up front. This piece of code sets 'defaults' for the inputData keys:
// ☸
class DefaultKeys {
constructor(keys={}){Object.assign(this,{
propertyType : 'default_value',
loanType : 'default_value'
}, keys)}
}
let values = new DefaultKeys(inputData)
// ☸
Now to your actual question... It is possible to use switch() like the lookups provided by Zapier:
let newPropertyType = switch (propertyType) {
case 'SINGLE_FAMILY_DETACHED':
'Single Family Detached' // a function could also make this transformation
break;
case 'SINGLE_FAMILY_ATTACHED':
'Single Family Attached'
default:
'default_value';
}
So then copy that section for each of your different 'keys'.
Lastly, output your results for the next Zapier actions to access:
output = {propertyType: newPropertyType, loanType: newLoanType};

How to get the current substate and the parent state out of the Spring Statemachine?

I am running a hierachical Spring Statemachine and - after walking through the inital transitions into state UP with the default substate STOPPED - want to use statemachine.getState(). Trouble is, it gives me only the parent state UP, and I cannot find an obvious way to retrieve both the parent state and the sub state.
The machine has states constructed like so:
StateMachineBuilder.Builder<ToolStates, ToolEvents> builder = StateMachineBuilder.builder();
builder.configureStates()
.withStates()
.initial(ToolStates.UP)
.state(ToolStates.UP, new ToolUpEventAction(), null)
.state(ToolStates.DOWN
.and()
.withStates()
.parent(ToolStates.UP)
.initial(ToolStates.STOPPED)
.state(ToolStates.STOPPED,new ToolStoppedEventAction(), null )
.state(ToolStates.IDLE)
.state(ToolStates.PROCESSING,
new ToolBeginProcessingPartAction(),
new ToolDoneProcessingPartAction());
...
builder.build();
ToolStates and ToolEvents are just enums. In the client class, after running the builder code above, the statemachine is started with statemachine.start(); When I subsequently call statemachine.getState().getId(); it gives me UP. No events sent to statemachine before that call.
I have been up and down the Spring statemachine docs and examples. I know from debugging that the entry actions of both states UP and STOPPED have been invoked, so I am assuming they are both "active" and would want to have both states presented when querying the statemachine. Is there a clean way to achieve this ? I want to avoid storing the substate somewhere from inside the Action classes, since I believe I have delegated all state management issues to the freakin Statemachine in the first place and I would rather like to learn how to use its API for this purpose.
Hopefully this is something embarrasingly obvious...
Any advice most welcome!
The documentation describes getStates():
https://docs.spring.io/spring-statemachine/docs/current/api/org/springframework/statemachine/state/State.html
java.util.Collection<State<S,E>> getStates()
Gets all possible states this state knows about including itself and substates.
stateMachine.getState().getStates();
to wrap it up after SMA's most helpful advice: turns out the stateMachine.getState().getStates(); does in my case return a list of four elements:
a StateMachineState instance containing UP and STOPPED
three ObjectState instances containing IDLE, STOPPED and PROCESSING,
respectively.
this leads me to go forward for the time being with the following solution:
public List<ToolStates> getStates() {
List<ToolStates> result = new ArrayList<>();
Collection<State<ToolStates, ToolEvents>> states = this.stateMachine.getState().getStates();
Iterator<State<ToolStates, ToolEvents>> iter = states.iterator();
while (iter.hasNext()) {
State<ToolStates, ToolEvents> candidate = iter.next();
if (!candidate.isSimple()) {
Collection<ToolStates> ids = candidate.getIds();
Iterator<ToolStates> i = ids.iterator();
while (i.hasNext()) {
result.add(i.next());
}
}
}
return result;
}
This maybe would be more elegant with some streaming and filtering, but does the trick for now. I don't like it much, though. It's a lot of error-prone logic and I'll have to see if it holds in the future - I wonder why there isn't a function in the Spring Statemachine that gives me a list of the enum values of all the currently active states, rather than giving me everything possible and forcing me to poke around in it with external logic...

AnyLogic agent-based modelling: ClassCastException

I am working with an agent-based simulation of an infectious disease epidemic in AnyLogic. I have two agents types in my model- Person and Building. I'm trying to write a function that counts the number of infectious contacts that the agent type 'Person' has at any given point in time. Below is my code for the function:
int infectedConnections = 0;
if (getConnections() != null)
for (Agent a : this.getConnections())
{
Person p = (Person) a;
if (p.IsCurrentlyInfected())
infectedConnections++;
}
return infectedConnections ;
The code compiles without any errors but during runtime, it throws up a java.lang.ClassCastException with the message: model.Building cannot be cast to model.Person.
When I try the same code with just one agent type (i.e. 'Person'), the model runs fine and the function returns the correct value. Could someone tell me how I could rectify my code so that I am able to run the function for 'Person' please?
If you just want to ignore agents of type Building, then you can do the following:
int infectedConnections = 0;
if (getConnections() != null) {
for (Agent a : this.getConnections())
{
if(a instanceof Person) {
Person p = (Person) a;
if (p.IsCurrentlyInfected()) {
infectedConnections++;
}
}
}
}
return infectedConnections;
The problem is that (Person) a; will fail if a is a Building instead of a Person.
Although Rob's answer solves your problem, note that having mixed Person and Building connections is really the 'root cause' of your problems: in general, mixing types in a collection of things is a design flaw for the type of reasons you're seeing (and probably your agents' connections to other Person agents or Building agents are two conceptually different relationships).
In AnyLogic you can have multiple networks per agent, not just the default connections one, by adding extra Link to agents elements. So, for example, your Person agent could have one for family relationships (say called family connecting to Person agents) and one for places they live/work in (say called workHomePlaces connecting to Building agents); obviously I'm inventing possible purposes of these networks.
Then you can do things like family.getConnections() and workHomePlaces.getConnections(), avoiding the issues you're encountering and having a more conceptually-correct design.
In the help, see
Agent Based Modeling --> Agent interaction --> Defining custom contact links.

is it possible to call Java functions from aiml?

I am creating a chatbot using Java and program ab. In few places I can’t answer the questions directly, I have to process something or call a web service and process the result and then reply back. In such cases how to include the result of my java function to the responses in the aiml.
Say,
User: What is the price of the product A?
Bot: The price of product A is $50
In the above example, $50 is not going to be same always. I have to take that in run time. So how to solve this problem?
**AIML:**
<category>
<pattern>WHAT IS THE PRICE OF THE *</pattern>
<template>The price of <star/> is $<call some function price(productA)>
</template>
</category>
**JAVA:**
public int price(String product){
// gets the product price
// do the conversion
// apply discount
return price;
}
Please someone help me. Thanks in advance.
Typically AIML extensions are implemented as an extension tag. So you wouldn't call a programming language method/function directly from AIML script. In the AB documentation you can find more details about implementing this kind of functionality here. Below is the relevant text with an updated link to PCAIMLProcessorExtension found in a forked project on GitHub. There a couple of practical examples on of working extensions can be found.
AIMLProcessorExtension
Program AB defines a Java Interface called AIMLProcessorExtension that
you can use to define new AIML tags.
A class implementing AIMLProcessorExtension must provide:
a Set of tag names.
a function to recursively evaluate the XML parse tree for each node associated with a new tag.
The Program AB source
includes a sample implementation of this interface called
PCAIMLProcessorExtension, which defines a collection of tags
simulating a contacts database.
There is a simple and general option, you can keep a keyword to be used in switch later on, e.g.
AIML template will have a keyword for operation,
<category>
<pattern>WHAT IS THE PRICE OF THE *</pattern>
<template>PRICE,The price of <star/> is,<star/> </template>
And update java code like:
String response = aimlResponse(request);
String [] responseComponents = reponse.parse(",");
String method = responseComponents[0];
//Then use switch, also apply size check on array after parsing in case of response with No keywords
Switch method:
{
case PRICE:
//here add the price to response string
String price = price(responseComponents[2]);
response = responseComponents[1]+ price;
break;
}

Getting All Workitems from Team Area

I have the following objects:
ITeamRepository repo;
IProjectArea projArea;
ITeamArea teamArea;
The process of obtaining the projArea and the teamArea is quite straightforward (despite the quantity of objects involved). However I can't seem to find a way to obtain a list with all the Workitems associated with these objects in a direct way. Is this directly possible, probably via the IQueryClient objects?
This 2012 thread (so it might have changed since) suggests:
I used the following code to get the work items associated with each project area:
auditableClient = (IAuditableClient) repository.getClientLibrary(IAuditableClient.class);
IQueryClient queryClient = (IQueryClient) repository.getClientLibrary(IQueryClient.class);
IQueryableAttribute attribute = QueryableAttributes.getFactory(IWorkItem.ITEM_TYPE).findAttribute(currProject, IWorkItem.PROJECT_AREA_PROPERTY, auditableClient, null);
Expression expression = new AttributeExpression(attribute, AttributeOperation.EQUALS, currProject);
IQueryResult<IResolvedResult<IWorkItem>> results = queryClient.getResolvedExpressionResults(currProject, expression, IWorkItem.FULL_PROFILE);
In my code, currProject would be the IProjectArea pointer to the current project as you loop through the List of project areas p in your code.
The IQueryResult object 'results' then contains a list of IResolvedResult records with all of the work items for that project you can iterate through and find properties for each work item.

Categories