Quantity not appearing on invoice created by WHMCS - php

I am trying to place an order via WHMCS API on my local environment. This is my order code,
$postfields["action"] = "addorder";
$postfields["clientid"] = "104";
$postfields["billingcycle"] = "monthly";
$postfields["pid"] = "55";
$postfields['configoptions'] = base64_encode(serialize(array(1 => 3)));
$postfields["regperiod"] = "5";
$postfields["paymentmethod"] = "paypal";
It is listed on the API doc that 'configoptions',
$postfields['configoptions'] = base64_encode(serialize(array(1 => 3)));
^ is for changing the order quantity and other options(first element is for the quantity). Problem is that the invoice generated by WHMCS only contains quantity as 1 and not 3.
---------------------------------------------------------Edit 1 ------------------------------------------------------------------
I have looked into the product configurations, "Tick this box to allow customers to specify if they want more than 1 of this item when ordering" option is ticked as well!

A bit late to the game but oh well.
In the current WHMCS API documentation for the AddOrder function I have not been able to find anything regarding quantity, I have a feeling that at this point that simply enables an input in the order form and WHMCS handles that input somehow.
I did find a way that might work for you though. Im not sure how you are actually using the API if it's driven by some custom form somewhere or what but you can do the following.
in lieu of:$postfields['configoptions'] = base64_encode(serialize(array(1 => 3))); which doesn't seem to work you can just use the 'pid' field to specify the quantity, something like this:
$quantity = trim(str_repeat("{$pid},", $_POST['qty']), ',');
$postfields["pid"] = $quantity;
Simply repeating the product ID as many times as desired sets the quantity, you can do basically the same thing using the local API function, see below:
$quantity = array_fill(0, $_POST['qty'], $pid);
$command = 'AddOrder';
$postData = array(
'clientid' => '1',
'pid' => $quantity,
'domain' => array('example.com'),
'billingcycle' => array('monthly'),
'paymentmethod' => 'PayPal',
);
The result of the above code will be a single order with however many products ($pid) were specified in $_POST['qty']

Related

PHP - Pulling array and splitting the strings

Not sure how to title this properly but here's the issue I am running into currently. I built a cart and checkout system and it loads all the data into a database when it finalized the order. To save some space, I stored just the item IDs originally but then I ran into the issue of if I deleted the item from the database (because it was discontinued or whatever) then it wouldn't return the info I needed. And if they ordered more then 1 item the database record would be wrong. So I stored the data like so:
Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2
OR
1:3:20.00:Flower Hat, 2:1:17.75:diamonds
The issue I have right now that I need help with is this. I need to seperate the four values into variables like $price, $item, $id, $ammount so I can display them on the order history page and I need to loop through all items on the array so I can print a row for each item with all four fields respective to that item.
I use strpos already to get the shipping info from the same database field which is formatted as METHOD:Price but since I have 3 :'s on my string I'm not sure how to go through each one. Thanks.
Here's a function
function parseItems($dbjunk){
$cart = array();
$items = explode(",",$dbjunk);
foreach($items as $i){
$chunks = explode(":", $i);
$cart[] = array(
"ItemID" => $chunks[0] ,
"Quantity" => $chunks[1] ,
"Price" => $chunks[2] ,
"name" => $chunks[3]
);
}
return $cart;
}
Example usage:
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
print_r($parsed);
See: https://3v4l.org/rBkXF
If you need variables instead of an array you can use list(), like this..
$dbjunk = "Itemid:Quantity:Price:name, itemid2:quantity2:price2:name2";
$parsed = parseItems($dbjunk);
foreach($parsed as $p){
list($itemID, $Quantity, $Price, $name) = array_values($p);
var_dump($itemID, $Quantity, $Price, $name);
}
see: https://3v4l.org/l4vsn
You should not physically delete items from your database. Instead, put a new column named 'is_active' or something like that to indicate whether the product is active/non-deleted.
Answering your question, here is my suggestion:
$orderString = '1:3:20.00:Flower Hat, 2:1:17.75:diamonds';
$items = array();
foreach(explode(', ', $orderString) as $itemString) {
$itemData = explode(':', $itemString);
$items[] = array(
'id' => $itemData[0],
'amount' => $itemData[1],
'value' => $itemData[2],
'description' => $itemData[3]
);
}
with this code, you will obtain an array with the data of all the items in the string, no matter how much items are in the string
try something like
$data = 1:3:20.00:Flower Hat, 2:1:17.75:diamonds
list($price, $item, $uid, $id, $ammount) = explode(":", $data);
echo $user;
echo $item;
Read about First Normal Form. Basically, you want to store one value in one field. So, instead of this:
shipping = "method:price"
You want something like this:
shipping_method = "method"
shipping_price = "price"
Don't concern yourself with space -- it's essentially free nowadays.
Regarding your deleted items dilemma, your initial implementation was the way to go:
I stored just the item IDs originally
In addition to reverting to this technique, I would recommend two things:
Add a boolean field to your item table to represent if the item is currently available or not. This gives you the additional feature of being able to toggle items on/off without having to delete/insert records and change ids.
Before deleting an item, check to see if it's ever been ordered. If not, it's ok to delete. If so, instead just deactivate it.

Get multiple products info in a single SOAP request (magento api)

I'm trying to get products from Magento API with catalogProductList (soap v2) here is my function.
public function get_products() {
$products = array();
$login = $this->login_info();
$proxy = new SoapClient($login['url']);
$sessionId = $proxy->login($login['user'], $login['pass']);
$result = $proxy->catalogProductList($sessionId);
foreach($result as $value) {
$products[] = $proxy->catalogProductInfo($sessionId, $value->product_id);
}
echo "<pre>";
var_dump($products);
echo "</pre>";
}
However because the request it's in a loop it will make for each product a request to Magento API.
I'm wondering if there is a solution to get multiple products info (based on provided product_id) in the same request. Maybe 50 or 100 products info for each request I think will reduce a lot the time of getting all the products.
I have found on http://www.magentocommerce.com/api/soap/introduction.html
$params = array('filter' => array(
array('key' => 'status', 'value' => 'pending'),
array('key' => 'customer_is_guest', 'value' => '1')
));
$result = $client->salesOrderList($sessionId, $params);
but from my understanding it's more about filtering the products so I don't know if it helps too much.
Looks like you're calling the catalogProductList twice, first time outside the loop and the second time inside the loop passing invalid arguments, the doc here is showing that you only need to use the method once passing the session id plus you are able to pass two extra optional arguments (array of filters and the store view id or code) additionally if the returned result catalogProductEntity is not enough you can override that part of the API adding extra product information for example the media images.

Netsuite - get custom record with php toolkit

I've been handed a project to complete and the clients have asked for a field from a customrecord attached to each customer to appear on their website. We're integrating with Netsuite on login, and saving their data in our database so we don't have to keep accessing Netsuite (very slow).
On login, we access Netsuite to do a SearchMultiSelectCustomField and find the customer's company, and then do a CustomRecordSearchBasic and use their company ID to get a list of items they have access to.
We loop over each of those items, and then loop over their custom fields. One of the fields has a typeId of -10, which means we do an ItemSearchBasic to get this item's record and the item's custom fields, saving the internalId of this item.
At the end of this loop, we have an array of item IDs that a company is linked to. We also have the company ID (custrecord_nn_item_customer) and the Item ID (custrecord_nn_item_customer_list).
I need to perform a get request on a custom record to check if that customer has been approved for that item.
The customrecord's ID is 'customrecord_custitem', and internal Id is '1'.
The record has 3 fields (although only 2 show up for the customer's Netsuite Record page):
custrecord_lookup_item - this is the Item record code (custrecord_nn_item_customer_list from above)
custrecord_custitem_code is the code I need
My question (after all that) is does anyone have any examples or can point me in the right direction on how I can access a customrecord attached to a customer? I think all of the necessary information is provided, but I've never used Netsuite before or the PHP toolkit.
$this->depends('netsuite');
$this->netsuite->start();
// get the "customer" (aka company) that the user's contact record belongs to
$companySearch = $this->netsuite->complexObject('SearchMultiSelectCustomField')
->setFields(array(
'searchValue' => new nsListOrRecordRef(array('internalId' => $companyId)),
'internalId' => 'custrecord_nn_item_customer',
'operator' => 'anyOf'
));
// Fetch items that the user's company has access to
$search = $this->netsuite->complexObject('CustomRecordSearchBasic')
->setFields(array(
'recType' => new nsCustomRecordRef(array(
'internalId' => 260,
'type' => 'customRecord')
),
'customFieldList' => array($companySearch)
));
$response = $this->netsuite->client->search($search);
// loop over the items
foreach($this->netsuite->complexToSimple($response->recordList) as $record){
//var_dump($record);
$processor = null;
$this_item = '';
$this_person = '';
// foreach custom field (all the fields we're interested in, common name etc. are custom)
foreach($record['customFieldList']['customField'] as $customField){
$processor = $customField['value'];
$id = $processor['internalId'];
$typeId = $processor['typeId'];
if($customField['internalId']=='custrecord_nn_item_customer'){
$this_person = $id;
}elseif($customField['internalId']=='custrecord_nn_item_customer_list'){
$this_item = $id;
}
// a typeId of -10 = an Inventory Item
if($typeId == -10){
// do an ItemSearchBasic to fetch the item with it's custom fields
$itemSearch = $this->netsuite->complexObject('ItemSearchBasic')
->setFields(array(
'internalId' => array(
'operator' => 'anyOf',
'searchValue' => array('type' => 'inventoryItem', 'internalId' => $id)
)
));
$itemSearch = $this->netsuite->client->search($itemSearch);
// foreach custom item field
if($v=#$this->netsuite->complexToSimple($itemSearch->recordList)){
foreach($v as $itemRecord){
//var_dump($itemRecord);
$item = array('id' => $itemRecord['internalId']);
$items[] = $item;
}
}
}
}
}
It is inside the foreach loop that I need to get the customrecord field for the company ID and the current iteration of the item ID.
Set up a saved search with the results columns you need. Don't worry about filtering by customer.
Call the search from your code, and dynamically filter for the current customer.
Your code should be about 5-10 lines long to get that done, and should be super quick.

$this->Model->id not working before saveAll in CakePHP

I have the following code in CakePHP 2:
$this->Order->id = 5;
$this->Order->saveAll(array(
'Order' => array(
'person_id' => $this->Session->read('Person.id'),
'amount' => $total,
'currency_id' => $code
),
'Lineitem' => $lineitems /* a correctly-formatted array */
));
I would expect this to update the row with the Primary Key of 5 in the Order table and then insert the Lineitem rows with an order_id of 5.
However, all it does is create a new row in Order and then use the new id from the new Order record to create the Listitem rows.
Note: I'm only setting the ID as above for debugging purposes and to easily demonstrate this question. In my final code, I'll be checking to see if there's already a pending order with the current person_id and doing $this->Order->id = $var; if there is and $this->Order->create(); if there isn't.
In other words, sometimes I will want it to INSERT (in which case I will issue $this->Order->create(); ) and sometimes I will want it to UPDATE (in which case I will issue $this->Order->id = $var; ). The test case above should produce an UPDATE but it's producing an INSERT instead.
Any idea what I am doing wrong here?
The array you pass to Model->saveAll() doesnt't contain the order's id, so Cake creates a new one. If you wanto to update an existing record, either you set the order id in the passed array, or you retrieve it with a find. The documentation explicitly remarks
If you want to update a value, rather than create a new one, make sure
your are passing the primary key field into the data array
$order = $this->Order->findById(5);
// ... modify $order if needed
$this->Order->saveAll(array('Order' => $order, 'LineItem' => $items));
In your case, you may want to use something like the following to be as concise as possible. Model::saveAssociated() is smart enough to create or update depending on the id, but you must provide suitable input. Model::read($fields, $id) initializes the internal $data: for an existing record all fields will be read from the database, but for a nonexistent id, you'll need to supply the correct data for it to succeed. Assuming an order belongsTo a customer, I supply the customer id if the order doesn't exist
// set the internal Model::$data['Order']
$this->Order->read(null, 5);
// You may want to supply needed information to create
// a new order if it doesn't exist, like the customer
if (! $this->Order->exists()) {
$this->Order->set(array("Customer" => array("id" => $customer_id)));
}
$this->Order->set(array('LineItem' => $items));
$this->Order->saveAssociated();
As a final note, it seems you are implementing a shopping cart. If that's the case, maybe it'd be clearer to use a separate ShoppingCart instead of an Order with a finalized flag.
Have you tried following:
$this->Order->saveAll(array(
'Order' => array(
'id' => 5,
'person_id' => $this->Session->read('Person.id'),
'amount' => $total,
'currency_id' => $code
),
'Lineitem' => $lineitems /* a correctly-formatted array */
));
Its pretty much the same what you did with :
$this->Order->id = 5;
Maybe that would fix your problem.
Cake is checking if you set id field and if its there it updates record, if not found it creates new record instead.
update:
Then maybe check before you saveAll if there is id field, then save result of check to some boolean and create array to save determined by this boolean for example:
if($id_exist) $order['Order']['id'] = 5;
$order['Order']['id'] = 5;
$order['Order']['person_id'] = $this->Session->read('Person.id'),
$order['Order']['amount'] = $total;
$order['Order']['currency_id'] = $code;
$this->Order->saveAll(array(
'Order' => $order,
'Lineitem' => $lineitems /* a correctly-formatted array */
));

post rating for an individual item in a list using codeigniter

I’m having a heck of a time figuring out how to post a rating for an individual item in a list of items,
this code let’s me rate multiple items, but not single items:
for($i=0;$i<2;$i++){
$doc_item_id = $_POST['item_id0'][$i];
$doc_rating = $_POST['document_rating'][$i];
$it_rt = array(
'item_id' => $doc_item_id,
'rating' => $doc_rating,
);
$this->purchases_model->update_document($it_rt);
}
whereas this code let’s me rate only the first item (or last item depending on where i put the "break;"):
foreach($_POST['item_id0'] as $doc_item_id){
foreach($_POST['document_rating'] as $doc_rating){
}
break;
}
$it_rt = array(
'item_id' => $doc_item_id,
'rating' => $doc_rating,
);
$this->purchases_model->update_document($it_rt);
any thoughts on how to correct either of these such that the user could rate the individual item of their choosing would be greatly appreciated,
If the user is supposed to choose the item to rate (instead of rating all items at the same time), you should allow him to do so (showing only one item, let him select one using radio buttons...), and then you should be able, by PHP side, to retrieve the index of the item to modify.
Finally, in order to modify only one item, your code should look like (PHP side, you will certainly have to update your HTML form as well)
$i = $_POST['item_index']; // Here I'm supposing that you have added radio buttons
// named 'item_index' to allow user to choose the item to rate
$doc_item_id = $_POST['item_id0'][$i];
$doc_rating = $_POST['document_rating'][$i] ;
$it_rt = array(
'item_id'=> $doc_item_id,
'rating' => $doc_rating,
);
$this->purchases_model->update_document($it_rt);
In fact it would be nearly your original code without the for loop.
Looping through the entire list just to limit the item you want, is kinda bad.
Here's an example on how to do it using some array functions:
$last=true; // false for first
if($last){
$id=end($_POST['item_id0']);
}else{
$id=reset($_POST['item_id0']);
}
// alternative: $id=($last)?end($_POST['item_id0']):reset($_POST['item_id0']);
// test id
if($id===false){
// no item was supplied
}
if(!isset($_POST['document_rating'][$id])){
// somehow, the item id doesn't have a matching document rating
}
// everything is okay!
$doc_item_id = $_POST['item_id0'][$id];
$doc_rating = $_POST['document_rating'][$id];
$it_rt = array(
'item_id' => $doc_item_id,
'rating' => $doc_rating,
);
$this->purchases_model->update_document($it_rt);

Categories