How To add shipping rates for weight based shipping in opencart - php

Actually I want to add shipping rates based on region,I added shipping rates like below,
800:40.00,1250:60.00,1700:80.00,2200:100.00,2700:120.00,99999:40.00
If weight is 800 gms it should take 40 and also it should take from 800-1250gms 40 rs but even 1000gms it is taking 60 rs but it shouldn't take how to resolve this?

Use this code to check in range:
function in_range($number, $min, $max)
{
if (is_int($number) && is_int($min) && is_int($max))
{
return ($number >= $min && $number < $max);
}
return FALSE;
}
Also you have create array like this:
$array = array(
[0] => array(
minw : 1,
maxw : 1249,
rate : 40
),
[1] => array(
minw : 1250,
maxw : 1699,
rate : 60
)
);
After that to get rate use this loop function:
$weight = 500;
function get shipping_rate($array, $weight) {
foreach($array as offset => $arr) {
$minw = $arr['minw'];
$maxw = $arr['maxw'];
$rate = $arr['rate'];
if(in_range($weight, $minw, $maxw)) {
return $rate;
}
}
}

Related

PHP fake average rating generator

Let's imagine that the material has a rating of 2.7 with 7 votes.
I want to create a script that would generate my desired rating that would look real and not fake.
For example, I want the rating to change from 2.7 to 4.6, but the number of votes should also change proportionally.
I can't figure out how to implement it correctly.
My script will make the rating 6.0 as I want, but as a result the number of votes will be as high as 500+. I want to refine the script so that it is more realistic and changes the rating with minimal votes
My code:
My script will make the rating 6.0 as I want for example, but the number of votes will be as high as 500+. I want to generate the average values of the rating based on the previous values, while the deviation in the votes should not look fake.
<?php
class RatingFaker
{
private $totalRating = 10; // Maximum rating threshold (5 or 10)
private $maxRatingGenerate = 10; // We generate maximum rating values during the passage
private $minRatingGenerarate = 5; // Minimally generates a rating value during a pass
private $minRatingCheck = 3.5; // The minimum acceptable threshold from which we start to act
public function __construct($minRatingCheck)
{
$this->minRatingCheck = $minRatingCheck;
}
private function calcAverageRating($ratings = [])
{
$totalWeight = 0;
$totalReviews = 0;
foreach ($ratings as $weight => $numberofReviews) {
$WeightMultipliedByNumber = $weight * $numberofReviews;
$totalWeight += $WeightMultipliedByNumber;
$totalReviews += $numberofReviews;
}
//divide the total weight by total number of reviews
$averageRating = $totalWeight / $totalReviews;
return [
'rating' => $averageRating,
'vote_num' => $totalReviews
];
}
private function getRandVoters()
{
$randRating = rand($this->minRatingGenerarate, $this->maxRatingGenerate);
$randVoters = rand(1, 99);
return [
$randRating => $randVoters
];
}
private function ratingLoop($valueList)
{
$valueList = array_merge($valueList, $this->getRandVoters());
$newRating = $this->calcAverageRating($valueList);
if($newRating['rating'] < $this->minRatingCheck) {
$valueList = array_merge($valueList, $this->getRandVoters());
return $this->ratingLoop($valueList);
}
if($newRating['rating'] > 10) {
$newRating['rating'] = 10;
}
return [
'rating' => round($newRating['rating'], 1),
'sum' => round($newRating['vote_num'] * round($newRating['rating'], 1)),
'voters' => $newRating['vote_num']
];
}
public function check($currentRate, $currentVoteNum)
{
if($currentRate < $this->minRatingCheck) {
$rating = $this->ratingLoop([
$currentRate => $currentVoteNum,
]);
}
return $rating ?? [];
}
}
$currentRate = 2.4;
$voteNum = 88;
$oldRating = [
'rating' => $currentRate,
'sum' => round($voteNum * $currentRate),
'voters' => $voteNum
];
$rating = [];
$ratingFaker = new RatingFaker(6.0);
$rating = $ratingFaker->check($currentRate, $voteNum);
echo '<pre>';
echo 'Was:';
print_r($oldRating);
echo "<br>";
echo "<br>";
echo "<br>";
echo 'Now:';
print_r($rating);
echo '</pre>';
When the current rating is 2.5 based on 9 votes, and you want to get a rating of 6.0 with a minimal number of votes, you need to make sure the total value of 10 votes is 60 ( 60/10 = 6.0 ).
The current rating is : ( 2.5*9 / 9 ) = 2.5
With you extra vote it is: ( (2.5*9+x) / 10 ) = 6.0
Now you only have to find the correct value for x, which is 37.5

Woocommerce - Implementation of query args in the reviews counting graph only for the currently selected language

I have a code that displays reviews graph of the entire website and divides them into sections according to ratings. The problem is that this code calculates the total reviews of the whole website. I would need to filter the total reviews count according to the currently chosen language. I use WPML. Any advice?
Code:
function display_all_product_review_histogram($minimum_rating, $maximum_rating){
$all_product_review_average_rating = get_all_product_review_average_rating($minimum_rating, $maximum_rating);
$total_ratings = $all_product_review_average_rating[0]["total_ratings"];
$get_all_product_review_counts_by_ratings = get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating);
if($get_all_product_review_counts_by_ratings){
$output = '';
$sum = 0;
$total = 0;
$raw_percentages_array = array();
$percentages_array = array();
//When working with rounded percentages, we must make sure the total percentages add up to 100%.
//Creating array of rating values and its percentage
foreach ($get_all_product_review_counts_by_ratings as $key => $rating) {
$percentage = round($rating["amount"] / $total_ratings, 2) * 100;
$raw_percentages_array[] = array("value" => $rating["value"], "percent_of_total" => $percentage, 'amount'=> $rating["amount"]);
}
//Counting the total of our percents
foreach($raw_percentages_array as $key => $percent) {
$total += $percent[ "percent_of_total" ];
}
//Creating an array that will have the actual percentages after the rounding has been applied to it.
//This will help to see if we have 100% or we are not aligned
foreach($raw_percentages_array as $key => $percent){
$percentages_array[$percent["value"]] = round(($percent["percent_of_total"]/$total) * 100, 0);
}
$sum = array_sum($percentages_array); //Again counting the total of our new percents to see if it adds up to 100%
if($sum != 100){ //If we do not have 100%, then we will alter the highest percentage value so that we get a total of 100%
$highest_percentage_key = array_keys($percentages_array, max($percentages_array)); //Getting key of the highest percentage value
$percentages_array[$highest_percentage_key[0]] = 100 - ($sum - max($percentages_array)); //Alterning the percentage
}
//Now we are ready to create the output that will give us 100% in total
$r_count = 0;
$output .= "<div class='product-review-histogram'>";
foreach ($percentages_array as $key => $percentage) {
$output .= "<div class='histogram-row star-rating-". $key ."'>";
$output .= "<div class='histogram-col-1'>". $key ." star</div>";
$output .= "<div class='histogram-col-2'><div class='histogram-meter-bar'><div class='histogram-bar-temperature' style='width: ". $percentage ."%'></div></div></div>";
$output .= "<div class='histogram-col-3'>". $raw_percentages_array[$r_count]['amount'] ."</div>";
$output .= "</div>";
$r_count++;
}
$output .= "</div>";
return $output;
}else{
return;
}
}
UPDATE - sharing code of get_all_product_review_average_rating function:
function get_all_product_review_average_rating($minimum_rating, $maximum_rating){
$get_all_product_review_counts_by_ratings = get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating);
if($get_all_product_review_counts_by_ratings){ //If we have reviews
$average_rating_results = array();
$total_ratings = 0;
$total_rating_value = 0;
foreach ($get_all_product_review_counts_by_ratings as $key => $rating) {
$total_ratings = $total_ratings + $rating["amount"];
$current_rating_value = $rating["amount"] * $rating["value"];
$total_rating_value = $total_rating_value + $current_rating_value;
}
$average_rating = number_format($total_rating_value / $total_ratings, 1); //Rounding value to one decimal place
$average_rating_results[] = array(
"total_ratings" => $total_ratings,
"average_rating" => $average_rating
);
return $average_rating_results;
}else{
return;
}
}
UPDATE2 - sharing more of the functions related to the graph
function get_all_product_review_ratings(){
global $wpdb;
if ( false === ( $review_ratings = get_transient( 'all_product_review_ratings' ))){ //Checking if we have previously cached query results in order to save resources and increase speed
$review_ratings = $wpdb->get_results("
SELECT meta_value
FROM {$wpdb->prefix}commentmeta as commentmeta
JOIN {$wpdb->prefix}comments as comments ON comments.comment_id = commentmeta.comment_id
WHERE commentmeta.meta_key = 'rating' AND comments.comment_approved = 1
ORDER BY commentmeta.meta_value
", ARRAY_A);
$expiration = 60 * 5; //Expiring query results after 5 minutes
set_transient( 'all_product_review_ratings', $review_ratings, $expiration ); //Temporarily storing cached data in the database by giving it a custom name and a timeframe after which it will expire and be deleted
return $review_ratings;
}else{
return $review_ratings;
}
}
WHAT DO WE NEED TO CHANGE TO GET THIS IS PROBABLY THIS PART OF THE CODE:
$review_ratings = $wpdb->get_results("
SELECT meta_value
FROM {$wpdb->prefix}commentmeta as commentmeta
JOIN {$wpdb->prefix}comments as comments ON comments.comment_id = commentmeta.comment_id
WHERE commentmeta.meta_key = 'rating' AND comments.comment_approved = 1
ORDER BY commentmeta.meta_value
", ARRAY_A);
UPDATE 3:
function get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating){
$all_product_review_ratings = get_all_product_review_ratings();
if($all_product_review_ratings){ //If we have reviews
$all_product_review_ratings_one_dimensional_array = array_map("current", $all_product_review_ratings); //Converting two dimensional array to one dimensional array
$rating_counts = array_count_values($all_product_review_ratings_one_dimensional_array); //Creating array that consists of rating counts
$ratings = array();
while($maximum_rating >= $minimum_rating){
if(array_key_exists($maximum_rating, $rating_counts)){
$star_count = $rating_counts[$maximum_rating];
}else{
$star_count = 0;
}
//Creating array that contains information about
$ratings[] = array(
"value" => $maximum_rating,
"amount" => $star_count
);
$maximum_rating--;
}
return $ratings;
}else{
return;
}
}
function get_all_product_review_ratings() {
global $wpdb;
if (false === ( $review_ratings = get_transient('all_product_review_ratings'))) { //Checking if we have previously cached query results in order to save resources and increase speed
$review_ratings = array();
$args = array(
'status' => 'approve',
'type' => 'review',
'paged' => 0,
'meta_query' => array(
array(
'key' => 'verified',
'value' => 1
)
));
// The Query for getting reviews - WPML respected
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query($args);
foreach ($comments as $comment) {
$review_ratings[] = get_comment_meta($comment->comment_ID, 'rating', 1);
}
$expiration = 60 * 5; //Expiring query results after 5 minutes
set_transient('all_product_review_ratings', $review_ratings, $expiration); //Temporarily storing cached data in the database by giving it a custom name and a timeframe after which it will expire and be deleted
return $review_ratings;
} else {
return $review_ratings;
}
}

PHP Convert any kg amount to a readable metric unit

I am trying to create a mathematical function (in PHP) that will take a given number of Kg, and convert them to a readable form or better yet, return the unit best suited for that amount. The input will always be kg. Preferably log.
For example:
5 kg = (5) kg
0.5 kg = (500) gm
1000 kg = (1) tonne
0.001 kg = (1) gm
0.0001 kg = (100) mg
I know there is a way to do it using log or log10 functions but I cannot figure it out.
How could it be done?
I think something like this should work, but I'm sure there are people who can make a much better solution.
function outputWeight($kg)
{
$power = floor(log($kg, 10));
switch($power) {
case 5 :
case 4 :
case 3 : $unit = 'ton';
$power = 3;
break;
case 2 :
case 1 :
case 0 : $unit = 'kilogram';
$power = 0;
break;
case -1 :
case -2 :
case -3 : $unit = 'gram';
$power = -3;
break;
case -4 :
case -5 :
case -6 : $unit = 'milligram';
$power = -6;
break;
default : return 'out of range';
}
return ($kg / pow(10, $power)) . ' ' . $unit;
}
echo outputWeight(0.015) . '<br>';
echo outputWeight(0.15) . '<br>';
echo outputWeight(1.5) . '<br>';
echo outputWeight(15) . '<br>';
echo outputWeight(150) . '<br>';
The idea is that you can easily extend the range. This will output
15 gram
150 gram
1.5 kilogram
15 kilogram
150 kilogram
I did not thoroughly test this code!
After playing with it for a while, here is what I came up with
function readableMetric($kg)
{
$amt = $kg * pow(1000, 3);
$s = array('mcg', 'mg', 'gm', 'kg','tonne');
$e = floor(log10($amt)/log10(1000));
return [
"amount" => $amt/pow(1000, $e),
"unit" => $s[$e]
];
}
The following function internally uses an array with the assignments unit => conversion-factor. This array can easily be expanded or modified to meet your own requirements. A fixed limit of 1000 is used in the function. This means that the output value is always less than 1000, with the exception of tons. With an additional argument which is preset to 2, the number of maximum decimal places can be changed.
function scaleKg(float $kg, int $decimalPlaces = 2) : string {
$scale = [
'micrograms' => 1.E9,
'milligram' => 1.E6,
'gram' => 1.E3,
'kilogram' => 1,
'ton' => 1.E-3,
];
foreach($scale as $unit => $factor){
$mass = $kg * $factor;
if($mass < 1000) {
return round($mass,$decimalPlaces).' '.$unit;
}
}
return round($mass,$decimalPlaces).' '.$unit;
}
Some examples:
$kg = 1.212345;
echo scaleKg($kg); //1.21 kilogram
$kg = 455;
echo scaleKg($kg); //455 kilogram
$kg = 0.0456;
echo scaleKg($kg); //45.6 gram
$kg = 23456;
echo scaleKg($kg); //23.46 ton
$kg = 23489000;
echo scaleKg($kg); //23489 ton
$kg = 167E-6;
echo scaleKg($kg); //167 milligram
I find myself agreeing with Kiko that the shortest code isn't always the best or most readable.
Bearing that in mind bringing log into it seems like unnecessary complication. So I suggest a condensed version of my original code:
function readableMetric($mass)
{
$units = [
-3 => "tonne",
0 => "kg",
3 => "g",
6 => "mg",
];
foreach ($units as $x => $unit) {
if ( ($newMass = $mass * 10 ** $x) >= 1 ) {
return "{$newMass} {$unit}";
}
}
}
This is more extensible (e.g. you could easily add centigram)
The math is intuitive to most (powers of 10)
If you really want to golf it you can shrink it down to a one liner:
function readableMetric($m)
{
foreach([-3=>"tonne",0=>"kg",3=>"g",6 =>"mg"] as $x=>$g)if(($n=$m*10**$x)>=1)return"$n $g";
}
Original Answer
You could just do it with a series of if / else statements?
$values = [
5, 0.5, 1000, 0.001, 0.0001
];
function convertmass($mass) : string
{
if ($mass >= 1000) {
return ($mass / 1000) . " ton";
}
elseif ($mass < 0.001) {
return ($mass * 1000000) . " mg";
}
elseif ($mass < 1) {
return ($mass * 1000 ) . " g";
}
else {
return $mass . " kg";
}
}
foreach ($values as $mass) {
echo convertmass($mass), PHP_EOL;
}
Output:
5 kg
500 g
1 ton
1 g
100 mg
If you want slightly easier/more readable/more user friendly updating to add new measurements in then you can do something like this instead:
$values = [
5, 0.5, 1000, 0.001, 0.0001
];
function convertmass($mass) : string
{
$massLookup = [
[ "unit" => "kg", "min" => 1, "max" => 1000, "multiple" => 1],
[ "unit" => "tonne", "min" => 1000, "max" => 1000000, "multiple" => 0.001],
[ "unit" => "g", "min" => 0.001, "max" => 1, "multiple" => 1000],
[ "unit" => "mg", "min" => 0.000001, "max" => 0.001, "multiple" => 1000000],
];
foreach ($massLookup as $unit) {
if ($mass >= $unit["min"] && $mass < $unit["max"]) {
return ($mass * $unit["multiple"]) . " {$unit["unit"]}";
}
}
return "Measurement {$mass} kg is out of range";
}
foreach ($values as $mass) {
echo convertmass($mass), PHP_EOL;
}

How to avoid query inside loop in laravel

I have created a simple profit and loss calculation based on FIFO entry in my database of buy and sell order,
and get the buy orders first then I see the sell orders against them and i get the price difference between them and that my profit but now the problem is I have to get the fresh sell orders for every loop of buy order and my code get stuck when the data is large.
can anyone give me the solution for this?
Code:
//get all buy tx orders
$pnl_logs = BuyOrder::where('status', 0)->OrderBy('created_at', 'asc')->get()->take(50);
if ($pnl_logs->isEmpty())
return Response::json(['code' => 0, 'message' => 'No Record found in buy Order to update']);
foreach ($pnl_logs as $logs) {
//get current buy rate and sell rate from price automation table
$system_buy_rate = PriceAutomation::where('type', 0)->orderBy('updated_at', 'desc')->first();
$system_sell_rate = PriceAutomation::where('type', 1)->orderBy('updated_at', 'desc')->first();
//subtract percentage fees from buy orders
$sell_rate = $this->updateSellRate($logs->vendor_id, $logs->sell_rate, $system_buy_rate->base_rate);
//get all sell tx orders
$sell_orders = SellOrders::where('status', 0)->OrderBy('created_at', 'asc')->get()->take(50);
if ($sell_orders->isEmpty())
return Response::json(['code' => 0, 'message' => 'No Record found in Sell Order to update']);
$sum = 0;
$data = [];
foreach ($sell_orders as $key => $orders) {
$sum += $orders->remaining_amount;
$data[$key]['id'] = $orders->id;
$data[$key]['remaining_amount'] = $orders->remaining_amount;
$data[$key]['sell_rate'] = $orders->sell_rate * $orders->remaining_amount;
$data[$key]['system_sell_rate'] = $system_sell_rate->base_rate * $orders->remaining_amount;
$data[$key]['source'] = $orders->gold_source;
if ($sum >= $logs->gold_amount) {
$status = 0;
$rm_balance = 0;
$avg = 0;
$system_avg = 0;
$buy_rm_amount = $logs->gold_amount;
foreach ($data as $k => $v) {
$buy_rm_amount -= $v['remaining_amount'];
if ($buy_rm_amount > 0) {
//a sell tx order is completely consumed for buy tx order
$avg += $v['sell_rate'];
$system_avg += $v['system_sell_rate'];
$status = 1;
} else {
//if buy order is completely satisfied sell tx order
$rm_balance = $sum - $logs->gold_amount;
$avg += ($v['remaining_amount'] - $rm_balance) * $orders->sell_rate;
$system_avg += ($v['remaining_amount'] - $rm_balance) * $system_sell_rate->base_rate;
if ($rm_balance == 0) {
$status = 1;
} else {
$status = 0;
}
}
//update sell order status
SellOrders::where('id', $v['id'])->update(['status' => $status, 'remaining_amount' => $rm_balance, 'system_sell_rate' => $system_sell_rate->base_rate]);
//entry in pnl log
$pnlLogData = [
'tx_id' => $logs->tx_id,
'buy_order_amount' => $logs->gold_amount,
'sell_order_amount' => $v['remaining_amount'] - $rm_balance,
'gold_source' => $v['source']
];
PnlLog::create($pnlLogData);
}
$logs->system_sell_rate = ($logs->system_sell_rate == 0) ? $sell_rate['system_rate'] : $logs->system_sell_rate;
$logs->system_buy_rate = $system_avg;
$logs->buy_rate = $avg;
$logs->sell_rate = $sell_rate['rate'];
$logs->status = 1;
$logs->save();
break;
}

Find out if the price was zero when looking through php array of price history/changes

I have all the price changes in a array like this (date, pricechange). It is always in date order:
$pricehistory = array (
'2013-11-04' => 10,
'2013-11-10' => 0,
'2013-12-01' => 10
);
What I need is to find out if the price for a specific date was zero.
function was_free($date) {
// return boolean
}
was_free('2013-11-11'); //should return true;
was_free('2013-12-01'); //should return false;
Can someone please help me figuring out how to do this? I think I need to loop through the $pricehistory array backwards, but I'm not sure how to do it.
//$default - returned if price is not exits
function was_free($price_history, $current_date, $default = FALSE) {
if(isset($price_history[$current_date]))
{
return empty($price_history[$current_date]);
}
$current_timestamp = strtotime($current_date);
$history_timestamp = array();
foreach ($price_history as $date => $price)
{
$history_timestamp[strtotime($date)] = $price;
}
$history_timestamp[$current_timestamp] = NULL;
ksort($history_timestamp);
$previous_price = ($default) ? FALSE : TRUE;
foreach ($history_timestamp as $timestamp => $price)
{
if($timestamp == $current_timestamp)
{
break;
}
$previous_price = $price;
}
return empty($previous_price);
}
$price_history = array (
'2013-11-04' => 10,
'2013-11-10' => 0,
'2013-12-01' => 10
);
// run !!
var_dump(was_free($price_history, '2013-11-03'));
var_dump(was_free($price_history, '2013-11-04'));
var_dump(was_free($price_history, '2013-11-09'));
var_dump(was_free($price_history, '2013-11-10'));
var_dump(was_free($price_history, '2013-11-11'));
var_dump(was_free($price_history, '2013-12-01'));
var_dump(was_free($price_history, '2013-12-02'));
Try:
function was_free($date) {
return array_key_exists($date,$pricehistory) && $pricehistory[$date] === 0;
}
Since the $pricehistory isn't in the scope of the function, you may pass it as a parameter or access it using global.

Categories