Jump to content
  • Checkout
  • Login
  • Get in touch

osCommerce

The e-commerce.

Seperate Pricing Per Customer v3.5


scendent

Recommended Posts

Do I need to go through each affected php files and make changes manually? Cos this is what I'm trying to avoid doing.

It all depends. If the design of the site has altered the PHP files a lot then obviously you have to go through them manually, use the included diff files (if you are on Linux or a Mac) or using a file comparison program.

 

But I can't imagine classes and admin files being changed by the design, so if this is your first contribution you want to add you can just exchange files in those files.

 

Make sure you have a full backup of your files before tinkering with them :)

Link to comment
Share on other sites

So what is your question? With the drop-down, the hide checkbox and the price field you should be covered regarding specific prices for various options in each group.

 

Oops! Thanks for responding - I just missed this reply. The drop-down gives two prefix choices: + and -. I simply don't want prefixes. I did find a part of the code where I could add in another (blank) option, but I've somehow introduced some strange pricing error. The site is frr.aipathedog.com. Is there another way to get rid of prefixes so that I simply input the actual price and not add to the first price listed?

 

Thanks!

Audrey

Link to comment
Share on other sites

I simply don't want prefixes.

Well, that is the way osC calculates because you can have more than one attribute for a product (say a T-Shirt: price and color). But there is a contribution named something like Actual price in drop-down of attributes where instead of + or - an amount, the actual price calculated with + - (or the price when it costs nothing) is displayed.

Link to comment
Share on other sites

Hello,

 

Can anyone please advise me which version of SPPC I should install...I am running osCommerce 2.2-MS2.

 

I need to install ASAP and need to be sure I start installation with campatable version.

 

Thanks heaps!

Link to comment
Share on other sites

Hey Jan,

 

I am having a bugger of a time with a project at the moment and thought maybe you could shed some light on it for me :blush:

 

I have SPPC, STS and Master Products (among others, but these 3 main one's are affected in this project). I need to change the includes/modules/product_listing.php file (unless you know of a better way to do this) so on each category page I would have the following info for all of the products in that category:

 

Master | Master Name

Image | Master Description

------------------------------------------

Slave Item# | Slave Description | Slave Price | Qty Box | Add to Cart

 

The Master Image would have a rowspan of 2, with the Name and Description of the Master Product being the next columns 2 rows.

 

Under that would be another table with the Item #, Description, Price, a box to enter quantity and an add to cart button for each slave of that Master Product.

 

Right now my product_listing.php file only shows the master product name and a Buy Now button (which goes to the product_info.php page so you can choose a slave) with spots in between the two for Item# and price - both of these are blank as Master Products aren't for sale so they don't have item #'s or prices.

 

Do you have any thoughts on how I could accomplish this? My boss wants people to be able to order products from the category pages and not have to click to each individual products info page in order to add the product to their cart.

~Tracy
 

Link to comment
Share on other sites

The Master Image would have a rowspan of 2, with the Name and Description of the Master Product being the next columns 2 rows.

 

Under that would be another table with the Item #, Description, Price, a box to enter quantity and an add to cart button for each slave of that Master Product.

 

Right now my product_listing.php file only shows the master product name and a Buy Now button (which goes to the product_info.php page so you can choose a slave) with spots in between the two for Item# and price - both of these are blank as Master Products aren't for sale so they don't have item #'s or prices.

 

Do you have any thoughts on how I could accomplish this?

Pretty extensive rewrite of the product_listing module really. Hard to advice you on this but you would need to find out which slave products belong to which master and then group them. But I guess you knew that already.

Link to comment
Share on other sites

ok, I have sent a message to Jan but thought maybe others in this thread might be able to help.

 

I created a NEW site using RC2a and installed SPPC 4.2.1a using an SQL 4 database. Everything works great ! I have set up the two customer groups I needed and have tested the site after loading the more than 700 products into the site.

 

Perfect!

 

The problems is, my client also wants Discount coupon codes, No buy button if qty 0 and must log in to see pricing contributions as well.

 

When I tried to install ANY of the other 3 contributions, SPPC fails or the adding contribution fails.

 

Has anyone successfully integrated these contributions into SPPC that would be willing to share some code....or ideas ??

 

All help is greatly appreciated.

 

 

Chris

Link to comment
Share on other sites

must log in to see pricing contributions as well.

 

When I tried to install ANY of the other 3 contributions, SPPC fails or the adding contribution fails.

You asked about must log-in for pricing in a thread and I answered that. No reply from you so I guess you missed checking your own threads.

Link to comment
Share on other sites

I did, however the problem is 3 fold now because I need to get all 4 contributions to work together. OR, I need to inform my customer SPPC can't be installed. I am trying to find a solution by seeking help integrating the contributions I need for this specific customer.

 

 

I am sure, others would be interested in adding some or all of these contributions as well.

 

 

Chris

Link to comment
Share on other sites

I did, however the problem is 3 fold now because I need to get all 4 contributions to work together. OR, I need to inform my customer SPPC can't be installed. I am trying to find a solution by seeking help integrating the contributions I need for this specific customer.

 

I am sure, others would be interested in adding some or all of these contributions as well.

I'm sorry if this offends you (guess it will) but because you have not much of a clue about PHP doesn't mean that SPPC cannot be combined with other contributions. I know design and programming are two different fields and people are usual good in either one or the other but that is no reason to shift the blame for you not knowing how to combine these contribution to SPPC.

Link to comment
Share on other sites

Jan,

 

I am not easily offended. Your defensive posture about SPPC is warranted. My intention wasn't get put you on the defensive, SPPC works very well, as long as the site designer doesn't want to utilize other contributions as well. After reviewing the contributions again, it is obvious that members are creating contributions around the SPPC contribution and this is why I was asking if anyone had re-written code around SPPC that would allow me to integrate the 3 other contributions I am trying to install.

 

Thank you again for your response.

 

 

Chris

Link to comment
Share on other sites

Hi, Jan, greatly appreicate if you can help on this.

 

After I integrate the QBSPPC 1.02 with the SPPC 4.1.2a. I have this problem, the subtotal at the shopping cart does not refect the quantity price break value when I log in as wholeseller (retailer is fine). For example, the selling price is $35, buy 2 will be $33 each. If I buy two items, the shopping chart show $66, but subtotal shows $70.

 

here is the shopping_cart.php at include/class/

 

 

<?php
/*
 $Id: shopping_cart.php,v 1.35 2003/06/25 21:14:33 hpdl Exp $

 osCommerce, Open Source E-Commerce Solutions
 [url="http://www.oscommerce.com"]http://www.oscommerce.com[/url]

 Copyright © 2003 osCommerce

 Released under the GNU General Public License
*/

 class shoppingCart {
var $contents, $total, $weight, $cartID, $content_type;

function shoppingCart() {
  $this->reset();
}

function restore_contents() {
  global $customer_id;

  if (!tep_session_is_registered('customer_id')) return false;

// insert current cart contents in database
  if (is_array($this->contents)) {
	reset($this->contents);

	// BOF SPPC attribute hide/invalid check: loop through the shopping cart and check the attributes if they
// are hidden for the now logged-in customer
  $this->cg_id = $this->get_customer_group_id();
	while (list($products_id, ) = each($this->contents)) {
				// only check attributes if they are set for the product in the cart
			   if (isset($this->contents[$products_id]['attributes'])) {
			$check_attributes_query = tep_db_query("select options_id, options_values_id, IF(find_in_set('" . $this->cg_id . "', attributes_hide_from_groups) = 0, '0', '1') as hide_attr_status from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . tep_get_prid($products_id) . "'");
			while ($_check_attributes = tep_db_fetch_array($check_attributes_query)) {
				$check_attributes[] = $_check_attributes;
			} // end while ($_check_attributes = tep_db_fetch_array($check_attributes_query))
			$no_of_check_attributes = count($check_attributes);
			$change_products_id = '0';

			foreach($this->contents[$products_id]['attributes'] as $attr_option => $attr_option_value) {
				$valid_option = '0';
				for ($x = 0; $x < $no_of_check_attributes; $x++) {
					if ($attr_option == $check_attributes[$x]['options_id'] && $attr_option_value == $check_attributes[$x]['options_values_id']) {
						$valid_option = '1';
						if ($check_attributes[$x]['hide_attr_status'] == '1') {
						// delete hidden attributes from array attributes, change products_id accordingly later
						$change_products_id = '1';
						unset($this->contents[$products_id]['attributes'][$attr_option]);
						}
					} // end if ($attr_option == $check_attributes[$x]['options_id']....
				} // end for ($x = 0; $x < $no_of_check_attributes; $x++)
				if ($valid_option == '0') {
					// after having gone through the options for this product and not having found a matching one
					// we can conclude that apparently this is not a valid option for this product so remove it
					unset($this->contents[$products_id]['attributes'][$attr_option]);
					// change products_id accordingly later
					$change_products_id = '1';
				}
			} // end foreach($this->contents[$products_id]['attributes'] as $attr_option => $attr_option_value)

	  if ($change_products_id == '1') {
		   $original_products_id = $products_id;
		   $products_id = tep_get_prid($original_products_id);
		   $products_id = tep_get_uprid($products_id, $this->contents[$original_products_id]['attributes']);
					 // add the product without the hidden attributes to the cart
		   $this->contents[$products_id] = $this->contents[$original_products_id];
				 // delete the originally added product with the hidden attributes
		   unset($this->contents[$original_products_id]);
		}
			  } // end if (isset($this->contents[$products_id]['attributes']))
			} // end while (list($products_id, ) = each($this->contents))
   reset($this->contents); // reset the array otherwise the cart will be emptied
// EOF SPPC attribute hide/invalid check

	while (list($products_id, ) = each($this->contents)) {
	  $qty = $this->contents[$products_id]['qty'];
	  $product_query = tep_db_query("select products_id from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "'");
	  if (!tep_db_num_rows($product_query)) {
		tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET . " (customers_id, products_id, customers_basket_quantity, customers_basket_date_added) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id) . "', '" . tep_db_input($qty) . "', '" . date('Ymd') . "')");
		if (isset($this->contents[$products_id]['attributes'])) {
		  reset($this->contents[$products_id]['attributes']);
		  while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
			tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " (customers_id, products_id, products_options_id, products_options_value_id) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id) . "', '" . (int)$option . "', '" . (int)$value . "')");
		  }
		}
	  } else {
		tep_db_query("update " . TABLE_CUSTOMERS_BASKET . " set customers_basket_quantity = '" . tep_db_input($qty) . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "'");
	  }
	}
  }

// reset per-session cart contents, but not the database contents
  $this->reset(false);

  $products_query = tep_db_query("select products_id, customers_basket_quantity from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "'");
  while ($products = tep_db_fetch_array($products_query)) {
	$this->contents[$products['products_id']] = array('qty' => $products['customers_basket_quantity']);
// attributes
	$attributes_query = tep_db_query("select products_options_id, products_options_value_id from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products['products_id']) . "'");
	while ($attributes = tep_db_fetch_array($attributes_query)) {
	  $this->contents[$products['products_id']]['attributes'][$attributes['products_options_id']] = $attributes['products_options_value_id'];
	}
  }

  $this->cleanup();
}

function reset($reset_database = false) {
  global $customer_id;

  $this->contents = array();
  $this->total = 0;
  $this->weight = 0;
  $this->content_type = false;

  if (tep_session_is_registered('customer_id') && ($reset_database == true)) {
	tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "'");
	tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$customer_id . "'");
  }

  unset($this->cartID);
  if (tep_session_is_registered('cartID')) tep_session_unregister('cartID');
}

function add_cart($products_id, $qty = '1', $attributes = '', $notify = true) {
  // BOF Separate Pricing Per Customer, Price Break 1.11.3 modification
  global $new_products_id_in_cart, $customer_id, $languages_id;
// BOF Separate Pricing Per Customer 
  $this->cg_id = $this->get_customer_group_id();
// EOF Separate Pricing Per Customer
  $pf = new PriceFormatter;
  $pf->loadProduct($products_id, $languages_id);
  $qty = $pf->adjustQty($qty);

  // EOF Separate Pricing Per Customer, Price Break 1.11.3 modification



  $products_id_string = tep_get_uprid($products_id, $attributes);
  $products_id = tep_get_prid($products_id_string);


  if (defined('MAX_QTY_IN_CART') && (MAX_QTY_IN_CART > 0) && ((int)$qty > MAX_QTY_IN_CART)) {
	$qty = MAX_QTY_IN_CART;
  }

  $attributes_pass_check = true;

  if (is_array($attributes)) {
	reset($attributes);
	while (list($option, $value) = each($attributes)) {
	  if (!is_numeric($option) || !is_numeric($value)) {
		$attributes_pass_check = false;
		break;
	  }
	}
  }

  if (is_numeric($products_id) && is_numeric($qty) && ($attributes_pass_check == true)) {
// BOF SPPC attribute hide check, original query expanded to include attributes
			$check_product_query = tep_db_query("select p.products_status, options_id, options_values_id, IF(find_in_set('" . $this->cg_id . "', attributes_hide_from_groups) = 0, '0', '1') as hide_attr_status from " . TABLE_PRODUCTS . " p left join " . TABLE_PRODUCTS_ATTRIBUTES . " using(products_id) where p.products_id = '" . (int)$products_id . "'");
			while ($_check_product = tep_db_fetch_array($check_product_query)) {
				$check_product[] = $_check_product;
			} // end while ($_check_product = tep_db_fetch_array($check_product_query))
			$no_of_check_product = count($check_product);

 if (is_array($attributes)) {
			foreach($attributes as $attr_option => $attr_option_value) {
				$valid_option = '0';
				for ($x = 0; $x < $no_of_check_product; $x++) {
					if ($attr_option == $check_product[$x]['options_id'] && $attr_option_value == $check_product[$x]['options_values_id']) {
						$valid_option = '1';
						if ($check_product[$x]['hide_attr_status'] == '1') {
						// delete hidden attributes from array attributes
						unset($attributes[$attr_option]);
						}
					} // end if ($attr_option == $check_product[$x]['options_id']....
				} // end for ($x = 0; $x < $no_of_check_product; $x++)
				if ($valid_option == '0') {
					// after having gone through the options for this product and not having found a matching one
					// we can conclude that apparently this is not a valid option for this product so remove it
					unset($attributes[$attr_option]);
				}
			} // end foreach($attributes as $attr_option => $attr_option_value)
} // end if (is_array($attributes))
// now attributes have been checked and hidden and invalid ones deleted make the $products_id_string again
			$products_id_string = tep_get_uprid($products_id, $attributes);

	if ((isset($check_product) && tep_not_null($check_product)) && ($check_product[0]['products_status'] == '1')) {
// EOF SPPC attribute hide check

	  if ($notify == true) {
		$new_products_id_in_cart = $products_id;
		tep_session_register('new_products_id_in_cart');
	  }

	  if ($this->in_cart($products_id_string)) {
		$this->update_quantity($products_id_string, $qty, $attributes);
	  } else {
		$this->contents[$products_id_string] = array('qty' => (int)$qty);
// insert into database
		if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET . " (customers_id, products_id, customers_basket_quantity, customers_basket_date_added) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id_string) . "', '" . (int)$qty . "', '" . date('Ymd') . "')");

		if (is_array($attributes)) {
		  reset($attributes);
		  while (list($option, $value) = each($attributes)) {
			$this->contents[$products_id_string]['attributes'][$option] = $value;
// insert into database
			if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " (customers_id, products_id, products_options_id, products_options_value_id) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id_string) . "', '" . (int)$option . "', '" . (int)$value . "')");
		  }
		}
	  }

	  $this->cleanup();

// assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
	  $this->cartID = $this->generate_cart_id();
	}
  }
}

function update_quantity($products_id, $quantity = '', $attributes = '') {
  global $customer_id;

  $products_id_string = tep_get_uprid($products_id, $attributes);
  $products_id = tep_get_prid($products_id_string);

  if (defined('MAX_QTY_IN_CART') && (MAX_QTY_IN_CART > 0) && ((int)$quantity > MAX_QTY_IN_CART)) {
	$quantity = MAX_QTY_IN_CART;
  }

  $attributes_pass_check = true;

  if (is_array($attributes)) {
	reset($attributes);
	while (list($option, $value) = each($attributes)) {
	  if (!is_numeric($option) || !is_numeric($value)) {
		$attributes_pass_check = false;
		break;
	  }
	}
  }

  if (is_numeric($products_id) && isset($this->contents[$products_id_string]) && is_numeric($quantity) && ($attributes_pass_check == true)) {
	$this->contents[$products_id_string] = array('qty' => (int)$quantity);
// update database
	if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET . " set customers_basket_quantity = '" . (int)$quantity . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id_string) . "'");

	if (is_array($attributes)) {
	  reset($attributes);
	  while (list($option, $value) = each($attributes)) {
		$this->contents[$products_id_string]['attributes'][$option] = $value;
// update database
		if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " set products_options_value_id = '" . (int)$value . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id_string) . "' and products_options_id = '" . (int)$option . "'");
	  }
	}
  }
}

function cleanup() {
  global $customer_id;

  reset($this->contents);
  while (list($key,) = each($this->contents)) {
	if ($this->contents[$key]['qty'] < 1) {
	  unset($this->contents[$key]);
// remove from database
	  if (tep_session_is_registered('customer_id')) {
		tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($key) . "'");
		tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($key) . "'");
	  }
	}
  }
}

function count_contents() {  // get total number of items in cart 
  $total_items = 0;
  if (is_array($this->contents)) {
	reset($this->contents);
	while (list($products_id, ) = each($this->contents)) {
	  $total_items += $this->get_quantity($products_id);
	 // start Get 1 free
	  // start Get 1 free
	  // If this product qualifies for free product(s) add in the number of free products
	  if (is_array ($free_product = $this->get1free ($products_id))) {
		$total_items += $free_product['quantity'];
	  }
// end Get 1 free
	}
  }

  return $total_items;
}

function get_quantity($products_id) {
  if (isset($this->contents[$products_id])) {
	return $this->contents[$products_id]['qty'];
  } else {
	return 0;
  }
}

function in_cart($products_id) {
  if (isset($this->contents[$products_id])) {
	return true;
  } else {
	return false;
  }
}

function remove($products_id) {
  global $customer_id;

  unset($this->contents[$products_id]);
// remove from database
  if (tep_session_is_registered('customer_id')) {
	tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "'");
	tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "'");
  }
  // start Get 1 Free
	  // If this product qualifies for free product(s) remove the free products
	  if (is_array ($free_product = $this->get1free ($products_id))) {
		$pid = (int)$free_product['id'];
		print '<br>Found Product: ' . $pid;
		unset($this->contents[$pid]);
		// remove from database
		if (tep_session_is_registered('customer_id')) {
		  tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$customer_id . "' and products_id = '" . 

tep_db_input($pid) . "'");
		  tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$customer_id . "' and products_id = 

'" . tep_db_input($pid) . "'");
		}
	  }
// end Get 1 Free

// assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
  $this->cartID = $this->generate_cart_id();
}

function remove_all() {
  $this->reset();
}

function get_product_id_list() {
  $product_id_list = '';
  if (is_array($this->contents)) {
	reset($this->contents);
	while (list($products_id, ) = each($this->contents)) {
	  $product_id_list .= ', ' . $products_id;
	}
  }

  return substr($product_id_list, 2);
}

function calculate() {
global $currencies;

  $this->total = 0;
  $this->weight = 0;
  if (!is_array($this->contents)) return 0;
// BOF Separate Pricing Per Customer
// global variable (session) $sppc_customer_group_id -> class variable cg_id
  $this->cg_id = $this->get_customer_group_id();
// EOF Separate Pricing Per Customer
 // BOF Separate Pricing Per Customer, Price Break 1.11.3 mod
  global $languages_id;
  $pf = new PriceFormatter;
reset($this->contents);
  while (list($products_id, ) = each($this->contents)) {
	$qty = $this->contents[$products_id]['qty'];

// products price
//	$product_query = tep_db_query("select products_id, products_price, products_tax_class_id, products_weight from " . TABLE_PRODUCTS . " where products_id = '" . (int)$products_id . "'");

//	if ($product = tep_db_fetch_array($product_query)) {
	if ($product = $pf->loadProduct($products_id, $languages_id)){		
	  $prid = $product['products_id'];
	 $products_tax = tep_get_tax_rate($product['products_tax_class_id']);
 //		$products_price = $product['products_price'];
	  $products_price = $pf->computePrice($qty);
	  $products_weight = $product['products_weight'];
// EOF Separate Pricing Per Customer, Price Break 1.11.3 mod

/*		  $specials_query = tep_db_query("select specials_new_products_price from " . TABLE_SPECIALS . " where products_id = '" . (int)$prid . "' and status = '1'");
	  if (tep_db_num_rows ($specials_query)) {
		$specials = tep_db_fetch_array($specials_query);
		$products_price = $specials['specials_new_products_price'];
	  }  */

	  // BOF Separate Pricing Per Customer
  $specials_price = tep_get_products_special_price((int)$prid);
  if (tep_not_null($specials_price)) {
 $products_price = $specials_price;
  } elseif ($this->cg_id != 0){
	$customer_group_price_query = tep_db_query("select customers_group_price from " . TABLE_PRODUCTS_GROUPS . " where products_id = '" . (int)$prid . "' and customers_group_id =  '" . $this->cg_id . "'");
	if ($customer_group_price = tep_db_fetch_array($customer_group_price_query)) {
	$products_price = $customer_group_price['customers_group_price'];
	}
  }
// EOF Separate Pricing Per Customer

	  $this->total += $currencies->calculate_price($products_price, $products_tax, $qty);
	  $this->weight += ($qty * $products_weight);
	  // start Get 1 Free
	  // If this product qualifies for free product(s) add in the total weight of free products
	  if (is_array ($free_product = $this->get1free ($products_id))) {
		$this->weight += $free_product['quantity'] * $free_product['weight'];
	  }
// end Get 1 Free
	}

/*// attributes price
	if (isset($this->contents[$products_id]['attributes'])) {
	  reset($this->contents[$products_id]['attributes']);
	  while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
		$attribute_price_query = tep_db_query("select options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$prid . "' and options_id = '" . (int)$option . "' and options_values_id = '" . (int)$value . "'");
		$attribute_price = tep_db_fetch_array($attribute_price_query);
		if ($attribute_price['price_prefix'] == '+') {
		  $this->total += $currencies->calculate_price($attribute_price['options_values_price'], $products_tax, $qty);
		} else {
		  $this->total -= $currencies->calculate_price($attribute_price['options_values_price'], $products_tax, $qty);
		}
	  }
	}
  }
}   */

// attributes price
// BOF SPPC attributes mod
	if (isset($this->contents[$products_id]['attributes'])) {
	  reset($this->contents[$products_id]['attributes']);
   $where = " AND ((";
	while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
	 $where .= "options_id = '" . (int)$option . "' AND options_values_id = '" . (int)$value . "') OR (";
   }
   $where=substr($where, 0, -5) . ')';

   $attribute_price_query = tep_db_query("SELECT products_attributes_id, options_values_price, price_prefix FROM " . TABLE_PRODUCTS_ATTRIBUTES . " WHERE products_id = '" . (int)$products_id . "'" . $where ."");

   if (tep_db_num_rows($attribute_price_query)) { 
	   $list_of_prdcts_attributes_id = '';
			 // empty array $attribute_price
			 $attribute_price = array();
	   while ($attributes_price_array = tep_db_fetch_array($attribute_price_query)) { 
	   $attribute_price[] =  $attributes_price_array;
	   $list_of_prdcts_attributes_id .= $attributes_price_array['products_attributes_id'].",";
		}
	   if (tep_not_null($list_of_prdcts_attributes_id) && $this->cg_id != '0') { 
	 $select_list_of_prdcts_attributes_ids = "(" . substr($list_of_prdcts_attributes_id, 0 , -1) . ")";
 $pag_query = tep_db_query("select products_attributes_id, options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES_GROUPS . " where products_attributes_id IN " . $select_list_of_prdcts_attributes_ids . " AND customers_group_id = '" . $this->cg_id . "'");
 while ($pag_array = tep_db_fetch_array($pag_query)) {
	 $cg_attr_prices[] = $pag_array;
 }

 // substitute options_values_price and prefix for those for the customer group (if available)
 if ($customer_group_id != '0' && tep_not_null($cg_attr_prices)) {
	for ($n = 0; $n < count($attribute_price); $n++) {
	 for ($i = 0; $i < count($cg_attr_prices); $i++) {
		 if ($cg_attr_prices[$i]['products_attributes_id'] == $attribute_price[$n]['products_attributes_id']) {
			$attribute_price[$n]['price_prefix'] = $cg_attr_prices[$i]['price_prefix'];
			$attribute_price[$n]['options_values_price'] = $cg_attr_prices[$i]['options_values_price'];
		 }
	 } // end for ($i = 0; $i < count($cg_att_prices); $i++)
	  }
	} // end if ($customer_group_id != '0' && (tep_not_null($cg_attr_prices))
  } // end if (tep_not_null($list_of_prdcts_attributes_id) && $customer_group_id != '0')
// now loop through array $attribute_price to add up/substract attribute prices

  for ($n = 0; $n < count($attribute_price); $n++) {
		if ($attribute_price[$n]['price_prefix'] == '+') {
		  $this->total += $currencies->calculate_price($attribute_price[$n]['options_values_price'], $products_tax, $qty);
		} else {
		  $this->total -= $currencies->calculate_price($attribute_price[$n]['options_values_price'], $products_tax, $qty);
	}
  } // end for ($n = 0; $n < count($attribute_price); $n++)
	  } // end if (tep_db_num_rows($attribute_price_query))
	} // end if (isset($this->contents[$products_id]['attributes'])) 
  }
}
// EOF SPPC attributes mod

/*   function attributes_price($products_id) {
  $attributes_price = 0;

  if (isset($this->contents[$products_id]['attributes'])) {
	reset($this->contents[$products_id]['attributes']);
	while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
	  $attribute_price_query = tep_db_query("select options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES . " where products_id = '" . (int)$products_id . "' and options_id = '" . (int)$option . "' and options_values_id = '" . (int)$value . "'");
	  $attribute_price = tep_db_fetch_array($attribute_price_query);
	  if ($attribute_price['price_prefix'] == '+') {
		$attributes_price += $attribute_price['options_values_price'];
	  } else {
		$attributes_price -= $attribute_price['options_values_price'];
	  }
	}
  }

  return $attributes_price;
}	*/


// function attributes_price changed partially according to FalseDawn's post
// [url="http://www.oscommerce.com/forums/index.php?showtopic=139587"]http://www.oscommerce.com/forums/index.php?showtopic=139587[/url]
// changed completely for Separate Pricing Per Customer, attributes mod
function attributes_price($products_id) {
// global variable (session) $sppc_customer_group_id -> class variable cg_id
$this->cg_id = $this->get_customer_group_id();

  if (isset($this->contents[$products_id]['attributes'])) {
	reset($this->contents[$products_id]['attributes']);
   $where = " AND ((";
	while (list($option, $value) = each($this->contents[$products_id]['attributes'])) {
	 $where .= "options_id = '" . (int)$option . "' AND options_values_id = '" . (int)$value . "') OR (";
   }
   $where=substr($where, 0, -5) . ')';

   $attribute_price_query = tep_db_query("SELECT products_attributes_id, options_values_price, price_prefix FROM " . TABLE_PRODUCTS_ATTRIBUTES . " WHERE products_id = '" . (int)$products_id . "'" . $where ."");

  if (tep_db_num_rows($attribute_price_query)) {
	   $list_of_prdcts_attributes_id = '';
	   while ($attributes_price_array = tep_db_fetch_array($attribute_price_query)) { 
	   $attribute_price[] =  $attributes_price_array;
	   $list_of_prdcts_attributes_id .= $attributes_price_array['products_attributes_id'].",";
	  }

	   if (tep_not_null($list_of_prdcts_attributes_id) && $this->cg_id != '0') { 
	 $select_list_of_prdcts_attributes_ids = "(" . substr($list_of_prdcts_attributes_id, 0 , -1) . ")";
 $pag_query = tep_db_query("select products_attributes_id, options_values_price, price_prefix from " . TABLE_PRODUCTS_ATTRIBUTES_GROUPS . " where products_attributes_id IN " . $select_list_of_prdcts_attributes_ids . " AND customers_group_id = '" . $this->cg_id . "'");
 while ($pag_array = tep_db_fetch_array($pag_query)) {
	 $cg_attr_prices[] = $pag_array;
 }

 // substitute options_values_price and prefix for those for the customer group (if available)
 if ($customer_group_id != '0' && tep_not_null($cg_attr_prices)) {
	for ($n = 0; $n < count($attribute_price); $n++) {
	 for ($i = 0; $i < count($cg_attr_prices); $i++) {
		 if ($cg_attr_prices[$i]['products_attributes_id'] == $attribute_price[$n]['products_attributes_id']) {
			$attribute_price[$n]['price_prefix'] = $cg_attr_prices[$i]['price_prefix'];
			$attribute_price[$n]['options_values_price'] = $cg_attr_prices[$i]['options_values_price'];
	}
	 } // end for ($i = 0; $i < count($cg_att_prices); $i++)
  }
	} // end if ($customer_group_id != '0' && (tep_not_null($cg_attr_prices))
  } // end if (tep_not_null($list_of_prdcts_attributes_id) && $customer_group_id != '0')
// now loop through array $attribute_price to add up/substract attribute prices

  for ($n = 0; $n < count($attribute_price); $n++) {
		if ($attribute_price[$n]['price_prefix'] == '+') {
		  $attributes_price += $attribute_price[$n]['options_values_price'];
		} else {
		  $attributes_price -= $attribute_price[$n]['options_values_price'];
		}
  } // end for ($n = 0; $n < count($attribute_price); $n++)
  return $attributes_price;
   } else { // end if (tep_db_num_rows($attribute_price_query))
	 return 0;
   } 
 }  else { // end if (isset($this->contents[$products_id]['attributes']))
   return 0;
}
  } // end of function attributes_price, modified for SPPC with attributes


function get_products() {
  global $languages_id;

// BOF Separate Pricing Per Customer
 $this->cg_id = $this->get_customer_group_id();
// EOF Separate Pricing Per Customer

  if (!is_array($this->contents)) return false;
$pf = new PriceFormatter;

  $products_array = array();
  reset($this->contents);
  while (list($products_id, ) = each($this->contents)) {
/*		$products_query = tep_db_query("select p.products_id, pd.products_name, p.products_model, p.products_image, p.products_price, p.products_weight, p.products_carrot, p.products_tax_class_id from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd where p.products_id = '" . (int)$products_id . "' and pd.products_id = p.products_id and pd.language_id = '" . (int)$languages_id . "'");
	if ($products = tep_db_fetch_array($products_query)) {
	  $prid = $products['products_id'];
	  $products_price = $products['products_price'];

	  $specials_query = tep_db_query("select specials_new_products_price from " . TABLE_SPECIALS . " where products_id = '" . (int)$prid . "' and status = '1'");
	  if (tep_db_num_rows($specials_query)) {
		$specials = tep_db_fetch_array($specials_query);
		$products_price = $specials['specials_new_products_price'];
	  } */   

// BOF Separate Pricing Per Customer
 $specials_price = tep_get_products_special_price($prid);
 if (tep_not_null($specials_price)) {
 $products_price = $specials_price;
  } elseif ($this->cg_id != 0){
	$customer_group_price_query = tep_db_query("select customers_group_price from " . TABLE_PRODUCTS_GROUPS . " where products_id = '" . (int)$prid . "' and customers_group_id =  '" . $this->cg_id . "'");
	if ($customer_group_price = tep_db_fetch_array($customer_group_price_query)) {
	$products_price = $customer_group_price['customers_group_price'];
	}
 } 
// EOF Separate Pricing Per Customer
if ($products = $pf->loadProduct($products_id, $languages_id)) {
	  $products_price = $pf->computePrice($this->contents[$products_id]['qty']);
// EOF Separate Pricing Per Customer v4, Price Break 1.11.3 modification	

	  $products_array[] = array('id' => $products_id,
								'name' => $products['products_name'],
								'model' => $products['products_model'],
								'image' => $products['products_image'],
								'price' => $products_price,
								'quantity' => $this->contents[$products_id]['qty'],
								'weight' => $products['products_weight'],
								'carrot' => $products['products_carrot'],
								'final_price' => ($products_price + $this->attributes_price($products_id)),
								'tax_class_id' => $products['products_tax_class_id'],
								'attributes' => (isset($this->contents[$products_id]['attributes']) ? $this->contents[$products_id]['attributes'] : ''));
								// start Get 1 free
	  if (is_array ($free_product = $this->get1free ($products_id))) {
		// Add the free product to the shopping cart (Customer cannot alter this)
		$products_array[] = array('id' => $free_product['id'],
								  'name' => $free_product['name'],
								  'model' => $free_product['model'],
								  'image' => $free_product['image'],
								  'price' => 0,
								  'quantity' => $free_product['quantity'],
								  'weight' => $free_product['weight'],
								  'final_price' => 0,
								  'tax_class_id' => $products['products_tax_class_id'],
								  'attributes' => '',
								  'free' => 1
								 );
	  } //if (is_array
// end Get 1 free
	}
  }

  return $products_array;
}

function show_total() {
  $this->calculate();

  return $this->total;
}

function show_weight() {
  $this->calculate();

  return $this->weight;
}

function generate_cart_id($length = 5) {
  return tep_create_random_value($length, 'digits');
}

function get_content_type() {
  $this->content_type = false;

  if ( (DOWNLOAD_ENABLED == 'true') && ($this->count_contents() > 0) ) {
	reset($this->contents);
	while (list($products_id, ) = each($this->contents)) {
	  if (isset($this->contents[$products_id]['attributes'])) {
		reset($this->contents[$products_id]['attributes']);
		while (list(, $value) = each($this->contents[$products_id]['attributes'])) {
		  $virtual_check_query = tep_db_query("select count(*) as total from " . TABLE_PRODUCTS_ATTRIBUTES . " pa, " . TABLE_PRODUCTS_ATTRIBUTES_DOWNLOAD . " pad where pa.products_id = '" . (int)$products_id . "' and pa.options_values_id = '" . (int)$value . "' and pa.products_attributes_id = pad.products_attributes_id");
		  $virtual_check = tep_db_fetch_array($virtual_check_query);

		  if ($virtual_check['total'] > 0) {
			switch ($this->content_type) {
			  case 'physical':
				$this->content_type = 'mixed';

				return $this->content_type;
				break;
			  default:
				$this->content_type = 'virtual';
				break;
			}
		  } else {
			switch ($this->content_type) {
			  case 'virtual':
				$this->content_type = 'mixed';

				return $this->content_type;
				break;
			  default:
				$this->content_type = 'physical';
				break;
			}
		  }
		}
	  } else {
		switch ($this->content_type) {
		  case 'virtual':
			$this->content_type = 'mixed';

			return $this->content_type;
			break;
		  default:
			$this->content_type = 'physical';
			break;
		}
	  }
	}
  } else {
	$this->content_type = 'physical';
  }

  return $this->content_type;
}

function unserialize($broken) {
  for(reset($broken);$kv=each($broken);) {
	$key=$kv['key'];
	if (gettype($this->$key)!="user function")
	$this->$key=$kv['value'];
  }
}
// start Get 1 Free
function get1free ($products_id) {
  global $languages_id;
  $get_1_free_query = tep_db_query("select products_free_id,
										   products_free_quantity,
										   products_qualify_quantity,
										   products_multiple,
										   get_1_free_expires_date
									from " . TABLE_GET_1_FREE . "
									where products_id = '" . (int)$products_id . "'
									  and status = '1'"
								  );
  if (tep_db_num_rows($get_1_free_query) > 0) {
	$get_1_free = tep_db_fetch_array($get_1_free_query);
	//Check that the offer has not expired
	 //MNK bugfix 13.08.2007
	if (($get_1_free['get_1_free_expires_date'] <= date('Y-m-d H:i:s')) && ($get_1_free['get_1_free_expires_date'] != '0000-00-00 00:00:00')) {
	  //offer has expired, so update the database and return false
	  tep_db_query("update " . TABLE_GET_1_FREE . "
					set status = '0',
						date_status_change = now()
					where products_id = '" . (int)$products_id . "'"
				  );
	  return false;
	} else {
	  // Offer is valid, so check if the quantity qualifies
	  $products_quantity = $this->contents[$products_id]['qty'];
	  if ($products_quantity >= $get_1_free['products_qualify_quantity']) {
		// Qualifies, so get the quantity of free products
		$free_quantity = 1;
		if ($get_1_free['products_multiple'] > 1) {
		  $free_quantity = floor ($products_quantity / $get_1_free['products_qualify_quantity']);
		  if ($free_quantity > $get_1_free['products_multiple']) {
			$free_quantity = $get_1_free['products_multiple'];
		  }
		}
		// Get the info on the free product
		$products_free_query = tep_db_query("select pd.products_name,
													p.products_model,
													p.products_image,
													p.products_weight
											 from " . TABLE_PRODUCTS . " p,
												  " . TABLE_PRODUCTS_DESCRIPTION . " pd
											 where p.products_id = '" . (int)$get_1_free['products_free_id'] . "'
											   and pd.products_id = p.products_id
											   and pd.language_id = '" . (int)$languages_id . "'"
										   );
		$products_free = tep_db_fetch_array($products_free_query);
		// Return an array of free product values
		$output = array ( 'id' => $get_1_free['products_free_id'],
						  'quantity' => $free_quantity,
						  'name' => $products_free['products_name'],
						  'model' => $products_free['products_model'],
						  'image' => $products_free['products_image'],
						  'weight' => $products_free['products_weight']
						);
		return $output;
	  } //if ($products_quantity
	} //else
  }//if (tep_db_num_rows
  // offer was not valid (disabled or expired)
  return false;
}//function
// end Get 1 Free


// added for Separate Pricing Per Customer, returns customer_group_id
function get_customer_group_id() {
  if (isset($_SESSION['sppc_customer_group_id']) && $_SESSION['sppc_customer_group_id'] != '0') {
	$_cg_id = $_SESSION['sppc_customer_group_id'];
  } else {
	 $_cg_id = 0;
  }
  return $_cg_id;
}


 }
?>

Edited by Jan Zonjee
Link to comment
Share on other sites

For example, the selling price is $35, buy 2 will be $33 each. If I buy two items, the shopping chart show $66, but subtotal shows $70.

Looks like you left too much code from SPPC in there. This part should be removed (in function calculate). It nullifies what QPBPP has just calculated.

/*		  $specials_query = tep_db_query("select specials_new_products_price from " . TABLE_SPECIALS . " where products_id = '" . (int)$prid . "' and status = '1'");
	  if (tep_db_num_rows ($specials_query)) {
		$specials = tep_db_fetch_array($specials_query);
		$products_price = $specials['specials_new_products_price'];
	  }  */

	  // BOF Separate Pricing Per Customer
  $specials_price = tep_get_products_special_price((int)$prid);
  if (tep_not_null($specials_price)) {
 $products_price = $specials_price;
  } elseif ($this->cg_id != 0){
	$customer_group_price_query = tep_db_query("select customers_group_price from " . TABLE_PRODUCTS_GROUPS . " where products_id = '" . (int)$prid . "' and customers_group_id =  '" . $this->cg_id . "'");
	if ($customer_group_price = tep_db_fetch_array($customer_group_price_query)) {
	$products_price = $customer_group_price['customers_group_price'];
	}
  }
// EOF Separate Pricing Per Customer

Link to comment
Share on other sites

Well, that is the way osC calculates because you can have more than one attribute for a product (say a T-Shirt: price and color). But there is a contribution named something like Actual price in drop-down of attributes where instead of + or - an amount, the actual price calculated with + - (or the price when it costs nothing) is displayed.

 

Yes, thanks - I've tried Actual Attribute Price (http://www.oscommerce.com/community/contributions,1716) but couldn't get it to work - maybe not SPPC compatible? I also looked at "Actualy Price in Pull down option menus" (http://addons.oscommerce.com/info/716) and couldn't find the code to replace.

 

Anyone successfully integrated either of these contribs with SPPC? What I want is basically this:

 

Regular pet owner logs in and sees different size options for dog food.

- 20 lbs (29.99)

- 40 lbs (53.99)

- etc.

 

Animal shelter logs in and sees the following

- 20 lbs (19.99)

- 40 lbs (43.99)

- etc.

 

Anyone got a clue how to do this?

 

Thanks so much!

Audrey

Link to comment
Share on other sites

Thanks a bunch - it works!!! I was looking for the wrong code to replace. Only one issue thus far. All I see in "my account" is this:

 

1054 - Unknown column 's.public_flag' in 'where clause'

 

select count(*) as total from orders o, orders_status s where o.customers_id = '2' and o.orders_status = s.orders_status_id and s.language_id = '1' and s.public_flag = '1'

 

[TEP STOP]

 

My Account Information

 

I can't seem to figure out what's wrong. :-\

Link to comment
Share on other sites

Is there a quick way to copy specials from one customer group to another?

Yes (say customer_group_id 2 for example)

insert into specials select NULL as specials_id, products_id, specials_new_products_price, specials_date_added, specials_last_modified, expires_date, date_status_change, status, '2' as customers_group_id from specials where customers_group_id = '0';

Of course if you want a fraction of the price you would need something like (0.9 * specials_new_products_price) as specials_new_products_price.

Link to comment
Share on other sites

1054 - Unknown column 's.public_flag' in 'where clause'

 

select count(*) as total from orders o, orders_status s where o.customers_id = '2' and o.orders_status = s.orders_status_id and s.language_id = '1' and s.public_flag = '1'

I guess you used a file from the package (which is for RC2) but used an older version of osC to install this on. This particular one is caused by a few changes in the table orders (see upgrade.html in the download of RC2a for all the changes):

alter table orders_status add public_flag int DEFAULT '1';
alter table orders_status add downloads_flag int DEFAULT '0';
alter table orders modify payment_method varchar(255) NOT NULL;

There is also a change in the table whos_online:

alter table whos_online modify last_page_url text NOT NULL;

and there are a lot more changes that add certain indexes to certain tables. These indexes are not essential from a functional viewpoint but they make queries faster.

 

You might run into more of those things. Missing function tep_hide_session_id in the admin section, something with a missing function in the class currencies (catalog side) depending on which version you started with.
Link to comment
Share on other sites

Hi, and thank you for a very handy contribution, honors to Jan and all who have participated!

 

I have two questions:

 

Q1: I am using both English and Swedish in the admin area, do I need to install Swedish admin files as well?

(Easily done, just copying the English files and translate the admin text)

 

Q2: Will the TVA Intracom work with SPPC?

(I use this contrib in order to check if the VAT number is valid eithin the EU/EES area).

 

My site is a MS2.2 Visit My Website

 

Thanks in advance.

 

Sara

Link to comment
Share on other sites

Hi Everyone

 

Is anyone using this with the Individual boxes with Graphical borders (http://addons.oscommerce.com/info/1702) contribution?

 

This is a good contribution and i had a feeling it would conflict with SPPC.

 

Error i am having is this:

 

Parse error: syntax error, unexpected T_STRING, expecting ')' in C:\xampp\htdocs\shop\catalog\includes\modules\new_products.php on line 131

 

If anyone else is using the above contribution could you help me maybe others with how to interate this with SPPC

Link to comment
Share on other sites

Chris,

 

I would suggested implementing one new contribution at a time. Always make a backup of your working store before starting the editing to add the next contribution. A program like WinMerge can be highly useful for comparing files. I have many contributions running with SPPC (including Discount Coupon Codes). The difficulty happens when two contributions want to modify the same bit of stock osC code. You then have to know enough PHP to know how to re-write the code for both contributions, OR you can get advice from one of the contributions creators on how to get the two working together.

 

Another tip I found highly useful, is to do a site search using Google to search the forums for an error to see if someone else has already had this error and has the fix posted. You can do this by entering the following into the search box on google:

 

site:www.oscommerce.com/forums "my error here inside the quotes" +contribution I'm installing here

 

Remember, text inside of a quote causes the search engine to look for that text string. So if it has your unique domain name in the string then the engine won't find that - so you will either want to only enter up to the unique info into the quotes, or enter it all but with no quotes.

 

Hope that helps

 

 

Jan,

 

I am not easily offended. Your defensive posture about SPPC is warranted. My intention wasn't get put you on the defensive, SPPC works very well, as long as the site designer doesn't want to utilize other contributions as well. After reviewing the contributions again, it is obvious that members are creating contributions around the SPPC contribution and this is why I was asking if anyone had re-written code around SPPC that would allow me to integrate the 3 other contributions I am trying to install.

 

Thank you again for your response.

 

 

Chris

~Tracy
 

Link to comment
Share on other sites

Has anyone sent you the files yet? If not, PM me with your email address and which files you need help with and I will send them over to you ;)

 

 

Has anyone been able to get SPPC and Master/Slave contributions to work together? If so, would you consider sending me the applicable files? Thanks!

~Tracy
 

Link to comment
Share on other sites

Yeah, working on getting it all figured out :blush:

 

Hopefully starting fresh today after a nice long weekend will help my brain to get it all working today :rolleyes:

 

Pretty extensive rewrite of the product_listing module really. Hard to advice you on this but you would need to find out which slave products belong to which master and then group them. But I guess you knew that already.

~Tracy
 

Link to comment
Share on other sites

Hey Jan,

 

Do you happen to know if anyone has managed this before?

 

Aaarrgghh. Apparently, email won't work - it needs a unique id from the database tables specific to phpList (I have the tables in the same database as osC). I have to figure out where that id is to pull a query for it - but in the meantime, if anyone knows how to make the below work it will be a great help as whether I'm pulling an email address or a unique id I will need to code them similarly :blush:

~Tracy
 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...