Revert a number to its original value in PHP - php

I have a problem in reverting the original amount of a customer.
A customer can amortize its balance in 3 months.
So, if the balance is 1,100.00
1,100.00 / 3 = 366.666666667 rounded up to 366.67
But then, he decided to cancel the amortization.
What I do is amortized amount * 3, which is:
366.67 * 3 = 1,100.01
Expected output should be 1,100.00
Thanks!

Your problem here is the original calculation, if you have 1,100.00 to pay and simply divide by 3 with rounding, your customer will actually pay 1,100.01!
The usual solution is to compensate this difference in the last (or first) amount to pay:
n-1 first payments: total / n -> for your example: 2 times 366.67
last payment: total - sum of precedent payments -> for your example: 1,100.00 - (2 * 366.67) so 366.66 to pay
Like this the total paid will always be right, whatever you apply flooring or rounding, and you can reverse any time by adding each value.

Save the original value 1,100.00 somewhere (database, variable, etc.) and when they cancel their amortization, set the display from the saved value instead of calculating it.

Related

Calculate the exact margin from sales orders and purchase orders

I am trying to generate a report which calculates the margin from the below database. The problem is that the cost (existing in purchase_order_products table) of the product may change.
The cost of product with id 4022 on 2017-06-08 is 1110, however its cost is 1094 on 2017-07-25. This is confusing. I am unable to get the exact cost for each product sold.
I wrote a PHP algorithm which loops through all orders and purchase orders and used the oldest cost to newest cost. but the algorithm has a very high time complexity. Can this be done just using mysql query?
Please check below scenario:
Company created a purchase order for product X: quantity 3, cost 10. on day 1
Customers bought 2 product X sell price: 12 on day 1 (still have 1 item in inventory with cost 10)
Company created a purchase order for product X : quantity 4, cost 9. on day 2
Customers bought 3 product X sell price: 12 on day 2
Customers bought 2 product X sell price: 12 on day 3
Company created a purchase order for product X : quantity 2, cost 11. on day 3
Customers bought 2 product X sell price: 12 on day 3
The report:
day 1:
sold 2 product X for 12 , cost 10 , profit: 2 * (12 - 10)
day 2:
sold 3 product X for 12 , 1 item has a cost of 10, 2 items have a cost of 9 ,
profit: 1 * (12 - 10) + 2 * (12 - 9)
day 3:
sold 2 product X for 12 , cost 9 , profit: 2 * (12 - 9)
sold 2 product X for 12 , cost 11 , profit: 2 * (12 - 11)
Therefor the profit of newly sold products is calculated using the their corresponding cost. Hope you got my point.
Databse Structure:
4 Products From Database
Products Purchase orders for the above products
Sold Products
Dump File Attached here
Why don't you just take it easy and add a profit column to the orders table that is calculated in real time when a customer buys a product.This way you can calculate your marging solely from the sales orders given the fact that this is actualy already calculated somehow in order to generate the selling price. Of course this will work only for future sales but you can use your existing code with little modification to populate the profit column for old records and you will run this code only one time for the old transactions before the update.
To elaborate more:
Alter the table "sales_order" adding "profit" column . This way you can calculate the sum using the other related columns (total_paid, total_refund, total_due, grand_total) because you may want have more control over the report by including those monetary fields as needed in your calculation for example generating a report using total_payed only excluding tota_due or encluding it for different type of reports, in other words you can generate multiple reports types only from this table without overwhelming the DB system by adding this one column only.
Edit:
You can also add a cost column to this table for fast retrieving purpose and minimize joins and queries to other tables and if you want to take it a step further you can add a dedicated table for reports and it will be very helpful for example to generate a missing report from last month and checking old order status.
Some disclaimers:
this is an attempt to assist with the logic, so it's rough code(open to SQL injection attacks, so don't copy and paste this)
I can't test this query so there's probably mistakes in it, just trying to get you on the right track (and/or will make follow up edits)
This won't work if you need profit per order, only for profit per product. You could probably get a date range with a BETWEEN clause if needed.
That being said, I think something like this should work for you:
$productsIds = array('4022', '4023', '4160', '4548', '4601');
foreach($productIds as $pid){
$sql = "SELECT (soi.revenue - sum(pop.cost)) AS profit, sum(pop.cost) AS total_cost, sum(pop.quantity) AS total_purchased, soi.revenue, soi.total_sold
FROM purchase_order_products pop
JOIN (SELECT sum(price) AS revenue, sum(quantity_ordred) AS total_sold FROM sales_order_item WHERE product_id = ".$pid.") AS soi ON soi.product_id = pop.product_id
WHERE pop.product_id = ".$pid." GROUP BY pop.product_id HAVING sum(pop.quantity) < soi.total_sold ORDER BY pop.created_at ASC;";
$conn->query($sql);
//do what you want with results
}
The key thing here is using the HAVING clause after GROUP BY to determine where you cut off finding the sum of the purchase costs. You can sum them all as long as they're within that range, and you get the right dates ordering by created_at.
Again, I can't test this, and I wouldn't recommend using this code as is, just hoping this helps from a "here's a general idea of how to make this happen".
If I had time to recreate your databases I would, or if you provide sql dump files with example data, I could try to get you a working example.
The price of an object on a given time is given by the formula : "total price of the stock / total number in the stock".
To get this, you have two queries to execute :
The first one to know the amount of sold items (total price and quantities) :
sql:
SELECT SUM(row_total) sale_total_cost, SUM(quantity_ordered) sale_total_number
FROM sales_order_item soi
JOIN sales_order so ON soi.sales_order_id=so.id
WHERE so.purchase_date<'2017-06-07 15:03:30'
AND soi.product_id=4160;
the second one to know how much you have bought the products
sql:
SELECT SUM(pop.cost * pop.quantity) purchase_total_price, SUM(pop.quantity) purchase_total_number
FROM purchase_order_products pop
JOIN purchase_order po ON pop.purchase_order_id=po.id
WHERE po.created_at<'2017-06-07 15:03:30'
AND pop.product_id=4160;
The price of the product 4160 at 2017-02-01 14:23:35 is:
(purchase_total_price - sale_total_cost) / (purchase_total_number - sale_total_number)
The problem is that your "sales_order" table start on 2017-02-01 14:23:35, while your "purchase_order" table start on 2017-06-07 08:55:48. So the result will be incoherent as long as you can't track all your purchases from the start.
EDIT:
If you can modify you table structure and are only interested in future sells.
Adding the number of items sold in the purchase_order_products table
You have to modify purchase_order_products to have the consumption for each product:
ALTER TABLE `purchase_order_products` ADD COLUMN sold_items INT DEFAULT 0;
Initializing the data
In order for it to work, you have to make the sold_items column reflect your real stock
You should initialize your table with the following request
UPDATE `purchase_order_products` SET sold_items=quantity;
and then manually update the table with your exact stock for each product (which means that quantity_ordered-sold_items must reflect your real stock.
This has to be done only once.
adding the purchase price to the sales_order_item table
ALTER TABLE sales_order_item ADD total_purchase_price INT DEFAULT NULL
entering new sales order
When you enter new sales order, you will have to get the oldest purchase order with remaining items using the following command:
SELECT * FROM `purchase_order_products` WHERE quantity!=sold_items where product_id=4160 ORDER BY `purchase_order_id` LIMIT 1;
You will have then to increment the sold_items value, and calculate the total purchase price (sum) to fill the total_purchase_price column.
calculating margin
The margin will be easily calculated with the difference between row_total and total_purchase_price in the sales_order_item table
I appreciate you are using the FIFO method for the management of stock. However, this does not mean you need to use FIFO to calculate margins. The article https://en.wikipedia.org/wiki/Inventory_valuation gives an overview of the options. (Regulations in your country may exclude some options.)
I believe a repeatable solution for FIFO margin calculation of an individual sale is complex. There are complexities of opening balances, returns, partial deliveries, partial shipments, out-of-order processing, stock-take adjustments, damaged goods etc.
These issues do not seem to be addressed by the database structures in your question.
Typically, these issues are addressed by computing the margin/profit of a period (day, month etc) by calculating the change in value of the inventory over the period.
If you can use the average cost method, you can calculate the margin with pure SQL. I believe other methods would seem to require some iteration as there is no inherent order in SQL. (Your could improve performance by creating a new table and storing the previous period values.)
I would not be too worried about putting the whole solution in SQL as this would not appear to reduce the computational complexity of the problem. Still there might be speed advantages in doing as much of the calculation in the database engine, particularly if the data-set is large.
You might find this article interesting: Set-based Speed Phreakery: The FIFO Stock Inventory SQL Problem. (There are some clever people out there!)

Woocommerce Tax calculating issues (wrong price amount per line)

WooCommerce calculates the VAT (in this case 20%) per line (wrong), but really should calculate VAT per item (right).
For example, we have a product that is 0.13p (excl VAT), which shows as 0.16p (inc VAT) on the frontend. This is fine as 0.13p + 20% = 0.156p and is rounded up to 0.16p. If you add 5 of these to the cart you would expect to see 0.16p x 5 = 0.80p but instead we get 0.78p. My guess is that WooCommerce is calculating the VAT per line and not per item (e.g. 0.13p x 5 = 0.65p and then 0.65p + 20% = 0.78p). See below.Wrong Amount
I have tried all sorts of different settings with no success, this is how they are now (see pic attached).Tax Settings
Has anyone experienced the same issue? Have you found a solution? Obviously, I can't launch this with such a bug.. Many thanks!

JS: How to add, then deduct VAT and arrive back at EXACTLY the same original value? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I allow users to enter prices of products into an inventory, in either NET or Gross. If they enter the price in Gross, the NET is computed for them before being stored and uses the following code:
var vatrate = 12;
IsuppGross = parseInt(suppGross * 100); // makes it an integer
// calc net
var revVR = parseFloat('1.'+vatrate);
Net = ( ( IsuppGross / revVR) / 100 ).toFixed(2);
I struggled to get that working and am not sure if that is where the problem lies.
If I enter '100.00' as a gross figure and my VAT rate is 12%, it returns Net as '112.00', so it seems to be working.
So I enter a product with a Gross price of $100.00 and the net price is computed to be '$89.29' (which I'm assuming to right).
When creating an invoice for 10 of the above items, the bottom of the invoice looks like this:
Net Subtotal $892.90
VAT $107.15
Grand Total $1000.05
What I am expecting is:
Net Subtotal $892.90
VAT $107.10
Grand Total $1000.00
...especially since, when selling just one of the above, results in:
Net Subtotal $89.29
VAT $10.71
Grand Total $100.00
...which expected. It would therefore be reasonable to assume that purchasing 10 of the same items, would cost exactly ten times as much.
Here is the formula I'm using to add the VAT to the Net subtotal:
quantity x net price x 0.12 (10 x 89.29 x 0.12) = 107.148
The above then rounds to 107.15 which when added to the net subtotal is 1000.05.
What formula do I need to arrive at 1000 when I add the VAT back on please?
To Summarize / Clarify
This formula...
quantity x net price x 0.12 (10 x 89.29 x 0.12)
Gives me 107.148, but what I think I need it to give me is 107.10 instead.
So what javascript function can I used to make that happen (or how do I need to adjust my formula / convert it to code)?
UPDATE
#jakub is on the right track I think. I've found an easy way to test it by doing something like:
alert( (892.90 * 0.12).toFixed(2) ); // should equal 107.10
(still equals 107.15)
The above was based on input from Jakub, below. Notice that I'm not multiplying by 10 separately here, because I noticed that we're working at the subtotal level.
One way to do that would be to put rounding at a different place
round(quantity * price) != quantity * round(price)
The same goes for VAT, rounding the result is slightly different from rounding VAT from one product and then multiplying by quantity. Also, you know, that quantity has to be an integer, not a float (if not, it is a different case), so multiplying after rounding should never produce more decimal places.
I hope this helps a little bit.
Ok, to respond to your edit:
You have
(quantity * price * VAT).toFixed(2) = (10 * 89.29 * 0.12).toFixed(2) = (107.148).toFixed(2) = 107.15
You should have
quantity * (price * VAT).toFixed(2) = 10 * (89.29 * 0.12).toFixed(2) = 10 * (10.7148).toFixed(2) = 10 * 10.71 = 107.10
I think I'm correct in saying that the legal position is that the VAT amount invoiced must be the correct percentage of the goods & services invoiced, so one should not sum the VAT-inclusive line-item prices.
One system I worked on which showed VAT per line modified the last line's VAT amount to eliminate rounding errors. They will always be there unless you show your prices with 5 decimal places (assuming you have a VAT rate with 3 significant digits).
Basically the reason for this issue is that the computer is not able to represent most base 10 real numbers using floating point numbers, since the computer uses base 2.
Check this thread:
Why not use Double or Float to represent currency?
So one first step is to always use integers for the currency, in this case measured in cents instead of dollars, I presume.

Subtract a number from database and multiply by 2% +0.30

Assuming I have stored in the database the following
withdraw fee = 2
then upon withdrawing money i want the user to pay 2% for withdrawal fees for any amount he/she is receiving. Given the code below, it only deducts $2 instead of deducting %2 of the balance.
In my code, $postd_cashout is the fees to pay,
balance is the user's balance
What change should I make to this line for this to work
$postd_cashout = substr(number_format($ir['balance'], 3, '.', ','), 0, -1);
$postd_cashout = ($ir['balance']*(1.02));
This results in a gross withdrawal of the intended amount plus 2% of that amount. I am unclear if this is exactly what you are trying to achieve, however. The amount the withdrawee receives in hand would be represented in $ir['balance'] whereas the gross amount withdrawn is reflected in $postd_cashout.
optionally:
$withdrawalmultiplier = 1.02;
$postd_cashout = ($ir['balance']*($withdrawalmultiplier));
This allows you to change the fee amount anywhere it is referenced in the code as opposed to hardcoding a static number. the intial example is more clear, imho.
finally:
$fee = ($postd_cashout - $ir['balance'])
I suppose tracking the fee amount is useful for reporting a sum of fees paid or itemizing a receipt and it sounds like this is ultimately what you're wanting after re-reading the question a few times. If the fee amount is all you're after then the other answer fits more elegantly.
Just multiply the balance by the withdrawal fee as a percentage
$fees = ($ir['balance'] * $withdrawal_fee / 100);
You can then utilise $fees in your calculation.
Don't use number_format before the calculation as you want to avoid the commas - that converts the value to a string.

Mathematical problem help

I have some code where, if a user has referred X number of people, he will get X number of credits.
For example, referring 2 people = 1 credit. 4 people = 2 credits, and so on.
However where this gets tricky is, the numbers can be changed so he gets 1 credit per person, or 1 credit per 3 people, 1 credit for 5 people, etc.
If he gets 1 credits for 3 people, and he has referred 5 people, then I would like him to receive 1 credit, and have it stored that he still has 2 people for whom he didn't get any credits. So the next time he refers someone, it is 2 + 1 = 3, and he gets a credit.
My question is,
Given X = Number of people he needs to refer for 1 credit,
and Y = Number of people a user has refered,
(So X might be 3, as in 3 people per credit, and Y might be 6, in which case he should get 2 credits)
1) What's a straightforward formula or function which will X and Y, and return the number of credits which should be given to that person, and
2) Which will also give a remainder for the credits which can't be awarded yet. E.g if X is 3 and Y is 5, the credits would be 1, and remainder would be 2, so with the next referer Y will become 3 again and the user would get 1 credit?
1.)
creditsToPayout = Y/X; //use integer division to truncate, or floor result
remainderReferrals = Y % X; //remainder of Y / X, leftover referrals
You need integer division and modulus. For PHP see here for :
- intval($a / $b)
- $a % $b
If the number can change over time, what happens if, say, intially it is 3 people per credit. He refers 7 people and gets 2 credits with 1 person left over. Then the rule is changed to 4 people per credit. Under that rule he would only get 1 credit with 3 people left over. Do you take a credit back? I'm guessing not, that the new rule only applies to new credits. So I think you need to keep on your database or whatever, the number of credits received, and the number of referrals left that was not sufficient to make a credit. The number of un-credited referrals would then go up and down over time, as he makes new referrals and as they are "exchanged" for credits.
Frankly I think it would be simpler if you could make the rule be X credits per referral rather than X referrals per credit, and then just increase the cost of whatever it is you buy with the credits. Like, if the rule is 1 credit for 5 referrals, and when you get 10 credits you get a free iPod or whatever, then you need 50 referrals to get an iPod. So change it to 1 credit per referral and it takes 50 credits to get an iPod. Then you'd never have to deal with the fractions. But maybe you're not making up the rules and this is all irrelevant.
Number of credits = FLOOR(Y/X)
Remainder = Y-(X*FLOOR(Y/X))

Categories