Hi Dear,
I have trouble saving multiple items when I use the check out the system will remove all multiple items and print only one,
when I select multiple items the system will remove all, I found one item for each product.
I need to fix this problem.
import { SharedModule } from ‘…/…/app/shared.module’;
import { NgModule } from ‘@angular/core’;
import { IonicPageModule } from ‘ionic-angular’;
import { CheckoutPage } from ‘./checkout’;
@NgModule({
declarations: [
CheckoutPage
],
imports: [
IonicPageModule.forChild(CheckoutPage),
SharedModule
],
})
export class CheckoutPageModule {}
checkout.ts
import { Component } from ‘@angular/core’;
import { StatusBar } from ‘@ionic-native/status-bar’;
import { IonicPage, App, Platform, AlertController, NavController, Events, ModalController, NavParams } from ‘ionic-angular’;
import { AddressProvider, SettingsProvider, ToastProvider, UserProvider, LoadingProvider, CartProvider, WooCommerceProvider, OrderProvider } from ‘…/…/providers/providers’;
import { TranslateService } from ‘@ngx-translate/core’;
@IonicPage()
@Component({
selector: ‘page-checkout’,
templateUrl: ‘checkout.html’,
})
export class CheckoutPage {
checkout: string = “shipping”;
cart: any;
settings: any;
billing: any;
shipping: any;
zones: any;
shipping_lines: any[] = [];
shipping_method: any = [];
payments: any[] = [];
coupons: any[] = [];
tax: any;
order: any = {};
total: number = 0;
allowFreeShipping: boolean = false;
stripe: any = {
no: ‘’,
month: ‘’,
year: ‘’
};
razor: any = {};
coupon: any = {};
months: any = [‘January’, ‘February’, ‘March’, ‘April’, ‘May’, ‘June’, ‘July’, ‘August’, ‘September’, ‘October’, ‘November’, ‘December’];
years: any = [];
img: any = {
stripe: [
‘assets/img/logo/visa.svg’,
‘assets/img/logo/mastercard.svg’,
‘assets/img/logo/amex.svg’,
‘assets/img/logo/diners.svg’,
‘assets/img/logo/discover.svg’,
‘assets/img/logo/jcb.svg’
],
paypal: [
‘assets/img/logo/visa.svg’,
‘assets/img/logo/mastercard.svg’,
‘assets/img/logo/amex.svg’,
‘assets/img/logo/discover.svg’
],
razorpay: [
‘assets/img/logo/logo-razor.png’
]
};
constructor(private setting: SettingsProvider, private app: App, private statusBar: StatusBar, private alert: AlertController, private platform: Platform, private nav: NavController, private translate: TranslateService, private toast: ToastProvider, private user: UserProvider, private loader: LoadingProvider, private woo: WooCommerceProvider, private _cart: CartProvider, private events: Events, private _order: OrderProvider, private address: AddressProvider, public navParams: NavParams, public modal: ModalController) {
this.woo.loadPayments().then( x=> {
this.payments = x;
});
this.woo.loadCoupons().then( x=> {
this.coupons = x;
}, err => {
console.log(err);
})
this.cart = this._cart;
if(this.setting.all.zones.length <= 0){
this.loader.present();
this.woo.loadZones();
this.setting.load().then(x=>{
this.zones = x.zones;
this.loader.dismiss();
})
}else
this.zones = this.setting.all.zones;
this.woo.getTaxes().then( x=> {
this.tax = x;
console.log(x);
})
this.listenOrder();
}
ionViewDidEnter(){
if (this.platform.is(‘cordova’))
this.statusBar.styleDefault();
this.setOrder();
}
setOrder(){
if(this.address.getPrimary){
this.billing = this.address.getPrimary;
this.shipping = this.address.getPrimary;
}
if(this._order.billing)
this.billing = this._order.billing;
if(this._order.shipping)
this.shipping = this._order.shipping;
let tmp = (this.settings.value == 'shipping') ? this.shipping : this.billing;
if(this.shipping){
let id = this.woo.getSingleZone(this.setting.all.zones, this.shipping);
if(id){
this.loader.present();
this.woo.getShippingZoneMethod(id).then( x=> {
this.shipping_method = x;
this.loader.dismiss();
let tmp;
for(let i in x){
if(x[i].enabled && x[i].method_id == 'free_shipping'){
tmp = x[i].settings;
break;
}
}
if(tmp){
switch(tmp.requires.value){
case 'min_amount': // minimun order amount
if(tmp.min_amount.value && this.cart.total > parseInt(tmp.min_amount.value))
this.allowFreeShipping = true;
break;
case 'coupon': // coupon
if(this.coupon.description) // coupon valid
this.allowFreeShipping = true;
break;
case 'either': // minimun order amount or coupon
if(tmp.min_amount.value && this.cart.total > parseInt(tmp.min_amount.value) || this.coupon.description)
this.allowFreeShipping = true;
break;
case 'both': // minimun order amount and coupon
if(tmp.min_amount.value && this.cart.total > parseInt(tmp.min_amount.value) && this.coupon.description)
this.allowFreeShipping = true;
break;
default:
this.allowFreeShipping = true;
}
}
}, e=> {
console.log(e);
});
}else{
this.shipping_method = [];
this.translate.get(['NO_SHIPPING']).subscribe( x=> {
this.toast.showWithClose(x.NO_SHIPPING);
});
}
}else{
this.translate.get(['SELECT_SHIPPING']).subscribe( x=> {
this.toast.showWithClose(x.SELECT_SHIPPING);
});
}
}
viewCart(){
this.modal.create(‘MiniCartPage’, {isCheckout: true}, { cssClass: ‘inset-modal’ }).present();
}
setShipping(param){
this.shipping_lines = [];
let e = JSON.parse(param);
this.shipping_lines.push({
method_id: e.method_id,
method_title: e.title,
total: (e.settings.cost ? e.settings.cost.value : 0)
});
this.updateTotal();
this.total = this.cart.total + parseInt(this.shipping_lines[0].total);
}
setPayment(param){
this.years = [];
let e = JSON.parse(param);
this.order.payment_method = e.id;
this.order.payment_method_title = e.method_title;
this.order.payment_method_description = e.description;
if(e.id != ‘cod’) this.order.set_paid = true;
for(let i in this.payments)
this.payments[i].open = false;
for(let i in this.payments){
if(this.payments[i].id == e.id){
this.payments[i].open = true || !this.payments[i].open;
break;
}
}
if(e.id == 'stripe'){
if(e.settings.testmode.value == 'yes'){
this.stripe.publishable_key = e.settings.test_publishable_key.value;
this.stripe.secret_key = e.settings.test_secret_key.value;
}else{
this.stripe.publishable_key = e.settings.publishable_key.value;
this.stripe.secret_key = e.settings.secret_key.value;
}
for(let i=0; i<10; i++)
this.years.push(new Date().getFullYear() + i);
}
if(e.id == 'razorpay'){
if(e.settings.key_id.value)
this.razor.key = e.settings.key_id.value;
if(e.settings.key_secret.value)
this.razor.key = e.settings.key_secret.value;
}
}
listenOrder(){
this.events.subscribe(‘order:go’, (res) => {
this.setOrder();
});
}
selectAddress(action){
let params = {
action: action
}
this.modal.create(‘SavedAddressPage’, {params: params}).present();
}
addAddress(action){
let params = {
action: action
}
this.modal.create(‘AddAddressPage’, {params: params}).present();
}
next(){
this.checkout = ‘payment’;
}
isCouponValid(x){
console.log(this.coupon.input.toLowerCase());
console.log(x.toLowerCase());
return this.coupon.input.toLowerCase() == x.toLowerCase() ? true : false;
}
isCouponExpired(x){
return new Date().getTime() > new Date(x).getTime() ? true : false;
}
isMinimumValid(x){
return this.cart.total < x ? true : false;
}
isMaximumValid(x){
return this.cart.total > x ? true : false;
}
submitCoupon(){
this.allowFreeShipping = false;
this.order.coupon_lines = [];
this.coupon.err = ‘’;
this.coupon.description = ‘’;
if(this.coupons){
let errors = [
'Coupon is invalid', 'Coupon is expired', 'Subtotal must be > ', 'Subtotal must be < ', 'Coupon usage is limited'
]
let valid = false;
let x: any;
for(let i in this.coupons){
x = this.coupons[i];
if(this.isCouponValid(x.code)){
valid = true;
if(x.free_shipping)
this.allowFreeShipping = true;
break;
}
}
if(valid){
if(x.date_expires && this.isCouponExpired(x.date_expires))
this.coupon.err = errors[1];
else if(x.minimum_amount > 0 && this.isMinimumValid(x.minimum_amount))
this.coupon.err = errors[2] + x.minimum_amount;
else if(x.maximum_amount > 0 && this.isMaximumValid(x.maximum_amount))
this.coupon.err = errors[3] + x.maximum_amount;
else if(x.usage_limit && x.usage_count >= x.usage_limit)
this.coupon.err = errors[4];
else{
this.coupon.description = x.description || 'Congrat, your coupon is valid';
this.order.coupon_lines.push({
code: x.code,
discount: this.getTotalDiscount(x)
});
}
}else
this.coupon.err = errors[0];
this.updateTotal();
}
if(this.coupon.err){
this.translate.get(['OK', 'COUPON_CODE', 'COUPON_INVALID']).subscribe( x=> {
this.alert.create({
title: x.COUPON_CODE,
message: this.coupon.err,
buttons: [{
text: x.OK
}]
}).present();
});
}
}
getTotalDiscount(x:any){
let total = 0;
if(x.discount_type == ‘percent’)
total = x.amount * this.cart.total / 100;
else if(x.discount_type == ‘fixed_cart’)
total = x.amount;
else
total = x.amount * this.cart.totalQtyDetail;
return total;
}
updateTotal(){
let shipping = this.shipping_lines[0] ? parseInt(this.shipping_lines[0].total) : 0;
let discount = this.coupon.description ? parseInt(this.order.coupon_lines[0].discount) : 0;
this.total = this.cart.total + shipping - discount;
}
confirm(){
this.loader.present();
this.order.billing = this.billing;
this.order.shipping = this.shipping;
this.order.line_items = this.cart.lineItems;
this.order.currency = this.setting.all.settings.currency;
if(this.coupon.description){ // update line item total if coupon valid
let tmp: any;
tmp = this.order.coupon_lines[0].discount / this.cart.totalQtyDetail;
for(let i in this.order.line_items)
this.order.line_items[i].total = this.order.line_items[i].subtotal - (tmp.toFixed(2) * this.order.line_items[i].quantity);
}
this.order.shipping_lines = this.shipping_lines;
if(this.user.all) this.order.customer_id = this.user.id;
console.log(this.order);
this.loader.dismiss();
this.goTo('ThanksPage', this.order);
// CHECKOUT WITH PAYPAL
if(this.order.payment_method == 'paypal'){
if (!this.platform.is('cordova'))
this.shouldDeviceOnly();
else{
this.order.total = this.total;
this._order.checkoutPaypal(this.order).then((res)=>{
if(res){
this.createOrder(this.order);
}else{
this.loader.dismiss();
this.toast.show(res);
}
}, err=>{
this.loader.dismiss();
this.toast.show(err);
});
}
// CHECKOUT WITH STRIPE
}else if(this.order.payment_method == 'stripe'){
if (!this.platform.is('cordova'))
this.shouldDeviceOnly();
else{
this.order.total = this.total;
this._order.getStripeToken(this.stripe).then((token)=>{
if(token.id){
token.secret_key = this.stripe.secret_key;
this._order.checkoutStripe(this.order, token)
.subscribe( (res) => {
this.createOrder(this.order);
}, err => {
this.loader.dismiss();
this.toast.showWithClose(err.json().error.message);
});
}else{
this.loader.dismiss();
this.toast.showWithClose(token);
}
}, err => {
this.loader.dismiss();
this.toast.showWithClose(err);
})
}
// CHECKOUT WITH RAZOR PAY
}else if(this.order.payment_method == 'razorpay'){
if (!this.platform.is('cordova'))
this.shouldDeviceOnly();
else{
this.order.total = this.total;
this._order.checkoutRazorpay(this.order, this.razor)
.then( (res) => {
console.log(res);
this.createOrder(this.order);
}, err => {
this.loader.dismiss();
this.toast.showWithClose(err.description);
});
}
// CHECKOUT WITH OTHERs
}else if(this.order.payment_method == 'bacs' || this.order.payment_method == 'cod' || this.order.payment_method == 'cheque'){
this.createOrder(this.order);
// NOT AVAILABLE
}else{
this.loader.dismiss();
this.translate.get(['OK', 'NOT_AVAILABLE', 'PAYMENT_NOT_AVAILABLE']).subscribe( x=> {
this.alert.create({
title: x.NOT_AVAILABLE,
message: x.PAYMENT_NOT_AVAILABLE,
buttons: [{
text: x.OK
}]
}).present();
this.loader.dismiss();
return false;
});
}
}
shouldDeviceOnly(){
this.translate.get([‘OK’, ‘ONLY_DEVICE’, ‘ONLY_DEVICE_DESC’]).subscribe( x=> {
this.alert.create({
title: x.ONLY_DEVICE,
message: x.ONLY_DEVICE_DESC,
buttons: [{
text: x.OK
}]
}).present();
this.loader.dismiss();
return false;
});
}
createOrder(order: any){
this.woo.createOrder(order).then( x=>{
if(x){
this._order.reset().then(() => {});
this.cart.reset().then(() => {});
this.goTo(‘ThanksPage’, x);
}else{
this.toast.showWithClose(‘CORS issues, please use https.’);
}
this.loader.dismiss();
}, err=> {
this.loader.dismiss();
this.toast.show(err);
})
}
goTo(page, params){
this.app.getRootNav().setRoot(page, {params: params});
}
}
checkout.html
{{ 'SHIPPING' | translate}} {{ 'PAYMENT' | translate}}{{ 'BILLING_ADDRESS' | translate}}
{{ 'BILLING_DESC' | translate}}{{billing.first_name}} • {{billing.phone}}
{{billing.address_1}}
{{billing.city}}, {{billing.state}}, {{billing.postcode}}
{{billing.country}}
<ion-list margin-top padding-top>
<div padding-horizontal>
<h3>{{ 'SHIPPING_ADDRESS' | translate}}</h3>
<ion-note padding-bottom>{{ 'SHIPPING_DESC' | translate}}</ion-note>
</div>
<ion-item no-lines *ngIf="shipping">
<p>{{shipping.first_name}} • {{shipping.phone}}</p>
<p>{{shipping.address_1}}</p>
<p>{{shipping.city}}, {{shipping.state}}, {{shipping.postcode}}</p>
<p>{{shipping.country}}</p>
</ion-item>
<div padding-horizontal>
<button ion-button outline block icon-start *ngIf="!shipping" tappable (click)="addAddress(4)">
{{ 'ADD' | translate}} {{ 'NEW_ADDRESS' | translate}}
</button>
<button ion-button outline block icon-start *ngIf="shipping" tappable (click)="selectAddress(4)">
{{ 'SELECT' | translate}} {{ 'OTHER_ADDRESS' | translate}}
</button>
</div>
</ion-list>
<ion-list no-margin margin-top>
<div padding-horizontal>
<h3>{{ 'REVIEW_PURCHASE' | translate}}</h3>
<ion-note>{{ 'REVIEW_DESC' | translate}}</ion-note>
</div>
</ion-list>
<ion-list no-margin margin-top *ngIf="cart.all.length > 0">
<ion-item *ngFor="let x of cart.all">
<ion-thumbnail item-start>
<div class="img" [ngStyle]="{'background-image': 'url(' + x.images[0].src +')'}"></div>
</ion-thumbnail>
<h3 [innerHTML]="x.name"></h3>
<p>
<span class="disc" *ngIf="x.on_sale">{{x.regular_price | money}} •</span>
<span class="price">{{x.price | money}}</span>
<ng-container *ngIf="x.attributes.length > 0"><span *ngFor="let y of x.attributes">• <i>{{y.option || y.options[0]}}</i> </span></ng-container>
<span>• {{x.quantity}}x</span>
</p>
</ion-item>
</ion-list>
<ion-list margin-bottom padding-top *ngIf="coupons.length > 0">
<div padding-horizontal>
<h3>{{ 'COUPON_CODE' | translate}}</h3>
</div>
</ion-list>
<ion-list margin-bottom *ngIf="coupons.length > 0">
<ion-grid class="coupon" no-padding>
<ion-row align-items-center padding-horizontal>
<ion-col>
<ion-item no-padding no-padding>
<ion-input placeholder="{{ 'INPUT_CODE' | translate}}" [(ngModel)]="coupon.input" type="text"></ion-input>
</ion-item>
</ion-col>
<ion-col col-4>
<button ion-button small tappable color="secondary" (click)="submitCoupon()" block type="button" [disabled]="!coupon.input">{{ 'SUBMIT' | translate}}</button>
</ion-col>
</ion-row>
<ion-row class="coupon-result" align-items-center margin padding *ngIf="coupon.description">
<ion-col>{{coupon.description}}</ion-col>
</ion-row>
</ion-grid>
</ion-list>
<ion-list no-margin margin-top padding-top>
<div padding-horizontal>
<h3>{{ 'NOTE_SELLER' | translate}}</h3>
</div>
</ion-list>
<div padding>
<ion-textarea placeholder="{{ 'NOTE_SELLER_DESC' | translate}}" [(ngModel)]="order.customer_note"></ion-textarea>
</div>
<ion-list no-margin margin-top padding-top>
<div padding-horizontal>
<h3>{{ 'SHIPPING_METHOD' | translate}}</h3>
<ion-note>{{ 'SHIPPING_METHOD_DESC' | translate}}</ion-note>
</div>
</ion-list>
<ion-list radio-group no-margin margin-vertical (ionChange)="setShipping($event)">
<ng-container *ngFor="let x of shipping_method">
<ion-item mode="ios" *ngIf="(x.enabled && x.method_id != 'free_shipping') || (x.enabled && x.method_id == 'free_shipping' && allowFreeShipping)">
<ion-label>{{x.title}} <span *ngIf="x.settings.cost">({{x.settings.cost ? (x.settings.cost.value | money) : ''}})</span></ion-label>
<ion-radio mode="ios" [value]="x | json"></ion-radio>
</ion-item>
</ng-container>
</ion-list>
<div padding>
<button ion-button block icon-start tappable (click)="next()" [disabled]="shipping_lines.length == 0">
{{ 'NEXT' | translate}}
</button>
</div>
</div>
<div *ngSwitchCase="'payment'">
<ion-list margin-bottom>
<div padding-horizontal>
<h3>{{ 'PAYMENT_METHOD' | translate}}</h3>
<ion-note>{{ 'PAYMENT_METHOD_DESC' | translate}}</ion-note>
</div>
</ion-list>
<ion-list radio-group no-margin margin-top margin-bottom (ionChange)="setPayment($event)">
<ng-container *ngFor="let x of payments; let i = index">
<ion-item mode="ios" *ngIf="(x.enabled && x.id != 'razorpay') || (x.enabled && x.id == 'razorpay' && setting.all.settings.currency == 'INR')" [ngClass]="{'section-active': x.open, 'section': !x.open}">
<ion-label>
{{x.method_title ? x.method_title : x.title}}
<img *ngFor="let x of img[x.id]" [src]="x" />
</ion-label>
<ion-radio mode="ios" [value]="x | json"></ion-radio>
</ion-item>
<ion-list class="accord" no-lines padding no-margin *ngIf="x.open && x.description" [ngClass]="{'section-active': x.open, 'section': !x.open}">
<ion-item [innerHTML]="x.description" no-padding></ion-item>
<ion-grid class="stripe-form" *ngIf="x.id == 'stripe'">
<ion-row>
<ion-col>
<ion-item no-padding>
<ion-label floating>Card No</ion-label>
<ion-input [(ngModel)]="stripe.no" [class.invalid]="!stripe.no" type="number" min="16" inputmode="numeric" pattern="[0-9]*"></ion-input>
</ion-item>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-item no-padding>
<ion-label floating>Month</ion-label>
<ion-select [(ngModel)]="stripe.month" [class.invalid]="!stripe.month">
<ion-option *ngFor="let x of months; let i = index" [value]="i+1">{{x}}</ion-option>
</ion-select>
</ion-item>
</ion-col>
<ion-col>
<ion-item no-padding>
<ion-label floating>Year</ion-label>
<ion-select [(ngModel)]="stripe.year" [class.invalid]="!stripe.year">
<ion-option *ngFor="let x of years; let i = index" [value]="x">{{x}}</ion-option>
</ion-select>
</ion-item>
</ion-col>
<ion-col>
<ion-item no-padding>
<ion-label floating>CVC</ion-label>
<ion-input [(ngModel)]="stripe.cvc" type="password" min="3" [class.invalid]="!stripe.cvc" min="3" inputmode="numeric" pattern="[0-9]*"></ion-input>
</ion-item>
</ion-col>
</ion-row>
</ion-grid>
</ion-list>
</ng-container>
</ion-list>
<ion-list margin-bottom padding-top>
<div padding-horizontal>
<h3>Total</h3>
</div>
</ion-list>
<ion-list no-margin margin-top class="total">
<ion-item>
{{ 'SUBTOTAL' | translate}} ({{cart.totalQtyDetail}} items)
<span item-end>{{cart.total | money}}</span>
</ion-item>
<ion-item *ngIf="coupon.description">
Coupon: {{order.coupon_lines[0].code}}
<span item-end>{{(order.coupon_lines[0].discount * -1) | money}}</span>
</ion-item>
<ion-item *ngIf="shipping_lines[0]">
{{ 'SHIPPING' | translate}} ({{shipping_lines[0].method_title}})
<span item-end>{{shipping_lines[0].total | money}}</span>
</ion-item>
<ion-item>
Total <span item-end>{{total | money}}</span>
</ion-item>
</ion-list>
<div padding>
<button ion-button block icon-start tappable (click)="confirm()" [disabled]="!order.payment_method || ((order.payment_method == 'stripe') && (!stripe.no || !stripe.month || !stripe.year || !stripe.cvc))">
{{ 'BUY_NOW' | translate}} {{total | money}}
</button>
</div>
</div>