How to display multiple Offer and price with custom text? - schema.org

In Google Rich Text SEO, I want google to display 2 offers to my product page in search as
Offers
$5 to $15 // the first line
Sale Price: $20 Member Price: $5 // second line
{
"#context":"http://schema.org",
"#type":"Product",
"name":"Different retail prices same compare at prices",
"image":"//example-img.jpg",
"description":"V Neck top",
"brand":{
"#type":"Brand",
"name":"My Brand"
},
"sku":"1162-BLK-XL",
"gtin12":"",
"offers":{
"#type":"AggregateOffer",
"url":"/products/XYZ",
"priceCurrency":"USD",
"lowPrice":"5.00",
"highPrice": "15.00",
"offerCount":"1",
"itemCondition":"http://schema.org/NewCondition",
"availability":"http://schema.org/InStock",
"seller":{
"#type":"Organization",
"name":"XYZ"
},
"offers": [{
"type": "Offer",
"lowPrice": "Sell Price 5.00",
"highPrice": "Member Price 3.00"
}]
}
}
And it is showing just -
How can I achieve the above?
Any help would be appreciated.

Related

Rounding tax amount for Paypal

In a US e-commerce webshop I am looking for input on how to solve an issue with Paypal Orders API
Example
The price per lamp excluding tax is $1547
A customer adds 2 of these lamps to his shopping basket
A third party service will calculate the tax amount for the two lamps to be $274.59
The total price for 2 lamps including tax is
2*1547 + 274.59 = $3368.59
When paying using Paypal we need to send the different amounts to Paypal Orders API.
This is where the issue occur with the tax amount.
Paypal want's it "pr unit", meaning 274.59 / 2 = $137.295
But Paypal will only accept 2 digits :-(
Below is how the order should be sent if 3 digits was allowed:
"purchase_units": [{
"amount": {
"currency_code": "USD",
"value": "3368.59",
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": "3094"
},
"tax_total": {
"currency_code": "USD",
"value": "274.59"
}
}
},
"items": [{
"name": "Oval lamp",
"tax": {
"currency_code": "USD",
"value": "137.295"
},
"unit_amount": {
"currency_code": "USD",
"value": "1547"
},
"quantity": "2"
}
]]
This will give me an error:
"details": [
{
"field": "/purchase_units/0item/0/tax/value",
"value": "137.295",
"issue": "DECIMAL_PRECISION",
"description": "If the currency supports decimals, only two decimal place precision is supported."
}
]
If I then round the tax from $137.295 to $137.30 I get this error:
"details": [
{
"field": "/purchase_units/0/amount/breakdown/tax_total/value",
"value": "274.59",
"issue": "TAX_TOTAL_MISMATCH",
"description": "Should equal sum of (tax * quantity) across all items for a given purchase_unit"
}
]
If I update the total tax amount from 274.59 to 274.6 I get this error:
"details": [
{
"field": "/purchase_units/0/amount/value",
"value": "3368.59",
"issue": "AMOUNT_MISMATCH",
"description": "Should equal item_total + tax_total + shipping + handling + insurance - shipping_discount - discount."
}
]
My only option now is to change the total amount from $3368.59 to $3368.6, but that is not correct!
Any input is appreciated
Not much to say here--your question has the solution. Calculate the tax per item, round up or down as appropriate, and you'll have a different tax total. Use that.
If you want to adjust the order total to some different calculation, you'll need to add another line item with the positive or negative amount.

Confused about how #id in structured data works

Basically, I'm trying to add BlogPosting, TechArticle and WebPage structured data types to my posts, but I'm getting errors in Google's structured data testing tool. They seem to be centred around when I link back to an Organization structured data type I've defined on my homepage, to save me having to repeat the same code across multiple pages.
Here's the structured data testing tool instance. Can anybody explain how I can properly link to the Organization data type (which is sitting on my homepage) in the author, creator and publisher properties?
https://search.google.com/structured-data/testing-tool#url=https%3A%2F%2Fwww.lukeharrison.dev%2Farticles%2Fmike-brewer-motors-wins-best-online-experience-at-autotraders-2018-retailer-awards%2F
I feel as though it may be down to me not fully understanding the #id property, and how to properly can use it to link structured data together to reduce repetitive data.
Here's the code involved:
The BlogPosting
The linked Organisation
The errors I'm receiving
Example of BlogPosting
{
"#context": "http://schema.org",
"#type": "BlogPosting",
"about": "Great news! Mike Brewer Motors - a project I've been heavily involved in over the past few years - has won the 'Best Online Experience' at the Autotrader 2018 Retailer Awards.",
"articleSection": "Blog Posts",
"author": {
"id": "https://www.lukeharrison.dev#organization"
},
"copyrightHolder": {
"id": "https://www.lukeharrison.dev#person"
},
"copyrightYear": "2019",
"creator": {
"id": "https://www.lukeharrison.dev#organization"
},
"dateCreated": "2018-07-20",
"dateModified": "2018-07-20",
"datePublished": "2018-07-20",
"description": "Great news! Mike Brewer Motors - a project I've been heavily involved in over the past few years - has won the 'Best Online Experience' at the Autotrader 2018 Retailer Awards.",
"genre": "Web Design & Front-End Development",
"headline": "Mike Brewer Motors wins 'Best Online Experience' at Autotrader's 2018 Retailer Awards - Luke Harrison",
"image": {
"#type": "ImageObject",
"height": 512,
"url": "https://s.gravatar.com/avatar/c34b34964896ad0552a5b342ae08c1e2?s=512",
"width": 512
},
"inLanguage": "en-GB",
"isFamilyFriendly": "true",
"keywords": [
"news"
],
"mainEntityOfPage": "https://www.lukeharrison.dev/articles/mike-brewer-motors-wins-best-online-experience-at-autotraders-2018-retailer-awards",
"publisher": {
"id": "https://www.lukeharrison.dev#organization"
}
}
Example linked Organization, which sits on another page
{
"#context": "http://schema.org",
"#id": "https://www.lukeharrison.dev#organization",
"#type": "Organization",
"additionalType": [
"http://www.productontology.org/id/Web_design",
"http://www.productontology.org/doc/Search_engine_optimization",
"http://www.productontology.org/doc/Web_development"
],
"foundingDate": "2013",
"legalName": "Luke Harrison - UX / Web Developer",
"logo": "https://www.lukeharrison.dev/img/share-26bfb69f23.png",
"name": "Luke Harrison - UX / Web Developer",
"sameAs": [
"https://twitter.com/webdevluke?lang=en-gb",
"https://www.linkedin.com/in/lukedidit/",
"https://github.com/WebDevLuke",
"https://codepen.io/lukedidit/"
],
"url": "https://www.lukeharrison.dev"
}
The errors I'm receiving in my BlogPosting structure
author, creator and publisher:
The attribute publisher.itemtype has an invalid value.
A value for the name field is required.
The errors are about Google’s Article rich result (if you don’t want to get this rich result, you can ignore these errors).
For AMP pages, author and publisher are required properties. They require actual items as value, #id references are not supported. You can still provide the #id, but you need to specify the #type and the required properties in addition.

Fix SDTT warning on JobPosting: "The value field is recommended."

On the Google Structured Data Testing Tool I get a warning for not entering a value in the baseSalary property.
The value field is recommended. Please provide a value if available.
However, I have added a value.
{
"#context": "http://schema.org",
"#type": "JobPosting",
"hiringOrganization": "Google",
"validThrough": "2018-12-31T00:00",
"baseSalary": {
"#type": "MonetaryAmount",
"currency": "USD",
"value": {
"#type": "QuantitativeValue",
"minValue": 40.00,
"maxValue": 50.00,
"unitText": "HOUR"
}
},
"jobBenefits": "Medical, Life, Dental",
"datePosted": "2011-10-31",
"description": "Description: ABC Company Inc. seeks a full-time mid-level software engineer to develop in-house tools.",
"educationRequirements": "Bachelor's Degree in Computer Science, Information Systems or related fields of study.",
"employmentType": "Full-time",
"experienceRequirements": "Minumum 3 years experience as a software engineer",
"incentiveCompensation": "Performance-based annual bonus plan, project-completion bonuses",
"industry": "Computer Software",
"jobLocation": {
"#type": "Place",
"address": {
"#type": "PostalAddress",
"addressLocality": "Poole",
"addressRegion": "Dorset",
"streetAddress": "33 Holton Road",
"postalCode": "BH16 6LT"
}
},
"occupationalCategory": "15-1132.00 Software Developers, Application",
"qualifications": "Ability to work in a team environment with members of varying skill levels. Highly motivated. Learns quickly.",
"responsibilities": "Design and write specifications for tools for in-house customers Build tools according to specifications",
"salaryCurrency": "USD",
"skills": "Web application development using Java/J2EE Web application development using Python or familiarity with dynamic programming languages",
"specialCommitments": "VeteranCommit",
"title": "Software Engineer",
"workHours": "40 hours per week"
}
Could someone please provide a fix so the code passes the Google Structured Data Testing Tool?
Your code violates the standard:
baseSalary doesn't contain something like hours, but only currency and the value or range.
Beside of this there is a inconsistency:
you write on one place:
"minValue": 40.00,
"maxValue": 50.00,
"unitText": "HOUR"
On another place:
"workHours": "40 hours per week"
What now? 40 hours or between 40 and 50?
Another thing: workHours are not for amount of working hours per week, but for typical beginning and ending of shift.

How to create a Subscription payment using Paypal client-side rest api?

The Client-side REST integration documentaion describes about creating a express checkout for one or more items.
How can i use the same for creating a subscription or Recurring payment? How should the following be modified?
payment: function(data, actions) {
return actions.payment.create({
transactions: [
{
amount: { total: '1.00', currency: 'USD' }
}
]
});
},
I found a similar Rest api for Node. Not sure how it would be on JS.
First you need to create a billing plan:
billing_plan_attributes = {
"name": PLAN_NAME_HERE,
"description": PLAN_DESCRIPTION,
"merchant_preferences": {
"auto_bill_amount": "yes", # yes if you want auto bill
"cancel_url": "http://www.cancel.com", # redirect uri if user cancels payment
"initial_fail_amount_action": "continue",
"max_fail_attempts": "1",
"return_url": RETURN_URL,
"setup_fee": {
"currency": CURRENCY,
"value": VALUE # how much do you want to charge
}
},
"payment_definitions": [
{
"amount": {
"currency": request.form['currency'],
"value": request.form['amount']
},
"cycles": CYCLES, # how much time this subscription will charge user
"frequency": FREQ, # month, day
"frequency_interval": INTERVAL, # per month or per three month or so on
"name": NAME,
"type": TYPE
}
],
"type": TYPE
}
billing_plan = BillingPlan(billing_plan_attributes)
if billing_plan.create():
print("success")
The attributes used have literal meaning here. Now since you have created a billing plan you need to give users some interface so that they can subscribe with it. Below is a sample code for this:
billing_agreement = BillingAgreement({
"name": "Organization plan name",
"description": "Agreement for " + request.args.get('name', ''),
"start_date": (datetime.now() + timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'),
"plan": {
"id": request.args.get('id', '')
},
"payer": {
"payment_method": "paypal"
},
"shipping_address": {
"line1": "StayBr111idge Suites",
"line2": "Cro12ok Street",
"city": "San Jose",
"state": "CA",
"postal_code": "95112",
"country_code": "US"
}
})
if billing_agreement.create():
for link in billing_agreement.links:
if link.rel == "approval_url":
approval_url = link.href
In the last line you get the approval link which can be given to user.
Next you have to setup an endpoint which will be the callback url if user approves the payment.
billing_agreement_response = BillingAgreement.execute(payment_token)
payment_token is sent by paypal to your callback url.

Ionic "track by" error with tinder cards

I started learning Ionic 2 weeks ago and right now I am creating a small project to practice.You can download my project from my Github : https://github.com/KaanYildirim/ionicTest
I am trying to use tinder like cards which is created from the ionic team itself. (https://github.com/driftyco/ionic-ion-tinder-cards)
I have tried every possible solution with "track by" expression but I am still getting this error:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: card in cards track by card.id, Duplicate key: undefined, Duplicate value: undefined
I have tried to fix this error with "track by $index" and "track by card.id "(every card has an "id" attribute in .Json file) but it didn't worked. I guess that i made a small mistake and can't find it.
Can someone please help me? Thanks
index.html:
<td-cards>
<td-card ng-repeat="card in cards track by card.id" on-destroy="cardDestroyed($index)" on-swipe="cardSwiped($index)">
<div class="list card myCard">
<!-- Card Header-->
<div class="item topicDescription cardHeader">
<p>{{card.topicDescription}}</p>
</div>
<!-- Card Body-->
<div class="item item-body noBorder">
<img class="full-image" src="{{card.image}}">
<h3 class="cardTitle">{{card.title}}</h3>
<p>{{card.summary}}</p>
</div>
<!-- Card Footer-->
<div class="item tabs tabs-secondary tabs-icon-left cardFooter">
<a class="tab-item" ng-click="readMore($index)" href="#">
<i class="{{card.actionButtonIcon}}"></i>
{{card.actionButtonText}} {{card.type}} ( {{card.additionalInfo}} )
</a>
<a class="tab-item" ng-click="share($index)" href="#">
<i class="icon ion-share"></i>
Share
</a>
</div>
</div>
</td-card>
</td-cards>
Json File:
{
"articles": [
{
"id":1,
"topicDescription": "Find a Idea",
"image": "img/uber.jpg",
"title": "Uber Lowers Fares In Over 100 Cities",
"summary": "Uber is lowering prices in over 100 U.S. and Canadian cities, effective tomorrow. January is a slower month for the car service and the company says it is reducing fares in order to increase demand.",
"link": "http://techcrunch.com/2016/01/08/uber-lowers-fares-in-over-100-cities/",
"actionButtonIcon": "icon ion-ios-glasses-outline",
"actionButtonText": "Read",
"type":"Article",
"additionalInfo": "3 min"
},
{
"id":2,
"topicDescription": "Test a Idea",
"image": "img/lean.jpg",
"title": "The Lean Startup",
"summary": "Great book about startups and how to validate your idea without spending to much money and time.",
"link": "http://www.amazon.de/Lean-Startup-Innovation-Successful-Businesses/dp/0670921602/ref=sr_1_2?ie=UTF8&qid=1452779528&sr=8-2&keywords=the+lean+startup",
"actionButtonIcon": "icon ion-ios-bookmarks-outline",
"actionButtonText": "Buy",
"type":"Book",
"additionalInfo": "Amazon"
},
{
"id":3,
"topicDescription": "Build",
"image": "img/evernote.jpg",
"title": "Note Taking App",
"summary": "From short lists to lengthy research, no matter what form your writing takes, Evernote keeps you focused on moving those ideas from inspiration to completion.",
"link": "https://evernote.com/?var=3",
"actionButtonIcon": "icon ion-hammer",
"actionButtonText": "Download",
"type":"App",
"additionalInfo": "App Store"
},
{
"id":4,
"topicDescription": "Measure",
"image": "img/steve.jpg",
"title": "Steve Blank: How to Build a Great Company",
"summary": "Join Silicon Valley serial entrepreneur-turned-educator Blank in a lively discussion with Dan'l Lewin of Microsoft. This program will introduce best practices, lessons and tips that have swept the startup world, offering a wealth of proven advice and information for entrepreneurs of all stripes.",
"link": "https://www.youtube.com/watch?v=1RTcXwJuCaU",
"actionButtonIcon": "icon ion-ios-videocam-outline",
"actionButtonText": "Watch",
"type":"Video",
"additionalInfo": "Youtube"
},
{
"id":5,
"topicDescription": "Find a Idea",
"image": "img/uber.jpg",
"title": "Uber Lowers Fares In Over 100 Cities",
"summary": "Uber is lowering prices in over 100 U.S. and Canadian cities, effective tomorrow. January is a slower month for the car service and the company says it is reducing fares in order to increase demand.",
"link": "http://techcrunch.com/2016/01/08/uber-lowers-fares-in-over-100-cities/",
"actionButtonIcon": "icon ion-ios-glasses-outline",
"actionButtonText": "Read",
"type":"Article",
"additionalInfo": "3 min"
},
{
"id":6,
"topicDescription": "Test a Idea",
"image": "img/lean.jpg",
"title": "The Lean Startup",
"summary": "Great book about startups and how to validate your idea without spending to much money and time.",
"link": "http://www.amazon.de/Lean-Startup-Innovation-Successful-Businesses/dp/0670921602/ref=sr_1_2?ie=UTF8&qid=1452779528&sr=8-2&keywords=the+lean+startup",
"actionButtonIcon": "icon ion-ios-bookmarks-outline",
"actionButtonText": "Buy",
"type":"Book",
"additionalInfo": "Amazon"
},
{
"id":7,
"topicDescription": "Build",
"image": "img/evernote.jpg",
"title": "Note Taking App",
"summary": "From short lists to lengthy research, no matter what form your writing takes, Evernote keeps you focused on moving those ideas from inspiration to completion.",
"link": "https://evernote.com/?var=3",
"actionButtonIcon": "icon ion-hammer",
"actionButtonText": "Download",
"type":"App",
"additionalInfo": "App Store"
},
{
"id":8,
"topicDescription": "Measure",
"image": "img/steve.jpg",
"title": "Steve Blank: How to Build a Great Company",
"summary": "Join Silicon Valley serial entrepreneur-turned-educator Blank in a lively discussion with Dan'l Lewin of Microsoft. This program will introduce best practices, lessons and tips that have swept the startup world, offering a wealth of proven advice and information for entrepreneurs of all stripes.",
"link": "https://www.youtube.com/watch?v=1RTcXwJuCaU",
"actionButtonIcon": "icon ion-ios-videocam-outline",
"actionButtonText": "Watch",
"type":"Video",
"additionalInfo": "Youtube"
}
]
}
I examined your code. In your controllers.js file you handle the cardSwiped event by manually adding an undefined card to your list
$scope.cardSwiped = function(index) {
var newCard = // new card data
$scope.cards.push(newCard);
};
This causes your cards to have multiple undefined elements that ng-repeat will be forced to handle as duplicates. Remove/fix that handler and things should work.
BTW, this code will work normally because javascript will handle them as a single line var newCard = $scope.cards.push(newCard); This means at the end of the function your newCard variable will have the new length of the cards array.