import { Component, Output, EventEmitter, ViewChild } from '@angular/core'; import { BsModalRef, BsModalService } from 'ngx-bootstrap'; import { CartService } from '../../../services/cart.service'; import { LoginModalComponent } from '../../custom-portal-pages/header-components/login-modal/login-modal.component'; import { ToastrService } from 'ngx-toastr'; import { Router } from '@angular/router'; import { NewAddressDialogComponent } from '../../custom-portal-pages/common-components/new-address/new-address.component'; import { AlertModalComponent } from '../alert-modal/alert-modal.component'; import { AuthenticationService } from '../../../services/authentication.service'; import { ManageConfigService } from '../../../services/manage.configuration.service'; @Component({ selector: 'espl-cart', templateUrl: 'cart.component.html', styleUrls: ['cart.css'] }) export class CartComponent { checkOutInProgress: boolean; addressesDisplayed: boolean = false; defaultAddress; itemsInCart: []; taxGroups; taxSlabs; appliedTaxSlabs: any[]; savedAddresses: any[]; subTotalDiscountPrice: number; subTotalSalesPrice: number; cartItemsCount: number; creditsAdded: number = 0; upfrontDiscount: number = 0; handlingFee: number; checkOutAmount: number = 0; isWalletAmountAvailable: boolean; isWalletAmountUsed: boolean; usedWalletAmount: number = 0; user_wallet_value: number; config: any; user: any; org: any; locations: any; addressId: number; locationCode: number; bsModalRef: BsModalRef; isTaxGroupSelectedOnItems: boolean; totalTaxAmount: number; @ViewChild('esplcart') esplcart; @Output() reloadCache = new EventEmitter(); displayWalletMsgToAddItems: boolean; remAmtTobeAddedForWalletCredit: number; invoiceState: any; hidecart() { this.esplcart.nativeElement.style.width = '0px'; } constructor(private toastr: ToastrService, private cartService: CartService, private modalService: BsModalService, private router: Router, private auth:AuthenticationService, private manageConfigService: ManageConfigService ) { } ngOnInit() { this.auth.user.subscribe((userData) => { this.user = userData; }) this.invoiceState = 2; // by default 'CONFIRMED' this.isTaxGroupSelectedOnItems = true;//TODO:Need to change based on address UI. this.appliedTaxSlabs = []; this.totalTaxAmount = 0; this.config = JSON.parse(localStorage.getItem('config')); this.user = JSON.parse(localStorage.getItem('user')); this.org = JSON.parse(localStorage.getItem('org')); this.locations = JSON.parse(localStorage.getItem('locations')); this.cartService.getItemsInCart().subscribe(result => { this.itemsInCart = JSON.parse(result) || []; this.subTotalDiscountPrice = this.cartService.getSum(this.itemsInCart, "totalDiscountPrice"); this.calculateUpfrontDiscount(); this.calculateCreditsAdded(); this.subTotalSalesPrice = this.cartService.getSum(this.itemsInCart, "totalSalesPrice"); this.cartItemsCount = this.cartService.getSum(this.itemsInCart, "numItems"); this.calculateHandlingFee(); this.checkOutAmount = this.subTotalDiscountPrice + this.handlingFee - this.upfrontDiscount; this.calculateAvailableWalletAmount(); }); this.cartService.taxGroupSourceBS.subscribe(result => { this.taxGroups = result || []; }); this.cartService.taxSlabData.subscribe(result => { this.taxSlabs = result || []; }); this.cartService.getIsWalletAmountUsed().subscribe(isUsed => { this.isWalletAmountUsed = isUsed; }) this.cartService.getUsedWalletAmount().subscribe(amount => { this.usedWalletAmount = amount; }) } private calculateCreditsAdded() { let config = this.config; if (config) { if (config.wallet_credit_discount) { if (this.subTotalDiscountPrice >= config.wallet_min_cart_value) { this.creditsAdded = config.wallet_discount_provided; } else this.creditsAdded = 0; } } } private calculateUpfrontDiscount() { let config = this.config; if (config) { if (config.upfront_discount) { if (this.subTotalDiscountPrice >= config.upfront_min_cart_value) { this.upfrontDiscount = config.upfront_discount_value; } else this.upfrontDiscount = 0; } } } private calculateHandlingFee() { let config = this.config; if (config) { if (this.subTotalDiscountPrice < config.handling_min_cart_value) this.handlingFee = config.handling_fee; else this.handlingFee = 0; } } useWalletOption(event) { this.cartService.setIsWalletAmountUsed(event.srcElement.checked); let config = this.config; if (config && config.max_wallet_applied && this.isWalletAmountUsed && this.isWalletAmountAvailable) { const availableWallet = this.user_wallet_value < config.max_wallet_applied ? this.user_wallet_value : config.max_wallet_applied; const usedWallet = this.subTotalDiscountPrice < availableWallet ? this.subTotalDiscountPrice : availableWallet; this.cartService.setUsedWalletAmount(usedWallet); } else { this.cartService.setUsedWalletAmount(0); this.cartService.setIsWalletAmountUsed(false); } } calculateAvailableWalletAmount() { let config = this.config; let user = this.user; if (user && user.wallet && user.wallet > 0) { if(this.subTotalDiscountPrice >= config.wallet_dicount_min_cart) { this.isWalletAmountAvailable = true; this.displayWalletMsgToAddItems = false; } else { this.isWalletAmountAvailable = false; this.displayWalletMsgToAddItems = true; this.cartService.setUsedWalletAmount(0); this.cartService.setIsWalletAmountUsed(false); this.remAmtTobeAddedForWalletCredit = config.wallet_dicount_min_cart - this.subTotalDiscountPrice; } this.user_wallet_value = user.wallet; } else { this.isWalletAmountAvailable = false; this.displayWalletMsgToAddItems = false; this.cartService.setIsWalletAmountUsed(false); } } updateItemsInCart(product, operationType) { this.cartService.updateItemsInCart(product, operationType); }; getOriginalAmount(taxOnItem, amount) { if (taxOnItem) { if (this.isTaxGroupSelectedOnItems) { const tax_slabs = this.taxGroups.filter(taxGroup => taxGroup['tax_group_id'] === taxOnItem); const percentage: number = tax_slabs.reduce((totalTaxPercent: any, taxslab: any) => totalTaxPercent + Number(taxslab.percentage), 0); amount = (amount * 100) / (100 + percentage); } else { const tax_slab: any = this.taxSlabs.find(p => Number(p['tax_slab_id']) === Number(taxOnItem)); amount = (amount * 100) / (100 + Number(tax_slab.percentage)); } } return Number(amount.toFixed(2)); } getAppliedTaxSlabs(taxOnItem, amount) { if (taxOnItem) { if (this.isTaxGroupSelectedOnItems) { const tax_slabs = this.taxGroups.filter(taxGroup => Number(taxGroup['tax_group_id']) === Number(taxOnItem)); tax_slabs.forEach(p => { const cumPercentage = tax_slabs.reduce((p, q) => p + Number(q['percentage']), 0); const cumTax = (amount - Number(((amount * 100) / (100 + cumPercentage)).toFixed(2))).toFixed(2); let tax = cumPercentage ? (p['percentage'] / cumPercentage) * Number(cumTax) : 0; this.appliedTaxSlabs.push({ taxSlabId: p['tax_slab_id'], slabName: p['tax_slab_name'], tax: tax }); }); } else { const tax_slab = this.taxSlabs.find(p => Number(p['tax_slab_id']) === Number(taxOnItem)); const tax = (amount - (amount * 100) / (100 + Number(tax_slab['percentage']))).toFixed(2); this.appliedTaxSlabs.push({ taxSlabId: tax_slab['tax_slab_id'], slabName: tax_slab['tax_slab_name'], tax: tax }); } } } calculateCumulativeTax() { let taxSlabs = new Set(); for (const taxslab of this.appliedTaxSlabs) { taxSlabs.add(taxslab['taxSlabId']); } let cumulativeTaxSlabDetails = []; for (let item of taxSlabs) { const tax_slabs = this.appliedTaxSlabs.filter(p => p['taxSlabId'] === item); if (tax_slabs.length > 0) { const cumAmount: number = tax_slabs.reduce((p: any, q: any) => (Number(p) + Number(q.tax)).toFixed(2), 0); cumulativeTaxSlabDetails.push({ taxSlabId: tax_slabs[0]['taxSlabId'], slabName: tax_slabs[0]['slabName'], cumAmount: cumAmount }) } } return cumulativeTaxSlabDetails; } findLocationCode(){ if(this.defaultAddress){ let currentLocation = this.locations.find((location)=> location.location_name===this.defaultAddress.location_name); if(currentLocation) return currentLocation.location_id; } } setTaxInfo(){ if(this.defaultAddress.location_state!==this.org.location_state){ this.isTaxGroupSelectedOnItems = false; this.addressId = this.defaultAddress.address_id; this.locationCode = this.findLocationCode(); }else{ this.isTaxGroupSelectedOnItems = true; } } setDeliveryAddress(deliveryAddress, event){ if(this.defaultAddress){ this.defaultAddress.is_default = false; } if(event.target.checked){ deliveryAddress.is_default = true; this.defaultAddress = deliveryAddress; this.addressId = this.defaultAddress.address_id; this.locationCode = this.findLocationCode(); this.setTaxInfo(); }else{ this.defaultAddress = {}; } } updateDefaults(){ this.defaultAddress = this.savedAddresses.find((savedAddress)=>{ return savedAddress.is_default; }); if(this.defaultAddress){ this.addressId = this.defaultAddress.address_id; if(this.defaultAddress.location_state!==this.org.location_state){ this.isTaxGroupSelectedOnItems = false; } } this.locationCode = this.findLocationCode(); } proceedToCheckOut(){ window.scroll({ top: 0, left: 0, behavior: 'smooth' }); if(this.user){ this.addressesDisplayed = true; this.savedAddresses = this.user.addresses || []; this.updateDefaults(); }else{ this.login(); } } updateUserWallet():void{ let user = JSON.parse(localStorage.user); let walletAmountChanged = false; if(user){ if(this.creditsAdded){ user.wallet += this.creditsAdded; walletAmountChanged = true; } if(this.usedWalletAmount){ user.wallet -= this.usedWalletAmount; walletAmountChanged = true; } if(walletAmountChanged){ localStorage.user = JSON.stringify(user); } } } openDialog(): void{ this.bsModalRef = this.modalService.show(NewAddressDialogComponent, { backdrop: 'static', keyboard: false, animated: true, ignoreBackdropClick: true, initialState: { data: '', title: 'Address Details', config: "{ backdrop: 'static' }", } }); this.bsModalRef.content.event.subscribe(newAddress => { if(newAddress){ this.user.addresses = this.user.addresses || []; if(newAddress.is_default){ if(this.defaultAddress){ this.defaultAddress.is_default = false; } this.defaultAddress = newAddress; this.addressId = this.defaultAddress.address_id; this.setTaxInfo(); let currIndex = this.user.addresses.findIndex( address => { return address.is_default }); if(currIndex > -1){ this.user.addresses[currIndex].is_default = false; } } this.user.addresses.push(newAddress); localStorage.user = JSON.stringify(this.user); this.updateDefaults(); } }); } handleValidationErrors(checkOutStatus){ this.toastr.error('Syncing item prices with server, please review you cart and proceed to checkout!'); this.hidecart(); if(!checkOutStatus.isValidCustomerWallet){ this.auth.getWalletValue(this.user.username).subscribe((result: { status: string, message: string, data })=>{ if (result.status === 'success') { let walletValue = result.data; if(localStorage.getItem('user')){ let user = JSON.parse(localStorage.getItem('user')); user.wallet = walletValue; localStorage.user = JSON.stringify(user); } } }); } if(!checkOutStatus.isValidHandlingFee || !checkOutStatus.isValidUpfrontDiscount || !checkOutStatus.isValidUsedWalletAmount || !checkOutStatus.isValidCheckoutAmount){ this.manageConfigService.getExisitingConfiguration().subscribe((result: { status: string, message: string, data }) => { let locationId = this.config.location_id; this.config = result.data[0]; this.config.location_id = locationId; localStorage.config = JSON.stringify(this.config); if(!checkOutStatus.isValidUsedWalletAmount){ this.cartService.setUsedWalletAmount(0); this.cartService.setIsWalletAmountUsed(false); } }); } if(!checkOutStatus.isValidItemVariants){ this.reloadCache.emit(this.itemsInCart); } } geCorpInternalValueChanged(checkedEvent) { this.invoiceState = checkedEvent.srcElement.checked ? 11 : 2; } //On click of checkout button checkout() { if(!this.checkOutInProgress){ let user = JSON.parse(localStorage.getItem('user')); if (user === null) { this.login(); } else { if(this.defaultAddress){ if(this.locationCode!==this.config.location_id){ this.bsModalRef = this.modalService.show(AlertModalComponent, { backdrop: 'static', keyboard: false, animated: true, ignoreBackdropClick: true, initialState: { title: 'Alert', data: 'Items in cart are from different location. Please review the delivery address or update your location', buttonText:'Clear Cart', deleteBtn:'Review Cart' } }); this.bsModalRef.content.event.subscribe(res => { let alertConfirm = res; if (!alertConfirm) { this.clearCart(); } }); }else{ this.checkOutInProgress = true; const payload = { itemsInCart: this.itemsInCart, user: {'token': this.user.token, 'username': this.user.username, 'wallet': this.user.wallet}, isWalletAmountUsed: this.isWalletAmountUsed, subTotalSalesPrice: this.subTotalSalesPrice, usedWalletAmount: this.usedWalletAmount } const todayDate = new Date(); const todayDateString = todayDate.toISOString(); payload['customerSSO'] = this.user.username; payload['customerAddress'] = this.addressId;//TODO:Need to change based on address UI. payload['sourceOfSupply'] = this.org.location_code_id;//TODO:Need to change based on address UI. payload['destOfSupply'] = this.locationCode;//TODO:Need to change based on address UI. payload['invoiceDate'] = todayDateString; payload['paymentTerm'] = 1; payload['dueDate'] = todayDateString; payload['itemPriceType'] = 'Tax Inclusive'; payload['subTotal'] = this.subTotalDiscountPrice; payload['shippingCharges'] = this.handlingFee; payload['discountTaxType'] = 'after_tax'; payload['discountValue'] = this.upfrontDiscount; payload['totalAmount'] = this.checkOutAmount; payload['paidAmount'] = null; payload['assignTo'] = null; payload['invoiceState'] = this.invoiceState; payload['shipmentDate'] = null; payload['orderStatus'] = 2; payload['depositTo'] = 1; payload['markAsPaid'] = null; payload['paymentMode'] = 1; payload['addedItems'] = []; payload['isTaxGroupSelectedOnItems'] = this.isTaxGroupSelectedOnItems; for (let i = 0; i < this.itemsInCart.length; i++) { //TODO: For non-taxable items taxslab and taxgroups are harded with auto-generated primary key value of Non-taxable tax slab and group. const taxOnItem: number = Number(this.itemsInCart[i]['taxable'] ? (this.isTaxGroupSelectedOnItems ? this.itemsInCart[i]['intraTaxGroup'] : this.itemsInCart[i]['interTaxSlab']) : (this.isTaxGroupSelectedOnItems ? 5 : 7)); const amount: number = Number(this.itemsInCart[i]['totalDiscountPrice']); const originalAmt: number = this.getOriginalAmount(taxOnItem, amount); this.getAppliedTaxSlabs(taxOnItem, amount); this.totalTaxAmount = Math.round((this.totalTaxAmount + amount - originalAmt) * 100 )/100; payload['addedItems'].push({ itemId: this.itemsInCart[i]['variant_id'], quantity: this.itemsInCart[i]['numItems'], price: this.itemsInCart[i]['discount_price'], isInventory: this.itemsInCart[i]['isInventory'], costPrice: Number(this.itemsInCart[i]['cost_price']), amount: amount, originalAmt: originalAmt, taxOnItem: taxOnItem, selectedConstituent: this.itemsInCart[i]['constituent_name'] ? this.itemsInCart[i]['constituent_name'] : '', accountNameId:1 }); } payload['discountAccount'] = 14; payload['totalTaxAmount'] = Number(this.totalTaxAmount.toFixed(2)); payload['taxSlabs'] = this.calculateCumulativeTax(); this.cartService.checkout(payload).subscribe( response => { const data: any = response as any[]; this.checkOutInProgress = false; if (data.status === 'success') { //this.updateUserWallet(); //this.cartService.setUsedWalletAmount(0); //this.cartService.setIsWalletAmountUsed(false); //this.clearCart(); this.router.navigate(['/home/orderConfirmation', data.data.invoice_id]); this.hidecart(); } },(error)=>{ this.handleValidationErrors(error.error.message); }); } }else{ this.bsModalRef = this.modalService.show(AlertModalComponent, { backdrop: 'static', keyboard: false, animated: true, ignoreBackdropClick: true, initialState: { data: 'Please select a delivery address', infoPopup: 'true' } }); } } } } clearCart() { this.itemsInCart = []; localStorage.cartItems = JSON.stringify(this.itemsInCart); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)) } /* @usage: called click on login button @purpose:To open the login Dialog. */ login() { this.bsModalRef = this.modalService.show(LoginModalComponent, { initialState: { title: 'Login', } }); this.bsModalRef.content.event.subscribe(modelResult => { if (modelResult) { if (localStorage.getItem('user')) { window.location.reload(); //write logic for checkout after login } } }); } }