Opencart - Auto Disable "out of stock" Products - php

I'm looking for something more advanced than viewtopic.php?t=7080
I need to hide (or disable) products that are out of stock AND are in a specific category.
This problem arose because I have a category called "Clearance" and I want clearance items to automatically disable after selling out, as we'll never get more in stock. At the same time I want products in all other categories to continue to display after being out of stock.
Please help.
Mike

I would do this inside the confirm method of the order model. This is where quantities for products are updated once a sale is confirmed.
Open:
catalog/model/checkout/order.php
Within the confirm() method you'll find a line like:
foreach ($order_product_query->rows as $order_product) {
You could create a new method that would return the existing quantity for the given product, subtract the sold amount and check to see if the new quantity is 0, plus it would check if the product is attached to your given category.
If so, then set the product status to disabled if you don't want it to show at all, or set the stock_status to Out of Stock if you just want to show that it's sold out.
// check quantity and categories
private function checkQuantity ($product_id) {
$return = array();
// first check if product is attached to your specified category and add boolean to array
$categories = $this->db->query ("SELECT category_id FROM " . DB_PREFIX . "product_to_category WHERE product_id = '" . (int)$product_id . "'");
if (in_array($your_clearance_category_id, $categories->rows)):
$return['check'] = true;
else:
$return['check'] = false;
endif;
// get your pre-sale quantity and add to array
$quantity = $this->db->query ("SELECT quantity FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product_id . "'");
$return['quantity'] = $quantity->row['quantity'];
return $return;
}
Then add this just after the opening of your foreach ($order_product_query->rows as $order_product) { structure:
$checks = $this->checkQuantity($order_product['product_id']);
if ($checks['check']):
if (((int)$check['quantity'] - (int)$order_product['quantity']) <= 0):
$this->db->query ("UPDATE " . DB_PREFIX . "product SET status = '0' WHERE product_id = '" . (int)$order_product['product_id'] . "'");
endif;
endif;
Haven't tested but it should work with or without a couple tweaks.

Related

Issue is This function shows me same product_id output on related products

The issue is Output on related products it shows on every related product box same total counted number in OpenCart. So, it see just main product_id. So, must indicate related product_id somehow. I tried many many ways but it don`t work for me. Can someone help me to fix this?
There is function on modules:
public function getUnitsSold($product_id) {
$query = $this->db->query("SELECT SUM(op.quantity) AS total FROM `" . DB_PREFIX . "order_product` op LEFT JOIN `" . DB_PREFIX . "order` o ON (op.order_id = o.order_id) WHERE o.order_status_id = '5' AND op.product_id = '" . (int)$product_id . "'");
if ($query->row) {
return $query->row['total'];
} else {
return FALSE;
}
}
And this is simply template output.
<?php if ($tproducts) { ?>
<?php foreach ($tproducts as $product) { ?>
<?php if ($product['units_sold']) { ?>
<?php echo $text_units_sold; ?> <?php echo $product['units_sold']; ?>
<?php } ?>
<?php } ?>
<?php } ?>
In controller where is related product array is a possibility to indicate maybe this function query and then make right output.
something like that units_sold?
$data['tproducts'][] = array(
'product_id' => $result['product_id'],
'units_sold' => $this->db->query("SELECT SUM(op.quantity) AS total FROM `" . DB_PREFIX . "order_product` op LEFT JOIN `" . DB_PREFIX . "order` o ON (op.order_id = o.order_id) WHERE o.order_status_id = '5' AND op.product_id = '" . (int)$product_id . "'"),
);
or maybe
$data['tproducts'][] = array(
'product_id' => $result['product_id'],
'units_sold' => $this->model_catalog_product->getUnitsSold($this->request->get['product_id']),
);
You'll want to store the amount of sold items on the item itself.
Increment the number as if it is a reverse stock.
So, I'd just ALTER TABLE oc_product ADD amount_sold INT(8) NULL DEFAULT NULL;
Then, just display that simple column value. The storage of the orders must be modified and becomes a little bit slower (in the order of .001 - .0001s).
This way the store will keep performing well in the future, even when your order item table has become huge.
Let the storage handler be the working horse. Take a look at ModelCheckoutOrder::addOrderHistory(), when they subtract the quantity, you must add your quantity :)
"UPDATE " . DB_PREFIX . "product SET /*.... opencart default shit */, amount_sold = (amount_sold + " . (int)$order_product['quantity'] . ")

How do I get the lowest value from a MySQL (in PHP) row and obtain a name (or ID) that goes with it?

I have the follwing structure:
id,name,product,price
Now, I want to know how I can get the lowest value from price - and - get the name that belongs to the price. Here's a example:
0,seller1,cake,5
1,seller2,cake,2.50
Obviously seller2 has the lowest price. But I need to get that price - and the name that belongs to that price - and display it in PHP.
Something like this:
echo $seller . " sells " . $product . " for " . $price . ".";
I hope I have been clear enough.
Kind regards,
Hillebrand
The SQL to select what you need would be:
SELECT name, product, price FROM `table` ORDER BY price LIMIT 1
(Note that you didn't provide the table name so you'll need to replace table with the correct name.)
You can then use mysqli_stmt_fetch to fetch the results:
$stmt = $mysqli->prepare("SELECT name, product, price FROM `table` ORDER BY price LIMIT 1");
$stmt->execute();
$stmt->bind_result($seller, $product, $price);
$stmt->fetch();
echo $seller . ' sells ' . $product . ' for ' . $price . '.';
Keep in mind that this will only select the first product with the lowest price. You may need to consider how you'd like this to behave if you have two or more items which are equal in having the lowest price (e.g. 0). Should it display them all? Should there be some other field to signify precedence?
maybe
$table = mysql_query("SELECT name, price FROM table ORDER BY price ASC LIMIT 1");
while($y = mysql_fetch_object($table))
{
echo $y->name;
}

dual database compare and update inventory value zencart stock function

Things get lost or broken, so basically, what I want to do is to compare actual inventory database against zencart store stock and update zencart stock if it is greater than the real inventory database.
I have a table 'products' in my first database (zencart) and second database (inventory), like this:
products_id products_model products_quantity
zencart.products :
products_id : 3 | products_model : J293-04 | products_quantity : 4 |
[...]
inventory.products :
products_id : 15 | products_model : J293-04 | products_quantity : 1 |
[...]
The inventory.products database is the actual count of the products available.
When the zencart stock query function tests if goods are available,
I want it to compare stock quantity with the inventory database.
If the zencart stock quantity is > than inventory stock, then
update zencart stock quantity to = inventory stock.
The zencart stock functions use zencart.products.product_id
so the zencart.products.products_model has to be used to compare the 2 databases.
This is what I have come up replace the zencart stock count function. It seems to be overly complex, and I am not sure if a inventory global $db2; needs to be put in.
function zen_get_products_stock($products_id) {
global $db;
$products_id = zen_get_prid($products_id);
$stock_query = "select products_quantity
from " . TABLE_PRODUCTS . "
where products_id = '" . (int)$products_id . "'";
$stock_model_query = "select products_model
from " . TABLE_PRODUCTS . "
where products_id = '" . (int)$products_id . "'";
$inv_stock_query = "select products_quantity
from inventory.products.products_model
where zencart.products.products_model =
inventory.products.products_model
if $stock_query > $inv_stock_query
{
$stock_query = $inv_stock_query
UPDATE
inventory.products,
zencart.products
SET
zencart.products.products_quantity = inventory.products.products_quantity
WHERE
zencart.products.products_model = inventory.products.model
}
$stock_values = $db->Execute($stock_query);
return $stock_values->fields['products_quantity'];
}
Original code from zencart/includes/functions/functions_lookups.com
/**
* Return a product's stock count.
*
* #param int The product id of the product who's stock we want
*/
function zen_get_products_stock($products_id) {
global $db;
$products_id = zen_get_prid($products_id);
$stock_query = "select products_quantity
from " . TABLE_PRODUCTS . "
where products_id = '" . (int)$products_id . "'";
$stock_values = $db->Execute($stock_query);
return $stock_values->fields['products_quantity'];
}
/**
* Check if the required stock is available.
*
* If insufficent stock is available return an out of stock message
*
* #param int The product id of the product whos's stock is to be checked
* #param int Is this amount of stock available
*
* #TODO naughty html in a function
*/
function zen_check_stock($products_id, $products_quantity) {
$stock_left = zen_get_products_stock($products_id) - $products_quantity;
$out_of_stock = '';
if ($stock_left < 0) {
$out_of_stock = '<span class="markProductOutOfStock">' . STOCK_MARK_PRODUCT_OUT_OF_STOCK . '</span>';
}
return $out_of_stock;
}
Thank you for your help.

Custom price calculation in prestashop

I'm working on a Prestashop 1.5.x website, where I need to add a custom price-calculation rule for a specific product.
My goal is to add 10 dollars per order, but PS adds extra cost by product quantity, so if you order 20 products it ask you 200$ instead of 10...
I need to override the calculating process in /classes/Product.php, with something like:
if (product_id = 44) { $price = $price + 10; }
else { $price = $price }
Have you got any idea?
You have to create an override of the Product class in prestashop. To do so, create a new file in override/classes called Product.php and put this code in it :
<?php
class Product extends ProductCore
{
// Here we will put every method or property override
}
In this class, you will copy / paste the static method priceCalculation (it's at line 2567 of original Product.php file for me). When done, just add these lines at the end of the method, just before the self::$_prices[$cache_id] = $price; :
if ($id_product == 44 && Context::getContext()->customer->isLogged()) {
$customer = Context::getContext()->customer;
$nbTimesBoughtThisProduct = (int) Db::getInstance()->getValue('
SELECT COUNT(*)
FROM `' . _DB_PREFIX_ . 'product` p
JOIN `' . _DB_PREFIX_ . 'order_detail` od
ON p.`id_product` = od.`product_id`
JOIN `' . _DB_PREFIX_ . 'orders` o
ON od.`id_order` = o.`id_order`
WHERE o.`id_customer` = ' . $customer->id . '
AND p.`id_product` = ' . $id_product . '
');
$price += $nbTimesBoughtThisProduct * 10;
}
I did not have the time to test these, but I think that's the way to do what you want to do.
priceCalculation is the method called each time Prestashop needs a product's price. By putting this code at the end of this method, we modify the returned price.
The code first checks if the customer is logged (we can't get orders from him if he is not). If so, a query retrieves the amount of times this customer bought this product in the past. This number is multiplied by ten, and the value is added to the price.
EDIT: If, as Cyril Tourist said, you want to also count the current cart, get this new code (still not tested, but should work) :
if ($id_product == 44 && Context::getContext()->customer->isLogged()) {
$customer = Context::getContext()->customer;
$nbTimesBoughtThisProduct = (int) Db::getInstance()->getValue('
SELECT COUNT(*)
FROM `' . _DB_PREFIX_ . 'product` p
JOIN `' . _DB_PREFIX_ . 'order_detail` od
ON p.`id_product` = od.`product_id`
JOIN `' . _DB_PREFIX_ . 'orders` o
ON od.`id_order` = o.`id_order`
WHERE o.`id_customer` = ' . $customer->id . '
AND p.`id_product` = ' . $id_product . '
');
$productsInCart = Context::getContext()->cart->getProducts();
foreach ($productsInCart as $productInCart) {
if ($productInCart['id_product'] == 44) {
$nbTimesBoughtThisProduct++;
}
}
$price += $nbTimesBoughtThisProduct * 10;
}
Also, I advice you to store the "44" product ID in a constant, configuration variable, or anything, but not keeping it in the code like that. I did that just for the example.

Issue on store credit of opencart 1.5.6

I want to create an order for a customer in the administration. The customer has certain credit (let's say $200). The order total is calculated like order total - customer's credit = new order total.
The problem is the customer's credit does not change after creating an order.
For example:
the order total is: $500
credit is: $200
then the order total is : $500 - $200 = $300
but the customer's credit is still: $200
Has anybody else had the same problem?
I try to change the status of that order, both processing and setting, but it doesn't work.
The transaction in customer info page does not change.
I have checked the code in backend - there is no code that would operate with oc_customer_transaction table.
In frontend, there is a function in /catalog/model/total/credit.php
public function confirm($order_info, $order_total) {
$this->language->load('total/credit');
if ($order_info['customer_id']) {
$this->db->query("INSERT INTO " . DB_PREFIX . "customer_transaction SET
customer_id = '" . (int)$order_info['customer_id'] . "',
order_id = '" . (int)$order_info['order_id'] . "',
description = '" . $this->db->escape(
sprintf($this->language->get('text_order_id'),
(int)$order_info['order_id'])) . "',
amount = '" . (float)$order_total['value'] . "',
date_added = NOW()");
}
}
it is called during the checkout process to recalculate customer's credit balance. But I haven't found such code in backend.
I already fix that.
code:
$this->db->query("INSERT INTO " . DB_PREFIX . "customer_transaction SET
customer_id = '" . (int)$order_info['customer_id'] . "',
order_id = '" . (int)$order_info['order_id'] . "',
description = '" . $this->db->escape(
sprintf($this->language->get('text_order_id'),
(int)$order_info['order_id'])) . "',
amount = '" . (float)$order_total['value'] . "',
date_added = NOW()");
just add the credit calculate code when at following place:
1./admin/model/sale/order.php addOrder method
a. when you add product to a new customer order in the backend, the system will send request to the frontend (/catalog/checkout/mannual.php index ) wo calculate the order total(such as: subtotal, credit, shipping, total). after this request, order total in the page will be refreshed
b. when you save the order, the (admin/model/sale/order.php) addOrder method will be called eventually. You just need add code above to that function.
insert into..... customer_transaction means use the credit
2./admin/model/sale/order.php editOrder method
a. when you edit a order, the each item in totals will be changed. so, you should delete all credit you used for this order before.
delete * from oc_customer_transaction where 'order_id'=$order_id
b. since the each item of totals(involve credit) has been recalculated in step1, so this method will receive the new credit amount. just insert the new amount by code blow
3.you do not need to change admin/model/sale/order.php deleteOrder method
because it delete all totals, include item in the data table oc_customer_transaction
things done!

Categories