Modify WooCommerce's API REST response only for specific client/key - php

I have successfully created a code to modify the Woocommerce's REST API response for order requests. It converts our store's other currency (CLP) to USD.
The problem is that I need to use this modification only for a specific 3rd party API client/key.
I would be grateful if you could guide me or help me to achieve it.
Below are my snippets, both for WC Rest API V2/3 and Legacy.
add_filter('woocommerce_rest_prepare_shop_order_object', 'filter_order_response', 10, 3);
function filter_order_response($response, $post, $request){
if ($response->data["currency"] == 'CLP') {
$ex = 812;
$response->data["currency"] = 'USD';
$response->data["total"] = round($response->data["total"]/$ex,1);
$response->data["discount_total"] = round($response->data["discount_total"]/$ex,1);
for($i = 0; $i < count($response->data['line_items']); $i++)
{
$response->data["line_items"][$i]["total"] = round($response->data["line_items"][$i]["total"]/$ex,1);
$response->data["line_items"][$i]["subtotal"] = round($response->data["line_items"][$i]["subtotal"]/$ex,1);
$response->data["line_items"][$i]["price"] = round($response->data["line_items"][$i]["price"]/$ex,1);
}
for($i = 0; $i < count($response->data['coupon_lines']); $i++)
{
$response->data["coupon_lines"][$i]["discount"] = round($response->data["coupon_lines"][$i]["discount"]/$ex,1);
}
for($i = 0; $i < count($response->data['refunds']); $i++)
{
$response->data["refunds"][$i]["total"] = round($response->data["refunds"][$i]["total"]/$ex,1);
}
return $response;
}
else {
return $response;
}
}
Legacy WC API filter:
add_filter('woocommerce_api_order_response', 'filter_order_response_legacy', 20, 4);
function filter_order_response_legacy($order_data, $order, $fields, $server){
if ($order_data["currency"] == 'CLP') {
add_filter('woocommerce_api_customer_response', 'filter_customer_response_legacy', 10, 4);
$ex = 850;
$order_data["currency"] = 'USD';
$order_data["total"] = round($order_data["total"]/$ex,1);
$order_data["subtotal"] = round($order_data["subtotal"]/$ex,1);
$order_data["total_discount"] = round($order_data["total_discount"]/$ex,1);
for($i = 0; $i < count($order_data['line_items']); $i++)
{
$order_data["line_items"][$i]["total"] = round($order_data["line_items"][$i]["total"]/$ex,1);
$order_data["line_items"][$i]["subtotal"] = round($order_data["line_items"][$i]["subtotal"]/$ex,1);
$order_data["line_items"][$i]["price"] = round($order_data["line_items"][$i]["price"]/$ex,1);
}
for($i = 0; $i < count($order_data['coupon_lines']); $i++)
{
$order_data["coupon_lines"][$i]["amount"] = round($order_data["coupon_lines"][$i]["amount"]/$ex,1);
}
$order_data["customer"]["total_spent"] = round($order_data["customer"]["total_spent"]/$ex,1);
return $order_data;
}
else {
return $order_data;
}
}
function filter_customer_response_legacy($customer_data, $customer, $fields, $server){
$ex = 850;
$customer_data["total_spent"] = round($customer_data["total_spent"]/$ex,1);
return $customer_data;
}

You can get the current request's user ID and their consumer key by doing something like this:
add_filter( 'woocommerce_rest_prepare_shop_order_object', 'filter_order_response', 10, 3 );
function filter_order_response( $response, $order, $request ) {
global $wpdb;
$consumer_key = $request->get_param( 'oauth_consumer_key' );
$user_id = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT user_id FROM {$wpdb->prefix}woocommerce_api_keys WHERE consumer_key = %s",
wc_api_hash( $consumer_key )
)
);
// Your code goes here...
return $response;
}

My recommendation would be to check the user ID under which the REST call is being handled.
WooCommerce allows you to map a set of credentials to a specific user. You can create a dedicated user, with the appropriate role and permission, take note of its ID, then check for the user ID as follows:
if(get_current_user_id() === <THE SPECIFIC ID>) {
// Run your custom logic
}
Further suggestions
If you're running a multi-currency shop, I would also suggest to replace the check for "CLP" with "not USD". Example:
if ($response->data["currency"] != 'USD') {
// Convert the amounts
}
This would allow you to return a USD value for orders placed in any currency, not just CLP.
If there's a chance that the client will fetch the same orders more than once, it could be a good idea to save the exchange rate used to calculate the USD amounts against the order meta, then use it for future calls. Exchange rates change over time, and keeping the one used for the first reply would allow your code to return consistent values.

Related

PHP - Calculate Average Rating Not Working?

I've been working on a movie review website and I can't quite get the calculate average rating functionality working. In the code below, In the first instance I am grabbing the current rating of the movie [$totalRating] via an API and setting the counter [$numRatings]. Then via an API I am collecting all of the ratings of that movie, attempting to to add them to the total rating, updating the counter within the loop.
However, when I rate movies they simply are updated to the registered rating (say I input an 8 it becomes an 8) and the division never takes place. Was wondering if anyone has any solutions or can see where I am going wrong?
function setUserRating($movieID)
{
$ep = "http://localhost:8888/MovieRating/api/?movieDetails=$movieID";
$response = file_get_contents($ep);
$Movies = json_decode($response, true);
$baseRating = $Movies[0]['movieRating'];
$numRatings = 1;
$totalRating = $baseRating;
$ep = "http://localhost:8888/MovieRating/api/?allMovieRatings=$movieID";
$resp = file_get_contents($ep);
$userRatings = json_decode($resp, true);
if (isset($userRatings['movie_ratings'])) {
$reviews = $userRatings['movie_ratings'];
}
if (isset($reviews)) {
foreach ($reviews as $row) {
$numRatings++;
$totalRating = $totalRating + $row['rating'];
}
}
$avgUserRating = $totalRating / $numRatings;
return $avgUserRating;
}
Might just need a small adjustment
function setUserRating($movieID)
{
$ep = "http://localhost:8888/MovieRating/api/?movieDetails=$movieID";
$response = file_get_contents($ep);
$Movies = json_decode($response, true);
$baseRating = $Movies[0]['movieRating'];
$numRatings = 0; //1
$totalRating = 0; //$baseRating;
$ep = "http://localhost:8888/MovieRating/api/?allMovieRatings=$movieID";
$resp = file_get_contents($ep);
$userRatings = json_decode($resp, true);
if (array_key_exists($userRatings['movie_ratings'])) {
$reviews = $userRatings['movie_ratings'];
}
if (isset($reviews)) {
foreach ($reviews as $row) {
++$numRatings;
$totalRating += $row['rating'];
}
}
return $numRatings > 0 ? $totalRating / $numRatings : $baseRating;
}

Stop multishipping from splitting orders in magento

The issue:
I need to stop the multishipping core module from splitting quantities into separate orders. I almost need it to act like Cart page, where I update quantity and it won't split them. I have a customer that may order 100 items (of the same thing) for one store and 20 for another. That then creates 120 separate orders and 120 lines to go through and add addresses.
I have searched everywhere and haven't found much help. Below I believe is the code that is associated with the splitting (core/Mage/Checkout/Model/Type/Multishipping). Also attached is what the issue is. Any direction is much appreciated.
ver 1.7
protected function _addShippingItem($quoteItemId, $data)
{
$qty = isset($data['qty']) ? (int) $data['qty'] : 1;
//$qty = $qty > 0 ? $qty : 1;
$addressId = isset($data['address']) ? $data['address'] : false;
$quoteItem = $this->getQuote()->getItemById($quoteItemId);
if ($addressId && $quoteItem) {
/**
* Skip item processing if qty 0
*/
if ($qty === 0) {
return $this;
}
$quoteItem->setMultishippingQty((int)$quoteItem->getMultishippingQty()+$qty);
$quoteItem->setQty($quoteItem->getMultishippingQty());
$address = $this->getCustomer()->getAddressById($addressId);
if ($address->getId()) {
if (!$quoteAddress = $this->getQuote()->getShippingAddressByCustomerAddressId($address->getId())) {
$quoteAddress = Mage::getModel('sales/quote_address')->importCustomerAddress($address);
$this->getQuote()->addShippingAddress($quoteAddress);
}
$quoteAddress = $this->getQuote()->getShippingAddressByCustomerAddressId($address->getId());
if ($quoteAddressItem = $quoteAddress->getItemByQuoteItemId($quoteItemId)) {
$quoteAddressItem->setQty((int)($quoteAddressItem->getQty()+$qty));
} else {
$quoteAddress->addItem($quoteItem, $qty);
}
/**
* Require shiping rate recollect
*/
$quoteAddress->setCollectShippingRates((boolean) $this->getCollectRatesFlag());
}
}
return $this;
}
So if anyone else has this issue I was able to figure it out. I was in the wrong function.
getQuoteShippingAddressesItems()
Located in core/Mage/Checkout/Model/Type/Multishipping.php around line 116.
Changed the following code:
for ($i = 0, $n = $item->getQty(); $i < $n; $i++)
To
for ($i = 0, $n = 1; $i < $n; $i++)
$addressItem->setQty($item->getQty)

Catch Tweets with JSON and sort by likes?

I am currently running a wordpress backend and want to display some tweets based on hastags on my website. For the general API request and database storage, I use this function:
private function parseRequest($json) {
$tmp = $json;
$result = array();
if (isset($json['statuses'])) {
$tmp = $json['statuses'];
}
if (isset($tmp) && is_array($tmp)){
foreach ($tmp as $t) {
$this->image = null;
$this->media = null;
$tc = new \stdClass();
$tc->feed_id = $this->id();
$tc->id = $t['id_str'];
$tc->type = $this->getType();
$tc->nickname = '#'.$t['user']['screen_name'];
$tc->screenname = (string)$t['user']['name'];
$tc->userpic = str_replace('.jpg', '_200x200.jpg', str_replace('_normal', '', (string)$t['user']['profile_image_url']));
$tc->system_timestamp = strtotime($t['created_at']);
$tc->text = $this->getText($t);
$tc->userlink = 'https://twitter.com/'.$t['user']['screen_name'];
$tc->permalink = $tc->userlink . '/status/' . $tc->id;
$tc->media = $this->getMedia($t);
#$tc->additional = array('shares' => (string)$t['retweet_count'], 'likes' => (string)$t['favorite_count'], 'comments' => (string)$t['reply_count']);
if ($this->isSuitablePost($tc)) $result[$tc->id] = $tc;
}
}
return $result;
}
Now I am looking for a function that counts all the variable in the "additional array together e.g. shares + likes + comments and sorts all posts based on the resulting number.
I am using the standard wordpress sql database. I cannot find a solution or I am just blind.
Thanks in regards
You could use a simple usort function:
usort($tc, function($a, $b) {
$a_sum = array_sum($a->additional);
$b_sum = array_sum($b->additional);
if ($a_sum == $b_sum) {
return 0;
}
return ($a_sum < $b_sum) ? -1 : 1;
});

Weighted Load Balancing Algorithm into PHP Application

I want to resolve weighted an Adapter from an factory which could be configured by user (enable/disable and weight %).
Example:
AdapterW ≃ 20% of transaction
AdapterX ≃ 30% of transaction
AdapterY ≃ 40% of transaction
AdapterZ ≃ 10% of transaction
I can grant that all items will never sum more than one hundred (100%), but sometimes any adapter could be deactivated.
I have the following parameters:
public function handleAdapter()
{
$isWActive = (boolean)$this->_config[self::W];
$isXActive = (boolean)$this->_config[self::X];
$isYActive = (boolean)$this->_config[self::Y];
$isZActive = (boolean)$this->_config[self::Z];
$WPercentage = (int)$this->_config[self::LOAD_BALANCE_W];
$XPercentage = (int)$this->_config[self::LOAD_BALANCE_X];
$YPercentage = (int)$this->_config[self::LOAD_BALANCE_Y];
$ZPercentage = (int)$this->_config[self::LOAD_BALANCE_Z];
.
.
.
return (self::W | self::X | self::Y | self::Z);
}
How can i balance weighted between this adapters dynamically?
Edit
created a gist to a executable code: https://gist.github.com/markomafs/5d892d06d6670909f9b4
This may not be the best approach, but you can try something like this:
public function handleAdapter()
{
//an array to return the balanced entries
$balancedEntries[] = false;
//verifies which of the options are active
$isWActive = (boolean)$this->_config[self::W];
$isXActive = (boolean)$this->_config[self::X];
$isYActive = (boolean)$this->_config[self::Y];
$isZActive = (boolean)$this->_config[self::Z];
//get configured percentage of each
$WPercentage = (int)$this->_config[self::LOAD_BALANCE_W];
$XPercentage = (int)$this->_config[self::LOAD_BALANCE_X];
$YPercentage = (int)$this->_config[self::LOAD_BALANCE_Y];
$ZPercentage = (int)$this->_config[self::LOAD_BALANCE_Z];
//here you fill the array according to the proportion defined by the percentages
if ($isWActive) {
for ($i = 0; $i < $WPercentage; $i++) {
$balancedEntries[] = self::W;
}
}
if ($isXActive) {
for ($i = 0; $i < $XPercentage; $i++) {
$balancedEntries[] = self::X;
}
}
if ($isYActive) {
for ($i = 0; $i < $YPercentage; $i++) {
$balancedEntries[] = self::Y;
}
}
if ($isZActive) {
for ($i = 0; $i < $ZPercentage; $i++) {
$balancedEntries[] = self::Z;
}
}
return $balancedEntries;
}
And then, in case you want a proportion of 1 to 100 (as in percentages):
$balancedResult = $balancedEntries[array_rand($balancedEntries, 1)];
Since array_rand will return 1 key from the original array, you use it to get it's value.
Another try, this should work for your case - But it only work if you have an adapter as a single char string, this is not visible by your question.
public function handleAdapter()
{
# a map with all adapters
$map = array(
self::W => self::LOAD_BALANCE_W,
self::X => self::LOAD_BALANCE_X,
self::Y => self::LOAD_BALANCE_Y,
self::Z => self::LOAD_BALANCE_Z
);
# generate a string map with one char per percentage point
$stringMap = "";
foreach($map as $key => $value){
# skip if disabled
if(!$this->_config[$key]) continue;
# repeat the key for each percentage point
$stringMap .= str_repeat($key, (int)$this->_config[$value]);
}
# return a random string char from the map
return $stringMap[rand(0, strlen($stringMap) - 1)];
}
Edit: I've misunderstood the question, the answer is wrong.
I understand your question so that you always want to return the adapter with the lowest load to force traffic to this adapter.
public function handleAdapter()
{
$isWActive = (boolean)$this->_config[self::W];
$isXActive = (boolean)$this->_config[self::X];
$isYActive = (boolean)$this->_config[self::Y];
$isZActive = (boolean)$this->_config[self::Z];
$WPercentage = (int)$this->_config[self::LOAD_BALANCE_W];
$XPercentage = (int)$this->_config[self::LOAD_BALANCE_X];
$YPercentage = (int)$this->_config[self::LOAD_BALANCE_Y];
$ZPercentage = (int)$this->_config[self::LOAD_BALANCE_Z];
$map = array();
if($isWActive) $map[self::W] = $WPercentage;
if($isXActive) $map[self::X] = $XPercentage;
if($isYActive) $map[self::Y] = $YPercentage;
if($isZActive) $map[self::Z] = $ZPercentage;
asort($map);
return key($map);
}
Edit: Fixed wrong sort(), you need asort() to maintain the index.

Codeignighter Cart class base fee

I have a unique shop where some products incur a base fee, lets say
A photographer charges $20 for the first hour then $1 there-after.
I am passing a variable into my codeignighter cart ; so for 5 hours I would pass the variable into cart->insert();
$item['id'] = 1;
$item['qty'] = 5;
$item['base'] = 20.00;
I made some changes to the cart class so this would work and has been fine so far, what I now need and cant seem to figure this out is when there are options it considers it a different product and this fee is charged once per rowid.
I would like my class to only allow 1 charge for the item regardless of the various options.
Below are the three functions I created inside my Cart class
and I call set_base($item) in the _save_cart() function.
private function set_base($item)
{
if( $this->base_exist($item) )
{
return FALSE;
}
// Only allow the base cost for 1 row id, it doesnt matter which one, just one
$this->_base_indexes['rowid'][$item['id']] = $item['rowid'];
$this->_cart_contents['cart_total'] += $item['base'];
return TRUE;
}
private function base_exist($item)
{
if ( array_key_exists($item['id'] , $this->_base_indexes['applied']) )
{
if ( ( $item['rowid'] == $this->_base_indexes['applied'][$item['id']] ) )
{
return TRUE;
}
}
return FALSE;
}
private function base_reset()
{
$this->_base_indexes = array();
$this->_base_indexes['applied'] = array();
return $this->_base_indexes;
}
Inside _save_cart();
I call
$this->base_reset();
Inside the cart_contents() loop I have added;
if(isset($val['base']))
{
$this->set_base($val);
}
$this->_cart_contents['cart_total'] += ($val['price'] * $val['qty']);
Hope this was clear :/
OK i changed it a little bit,
the foreach loop in the save_cart function now looks like; and I can remove the three functions I had before.
foreach ($this->_cart_contents as $key => $val)
{
// We make sure the array contains the proper indexes
if ( ! is_array($val) OR ! isset($val['price']) OR ! isset($val['qty']))
{
continue;
}
if(isset($val['base']))
{
//If it doesnt exist, add the fee
if (!(isset($this->_base_indexes[$val['id']]) == $val['rowid']) )
{
$this->_base_indexes[$val['id']] = $val['rowid'];
$this->_cart_contents['cart_total'] += $val['base'];
$sub = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']) + $val['base'];
}
else
{
//$this->_cart_contents[$key]['base'] = 0;
$sub = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']);
}
}
$this->_cart_contents['cart_total'] += ($val['price'] * $val['qty']);
$this->_cart_contents['total_items'] += $val['qty'];
$this->_cart_contents[$key]['subtotal'] = $sub;
}

Categories