Opencart price calculating, custom price calculation - php

Im currently working on an opencart site. I have wrote custom price calculation php, depending which options are selected in order. This work fine, when options are select, radio ot checkboxes. But..
I have an option, where customer can input a number with text field. I use this number in price calculation, so depending on this value, opencart calculate the price. I send this number using SESSION to system/library/cart.php, where i use it for calculation. This works fine when customer order just once.
When customer already have a product in his cart, and want make another order, opencart will overwrite the session value, and this will recalculate price for the item already in cart.
is there any good method to store separately this session values?
Here is my modified system/library/cart.php:
if ($product_id == '65') {
$pqty = $_SESSION['pqty'];
$contents = file_get_contents("http://somepage.com/system/library/calculate.php?&qty=".$quantity."&pqty=".$pqty."&pnh=".$pnh."&czp=".$czp."&czt=".$czt."&bnd=".$bnd."&covcho=".$covcho."&covczp=".$covczp."&covczt=".$covczt."&lam=".$lam);
$contents = utf8_encode($contents);
$calcprice = json_decode($contents);
$this->data[$key] = array(
'key' => $key,
'product_id' => $product_query->row['product_id'],
'name' => $product_query->row['name'],
'model' => $product_query->row['model'],
'shipping' => $product_query->row['shipping'],
'image' => $product_query->row['image'],
'option' => $option_data,
'download' => $download_data,
'quantity' => $quantity,
'minimum' => $product_query->row['minimum'],
'subtract' => $product_query->row['subtract'],
'stock' => $stock,
'price' => $calcprice / quantity,
'total' => $calcprice,
'reward' => $reward * $quantity,
'points' => ($product_query->row['points'] ? ($product_query->row['points'] + $option_points) * $quantity : 0),
'tax_class_id' => $product_query->row['tax_class_id'],
'weight' => ($product_query->row['weight'] + $option_weight) * $quantity,
'weight_class_id' => $product_query->row['weight_class_id'],
'length' => $product_query->row['length'],
'width' => $product_query->row['width'],
'height' => $product_query->row['height'],
'length_class_id' => $product_query->row['length_class_id'],
'recurring' => $recurring
);

You created if ($product_id == '65') { in your system file. Which means you have to make code for every product id which is not feasible solution.
My suggestion is that you should create a session array like $this->session->data['custom_price']['your_product_id'] = value entered by customer. And using this you should calculate price for each item.

Is the issue for you that opencart is NOT creating a separate item in your cart and instead doubling it up on the same product? I was unclear if this was your exact problem, but if it is - you can enable duplicate products to be in your cart by modifying the following in your system/library/cart.php file:
Around line 290, you can change:
public function add($product_id, $quantity = 1, $option = array(), $recurring_id = 0) {
$query = $this->db->query("SELECT COUNT(*) AS total FROM " . DB_PREFIX . "cart WHERE api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND customer_id = '" . (int)$this->customer->getId() . "' AND session_id = '" . $this->db->escape($this->session->getId()) . "' AND product_id = '" . (int)$product_id . "' AND recurring_id = '" . (int)$recurring_id . "' AND `option` = '" . $this->db->escape(json_encode($option)) . "'");
if (!$query->row['total']) {
$this->db->query("INSERT " . DB_PREFIX . "cart SET api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "', customer_id = '" . (int)$this->customer->getId() . "', session_id = '" . $this->db->escape($this->session->getId()) . "', product_id = '" . (int)$product_id . "', recurring_id = '" . (int)$recurring_id . "', `option` = '" . $this->db->escape(json_encode($option)) . "', quantity = '" . (int)$quantity . "', date_added = NOW()");
} else {
$this->db->query("UPDATE " . DB_PREFIX . "cart SET quantity = (quantity + " . (int)$quantity . ") WHERE api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "' AND customer_id = '" . (int)$this->customer->getId() . "' AND session_id = '" . $this->db->escape($this->session->getId()) . "' AND product_id = '" . (int)$product_id . "' AND recurring_id = '" . (int)$recurring_id . "' AND `option` = '" . $this->db->escape(json_encode($option)) . "'");
}
$this->data = array();
}
Change to:
// Modified to ENABLE duplicate product
public function add($product_id, $quantity = 1, $option = array(), $recurring_id = 0) {
$query = $this->db->query("INSERT " . DB_PREFIX . "cart SET api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "', customer_id = '" . (int)$this->customer->getId() . "', session_id = '" . $this->db->escape($this->session->getId()) . "', product_id = '" . (int)$product_id . "', recurring_id = '" . (int)$recurring_id . "', `option` = '" . $this->db->escape(json_encode($option)) . "', quantity = '" . (int)$quantity . "', date_added = NOW()");
$this->data = array();
}
// End
I use this modification because I have my own custom pricing, too, and it interfers with OpenCart's original code when it was trying to multiply the product in cart. As you can tell from the code, you're removing OC's query of product total and preventing it from over-riding / increasing the QTY of the same product when you add another instance of it into your cart. Instead, a separate instance/item will be added instead. It won't tamper with the functionality of a customer adding more than 1 QTY from the product page or increasing it in their view cart page, so that all stays the same still in case that's still needed. This just affects how products of the same product id are added into the cart.

Related

Opencart: Error No:1062 Duplicate entry '1' for key 'PRIMARY'

I'm developing a carousel extension for opencart that has Item ID, Item Name, Link, Image, Sort Order. The carousel had an issue while saving it will change the item id so I had to modify the code to get fixed ID queryed to the DB, however now I get the 1062 Error.
Notice: Error: Duplicate entry '1' for key 'PRIMARY' Error No: 1062
INSERT INTO crousal SET crousal_id = '1', name = 'Baby & Toys', link =
'/index.php?route=product/product&product_id=7570', image =
'data/carousel/banner2.jpg', sort_order = '0' in
/home/user/public_html/system/database/mysql.php on line 49
Sharing the model/carousel.php editCarousel Function
public function editCrousal($crousal_image) {
$crousal_id = $this->db->getLastId();
$this->db->query("DELETE FROM " . DB_PREFIX . "mobiapp_crousal WHERE crousal_id = '" . (int)$crousal_id . "'");
if (isset($crousal_image['crousal_image'])) {
foreach ($crousal_image['crousal_image'] as $crousal_image) {
$this->db->query("INSERT INTO " . DB_PREFIX . "mobiapp_crousal SET crousal_id = '" . (int)$crousal_id . "', name = '" . $this->db->escape($crousal_image['name']) . "', link = '" . $this->db->escape($crousal_image['link']) . "', image = '" . $this->db->escape($crousal_image['image']) . "', sort_order = '" . (int)$crousal_image['sort_order'] . "'");
$crousal_id = $this->db->getLastId();
}
}
}
Any advice why I'm getting this error and how to resolve, thank you in advanced.
P.S.: Opencart 1.5.x
Edited: DB Structure & Module info
$this->db->query("
CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "mobiapp_crousal` (
`crousal_id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`link` VARCHAR(255) NOT NULL,
`image` VARCHAR(255) NOT NULL,
`sort_order` INT(3) NOT NULL,
PRIMARY KEY (`crousal_id`)
) ENGINE=MyISAM DEFAULT COLLATE=utf8_general_ci;");
Model File
public function addCrousal($crousal_image) {
$this->db->query("INSERT INTO " . DB_PREFIX . "mobiapp_crousal SET name = '" . $this->db->escape($crousal_image['name']) . "', sort_order = '" . (int)$crousal_image['sort_order'] . "'");
$crousal_id = $this->db->getLastId();
if (isset($crousal_image['crousal_image'])) {
foreach ($crousal_image['crousal_image'] as $crousal_image) {
$this->db->query("INSERT INTO " . DB_PREFIX . "mobiapp_crousal SET crousal_id = '" . (int)$crousal_id . "', link = '" . $this->db->escape($crousal_image['link']) . "', image = '" . $this->db->escape($crousal_image['image']) . "'");
$crousal_id = $this->db->getLastId();
}
}
}
public function editCrousal($crousal_image) {
$crousal_id = $this->db->getLastId();
$this->db->query("DELETE FROM " . DB_PREFIX . "mobiapp_crousal WHERE crousal_id = '" . (int)$crousal_id . "'");
if (isset($crousal_image['crousal_image'])) {
foreach ($crousal_image['crousal_image'] as $crousal_image) {
$this->db->query("INSERT INTO " . DB_PREFIX . "mobiapp_crousal SET crousal_id = '" . (int)$crousal_id . "', name = '" . $this->db->escape($crousal_image['name']) . "', link = '" . $this->db->escape($crousal_image['link']) . "', image = '" . $this->db->escape($crousal_image['image']) . "', sort_order = '" . (int)$crousal_image['sort_order'] . "'");
$crousal_id = $this->db->getLastId();
}
}
}
public function getCrousalImages() {
$crousal_image_data = array();
$crousal_image_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "mobiapp_crousal ORDER BY sort_order ASC");
foreach ($crousal_image_query->rows as $crousal_image) {
$crousal_image_description_data = array();
$crousal_image_description_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "mobiapp_crousal WHERE crousal_id = '" . (int)$crousal_image['crousal_id'] . "'");
$crousal_image_data[] = array(
'crousal_image' => $crousal_image,
'link' => $crousal_image['link'],
'name' => $crousal_image['name'],
'crousal_id' => $crousal_image['crousal_id'],
'image' => $crousal_image['image'],
'sort_order' => $crousal_image['sort_order']
);
}
return $crousal_image_data;
}
I did review for this module. Seems like this module has totally wrong structure. As you can see in method addCrousal foreach-statement with insertion to database. But in this insert carousal_id not incrementing so in the table will be records with not unique carousal_id. So this column can't be PRIMARY.
I suggest you to rewrite module with two tables "Slides" with relations (has many) "Images". Or you can remove PRIMARY index and operation will pass but it's not true solution.

Opencart 2.x add only single item in cart with any quantity

i want customer only add single item in her cart with any number of quantity. if cart already have item it's should be remove and newly added item add to cart in Opencart 2.x.
open system/library/cart.php. You will find follwoing function.
public function add
You can run delete query at very fast in this function.
public function add($product_id, $quantity = 1, $option = array(), $recurring_id = 0) {
$this->db->query("DELETE FROM " . DB_PREFIX . "cart");
$this->db->query("INSERT " . DB_PREFIX . "cart SET api_id = '" . (isset($this->session->data['api_id']) ? (int)$this->session->data['api_id'] : 0) . "', customer_id = '" . (int)$this->customer->getId() . "', session_id = '" . $this->db->escape($this->session->getId()) . "', product_id = '" . (int)$product_id . "', recurring_id = '" . (int)$recurring_id . "', `option` = '" . $this->db->escape(json_encode($option)) . "', quantity = '" . (int)$quantity . "', date_added = NOW()");
}
This is complete function.

foreach only adds 1 row to table

I am using the opencart system and I've added a specific form for our company. Basically it keeps up with our orders as we input into the system. I'm trying to add to multiple records to a table, but it only will work for the first one.
$this->db->query("INSERT INTO " . DB_PREFIX . "customer_orders SET customer = '" . $data['customer'] . "', email = '" . $data['email'] . "', telephone = '" . $data['telephone'] . "', purchase_order = '" . $data['purchase_order'] . "', date_received = '" . $date . "', date_due = '" . $data['date_due'] . "', insurance = '" . $data['insurance'] . "'");
$customer_order = $this->db->getLastId();
foreach ($data['description'] as $description) {
$this->db->query("INSERT INTO " . DB_PREFIX . "customer_order_description SET customer_order_id = '" . $customer_order . "', description = '" . $description . "'");
}
This item would have 2 descriptions, so it should place each description in the order description table, but it only does the first one.

Push Updated Product Price to Past Orders in Opencart 2.x

Attempting to push new product prices to past orders. Essentially, when I edit the product price it needs to update in all orders containing that price Here's the code:
public function editProduct($product_id, $data) {
$this->event->trigger('pre.admin.product.edit', $data);
$this->db->query("UPDATE " . DB_PREFIX . "product SET model = '" . $this->db->escape($data['model']) . "', sku = '" . $this->db->escape($data['sku']) . "', upc = '" . $this->db->escape($data['upc']) . "', ean = '" . $this->db->escape($data['ean']) . "', jan = '" . $this->db->escape($data['jan']) . "', isbn = '" . $this->db->escape($data['isbn']) . "', mpn = '" . $this->db->escape($data['mpn']) . "', location = '" . $this->db->escape($data['location']) . "', quantity = '" . (int)$data['quantity'] . "', minimum = '" . (int)$data['minimum'] . "', subtract = '" . (int)$data['subtract'] . "', stock_status_id = '" . (int)$data['stock_status_id'] . "', date_available = '" . $this->db->escape($data['date_available']) . "', manufacturer_id = '" . (int)$data['manufacturer_id'] . "', shipping = '" . (int)$data['shipping'] . "', price = '" . (float)$data['price'] . "', points = '" . (int)$data['points'] . "', weight = '" . (float)$data['weight'] . "', weight_class_id = '" . (int)$data['weight_class_id'] . "', length = '" . (float)$data['length'] . "', width = '" . (float)$data['width'] . "', height = '" . (float)$data['height'] . "', length_class_id = '" . (int)$data['length_class_id'] . "', status = '" . (int)$data['status'] . "', tax_class_id = '" . (int)$data['tax_class_id'] . "', sort_order = '" . (int)$data['sort_order'] . "', date_modified = NOW() WHERE product_id = '" . (int)$product_id . "'");
//Push Product Edits //
$product_qry = $this->db->query("SELECT price FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product_id . "'");
$new_price = $product_qry->row['price'];
$order_product_id_qry = $this->db->query("SELECT order_product_id FROM " . DB_PREFIX . "order_product");
$order_product_id = $order_product_id_qry->row['order_product_id'];
$order_qry = $this->db->query("SELECT quantity FROM " . DB_PREFIX . "order_product WHERE order_product_id = '" . (int)$order_product_id . "'");
$product_quantity = $order_qry->row['quantity'];
$new_total = $product_quantity * $new_price;
$this->db->query("UPDATE " . DB_PREFIX . "order_product SET price = '" . $new_price . "' WHERE product_id = '" . (int)$product_id ."'");
$this->db->query("UPDATE " . DB_PREFIX . "order_product SET total = '" . $new_total . "' WHERE order_product_id = '" . (int)$order_product_id . "'");
Updating the price is working great. I am no longer receiving an errors, but the order total is not updating. Any idea why?
I added a MYSQL Trigger onto the DB
CREATE TRIGGER `after_product_update` AFTER UPDATE ON `oc_product` FOR EACH ROW
BEGIN
UPDATE `order_product`
SET `price` = NEW.`price`, `total` = `quantity` * NEW.`price` WHERE `product_id` = NEW.`product_id`;
END
Do note other triggers have to be added to the tables oc_order_total in order to update the Subtotal and Total fields there.

Opencart get product downloads

I want to add a new tab into the products page allowing logged in customers to directly download from product page.
At first this seems simple, but it seems that opencart is missing the download_id from order_download table so maybe I am doing this all wrong.
UPDATE: Been doing some digging into the admin and find that opencart is actually using the filename instead of download_id so guess I will have to use that. E.g:
$this->db->query("UPDATE " . DB_PREFIX . "order_download SET `filename` = '" . $this->db->escape($data['filename']) . "', mask = '" . $this->db->escape($data['mask']) . "', remaining = '" . (int)$data['remaining'] . "' WHERE `filename` = '" . $this->db->escape($download_info['filename']) . "'");
The updated method below so am I doing this correct? Seems a lot of queries so not sure if this can be improved?
public function getProductDownloads($product_id) {
$data = array();
$result = $this->db->query("SELECT download_id FROM " . DB_PREFIX . "product_to_download WHERE product_id = '" . (int)$product_id . "'");
foreach ($result->rows as $product_download) {
$product_download_query = $this->db->query("SELECT DISTINCT * FROM " . DB_PREFIX . "download d LEFT JOIN " . DB_PREFIX . "download_description dd ON (d.download_id = dd.download_id) WHERE d.download_id = '" . (int)$product_download['download_id'] . "' AND dd.language_id = '" . (int)$this->config->get('config_language_id') . "'");
foreach ($product_download_query->rows as $download) {
if (!file_exists(DIR_DOWNLOAD . $download['filename'])) continue;
$row = array(
'download_id' => $download['download_id'],
'date_added' => date($this->language->get('date_format_short'), strtotime($download['date_added'])),
'name' => $download['name'],
'href' => ''
);
if($this->customer->isLogged()){
// 1. Get customer orders
$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download od LEFT JOIN `" . DB_PREFIX . "order` o ON (od.order_id = o.order_id) WHERE o.customer_id = '" . (int)$this->customer->getId(). "' AND o.order_status_id > '0' AND o.order_status_id = '" . (int)$this->config->get('config_complete_status_id') . "' AND (od.remaining = -1 OR od.remaining > 0) AND od.filename = '" . $this->db->escape($download['filename']) . "'");
foreach($order_download_query->rows as $order_download) {
// 2. Check customer ordered product
$order_product_download_query = $this->db->query("SELECT 1 FROM " . DB_PREFIX . "order_product op WHERE op.order_product_id = '" . (int)$order_download['order_product_id']. "' AND op.product_id = '" . (int)$product_id . "'");
if($order_product_download_query->row) {
$row['href'] = $this->url->link('account/download/download', 'order_download_id=' . $order_download['order_download_id'], 'SSL');
$row['remaining'] = $order_download['remaining'];
break;
}
}
}
$data[] = $row;
}
}
return $data;
}
First You don't have to run update query, after Placing order it adds data
see /catalog/model/checkout/order.php::addOrder()
To download files
Product Must have download File
Order Status should be Complete
Download remaining should be more than 0
see /catalog/model/account/download.php::getDownloads()
Solution
add following code after if ($product_info) { around line 170 of /catalog/controller/product/product.php
if ($this->customer->isLogged()) {
$this->load->model('account/download');
$results = $this->model_account_download->getDownloadByProduct($product_id);
foreach ($results as $result) {
if (file_exists(DIR_DOWNLOAD . $result['filename'])) {
$size = filesize(DIR_DOWNLOAD . $result['filename']);
$i = 0;
$suffix = array(
'B',
'KB',
'MB',
'GB',
'TB',
'PB',
'EB',
'ZB',
'YB'
);
while (($size / 1024) > 1) {
$size = $size / 1024;
$i++;
}
$this->data['downloads'][] = array(
'order_id' => $result['order_id'],
'name' => $result['name'],
'remaining' => $result['remaining'],
'size' => round(substr($size, 0, strpos($size, '.') + 4), 2) . $suffix[$i],
'href' => $this->url->link('account/download/download', 'order_download_id=' . $result['order_download_id'], 'SSL')
);
}
}
}
Default download method fetches all downloads by customer but we need downloads on product by customer
so /catalog/model/account/download.php add new function. This will fetch associated downloads of product if customer have remaining download of that product.
public function getDownloadByProduct($product_id) {
$query = $this->db->query("SELECT o.order_id, o.date_added, od.order_download_id, od.name, od.filename, od.remaining FROM " . DB_PREFIX . "order_download od LEFT JOIN `" . DB_PREFIX . "order` o ON (od.order_id = o.order_id) LEFT JOIN `" . DB_PREFIX . "order_product` op ON (o.order_id = op.order_id) WHERE o.customer_id = '" . (int)$this->customer->getId() . "' AND o.order_status_id > '0' AND o.order_status_id = '" . (int)$this->config->get('config_complete_status_id') . "' AND od.remaining > 0 AND op.product_id = ' " . $product_id . " ' ORDER BY o.date_added DESC");
return $query->rows;
}
now in product.tpl file you can echo download
<?php
if(isset($downloads)){
foreach ($downloads as $download) { ?>
<?php echo $download['name'].'('.$download['remaining'].')' ?>
<?php }
}
?>
Hope This helps

Categories