OrderMgr getOrder() method always return null - demandware

I am writing a simple job that fetches the order status from external service.
Then I want to use this data to update the order.
Whenever I call a static method getOrder(id : String) on the OrderMgr I receive null.
The order with given ID exists and is visible in BM.
Can someone advise me what am I doing incorrectly?
importPackage(dw.order);
function execute( pdict : PipelineDictionary ) : Number
{
var mgr : OrderMgr = OrderMgr;
var logH : Logger = Logger.getLogger("test1", "test1");
var order : Order = mgr.getOrder("00000101");
if (order == null){
// always null, even if the order exists
logH.info("The order is null");
}
return PIPELET_NEXT;
}

Check in scope of what site you are running the job. If it’s in Organization scope, you have to change to the site scope.
Second when you will do update, don’t forget to use Transactions.

I think you need to use getOrder() method from a batch job in dw business manager, there are some scripts that does not allow you to call them from storefront

Related

Get the output of RestSetResponse without making HTTP request

I have a minimal (example) REST end-point test/people.cfc:
component
restpath = "test/people/"
rest = true
{
remote void function create(
required string first_name restargsource = "Form",
required string last_name restargsource = "Form"
)
httpmethod = "POST"
restpath = ""
produces = "application/json"
{
// Simulate adding person to database.
ArrayAppend(
Application.people,
{ "first_name" = first_name, "last_name" = last_name }
);
// Simulate getting people from database.
var people = Application.people;
restSetResponse( {
"status" = 201,
"content" = SerializeJSON( people )
} );
}
}
As noted here and in the ColdFusion documentation:
Note: ColdFusion ignores the function's return value and uses the response set using the RestSetResponse() function.
So the void return type for the function appears to be correct for the REST function.
Now, I know I can call it from a CFM page using:
httpService = new http(method = "POST", url = "https://localhost/rest/test/people");
httpService.addParam( name = "first_name", type = "formfield", value = "Alice" );
httpService.addParam( name = "last_name", type = "formfield", value = "Adams" );
result = httpService.send().getPrefix();
However, I would like to call the function without making a HTTP request.
Firstly, the REST CFCs do not appear to be accessible from within the REST directory. This can be solved simply by creating a mapping in the ColdFusion admin panel to the root path of the REST service.
I can then do:
<cfscript>
Application.people = [];
people = new restmapping.test.People();
people.create( "Alice", "Adams" );
WriteDump( application.people );
</cfscript>
This calls the function directly and the output shows it has added the person. However, the response from the REST function has disappeared into the aether. Does anyone know if it is possible to retrieve the response's HTTP status code and content (as a minimum - preferably all the HTTP headers)?
Update - Integration Testing Scenario:
This is one use-case (of several) where calling the REST end-point via a HTTP request has knock-on effects that can be mitigated by invoking the end-point directly as a method of a component.
<cfscript>
// Create an instance of the REST end-point component without
// calling it via HTTP request.
endPoint = new restfiles.test.TestRESTEndPoint();
transaction {
try {
// Call a method on the end-point without making a HTTP request.
endPoint.addValueToDatabase( 1, 'abcd' );
assert( getRESTStatusCode(), 201 );
assert( getRESTResponseText(), '{"id":1,"value":"abcd"}' );
// Call another method on the end-point without making a HTTP request.
endPoint.updateValueInDatabase( 1, 'dcba' );
assert( getRESTStatusCode(), 200 );
assert( getRESTResponseText(), '{"id":1,"value":"dcba"}' );
// Call a third method on the end-point without making a HTTP request.
endPoint.deleteValueInDatabase( 1 );
assert( getRESTStatusCode(), 204 );
assert( getRESTResponseText(), '' );
}
catch ( any e )
{
WriteDump( e );
}
finally
{
transaction action="rollback";
}
}
</cfscript>
Calling each REST function via a HTTP request will commit the data to the database after each request - cleaning up between tests where the data has been committed can get very complicated and often results in needing to flashback the database to a previous state (resulting in integration tests being unable to be run in parallel with any other tests and periods of unavailability during flashbacks). Being able to call the REST end-points without making lots of atomic HTTP requests and instead bundle them into a single transaction which can be rolled back means the testing can be performed in a single user's session.
So, how can I get the HTTP status code and response text which have been set by RestSetResponse() when I create an instance of the REST component and invoke the function representing the REST path directly (without using a HTTP request)?
#MT0,
The solution will* involve a few steps:
Change remote void function create to remote struct function create
Add var result = {"status" = 201, "content" = SerializeJSON( people )}
Change your restSetResponse(..) call to restSetResponse(result)
Add return result;
* The solution will not currently work, b/c ColdFusion ticket CF-3546046 was not fixed completely. I've asked Adobe to re-open it and also filed CF-4198298 to get this issue fixed, just in case CF-3546046 isn't re-opened. Please see my most recent comment on CF-3546046, and feel free to vote for either ticket. Once either is fixed completely, then the above-listed changes to your code will allow it to set the correct HTTP response when called via REST and to return the function's return variable when invoked directly. Note: you could also specify a headers struct w/in the result struct in step 2, if you also want to return headers when the function is invoked directly.
Thanks!,
-Aaron Neff

How can I automatically apply model filters to GET requests in Sails

I want all all the HTTP GET requests to the API generated by Sails to be restricted. So how can I apply a filter to all incoming API GET requests.
More specifically, most of my models have an attribute called publicityLevel. This tells whether a model is public or not. So I want all my models to automatically apply a filter (like publicityLevel: 'public') for all incoming GET requests.
Even more advanced, I'd like to write some code which decides whether the user can see a specific model or not. So if a user is an admin, don't apply this filter. If the user isn't an admin, apply this filter.
I had similar problem to solve with blueprints and I solved it.
If we are talking about BLUEPRINTS:
You can get modelName from req.options.model when you are using Blueprints.
I was using it to check if user belongs to the same group as element.
Unfortunately you can't use this[modelName] as option is giving you model name starting with small letter, so first you have to upper case first letter with e.g. var modelName = req.options.model.charAt(0).toUpperCase() + req.options.model.slice(1);
and then you are free to use this[modelName].whateverYouNeed
I used it for generic policy to let user editing only his own group elements.
var modelName = req.options.model.charAt(0).toUpperCase() + req.options.model.slice(1)
var elementID = null
if (req.params.id) { // To handle DELETE, PUT
elementID = req.params.id
}
if (req.body.id) { // To handle POST
elementID = req.body.id
}
this[modelName].findOne({
id: elementID
}).exec(function(err, contextElement) {
if(err) {
return res.serverError(err)
}
if(contextElement.group=== req.user.group.id) {
sails.log('accessing own: ' + modelName)
return next()
}
else {
return res.forbidden('Tried to access not owned object')
}
})

Mark an order as "Full Payment" on Sage 200

I am inserting orders on Sage 200 through an application using the client side, C# and APIs.
I would like to check the "Full payment" checkbox on the "Payment with order" tab.
Currently, I am setting the PaymentType property, which is not working.
order.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
order is an instance of Sage.Accounting.SOP.SOPOrder.
Do you know how I can check that property?
The following method should supply the required results.
private static void SetPaymentWithOrder(Sage.Accounting.SOP.SOPOrder sopOrder)
{
// Indicate that order has payment
sopOrder.PaymentWithOrder = true;
// This is full payment order
sopOrder.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
// Fetch the the Payment Methods. SOPPaymentMethods contructor accepts the boolean flag whether to fetch payment methods including card processing method or not.
Sage.Accounting.SOP.SOPPaymentMethods paymentMethodsCollection = new Sage.Accounting.SOP.SOPPaymentMethods(false);
// Set the first payment method of the collection to the order
sopOrder.PaymentMethod = paymentMethodsCollection.First;
}
dont know if you ever managed to figure this one out or not.
Not sure if you knew this, but you cannot modify the Sales Order on the view form, or at least shouldn't be trying to do so.
Using either of the Enter/Amend Sales Order forms will allow you to do so.
What is potentially happening, is that the properties that the controls are bound to are not updating the UI after your code has run.
You can simply force this to happen using the following
Fetching the underlying bound object
public Sage.Accounting.SOP.SOPOrderReturn SOPOrderReturn
{
get
{
//Loop over the boundobjects collection
//check if the bound object is of the type we want - e.g. SOPOrderReturn
//if correct type, return this object
Sage.Common.Collections.BoundObjectCollection boundObjects = this.form.BoundObjects;
if (boundObjects != null)
{
foreach (object boundObject in boundObjects)
{
if (boundObject is Sage.Accounting.SOP.SOPOrderReturn)
{
this._sopOrderReturn = boundObject as Sage.Accounting.SOP.SOPOrderReturn;
break;
}
}
}
return this._sopOrderReturn;
}
}
Fetch the correct underlying form type that the amendable form is, suspending the databinding,
perform your changes,
resuming the databinding
Sage.MMS.SOP.MaintainOrderForm maintainOrderForm = this.form.UnderlyingControl as Sage.MMS.SOP.MaintainOrderForm;
maintainOrderForm.BindingContext[this.SOPOrderReturn].SuspendBinding();
this.SOPOrderReturn.PaymentWithOrder = true;
this.SOPOrderReturn.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
maintainOrderForm.BindingContext[this.SOPOrderReturn].ResumeBinding();
should do the trick.

Get apex page header in trigger

I am trying to get the user agent calling the apex page header in an apex class through a trigger, to update a field depending on the user device (mobile or not).
Here's the code I'm using:
public static boolean isMobileDevice() {
String userAgent = ApexPages.currentPage().getHeaders().get('User-Agent');
if (userAgent == null) {
return false;
}
Pattern p = Pattern.compile('Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|NetFront|Silk-Accelerated|(hpw|web)OS|Fennec|Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune');
Matcher pm = p.matcher(userAgent);
return pm.find();
}
When the trigger runs, it returns this error:
System.NullPointerException: Attempt to de-reference a null object: Class.MyClass.isMobileDevice: line 129, column 1
The 129th line is this one :
String userAgent = ApexPages.currentPage().getHeaders().get('User-Agent');
Is there a workaround to get the user agent from a controller in an apex trigger or is it just impossible ?
Thanks in advance for any help you are able to provide.
I managed to do it finally.
I used a custom field on the object, and complete its value on creation of the record depending on user agent. Then in the trigger I only need to check that field and not the userAgent anymore.
Hope this can help.

Salesforce: Can I associate a completion of a task with a field update?

I'm trying to see if it's possible for a field in Opportunity to be updated (a checkbox to be checked true) when someone completes a related task. Is there a way to do this?
I don't think this can be done with cross-object workflow, since the WhatId field of a Task is a "polymorphic key". If I'm right, you'll have to use a Trigger on Task.
As Jeremy said you'll need a trigger, code will look something like (I've not checked field names etc. so treat this as almost-real pseudo code)!
trigger TaskAfterInsertUpdate on Task (after update, after insert)
{
list<opportunity> liOpportunities = new list<opportunity>();
list<id> liIDs = new list<id>();
for(Task sTask : trigger.new)
{
if(sTask.Status == 'Complete' && ('' + sTask.WhatId).startsWith('006'))
{
liIDs.add(sTask.WhatId);
}
}
for(Opportunity sOppty : [select Id, CheckBoxField__c from Opportunity where Id in : liIDS])
{
sOppty.CheckBoxField__c = true;
liOpportunities.add(sOppty);
}
update liOpportunities;
}
Hope this is of some help!