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.
Related
this function takes a ServicePoint object as argument, which has the following attributes:
adminId (String)
name (String)
serviceType (enum)
I want this function to create a new Table with name: "name+adminId". This is achieved.
Also I want this function to create a new Table (if it is not there already) by the name ServicePoints.
ServicePoints stores the relationship between user (with objectId = adminId) and the new Table.
To achieve this, I set "serviceTable" attribute with value as the new Table created, acting as a pointer.
When I run the code first time, I achieve the required tables. But, when I run the function second time, it doesn't add the new row/record to ServicePoints table.
I don't know why.
UPDATE I found that set ParseObject operation is the culprit. But, to my surprize, it executes successfully for the very first time. But fails every next time. This is really absurd behaviour from parse_server_sdk_flutter.
Future<bool> createServicePoint(ServicePoint servicePoint) async {
String newServicePointName = servicePoint.name + servicePoint.adminId;
var newServiceTable = ParseObject(newServicePointName);
var response = await newServiceTable.save();
if (response.success) {
print('Now adding new row to ServicePoints table');
var servicePointsTable = ParseObject('ServicePoints')
..set<String>("serviceName", servicePoint.name)
..set<String>("adminId", servicePoint.adminId)
..set<String>("serviceType", _typeToLabel[servicePoint.serviceType])
..set<ParseObject>("serviceTable", newServiceTable);
var recentResponse = await servicePointsTable.save();
return recentResponse.success;
} else {
return false;
}
}
If anyone runs into this problem, you need to check the result after saving the ParseObject. If there is error like "Can't save into non-existing class/table", then just go to the dashboard and create the table first.
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
I have created a website, And I don't to allowed customer to type link in browser.
I just want to allow customer click link on the website only.
please provide me a solution !!!
thank for help !!!
use token for in hyperlinks . deny if token wont match to value in session.
try the following:
in controller check if session['token'] is set,
if not set session['token'] to a rendom value.
if token not set or won't match to $_GET['token'] variable redirect to error page.
if token match to get variable (ie. $_GET['token']) then , pass that value to view.
i don't recomend this because doing this might affect the browser cache.
Controller constructor
function __construct()
{
parent::__construct();
$this->load->library('session');
if(!isset($_SESSION['token']))
{
$_SESSION['token'] = rand();
}
if((!$this->input->get('token')) || ($this->input->get('token') != $_SESSION['token']))
{
redirect('error_page');
}
// to pass to vew
$data['token'] = $_SESSION['token'];
$this->load->view('view_page',$data);
}
in view_page.php (view) replace links like this
Gallery link
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.
I am iterating through some data and generating parameterized URL links based on some conditions like this:
finishedHTML.append("<a href=\"http://" + domain + "&service=" + allEvents[eventCounter].EventService +"&day="+ offSet+(-1 * i) +"\"><img src=\"/info.jpg\" alt=\"Info\"/>");
I had the beginning of my application checking for URL parameters when the page was loaded/refreshed, and take some action depending on if the parameters were there and what they were.
However, I added a # to the beginning of the paramters, so the page wouldn't need to be refreshed, but now it's not triggering the function that checks the URL.
My question is how can I trigger an event in GWT when a user clicks a link? Do I need to generate GWT controls, and link a click handler? Is it possible to setup an event that fires when the URL is changed???
UPDATE:
Adam answered part of the initial question, but I can't get the querystring after "#". Is there a better way than the function below:
public static String getQueryString()
{
return Window.Location.getQueryString();
}
In other words, if I enter example.com?service=1 I get service=1 as my querystring. If I enter example.com#?service=1, I get a null value for the querystring..
Use History.addValueChangeHandler( handler ), and create a handler to catch the URL changes.
There's no need for click handlers etc., any change of the "hash" part in the URL will be sufficient.
EDIT:
See this code example - it will parse URLs of the form http://mydomain/my/path#tok1&tok2&tok3
public void onValueChange(ValueChangeEvent<String> event) {
String hash = event.getValue();
if ( hash.length() == 0 ) {
return;
}
String[] historyTokens = hash.split("&",0);
// do stuff according to tokens
}
(Just responding to your Update)
Have you tried
History.getToken()
to get the value after the "#"?