How To skip the Duplicate price items while adding to cart? - selenium

I am trying to add the items to the cart which are not same Price Items below is my code:
List<WebElement> priceSpans = getDriver().findElements(By.xpath("//div[#class='m-product-mini']//a//span[(contains(text(),'$')) and not(contains(#class,'priceTag-discount'))]"));
List<Double> priceOfProducts = new ArrayList<Double>();
for (WebElement webElement : priceSpans)
{
String priceText = webElement.getText();
if (priceText != null && priceText.length() > 0)
{
Double priceValue = Double.parseDouble(priceText.replace('$', ' ').trim());
priceOfProducts.add(priceValue);
System.out.println("The PLP Products Price are:" + priceValue);
}
}
Using the above code to print the price and below is the output:
The PLP Products Price are:69.99 The PLP Products Price are:64.99 The PLP Products Price are:59.99 The PLP Products Price are:54.99 The PLP Products Price are:49.99 The PLP Products Price are:59.99 The PLP Products Price are:39.99 The PLP Products Price are:79.99 The PLP Products Price are:119.99 The PLP Products Price are:69.99 The PLP Products Price are:79.99 The PLP Products Price are:119.99 The PLP Products Price are:69.99 The PLP Products Price are:119.99
So there are duplicate prices so how do I skip the duplicate one and how do I choose only one from the duplicate (i.e 2 products contains the same price ex:59.99 )

Simplest Solution, Just keep adding Current priceText to dummy String stringSoFar, and then check if that pricetext is already present in stringSoFar:
String stringSoFar="";
int counter=0;
for (WebElement webElement : priceSpans){
List<WebElement> refreshedPriceSpans = getDriver().findElements(By.xpath("//div[#class='m-product-mini']//a//span[(contains(text(),'$')) and not(contains(#class,'priceTag-discount'))]")); //to avoid stale exception
String priceText = refreshedPriceSpans.get(counter).getText();
stringSoFar = stringSoFar + priceText;
if (priceText != null && priceText.length() > 0 && !stringSoFar.contains(priceText))
{
Double priceValue = Double.parseDouble(priceText.replace('$', ' ').trim());
priceOfProducts.add(priceValue);
System.out.println("The PLP Products Price are:"+ priceValue);
}
counter++;
}

what about if we use Set, it self avoid duplicate values, where we can minimize if conditions
Set<Double> priceOfProducts = new HashSet<Double>();

You can use Map to avoid duplicate prices, check example code below.
In the map key is price and value is WebElement.
List<WebElement> priceSpans = getDriver().findElements(By.xpath("//div[#class='m-product-mini']//a//span[(contains(text(),'$')) and not(contains(#class,'priceTag-discount'))]"));
HashMap<Double, WebElement> priceOfProducts = new HashMap<>();
for (int i = 0; i < priceSpans.size(); i++) {
Double priceValue = Double.parseDouble(priceSpans.get(i).getText().replace('$', ' ').trim());
priceOfProducts.put(priceValue, priceSpans.get(i));
//System.out.println("The PLP Products Price are: " + priceValue);
}
priceOfProducts.forEach((k,v) -> System.out.println("The PLP Products Price are: " + k));

One thing before we get started, with your current code priceText is never going to equal null or be zero length because your XPath requires at least a '$' so you can remove the if check.
After that, you should take some time to look into Java streams. You can use them to do all kinds of collection processing, etc. like what you are doing here. Explanation of the different steps are in the code comments below.
By locator = By.xpath("//div[#class='m-product-mini']//a//span[(contains(text(),'$')) and not(contains(#class,'priceTag-discount'))]");
List<Double> priceOfProducts = getDriver().findElements(locator)
.stream() // turns the collection of WebElements into a stream
.map(e -> e.getText().replace("$", "").trim()) // turns the collection of WebElements into a collection of string (from .getText()), removes the '$', and trim()s
.distinct() // removes duplicates
.map(e -> Double.parseDouble(e)) // converts String to Double
.collect(Collectors.toList()); // the final piece... returns a List<Double>
priceOfProducts.forEach(System.out::println);
Since we don't have the original HTML, I mocked up some HTML with some different prices, extra whitespace all over, including one duplicate
<div id="base">
<span> $0.99 </span>
<span>$1.99 </span>
<span> $1.99 </span>
<span> $2.99 </span>
</div>
When I run the code on the HTML above (with an appropriate locator, By.cssSelector("#base > span")), I get the output
0.99
1.99
2.99
NOTE: You will need to add an import for the stream related code, import java.util.stream.Collectors;. Your IDE should help you with this but just in case...

Related

Relate/combine 2 different xpath Java Selenium

This url will show the search result of a product in Amazon site.
https://www.amazon.com/s?k=yellow+puma+shoes&s=price-asc-rank&qid=1559364287&ref=sr_st_price-asc-rank
Using this xpath I can get product name
//span[#class='a-size-base-plus a-color-base a-text-normal']
Using this xpath I can get price
//span[#class='a-offscreen']
Is there a way to combine these 2 so that I can relate product name with price. 1 Way I can think of is:
//span[#class='a-size-base-plus a-color-base a-text-normal']
List<WebElements> allProductNames**** Save them in a list. Then run a for loop
for()
{
text = getText
//span[text()='PUMA Mens Basket Classic']/../../../../../..//span[#class='a-offscreen']
}
If you have an idea for easier solution kindly suggest. Thanks in advance.
I would rather get all the items and then iterate through each of them with in a loop as shown below.
// get all products
List<WebElement> products = driver.findElements(By.xpath("//span[#data-component-type='s-search-results']//div[#class='sg-row'][2]"));
// create a map (consider it as dictionary that to hold key value pair) to hold product and price
Map<String, String> map = new HashMap<String, String>();
for (WebElement product : products) {
String item = "";
String price = "";
// get product name
item = product.findElement(By.xpath(".//span[#class='a-size-base-plus a-color-base a-text-normal']")).getText();
// get product price (some products have range so we have to get the prices and display)
List<WebElement> prices = product.findElements(By.xpath(".//span[#class='a-offscreen']"));
for (WebElement pPrice : prices) {
if (price !=""){
price = price + "-" + pPrice.getAttribute("textContent");
}else {
price = pPrice.getAttribute("textContent");
}
}
// push the product and price to the map
map.put(item, price);
}
System.out.println(map);

Automatically increase stock after order - Prestashop

I manually manage my stocks on Prestashop. I am looking for a solution to automatically return the initial stock after a sales order.
For example, a product is ordered in two copies with an initial stock of 7. I would like the stock to remain at 7 after the order and not at 5.
Do you know a technique that would allow me to realize this automatically?
Put a Hook on Order Confirmation (displayOrderConfirmation) in a new module (you can generate one at https://validator.prestashop.com/) and check whats inside the cart then put it again in your stocks :
public function hookDisplayOrderConfirmation($params) {
$order = $params['order'];
$cart = new Cart($order->id_cart);
$products = $cart->getProducts();
foreach ($products as $product) {
$removed_qty = (int) $product['quantity'];
$past_qty = (int) StockAvailable::getQuantityAvailableByProduct($product['id_product'], $product['id_product_attribute']);
$new_qty = $removed_qty + $past_qty;
StockAvailable::setQuantity($product['id_product'], $product['id_product_attribute'], $new_qty);
}
}

How to access order data on Big Commerce on confirmation screen

I need to add some JavaScript to the order confirmation page that includes details about the order. Although I can access the order id through a BigCommerce global variable, I cannot work out how to get the rest of the order details into my JavaScript.
For instance, I can access the BigCommerce order_id global %%GLOBAL_OrderId%% and use that in a JavaScript alert, but I also need to access the following:
order total
order tax
order shipping
order postcode
And foreach product in the order
product_id
unit_price
quantity
There these global items but when I try to access them they are blank, I presume that I need to loop through the cart contents.
%%GLOBAL_ProductModel%%
%%GLOBAL_ProductPrice%%
%%GLOBAL_ProductQty%%
I have read all the docs I can find. Can anyone give me an idea of how to achieve this. I need the values so I can pass them to a third party JS function for their use. All of that is waiting and ready but I cannot get the data out of Big Commerce templating system. The data is there, on the order.html template page, as the social sharing panel reads it, but again I cannot see how the social sharing snippet is accessing it.
I created a hacky script just for you that pulls the product data (as well as some order details).
It parses the data from the %%GLOBAL_ConversionCode%% template variable, and as such this script should be inserted in order.html immediately after the %%GLOBAL_ConversionCode%% variable.
Specifically, %%GLOBAL_ConversionCode%% outputs to:
<!-- Include the conversion tracking code for all analytics packages -->
<!-- Start conversion code for analytics_googleanalytics -->
<script type="text/javascript">
if(typeof(pageTracker) != 'undefined') {
pageTracker._addTrans(
'196',
'store-name',
'0.00',
'2.12',
'1.92',
'Austin',
'Texas',
'United States'
);
pageTracker._addItem(
'196',
'2004',
'TAKE YOUR TIME: Sweet Body Butter',
'',
'24.96',
'1'
);
pageTracker._trackTrans();
}
</script>
Solution:
<script>
//-------------- Main --------------//
//** Create the order data array from analytics script **//
var data = parseAnalyticsData(getAnalyticsScript());
//console.log(data);
/**
* Retrieve the order details as an object, properties are:
* id - The order ID.
* shipping - The order shipping cost.
* tax - The order tax cost.
* shippingTax - The order shipping tax cost.
* city - The order shipping city.
* state - The order shipping state.
* country - The order shipping country.
*/
var orderDetails = getOrderDetails(data);
console.log("Order ID = %d", orderDetails.id);
console.log("Order shipping city = %s", orderDetails.city);
console.log("Order subtotal = %f", orderDetails.subtotal);
/**
* Retrieve the order product details, as an array of product objects.
* Properties are:
* id - The product ID.
* description - The product description.
* tax - The product tax cost.
* price - The product price per product.
* qty - The product quantity purchased.
*/
var products = getOrderProducts(data);
//** Loop through the products array to access each product **//
console.log("Total number of products = %d", products.length);
for (x=0; x<products.length; x++) {
console.log("--------");
console.log("Item # ", x+1);
console.log("Product ID = %f", products[x].id);
console.log("Product QTY = %f", products[x].qty);
console.log("Product Price = %f", products[x].price);
console.log("--------");
}
//-------------- Functions --------------//
/**
* Parses the DOM to retrieve the order data analytics script.
*/
function getAnalyticsScript() {
var scripts = document.getElementsByTagName('script');
var thisScriptTag = scripts[scripts.length - 2];
var data = thisScriptTag.textContent || thisScriptTag.innerText;
return data;
}
/**
* Parses the raw analytics script element to remove all script
* text, and parse just the order related data into an array.
* #param script <String> - The raw order analytics script.
* #return <mixed> - Array containing the order data.
*/
function parseAnalyticsData(data) {
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
// This is hacky, and probably inefficient, but it removes all
// script related text, so the end result is just a comma separated
// array of the order and product data.
data = data.replace("if(typeof(pageTracker) != 'undefined') {", '');
data = data.replaceAll( 'pageTracker._addTrans(', '');
data = data.replaceAll( ' pageTracker._trackTrans();', '');
data = data.replaceAll( 'pageTracker._addItem(', '');
data = data.replaceAll(');', '');
data = data.replace('}', '');
data = data.replace( /\n/g, ",").replaceAll( ",,",",");
data = data.replace(/\s/g,'');
data = data.split(',');
data = cleanArray(data); // Remove all empty values from array.
return data;
}
/**
* Removes all empty data from array.
* #param array <mixed> - The array to clean.
*/
function cleanArray(array) {
var newArray = new Array();
for (var i = 0; i < array.length; i++) {
if (array[i]) {
newArray.push(array[i]);
}
}
return newArray;
}
/**
* Parse Analytics Data for Order Details
* #param data <mixed> - The order analytics data.
* #return <mixed> - Object containing the order details.
*/
function getOrderDetails(data) {
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
return {
id : parseFloat(data[0].replaceAll("'",'')),
subtotal : ( parseFloat(data[2].replaceAll("'",'')) - (parseFloat(data[3].replaceAll("'",'')) + parseFloat(data[4].replaceAll("'",'')) ) ),
total : parseFloat(data[2].replaceAll("'",'')),
tax : parseFloat(data[3].replaceAll("'",'')),
shipping : parseFloat(data[4].replaceAll("'",'')),
city : data[5].replaceAll("'",''),
state : data[6].replaceAll("'",''),
country : data[7].replaceAll("'",'')
}
}
/**
* Parse Analytics Data for All Order Product Details.
* #param data <mixed> - The order analytics data.
* #return <mixed> - Array containing individual product details.
*/
function getOrderProducts(data) {
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
var counter = -1; // Keep index of details per product.
var productsArray = []; // Init empty array to hold all products.
var product = {}; // Init empty object to hold single product data.
//** Product data starts at index 8 **//
for (x=8; x<data.length; x++) {
counter++;
switch (counter) {
case 1:
product.id = parseFloat(data[x].replaceAll("'",''));
break;
case 2:
product.description = data[x].replaceAll("'",'');
break;
case 3:
product.tax = parseFloat(data[x].replaceAll("'",''));
break;
case 4:
product.price = parseFloat(data[x].replaceAll("'",''));
break;
case 5:
product.qty = parseFloat(data[x].replaceAll("'",''));
counter = -1; // reset counter
productsArray.push(product); // push product to products array
product = {};
break;
}
}
return productsArray;
}
</script>

how to update(subtract) the value of database after customer order ASP.NET

i have an add product function and it registers well in my database. it looks like this
after that, customer orders and what i have currently is that it only updates the label (available stock) not in the database. here is my code for that after button click:
DataTable dtResult = k.SaveCustomerDetails();
for (int i = 0; i < dt.Rows.Count; i++) // loop on how many products are added by the user
{
ShoppingCart SaveProducts = new ShoppingCart()
{
CustomerID = Convert.ToInt32(dtResult.Rows[0][0]),
ProductID = Convert.ToInt32(dt.Rows[i]["ProductID"]),
TotalProducts = Convert.ToInt32(dt.Rows[i]["ProductQuantity"]), //subtracts the product quantity depending
//on the customer order
};
SaveProducts.SaveCustomerProducts();
}
var customerId = Convert.ToInt32(dtResult.Rows[0][0]);
Response.Redirect(String.Format("OrderSummary.aspx?Id={0}", customerId.ToString()));
what I want to happen is to update the product quantity as well in the database? any idea on how to do it? please and thank you sirs

Magento cart error "Maximum one item to add the shopping cart."

I checked the option in the system -> config -> Inventory and it's set to 1000 the Maximum Qty Allowed in Shopping Cart i can add the same product so it supplements the Qty of that product by one more, but if i add another product i get this Maximum Qty Allowed in Shopping Cart , any idea how can i fix the cart so i will be able to add more items to the cart ?
PS: i have Magento ver. 1.6.1.0
Thanks all in advance!
I would like to recommend you to do the following:
First check system -> config -> Inventory settings for all your stores. Typically users get such errors when the settings are inappropriate on different store leves.
But if you get this error adding another product, then go to the Inventory tab of your product and check whether the Maximum Qty Allowed in Shopping Cart is populated correctly.
Your error 'Maximum one item to add the shopping cart.' is quite unique and it's actually a custom error not native to Magento. I've found it in some code of a client of mine. You'll have to look for the following code blocks in a few files:
if ($cartItems >= 1) {
Mage::getSingleton('core/session')->addError($this->__('Maximum one item to add the shopping cart.'));
$this->_goBack();
return;
}
and
if ($params['product'] != $productId) {
if ($cartItems >= 1) {
$this->_getSession()->addError($this->__('Maximum one item to add the shopping cart.'));
$this->_goBack();
return;
}
}
and
if ($params['product'] != $productId) {
if ($cartItems > 1) {
Mage::getSingleton('checkout/session')->addError($this->__('Maximum one product to add the shopping cart.'));
$this->_redirect('checkout/cart');
return;
}
}
and
if ($item->getProductId() != $productId) {
if ($cartItems >= 1) {
$this->_getSession()->addError($this->__('Maximum one item to add the shopping cart.'));
$this->_goBack();
return;
}
}
You'll be likely to find them in /app/code/local/{Name}/{Module}/controllers/Checkout/CartController.php /app/code/local/{Name}/{Module}/controllers/Checkout/OnepageController.php /app/code/local/{Name}/{Module}/controllers/Sales/OrderController.php
Mentionably, {Name} is not necessarily limited to one extension... I've found it in multiple, perform a search all through all the files in /app/code/local to be sure.
In order to 'fix' it, either change the '1' in if ($cartItems > 1) { to some other (higher) number, or comment that if statement out and replace it with if(false) {.
if ($params['product'] != $productId) {
if ($cartItems > 1) {
Mage::getSingleton('checkout/session')->addError($this->__('Maximum one product to add the shopping cart.'));
$this->_redirect('checkout/cart');
return;
}
}