Creating a Bigcommerce Shipment - bigcommerce

Using the Bigcommerce PHP library I want to create a new shipment for a specific order.
use Bigcommerce\Api\Resources as Resources;
$shipment = new Resources\Shipment();
$shipment->order_id = 100;
$shipment->order_address_id = 3;
$shipment->items = ['order_product_id' => 4, 'quantity' => 1];
$shipment->create();
It is returning: Uncaught Client Error (400): The required field 'order_product_id' was not supplied.
The Bigcommerce console says to pass items like this: [{"order_product_id":3,"quantity":1}]
I have tried passing JSON objects and stdClass objects to the items field, but none of them are working for me. Is there a more efficient way to create a shipment?

The problem was that:
$shipment->items = ['order_product_id' => 4, 'quantity' => 1];
Needed to be in object format:
$shipment->items = [['order_product_id' => 4, 'quantity' => 1]];

Related

Google Sheet API - How to get only updated rows

I could not able to find in the documentation on how to get only updated records/rows from Google Sheets API.
Is there a way, that I can get a timestamp of each record when it was last modified?
any guidance or any links that would solve this issue.
Thanks!
You cannot do this directly with Sheets API. You can keep track of the changes in a file using Drive API, though, but I don't think this is what you want to do.
I'd propose using an onEdit trigger using Apps Script. Every time the spreadsheet is modified, you could retrieve the data of the edited range and store it somewhere, as well as the current date.
It could be something on the following lines:
function onEdit(e) {
var timestamp = new Date();
var range = e.range;
var editedRow = range.getRow();
// Store timestamp and editedRow index somewhere you can retrieve it later (it could be in the spreadsheet itself)
}
Update:
You can create the trigger remotely using Apps Script API. First you should create a project bound to your spreadsheet and then add the corresponding code by calling projects.updateContent (you should add two files, the script itself, which contains the onEdit trigger, and the manifest file). Just beware that you can only use simple triggers with this API, not installable ones. But in your situation, that's more than enough.
I hope this is of any help.
WRITE OPERATION:
For $response = $service->spreadsheets_values->update() process (Writting file after creating it), response will be as follow:
Google_Service_Sheets_UpdateValuesResponse Object
(
[spreadsheetId] => XXX
[updatedCells] => 7
[updatedColumns] => 7
[updatedDataType:protected] => Google_Service_Sheets_ValueRange
[updatedDataDataType:protected] =>
[updatedRange] => Sheet1!A1:G1
[updatedRows] => 1
[internal_gapi_mappings:protected] => Array
(
)
[modelData:protected] => Array
(
)
[processed:protected] => Array
(
)
)
To Get Rows = $response->getUpdatedRows();
To Get Cells = $response->getUpdatedCells();
To Get Columns= $response->getUpdatedColumns();
and so on...
APPEND OPERATION:
For $response = $service->spreadsheets_values->append() process, response will be as follow:
Google_Service_Sheets_AppendValuesResponse Object
(
[spreadsheetId] => XXXX
[tableRange] => Sheet1!A1:G1
[updatesType:protected] => Google_Service_Sheets_UpdateValuesResponse
[updatesDataType:protected] =>
[internal_gapi_mappings:protected] => Array
(
)
[modelData:protected] => Array
(
[updates] => Array
(
[spreadsheetId] => XXXX
[updatedRange] => Sheet1!A2:G7
[updatedRows] => 6
[updatedColumns] => 7
[updatedCells] => 42
)
)
[processed:protected] => Array
(
)
)
To Get Rows = $response->getUpdates()->getUpdatedRows();
To Get Cells = $response->getUpdates()->getUpdatedCells();
To Get Columns= $response->getUpdates()->getUpdatedColumns();
and so on...

Changes b/w ElasticSearch 1.x and 2.x

Does documentation exist on how to change code written in NEST 1.x to 2.x?
I've looked at these sites and they're incomplete:
https://github.com/elastic/elasticsearch-net/blob/master/docs/2.0-breaking-changes/nest-breaking-changes.md
https://github.com/elastic/elasticsearch-net
https://www.elastic.co/blog/ga-release-of-nest-2-0-our-dot-net-client-for-elasticsearch
For example I'd like to know how to replace the following:
1)
given ISearchResponse<T> searchResults = ...
How to do:
searchResults.ConnectionStatus
searchResults.RequestInformation.Request
2)
client.Get<T>(s => s.Id(id));
3)
Given QueryContainer query
new SearchDescriptor<T>()
.From(from)
.Size(pageSize)
.Query(query); //this dosen't work anymore
4)
MatchQuery doesn't accept fuziness as double and type parameters as string as it used to
5) QueryDescriptor seems gone gasp
6) client.Update is busted
var result = client.Update<CustomerProfile>(request => request
.Id(customer.CustomerId)
.Doc(customer)
.Refresh()
);
7) client.Get is busted in a similar way to client.Update
8) In Mappings the following setup doesn't work anymore
CreateIndexDescriptor cid = ...
cid.NumberOfReplicas(numReplicas)
.NumberOfShards(numShards)
.Settings(s => s
.Add("merge.policy.merge_factor", "10")
.Add("search.slowlog.threshold.fetch.warn", "1s")
)
.Analysis(a => a.TokenFilters etc etc
EDIT
9) Date Ranges:
startDate and endDate are DateTime type
var qd = new QueryContainerDescriptor<EsActivity>();
QueryContainer qc = qd.Range(r =>
r.Field("esactivity.timestamp")
.GreaterThanOrEquals(DateMath.Anchored(startDate))
.LessThanOrEquals(DateMath.Anchored(endDate))
);
.GreaterThanOrEquals expects a double parameter but on the documentation page it takes DateMath.Anchored(startDate)
10) Highlighting:
highlightFields: List<string>
Action<HighlightFieldDescriptor<T>> [] tmp = highlightFields.Select(field =>
new Action<HighlightFieldDescriptor<T>>(
highlighter => highlighter.Field(field)
)
).ToArray();
sd:SearchDescriptor<..>..
sd.Highlight(h => h
.PreTags(preTag)
.PostTags(postTag)
.OnFields(tmp)
);
I see I can replace OnFields(tmp) with .Fields(f=>f.OnAll()) but I'd still like to specify the fields myself in some way.
And how come there is a HighlightQuery option available since we already apply highlighting on a query object.. now there are 2 query calls.
I've converted the highlighting above to
var tmp = highlightFields.Select(field =>
Tuple.Create<Field, IHighlightField>(
Field.Create(field),
new HighlightField()
)
).ToDictionary(x => x.Item1, x => x.Item2);
sd.Highlight(h => new Highlight
{
PreTags = new[] { preTag },
PostTags = new[] { postTag },
Fields = tmp
}
);
1) searchResults.ApiCall replaces searchResults .ConnectionStatus.
You can get the request bytes with searchResults.ApiCall.RequestBodyInBytes and you will also need to set .DisableDirectStreaming() on ConnectionSettings in order to capture the bytes as the request is written to the request stream directly by default.
2) Use client.Get<T>(id) - The first parameter is a DocumentPath<T> type.
3) To pass a QueryContainer to a Fluent API descriptor, just return it from the Func<QueryContainerDescriptor<T>, QueryContainer>
new SearchDescriptor<T>()
.From(from)
.Size(pageSize)
.Query(_ => query);
4) match query fuzziness as a double mapped to a formula to calculate edit distance in Elasticsearch 1.x. Since this was removed in Elasticsearch 2.x, it is also gone from NEST. You can set fuzziness edit distance with
client.Search<Document>(s => s
.Query(q => q
.Match(m => m
.Query("this is my query")
.Fuzziness(Fuzziness.EditDistance(3))
)
)
);
Not sure what you're referring to with type, but I think you're referring to document type? If that's the case, document type takes a Types type which string implicitly converts to
client.Search<Document>(s => s
.Type("other-type")
.MatchAll()
);
5) QueryDescriptor<T> was renamed to QueryContainerDescriptor<T> to better reflect the fact that it's a descriptor for building a QueryContainer
6) Update API works
// specifying id
client.Update<Document>("document-id", u => u
.Doc(document)
.Refresh()
);
Since the first parameter is a DocumentPath<T>, the document instance (if you have it) can be passed as the first parameter
client.Update<Document>(document, u => u
.Doc(document)
.Refresh()
);
where index, type and id will be inferred from the document instance
7) See above
8) Create index settings have been revised to reflect the level at which the settings appear in the REST API json call
client.CreateIndex("index-name", c => c
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(2)
.SlowLog(sl => sl
.Search(sls => sls
.Fetch(slsf => slsf
.ThresholdWarn("1s")
)
)
)
.Analysis(a => a) // etc...
)
);
You can also use strings for settings if you prefer, although the fluent API will ensure the correct setting values are sent e.g. "search.slowlog.threshold.fetch.warn" is now "index.search.slowlog.threshold.fetch.warn"
client.CreateIndex("index-name", c => c
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(2)
.Setting("index.search.slowlog.threshold.fetch.warn", "1s")
.Analysis(a => a) // etc...
)
);
merge.policy.merge_factor is removed in Elasticsearch 2.0

How do you get the value of a "embed"?

I have a link field called lien. When I get it from the API through the Item it belongs to, I receive the following array:
[lien] => Array(
[0] => Array(
[embed] => 49935230
[file] => 129256002
)
)
I have no problem with the file.
How do you get the URL value?
The Embeds documentation: https://developers.podio.com/doc/embeds
A similar issue exists when getting the value of a category field through the Item object. It's an array of the selected option_id, it doesn't hold the option_text. The workaround is to get the corresponding App object and search for the option_text using the provided option_id.
The field's values are returned as a collection of embed objects. You can see documentation at: http://podio.github.io/podio-php/fields/#linkembed-field
E.g.:
$item = PodioItem::get_basic(123);
$field_id = 'embed';
$collection = $item->fields[$field_id]->values;
foreach ($collection as $embed) {
print "Embed id: ".$embed->embed_id;
print "Embed URL: ".$embed->original_url;
}

Bigcommerce API Tracking Number Create PHP

I am trying to update the tracking number of an order in Bigcommerce using the API. This is the code I am using:
//update BC of order status
$filter = array('status_id' => 2);
$order_status_update = BigCommerce::updateResource('/orders/' . 105, $filter);
$order = Bigcommerce::getOrder(105);
foreach($order->products as $shipment)
{
$filter = array(
'order_address_id' => $shipment->order_address_id,
'items'=> array(
'order_product_id' => $shipment->product_id,
'quantity' => $shipment->quantity
),
'tracking_number' => 'tracking number'
);
$add_tracking = BigCommerce::createResource('/orders/105/shipments', $filter);
var_dump($add_tracking);
}
I have followed the instructions from here:
https://developer.bigcommerce.com/api/stores/v2/orders/shipments#list-shipments
BigCommerce Uploading Tracking Numbers
But I can't seem to get it to work. Can someone help?
In advance, thanks for your help!
Akshay
The payload for creating a shipment is invalid due to the items field needing to be formatted as an object array and the use of the product_id as opposed to the ID of the product within the order.
The code provided is attempting to create one shipment per product in the order, is this intended? Ideally you would ship all items in one shipment, which is why the items field is meant to be an array of product objects.
Additionally, by creating a shipment for an order the order status will automatically change to "Shipped", so the first PUT request is unnecessary.
If you were trying to create a single shipment per order and are assuming no orders will have multiple addresses then this code should work.
$order = Bigcommerce::getOrder(105);
$filter = array(
'order_address_id' => $order->shipping_addresses[0]->id,
'tracking_number' => '123456'
);
foreach($order->products as $product) {
$items[] = array(
'order_product_id' => $product->id,
'quantity' => $product->quantity
);
}
$filter['items'] => $items;
$add_tracking = BigCommerce::createResource('/orders/105/shipments', $filter);
var_dump($add_tracking);

Magento bundle products - selection_id cannot be null?

I am trying to create a bundled product programmatically, and setting the options via this:
$new_options[$count] = array(
'required' => 0,
'position' => 1,
'parent_id' => $parentProduct->getId(),
'type' => 'select',
'title' => $product->getName(),
'default_title' => $product->getName()
);
$new_selections[$count] = array(array(
'product_id' => $product->getEntityId(),
'selection_qty' => $child['qty'],
'selection_can_change_qty' => 0,
'position' => 0,
'is_default' => 1,
'selection_price_type' => 0,
'selection_price_value' => 0.0
));
...
$parentProduct->setBundleOptionsData($new_options);
$parentProduct->setBundleSelectionsData($new_selections);
Which looks correct (as described in https://stackoverflow.com/a/4415800/494643). However, it is not working - I get an SQL exception complaining that Column 'selection_id' cannot be null'. How do I get around this? The selection id is an auto_increment column, so I can't get it until it is created, but it looks like it cannot be created?
The solution lies in the _beforeSave function of the Mage_Bundle_Model_Selection model.
This causes it to attempt to write the selection_id to the catalog_product_bundle_selection_price table, before it has saved the selection object - and therefore before it has generated a selection_id. The answer therefore is to force it to generate an id before it saves, so looking again at the _beforeSave function, we can see that it only saves the price if the store is not 0.
Specifically, this part:
$storeId = Mage::registry('product')->getStoreId();
if (!Mage::helper('catalog')->isPriceGlobal() && $storeId) {
which means that if we set the store id of the registry product to 0 first, we can cause it to save the selection, without saving the price. We would then need to reset the store to the previous value, and save again, to record the price - although only after having reloaded the object to get the newly generated selection id.