I need to sync Customers from NetSuite to another system and would like to search Customers by internalId range, using the PHP library for the API. Given that the internalId's are autoincrement fields, I would only need Customers with internalId greater than the highest ID in the external system.
Is there a way to do this? If so, how?
I've currently only been able to iterate over ALL records, using the SearchRequest and SearchMoreWithIdRequest. A slight optimization I can do with this is to iterate over the pages in reverse order to avoid pulling too much duplicate data, but would prefer to filter by internalId (greater-than) if possible.
Thanks
here is existing code
/// initial search
$search = new CustomerSearchBasic();
$request = new SearchRequest();
$request->searchRecord = $search;
$searchResponse = $service->search($request);
// cache the search ID because we're gonna need to re-search, with pagination, using this id
$searchId = $searchResponse->searchResult->searchId;
$totalRecords = $searchResponse->searchResult->totalRecords;
// process the results
process_response($searchResponse);
// get subsequent pages
for ($page = 2; $page < ceil($totalRecords / $pageSize); $page++) {
echo "[page: $page] ... searchId: '$searchId'" . PHP_EOL;
if (!$searchId) continue;
$request = new SearchMoreWithIdRequest();
$request->searchId = $searchId;
$request->pageIndex = $page;
$searchResponse = $service->searchMoreWithId($request);
// process the results
process_response($searchResponse);
}
function process_response($searchResponse) { ... }
Related
I am working with laravel's LengthAwarePaginator Class. My problem is that I cannot use
$users = DB::table('users')->paginate(15);
or in other words,larvel's querybuilder or eloquent results. The reason is I have provided user with a frontend where they can create queries dynamically that can as simple as a select query and can be as complicated as queries with multiple joins etc. So I am left with only option of using LengthAwarePaginator. Here is what I have done do far
private function queryWithPagination($queryString,$path,$fieldName = '',$sortOrder = '',$perPage = 100){
$queryString = str_replace(''',"'",$queryString);
$queryString = str_replace('**',"",$queryString);
if(!empty($fieldName) && !empty($sortOrder)){
$queryString .= " ORDER BY '{$fieldName}' {$sortOrder}";
}
$currentPage = LengthAwarePaginator::resolveCurrentPage();
$limit = $perPage +1; // to have pagination links clickable i.e next,previous buttons
$queryString.= " LIMIT {$limit}";
if($currentPage == 1){
$queryString.= " OFFSET 0";
}
else{
$offset = ($currentPage-1)*$perPage;
$queryString.= " OFFSET {$offset}";
}
$path = preg_replace('/&page(=[^&]*)?|^page(=[^&]*)?&?/','', $path);
$result = DB::connection('database')->select($queryString);
$collection = new Collection($result);
//$currentPageSearchResults = $collection->slice(($currentPage - 1) * $perPage, $perPage)->all();
$entries = new LengthAwarePaginator($collection, count($collection), $perPage);
$entries->setPath($path);
//dd($queryString,$result);
dd($entries);
return $entries;
}
As you can see I append LIMIT and OFFSET in the query otherwise, for complex queries the load time was getting greater resulting in bad user experience. The problem with current set up is that the last page is always set to 2 and when I get to second page I cannot browse more results i.e cases where records returned were more than 500 I can still only browse upto page 2. How do I fix this issue where by using limit offset I can still keep browsing all the results until I get to the last page and then disable the pagination links?
made the second parameter to LengthAwarePaginator dynamic as follows in the given code,it solved my problem
$entries = new LengthAwarePaginator($collection, (count($collection)>=101)?$currentPage*$limit:count($collection), $perPage);
I am trying to query for all payments assigned to an invoice using the consolibyte quickbooks php toolkit. I was hoping I could pull these back using a query but so far the only way I can see to do it is by grabbing all payments and then looping through and checking what is within the LinkedTxn array and checking if it has a type of 'Invoice' and that the 'TxnId' value matches my stored invoice id. What I have so far is this which gets the payments but is obviously not an option going forward as there may be tens of thousands of payments in the system:
public function getAllPaymentsForInvoice(Invoice $invoice)
{
$query = "SELECT * FROM Payment";
$payments = $this->qbPaymentService->query($this->context, $this->realm, $query);
$lines = [];
foreach ($payments as $payment) {
$num_lines = $payment->countLine();
for ($i = 0; $i < $num_lines; $i++) {
$line = $payment->getLine($i);
$txnId = $this->parseResponse($line->getLinkedTxn()->getTxnId());// convert {-1} to 1
$txnType = $line->getLinkedTxn()->getTxnType();
if ($txnType == 'Invoice' && $txnId == $invoice->qb_ref) {
$lines[] = $line;
}
}
}
return $lines;
}
Can anyone push me in the direction of a better way?
There's no easy, one-liner way to do this using the QuickBooks Online API. This just isn't something that QuickBooks Online itself supports.
There are two separate approaches you could take to optimize what you're doing.
The payments applied should always be for the same customer as the invoices, so you can change your query to SELECT * FROM Payment WHERE CustomerRef = 'xyz' where xyz is the CustomerRef from the invoice. Then, use your existing code to check exactly which invoices payments are applied to.
Use the CDC functionality to keep a cached copy of all payments in your own database, and query your own database for the information instead (a normal SQL database is considerably more flexible and query-able than what QuickBooks Online offers).
The CDC functionality is specifically designed to allow you to keep an accurate, cached copy of the QuickBooks data in your own application, specifically to address situations like you're running into. You pass it a timestamp, and it gives you everything that has changed since that timestamp. By remembering the date/time you last ran the ->cdc(...) method, you can continually get lightweight updates to any objects that have changed since you last queried them.
<?php
$CDCService = new QuickBooks_IPP_Service_ChangeDataCapture();
// What types of objects do you want to get?
$objects = array(
'Payment',
'Invoice',
);
// The date they should have been updated after
$timestamp = QuickBooks_Utilities::datetime($datetime_you_last_called_cdc_method);
$cdc = $CDCService->cdc($Context, $realm,
$objects,
$timestamp);
// You would cache all the stuff you get back here
print_r($cdc);
Docs links:
https://github.com/consolibyte/quickbooks-php/blob/master/docs/partner_platform/example_app_ipp_v3/example_cdc.php
https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/change_data_capture
The question is quite old, anyway, in case someone else is looking for answer:
$InvoiceService = new QuickBooks_IPP_Service_Invoice();
// $invoices = $InvoiceService->query($Context, $realm, "SELECT * FROM Invoice STARTPOSITION 1 MAXRESULTS 10");
// If, we have QB Invoice # i.e.DocNumber
$invoice_no = 1001;
$invoices = $InvoiceService->query($Context, $realm, "SELECT * FROM Invoice WHERE DocNumber = '$invoice_no' ");
foreach ($invoices as $Invoice)
{
$txnId = 0;
if (is_object($Invoice->getLinkedTxn()) && $Invoice->getLinkedTxn()->getTxnType() == 'Payment') {
$txnId = $Invoice->getLinkedTxn()->getTxnId();
}
print('Invoice # '.$Invoice->getDocNumber().' has a total of $'.$Invoice->getTotalAmt().' and Linked Payment ID: ' . $txnId . "\n");
}
I can list the users that have relations of a current user, but how do I list users that don't have relations with the current user. Or how do I exclude users that have relations with the current user from a list. I am happy to see it in javascript, ios etc..
$user = ParseUser::getCurrentUser();
$relation = $user->getRelation("follow");
$usersFollowed = $relation->getQuery()->find();
print_r($usersFollowed);
Thanks
I'm not using php, but you could try to use notEqualTo constraint to 'follow' with current user.
Something like query.notEqualTo('follow', Parse.User.current()); in js
I have found a work around to achieve what I wanted to achieve. I am happy for others to improve it.
$user = ParseUser::getCurrentUser();
$relation = $user->getRelation("follow");
$usersFollowed = $relation->getQuery()->find();
// loop through all the users that are being followed
for ($i = 0; $i < count($usersFollowed); $i++) {
$object = $usersFollowed[$i];
$usernames = $object->get('username');
// concatenate the usernames to produce a string
$str_usernames .= $usernames . ' ';
}
// convert the string into an array
$array_usernames = explode(" ", $str_usernames);
print_r($array_usernames);
echo "<br><br>";
// query all the usernames not contained in the above array
$query = new ParseQuery("_User");
$query->notContainedIn("username", $array_usernames);
$results = $query->find();
print_r($results);
I hope this helps others, it costs two api requests. I am not sure how it would perform over thousands or hundreds of thousands of usernames though.
I am facing problem to retrieve records in descending order with pagination limit from amazon dynamodb as in mysql.
Now I am using the following script, but it gives unordered list of records. I need the last inserted id is on top.
$limit = 10;
$total = 0;
$start_key = null;
$params = array('TableName' => 'event','AttributesToGet' =>array('id','interactiondate','repname','totalamount','fooding','nonfooding','pdfdocument','isMultiple','payment_mode','interaction_type','products','programTitle','venue','workstepId','foodingOther','interaction_type_other'), 'ScanFilter'=> array('manufacturername' => array("ComparisonOperator" => "EQ", "AttributeValueList" => array(array("S" => "$manufacturername")))),'Limit'=>$limit );
$itemsArray = array();
$itemsArray = array();
$finalItemsArray = array();
$finalCRMRecords = array();
do{
if(!empty($start_key)){
$params['ExclusiveStartKey'] = $start_key->getArrayCopy();
}
$response = $this->Amazon->Dynamodb->scan($params);
if ($response->status == 200) {
$counter = (string) $response->body->Count;
$total += $counter;
foreach($response->body->Items as $itemsArray){
$finalItemsArray[] = $itemsArray;
}
if($total>$limit){
$i =1;
foreach($response->body->Items as $items){
$finalItemsArray[] = $items;
if($i == $limit){
$start_key = $items->id->{AmazonDynamoDB::TYPE_NUMBER}->to_array();
$finalCRMRecords['data'] = $finalItemsArray;
$finalCRMRecords['start_key'] = $start_key;
break;
}
$i++;
}
}elseif($total<$limit){
$start_key = $response->body->LastEvaluatedKey->to_array();
}else{
$finalCRMRecords['data'] = $finalItemsArray;
if ($response->body->LastEvaluatedKey) {
$start_key =$response->body->LastEvaluatedKey->to_array();
break;
} else {
$start_key = null;
}
$finalCRMRecords['start_key'] = $start_key;
}
}
}while($start_key);
Regards
Sandeep Kumar Sinha
A Scan operation in DynamoDB can not change the sorting of the returned items. Also is Scan a pretty expensive operation as it always requires to read the whole table.
If you want to take advantage of DynamoDB, here's one advice:
Instead of looking for information, try to just find it.
In the sense of, use lookups instead of scan/query to get the information you need.
As an example, if you have a table that stores Events. Just store all events in that table, with their EventId as HashKey. Then you can have a second table EventLookups to store lookups to EventIds. In the EventLookups table you could put an Item like LookupId: LATEST-EVENT referencing some EventId: .... Every time you insert new events you can update the LATEST-EVENT entry to point to a newer Event. Or use a SET to store the latest 50 EventIds events in one Item.
-mathias
I'm trying to fetch 1000+ Twitter users from my database using this API call. However, Twitter lookup only allows 100 users per call, so how can I do it with 10 calls?
If I have 2232 users in my DB and I want to do a lookup on all users and get their details how to do it? Something which will count all the users being searched, break it into array of 100 elements, make the call for 100, and add the response back to database and then move onto the next 100.
I am using the tmhOAuth library for Twitter.
EDITED:
I was able to accomplish it using this code , but my next question is how can i bind those values back to my account ? because the screen_name is a entry and not the KEY of the array, so how can i do it ?
$accounts = $this->accounts->getAll();
$accounts_chunk = array_chunk($accounts,100);
foreach($accounts_chunk as $accounts){
$screen_names = "";
$last_key = end(array_keys($accounts));
foreach($accounts as $k => $account){
$screen_names .= $account->screen_name;
if($last_key == $k){
$screen_names .= "";
} else {
$screen_names .= ",";
}
}
$code = $this->twitter->request('GET', $this->twitter->url("1/users/lookup"),array('screen_name' => $screen_names));
echo "<pre>";print_r(json_decode($this->twitter->response));echo "</pre>";
}
But how to update values in DB using this .. i did a check but the sequence of the responses always changes so cannot use the current keys ..
You could loop through the max number of users and every hundredth time loop through hundred users and do your Twitter-magic there.
$iNumUsers = 2232; // or a mysql_num_rows-like result;
for($i = 0; $i < $iNumUsers; $i++) {
if($i % 100 == 0) {
for($j = $i; $j < 100; $j++) {
// your twitter-code here
}
}
}
Hi here are some simple steps to do this task
1: Get screen names from your db with limit of 100
2: impload with comma (join them with comma)
3: Send these 100 to users/lookup call and get data
4: (important) IF YOU RECEIVE AN ERROR OF "Rate limit exceeded" THEN USE PROXY
proxy will give you another chance to make next call of 100 users
5: decode json and send data to db
(important) if you use user's id instead of screen name then it will be easy to update db
Still have problem shout a comment here
The Twitter API says
You are strongly encouraged to use a POST for larger requests.
So try posting your 2,000 IDs to them.
With regards to the second part of your question
the sequence of the responses always changes so cannot use the current keys ..
Start with your array of user IDd - $ids
Get the response from Twitter as $tl
// Place the users into an array
$sortedUsers = array();
foreach ($tl as $user) {
$user_id = $user->id;
// $tl is *unsorted* - but $ids is *sorted*. So we place the users from $tl into a new array based on how they're sorted in $ids
$key = array_search($user_id, $ids);
$sortedUsers[$key] = $user;
}
// Sort the array by key so the most recent is at the top
ksort($sortedUsers);