'use strict';
/**
* Controller for the billing logic. It is used by both the single shipping and the multishipping
* functionality and is responsible for payment method selection and entering a billing address.
*
* @module controllers/COBilling
*/
/* API Includes */
var GiftCertificate = require('dw/order/GiftCertificate');
var GiftCertificateMgr = require('dw/order/GiftCertificateMgr');
var GiftCertificateStatusCodes = require('dw/order/GiftCertificateStatusCodes');
var PaymentInstrument = require('dw/order/PaymentInstrument');
var PaymentMgr = require('dw/order/PaymentMgr');
var ProductListMgr = require('dw/customer/ProductListMgr');
var Resource = require('dw/web/Resource');
var Status = require('dw/system/Status');
var StringUtils = require('dw/util/StringUtils');
var Transaction = require('dw/system/Transaction');
var URLUtils = require('dw/web/URLUtils');
var Countries = require('app_storefront_core/cartridge/scripts/util/Countries');
/* Script Modules */
var app = require('~/cartridge/scripts/app');
var guard = require('~/cartridge/scripts/guard');
/**
* Initializes the address form. If the customer chose "use as billing
* address" option on the single shipping page the form is prepopulated with the shipping
* address, otherwise it prepopulates with the billing address that was already set.
* If neither address is available, it prepopulates with the default address of the authenticated customer.
*/
function initAddressForm(cart) {
if (app.getForm('singleshipping').object.shippingAddress.useAsBillingAddress.value === true) {
app.getForm('billing').object.billingAddress.addressFields.firstName.value = app.getForm('singleshipping').object.shippingAddress.addressFields.firstName.value;
app.getForm('billing').object.billingAddress.addressFields.lastName.value = app.getForm('singleshipping').object.shippingAddress.addressFields.lastName.value;
app.getForm('billing').object.billingAddress.addressFields.address1.value = app.getForm('singleshipping').object.shippingAddress.addressFields.address1.value;
app.getForm('billing').object.billingAddress.addressFields.address2.value = app.getForm('singleshipping').object.shippingAddress.addressFields.address2.value;
app.getForm('billing').object.billingAddress.addressFields.city.value = app.getForm('singleshipping').object.shippingAddress.addressFields.city.value;
app.getForm('billing').object.billingAddress.addressFields.postal.value = app.getForm('singleshipping').object.shippingAddress.addressFields.postal.value;
app.getForm('billing').object.billingAddress.addressFields.phone.value = app.getForm('singleshipping').object.shippingAddress.addressFields.phone.value;
app.getForm('billing').object.billingAddress.addressFields.states.state.value = app.getForm('singleshipping').object.shippingAddress.addressFields.states.state.value;
app.getForm('billing').object.billingAddress.addressFields.country.value = app.getForm('singleshipping').object.shippingAddress.addressFields.country.value;
app.getForm('billing').object.billingAddress.addressFields.phone.value = app.getForm('singleshipping').object.shippingAddress.addressFields.phone.value;
} else if (cart.getBillingAddress() !== null) {
app.getForm('billing.billingAddress.addressFields').copyFrom(cart.getBillingAddress());
app.getForm('billing.billingAddress.addressFields.states').copyFrom(cart.getBillingAddress());
} else if (customer.authenticated && customer.profile.addressBook.preferredAddress !== null) {
app.getForm('billing.billingAddress.addressFields').copyFrom(customer.profile.addressBook.preferredAddress);
app.getForm('billing.billingAddress.addressFields.states').copyFrom(customer.profile.addressBook.preferredAddress);
}
}
/**
* Initializes the email address form field. If there is already a customer
* email set at the basket, that email address is used. If the
* current customer is authenticated the email address of the customer's profile
* is used.
*/
function initEmailAddress(cart) {
if (cart.getCustomerEmail() !== null) {
app.getForm('billing').object.billingAddress.email.emailAddress.value = cart.getCustomerEmail();
} else if (customer.authenticated && customer.profile.email !== null) {
app.getForm('billing').object.billingAddress.email.emailAddress.value = customer.profile.email;
}
}
/**
* Updates data for the billing page and renders it.
* If payment method is set to gift certificate, gets the gift certificate code from the form.
* Updates the page metadata. Gets a view and adds any passed parameters to it. Sets the Basket and ContinueURL properties.
* Renders the checkout/billing/billing template.
* @param {module:models/CartModel~CartModel} cart - A CartModel wrapping the current Basket.
* @param {object} params - (optional) if passed, added to view properties so they can be accessed in the template.
*/
function returnToForm(cart, params) {
var pageMeta = require('~/cartridge/scripts/meta');
// if the payment method is set to gift certificate get the gift certificate code from the form
if (!empty(cart.getPaymentInstrument()) && cart.getPaymentInstrument().getPaymentMethod() === PaymentInstrument.METHOD_GIFT_CERTIFICATE) {
app.getForm('billing').copyFrom({
giftCertCode: cart.getPaymentInstrument().getGiftCertificateCode()
});
}
pageMeta.update({
pageTitle: Resource.msg('billing.meta.pagetitle', 'checkout', 'SiteGenesis Checkout')
});
if (params) {
app.getView(require('~/cartridge/scripts/object').extend(params, {
Basket: cart.object,
ContinueURL: URLUtils.https('COBilling-Billing')
})).render('checkout/billing/billing');
} else {
app.getView({
Basket: cart.object,
ContinueURL: URLUtils.https('COBilling-Billing')
}).render('checkout/billing/billing');
}
}
/**
* Updates cart calculation and page information and renders the billing page.
* @transactional
* @param {module:models/CartModel~CartModel} cart - A CartModel wrapping the current Basket.
* @param {object} params - (optional) if passed, added to view properties so they can be accessed in the template.
*/
function start(cart, params) {
app.getController('COShipping').PrepareShipments();
Transaction.wrap(function () {
cart.calculate();
});
var pageMeta = require('~/cartridge/scripts/meta');
pageMeta.update({
pageTitle: Resource.msg('billing.meta.pagetitle', 'checkout', 'SiteGenesis Checkout')
});
returnToForm(cart, params);
}
/**
* Initializes the credit card list by determining the saved customer payment methods for the current locale.
* @param {module:models/CartModel~CartModel} cart - A CartModel wrapping the current Basket.
* @return {object} JSON object with members ApplicablePaymentMethods and ApplicableCreditCards.
*/
function initCreditCardList(cart) {
var paymentAmount = cart.getNonGiftCertificateAmount();
var countryCode;
var applicablePaymentMethods;
var applicablePaymentCards;
var applicableCreditCards;
countryCode = Countries.getCurrent({
CurrentRequest: {
locale: request.locale
}
}).countryCode;
applicablePaymentMethods = PaymentMgr.getApplicablePaymentMethods(customer, countryCode, paymentAmount.value);
applicablePaymentCards = PaymentMgr.getPaymentMethod(PaymentInstrument.METHOD_CREDIT_CARD).getApplicablePaymentCards(customer, countryCode, paymentAmount.value);
app.getForm('billing').object.paymentMethods.creditCard.type.setOptions(applicablePaymentCards.iterator());
applicableCreditCards = null;
if (customer.authenticated) {
var profile = app.getModel('Profile').get();
if (profile) {
applicableCreditCards = profile.validateWalletPaymentInstruments(countryCode, paymentAmount.getValue()).ValidPaymentInstruments;
}
}
return {
ApplicablePaymentMethods: applicablePaymentMethods,
ApplicableCreditCards: applicableCreditCards
};
}
/**
* Starting point for billing. After a successful shipping setup, both COShipping
* and COShippingMultiple call this function.
*/
function publicStart() {
var cart = app.getModel('Cart').get();
if (cart) {
// Initializes all forms of the billing page including: - address form - email address - coupon form
initAddressForm(cart);
initEmailAddress(cart);
var creditCardList = initCreditCardList(cart);
var applicablePaymentMethods = creditCardList.ApplicablePaymentMethods;
var billingForm = app.getForm('billing').object;
var paymentMethods = billingForm.paymentMethods;
if (paymentMethods.valid) {
paymentMethods.selectedPaymentMethodID.setOptions(applicablePaymentMethods.iterator());
} else {
paymentMethods.clearFormElement();
}
app.getForm('billing.couponCode').clear();
app.getForm('billing.giftCertCode').clear();
start(cart, {ApplicableCreditCards: creditCardList.ApplicableCreditCards});
} else {
app.getController('Cart').Show();
}
}
/**
* Adjusts gift certificate redemptions after applying coupon(s), because this changes the order total.
* Removes and then adds currently added gift certificates to reflect order total changes.
*/
function adjustGiftCertificates() {
var i, j, cart, gcIdList, gcID, gc;
cart = app.getModel('Cart').get();
if (cart) {
gcIdList = cart.getGiftCertIdList();
Transaction.wrap(function () {
for (i = 0; i < gcIdList.length; i += 1) {
cart.removeGiftCertificatePaymentInstrument(gcIdList[i]);
}
gcID = null;
for (j = 0; j < gcIdList.length; j += 1) {
gcID = gcIdList[j];
gc = GiftCertificateMgr.getGiftCertificateByCode(gcID);
if ((gc) && // make sure exists
(gc.isEnabled()) && // make sure it is enabled
(gc.getStatus() !== GiftCertificate.STATUS_PENDING) && // make sure it is available for use
(gc.getStatus() !== GiftCertificate.STATUS_REDEEMED) && // make sure it has not been fully redeemed
(gc.balance.currencyCode === cart.getCurrencyCode())) {// make sure the GC is in the right currency
cart.createGiftCertificatePaymentInstrument(gc);
}
}
});
}
}
/**
* Used to adjust gift certificate totals, update page metadata, and render the billing page.
* This function is called whenever a billing form action is handled.
* @see {@link module:controllers/COBilling~returnToForm|returnToForm}
* @see {@link module:controllers/COBilling~adjustGiftCertificates|adjustGiftCertificates}
* @see {@link module:controllers/COBilling~billing|billing}
*/
function handleCoupon() {
var CouponError;
// @FIXME what is that used for?
if (empty(CouponError)) {
/*
* Adjust gift certificate redemptions as after applying coupon(s),
* order total is changed. AdjustGiftCertificate pipeline removes and
* then adds currently added gift certificates to reflect order total
* changes.
*/
adjustGiftCertificates();
}
returnToForm(app.getModel('Cart').get());
}
/**
* Redeems a gift certificate. If the gift certificate was not successfully
* redeemed, the form field is invalidated with the appropriate error message.
* If the gift certificate was redeemed, the form gets cleared. This function
* is called by an Ajax request and generates a JSON response.
* @param {String} giftCertCode - Gift certificate code entered into the giftCertCode field in the billing form.
* @returns {object} JSON object containing the status of the gift certificate.
*/
function redeemGiftCertificate(giftCertCode) {
var cart, gc, newGCPaymentInstrument, gcPaymentInstrument, status, result;
cart = app.getModel('Cart').get();
if (cart) {
// fetch the gift certificate
gc = GiftCertificateMgr.getGiftCertificateByCode(giftCertCode);
if (!gc) {// make sure exists
result = new Status(Status.ERROR, GiftCertificateStatusCodes.GIFTCERTIFICATE_NOT_FOUND);
} else if (!gc.isEnabled()) {// make sure it is enabled
result = new Status(Status.ERROR, GiftCertificateStatusCodes.GIFTCERTIFICATE_DISABLED);
} else if (gc.getStatus() === GiftCertificate.STATUS_PENDING) {// make sure it is available for use
result = new Status(Status.ERROR, GiftCertificateStatusCodes.GIFTCERTIFICATE_PENDING);
} else if (gc.getStatus() === GiftCertificate.STATUS_REDEEMED) {// make sure it has not been fully redeemed
result = new Status(Status.ERROR, GiftCertificateStatusCodes.GIFTCERTIFICATE_INSUFFICIENT_BALANCE);
} else if (gc.balance.currencyCode !== cart.getCurrencyCode()) {// make sure the GC is in the right currency
result = new Status(Status.ERROR, GiftCertificateStatusCodes.GIFTCERTIFICATE_CURRENCY_MISMATCH);
} else {
newGCPaymentInstrument = Transaction.wrap(function () {
gcPaymentInstrument = cart.createGiftCertificatePaymentInstrument(gc);
cart.calculate();
return gcPaymentInstrument;
});
status = new Status(Status.OK);
status.addDetail('NewGCPaymentInstrument', newGCPaymentInstrument);
result = status;
}
} else {
result = new Status(Status.ERROR, 'BASKET_NOT_FOUND');
}
return result;
}
/**
* Updates credit card information from the httpParameterMap and determines if there is a currently selected credit card.
* If a credit card is selected, it adds the the credit card number to the billing form. Otherwise, the {@link module:controllers/COBilling~publicStart|publicStart} method is called.
* In either case, it will initialize the credit card list in the billing form and call the {@link module:controllers/COBilling~start|start} function.
*/
function updateCreditCardSelection() {
var cart, applicableCreditCards, UUID, selectedCreditCard, instrumentsIter, creditCardInstrument;
cart = app.getModel('Cart').get();
applicableCreditCards = initCreditCardList(cart).ApplicableCreditCards;
UUID = request.httpParameterMap.creditCardUUID.value || request.httpParameterMap.dwfrm_billing_paymentMethods_creditCardList.stringValue;
selectedCreditCard = null;
if (UUID && applicableCreditCards && !applicableCreditCards.empty) {
// find credit card in payment instruments
instrumentsIter = applicableCreditCards.iterator();
while (instrumentsIter.hasNext()) {
creditCardInstrument = instrumentsIter.next();
if (UUID.equals(creditCardInstrument.UUID)) {
selectedCreditCard = creditCardInstrument;
}
}
if (selectedCreditCard) {
app.getForm('billing').object.paymentMethods.creditCard.number.value = selectedCreditCard.creditCardNumber;
} else {
publicStart();
}
} else {
publicStart();
}
app.getForm('billing.paymentMethods.creditCard').copyFrom(selectedCreditCard);
initCreditCardList(cart);
start(cart);
}
/**
* Clears the form element for the currently selected payment method and removes the other payment methods.
*
* @return {Boolean} Returns true if payment is successfully reset. Returns false if the currently selected payment
* method is bml and the ssn cannot be validated.
*/
function resetPaymentForms() {
var cart = app.getModel('Cart').get();
var status = Transaction.wrap(function () {
if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals('PayPal')) {
app.getForm('billing').object.paymentMethods.creditCard.clearFormElement();
app.getForm('billing').object.paymentMethods.bml.clearFormElement();
cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD));
cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_BML));
} else if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_CREDIT_CARD)) {
app.getForm('billing').object.paymentMethods.bml.clearFormElement();
cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_BML));
cart.removePaymentInstruments(cart.getPaymentInstruments('PayPal'));
} else if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_BML)) {
app.getForm('billing').object.paymentMethods.creditCard.clearFormElement();
if (!app.getForm('billing').object.paymentMethods.bml.ssn.valid) {
return false;
}
cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD));
cart.removePaymentInstruments(cart.getPaymentInstruments('PayPal'));
}
return true;
});
return status;
}
/**
* Validates the billing form.
* @returns {boolean} Returns true if the billing address is valid or no payment is needed. Returns false if the billing form is invalid.
*/
function validateBilling() {
if (!app.getForm('billing').object.billingAddress.valid) {
return false;
}
if (!empty(request.httpParameterMap.noPaymentNeeded.value)) {
return true;
}
if (!empty(app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value) && app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_CREDIT_CARD)) {
if (!app.getForm('billing').object.valid) {
return false;
}
}
return true;
}
/**
* Handles the selection of the payment method and performs payment method-specific
* validation and verification on the entered form fields. If the
* order total is 0 (if the user has product promotions) then we do not
* need a valid payment method.
*/
function handlePaymentSelection(cart) {
var result;
if (empty(app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value)) {
if (cart.getTotalGrossPrice() > 0) {
result = {
error: true
};
} else {
result = {
ok: true
};
}
}
// skip the payment handling if the whole payment was made using gift cert
if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_GIFT_CERTIFICATE)) {
result = {
ok: true
};
}
if (empty(PaymentMgr.getPaymentMethod(app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value).paymentProcessor)) {
result = {
error: true,
MissingPaymentProcessor: true
};
}
if (!result) {
result = app.getModel('PaymentProcessor').handle(cart.object, app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value);
}
return result;
}
/**
* Gets or creates a billing address and copies it to the billingaddress form. Also sets the customer email address
* to the value in the billingAddress form.
* @transaction
* @param {module:models/CartModel~CartModel} cart - A CartModel wrapping the current Basket.
* @returns {boolean} true
*/
function handleBillingAddress(cart) {
var billingAddress = cart.getBillingAddress();
Transaction.wrap(function () {
if (!billingAddress) {
billingAddress = cart.createBillingAddress();
}
app.getForm('billing.billingAddress.addressFields').copyTo(billingAddress);
app.getForm('billing.billingAddress.addressFields.states').copyTo(billingAddress);
cart.setCustomerEmail(app.getForm('billing').object.billingAddress.email.emailAddress.value);
});
return true;
}
/**
* Checks if there is currently a cart and if one exists, gets the customer address from the httpParameterMap and saves it to the customer address book.
* Initializes the list of credit cards and calls the {@link module:controllers/COBilling~start|start} function.
* If a cart does not already exist, calls the {@link module:controllers/Cart~Show|Cart controller Show function}.
*/
function updateAddressDetails() {
var cart, address, billingAddress;
cart = app.getModel('Cart').get();
if (cart) {
address = customer.getAddressBook().getAddress(empty(request.httpParameterMap.addressID.value) ? request.httpParameterMap.dwfrm_billing_addressList.value : request.httpParameterMap.addressID.value);
app.getForm('billing.billingAddress.addressFields').copyFrom(address);
app.getForm('billing.billingAddress.addressFields.states').copyFrom(address);
billingAddress = cart.getBillingAddress();
app.getForm('billing.billingAddress.addressFields').copyTo(billingAddress);
initCreditCardList(cart);
start(cart);
} else {
//@FIXME redirect
app.getController('Cart').Show();
}
}
/**
* Form handler for the billing form. Handles the following actions:
* - __applyCoupon__ - gets the coupon to add from the httpParameterMap couponCode property and calls {@link module:controllers/COBilling~handleCoupon|handleCoupon}
* - __creditCardSelect__ - calls the {@link module:controllers/COBilling~updateCreditCardSelection|updateCreditCardSelection} function.
* - __paymentSelect__ - calls the {@link module:controllers/COBilling~publicStart|publicStart} function.
* - __redeemGiftCert__ - redeems the gift certificate entered into the billing form and returns to the cart.
* - __save__ - validates payment and address information and handles any errors. If the billing form is valid,
* saves the billing address to the customer profile, sets a flag to indicate the billing step is successful, and calls
* the {@link module:controllers/COSummary~start|COSummary controller Start function}.
* - __selectAddress__ - calls the {@link module:controllers/COBilling~updateAddressDetails|updateAddressDetails} function.
*/
function billing() {
app.getForm('billing').handleAction({
applyCoupon: function () {
var couponCode = request.httpParameterMap.couponCode.stringValue || request.httpParameterMap.dwfrm_billing_couponCode.stringValue;
// TODO what happened to this start node?
app.getController('Cart').AddCoupon(couponCode);
handleCoupon();
return;
},
creditCardSelect: function () {
updateCreditCardSelection();
return;
},
paymentSelect: function () {
// ToDo - pass parameter ?
publicStart();
return;
},
redeemGiftCert: function () {
var status = redeemGiftCertificate(app.getForm('billing').object.giftCertCode.htmlValue);
if (!status.isError()) {
returnToForm(app.getModel('Cart').get(), {
NewGCPaymentInstrument: status.getDetail('NewGCPaymentInstrument')
});
} else {
returnToForm(app.getModel('Cart').get());
}
return;
},
save: function () {
var cart = app.getModel('Cart').get();
if (!resetPaymentForms() || !validateBilling() || !handleBillingAddress(cart) || // Performs validation steps, based upon the entered billing address
// and address options.
handlePaymentSelection(cart).error) {// Performs payment method specific checks, such as credit card verification.
returnToForm(cart);
} else {
if (customer.authenticated && app.getForm('billing').object.billingAddress.addToAddressBook.value) {
app.getModel('Profile').get(customer.profile).addAddressToAddressBook(cart.getBillingAddress());
}
// Mark step as fulfilled
app.getForm('billing').object.fulfilled.value = true;
// A successful billing page will jump to the next checkout step.
app.getController('COSummary').Start();
return;
}
},
selectAddress: function () {
updateAddressDetails();
return;
}
});
}
/**
* Gets the gift certificate code from the httpParameterMap and redeems it. For an ajax call, renders an empty JSON object.
* Otherwise, renders a JSON object with information about the gift certificate code and the success and status of the redemption.
*/
function redeemGiftCertificateJson() {
var giftCertCode, giftCertStatus;
giftCertCode = request.httpParameterMap.giftCertCode.stringValue;
giftCertStatus = redeemGiftCertificate(giftCertCode);
let responseUtils = require('~/cartridge/scripts/util/Response');
if (request.httpParameterMap.format.stringValue !== 'ajax') {
// @FIXME we could also build an ajax guard?
responseUtils.renderJSON({});
} else {
responseUtils.renderJSON({
status: giftCertStatus.code,
success: !giftCertStatus.error,
message: Resource.msgf('billing.' + giftCertStatus.code, 'checkout', null, giftCertCode),
code: giftCertCode
});
}
}
/**
* Removes gift certificate from the basket payment instruments and
* generates a JSON response with a status. This function is called by an Ajax
* request.
*/
function removeGiftCertificate() {
if (!empty(request.httpParameterMap.giftCertificateID.stringValue)) {
var cart = app.getModel('Cart').get();
Transaction.wrap(function () {
cart.removeGiftCertificatePaymentInstrument(request.httpParameterMap.giftCertificateID.stringValue);
cart.calculate();
});
}
publicStart();
}
/**
* Updates the order totals and recalculates the basket after a coupon code is applied.
* Renders the checkout/minisummary template, which includes the mini cart order totals and shipment summary.
*/
function updateSummary() {
var cart = app.getModel('Cart').get();
Transaction.wrap(function () {
cart.calculate();
});
app.getView({
checkoutstep: 4,
Basket: cart.object
}).render('checkout/minisummary');
}
/**
* Renders a form dialog to edit an address. The dialog is supposed to be opened
* by an Ajax request and ends in templates, which trigger a certain JavaScript
* event. The calling page of this dialog is responsible for handling these
* events.
*/
function editAddress() {
app.getForm('billing').objectaddress.clearFormElement();
var address = customer.getAddressBook().getAddress(request.httpParameterMap.addressID.stringValue);
if (address) {
app.getForm('billinaddress').copyFrom(address);
app.getForm('billingaggdress.states').copyFrom(address);
}
app.getView({
ContinueURL: URLUtils.https('COBilling-EditBillingAddress')
}).render('checkout/billing/billingaddressdetails');
}
/**
* Form handler for the returnToForm form.
* - __apply __ - attempts to save billing address information to the platform. If there is an error, renders the
* components/dialog/dialogapply template. If it is successful, sets the ContinueURL to {@link module:controllers/COBilling~EditBillingAddress|EditBillingAddress} and renders the
* checkout/billing/billingaddressdetails template.
* - __remove __ - Checks if the customer owns any product lists. If they do not, removes the address from the customer address book
* and renders the components/dialog/dialogdelete template.
* If they do own product lists, sets the ContinueURL to {@link module:controllers/COBilling~EditBillingAddress|EditBillingAddress} and renders the checkout/billing/billingaddressdetails template.
*/
function editBillingAddress() {
app.getForm('returnToForm').handleAction({
apply: function () {
if (!app.getForm('billingaddress').copyTo(app.getForm('billingaddress').object)) {
app.getView({
ContinueURL: URLUtils.https('COBilling-EditBillingAddress')
}).render('checkout/billing/billingaddressdetails');
} else {
app.getView().render('components/dialog/dialogapply');
}
},
remove: function () {
if (ProductListMgr.getProductLists(app.getForm('billing').objectaddress.object).isEmpty()) {
customer.getAddressBook().removeAddress(app.getForm('billing').objectaddress.object);
app.getView().render('components/dialog/dialogdelete');
} else {
app.getView({
ContinueURL: URLUtils.https('COBilling-EditBillingAddress')
}).render('checkout/billing/billingaddressdetails');
}
}
});
}
/**
* Returns information of a gift certificate including its balance as JSON
* response. Required to check the remaining balance.
*/
function getGiftCertificateBalance() {
var giftCertificate = GiftCertificateMgr.getGiftCertificateByCode(request.httpParameterMap.giftCertificateID.value);
var responseUtils = require('~/cartridge/scripts/util/Response');
if (giftCertificate && giftCertificate.isEnabled()) {
responseUtils.renderJSON({
giftCertificate: {
ID: giftCertificate.getGiftCertificateCode(),
balance: StringUtils.formatMoney(giftCertificate.getBalance())
}
});
} else {
responseUtils.renderJSON({
error: Resource.msg('billing.giftcertinvalid', 'checkout', null)
});
}
}
/**
* Selects a customer credit card and returns the details of the credit card as
* JSON response. Required to fill credit card form with details of selected
* credit card.
*/
function selectCreditCard() {
var cart, applicableCreditCards, selectedCreditCard, instrumentsIter, creditCardInstrument;
cart = app.getModel('Cart').get();
applicableCreditCards = initCreditCardList(cart).ApplicableCreditCards;
selectedCreditCard = null;
// ensure mandatory parameter 'CreditCardUUID' and 'CustomerPaymentInstruments'
// in pipeline dictionary and collection is not empty
if (request.httpParameterMap.creditCardUUID.value && applicableCreditCards && !applicableCreditCards.empty) {
// find credit card in payment instruments
instrumentsIter = applicableCreditCards.iterator();
while (instrumentsIter.hasNext()) {
creditCardInstrument = instrumentsIter.next();
if (request.httpParameterMap.creditCardUUID.value.equals(creditCardInstrument.UUID)) {
selectedCreditCard = creditCardInstrument;
}
}
if (selectedCreditCard) {
app.getForm('billing').object.paymentMethods.creditCard.number.value = selectedCreditCard.getCreditCardNumber();
}
}
app.getView({
SelectedCreditCard: selectedCreditCard
}).render('checkout/billing/creditcardjson');
}
/**
* Revalidates existing payment instruments in later checkout steps.
*
* @param {module:models/CartModel~CartModel} cart - A CartModel wrapping the current Basket.
* @return {Boolean} true if existing payment instruments are valid, false if not.
*/
function validatePayment(cart) {
var paymentAmount, countryCode, invalidPaymentInstruments, result;
if (app.getForm('billing').object.fulfilled.value) {
paymentAmount = cart.getNonGiftCertificateAmount();
countryCode = Countries.getCurrent({
CurrentRequest: {
locale: request.locale
}
}).countryCode;
invalidPaymentInstruments = cart.validatePaymentInstruments(customer, countryCode, paymentAmount.value).InvalidPaymentInstruments;
if (!invalidPaymentInstruments && cart.calculatePaymentTransactionTotal()) {
result = true;
} else {
app.getForm('billing').object.fulfilled.value = false;
result = false;
}
} else {
result = false;
}
return result;
}
/**
* Attempts to save the used credit card in the customer payment instruments.
* The logic replaces an old saved credit card with the same masked credit card
* number of the same card type with the new credit card. This ensures creating
* only unique cards as well as replacing expired cards.
* @transactional
* @return {Boolean} true if credit card is successfully saved.
*/
function saveCreditCard() {
var i, creditCards, newCreditCard;
if (customer.authenticated && app.getForm('billing').object.paymentMethods.creditCard.saveCard.value) {
creditCards = customer.getProfile().getWallet().getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD);
Transaction.wrap(function () {
newCreditCard = customer.getProfile().getWallet().createPaymentInstrument(PaymentInstrument.METHOD_CREDIT_CARD);
// copy the credit card details to the payment instrument
newCreditCard.setCreditCardHolder(app.getForm('billing').object.paymentMethods.creditCard.owner.value);
newCreditCard.setCreditCardNumber(app.getForm('billing').object.paymentMethods.creditCard.number.value);
newCreditCard.setCreditCardExpirationMonth(app.getForm('billing').object.paymentMethods.creditCard.expiration.month.value);
newCreditCard.setCreditCardExpirationYear(app.getForm('billing').object.paymentMethods.creditCard.expiration.year.value);
newCreditCard.setCreditCardType(app.getForm('billing').object.paymentMethods.creditCard.type.value);
for (i = 0; i < creditCards.length; i++) {
var creditcard = creditCards[i];
if (creditcard.maskedCreditCardNumber === newCreditCard.maskedCreditCardNumber && creditcard.creditCardType === newCreditCard.creditCardType) {
customer.getProfile().getWallet().removePaymentInstrument(creditcard);
}
}
});
}
return true;
}
/*
* Module exports
*/
/*
* Web exposed methods
*/
/** Starting point for billing.
* @see module:controllers/COBilling~publicStart */
exports.Start = guard.ensure(['https'], publicStart);
/** Redeems gift certificates.
* @see module:controllers/COBilling~redeemGiftCertificateJson */
exports.RedeemGiftCertificateJson = guard.ensure(['https', 'get'], redeemGiftCertificateJson);
/** Removes gift certificate from the basket payment instruments.
* @see module:controllers/COBilling~removeGiftCertificate */
exports.RemoveGiftCertificate = guard.ensure(['https', 'get'], removeGiftCertificate);
/** Updates the order totals and recalculates the basket after a coupon code is applied.
* @see module:controllers/COBilling~updateSummary */
exports.UpdateSummary = guard.ensure(['https', 'get'], updateSummary);
/** Gets the customer address and saves it to the customer address book.
* @see module:controllers/COBilling~updateAddressDetails */
exports.UpdateAddressDetails = guard.ensure(['https', 'get'], updateAddressDetails);
/** Renders a form dialog to edit an address.
* @see module:controllers/COBilling~editAddress */
exports.EditAddress = guard.ensure(['https', 'get', 'csrf'], editAddress);
/** Returns information of a gift certificate including its balance as JSON response.
* @see module:controllers/COBilling~getGiftCertificateBalance */
exports.GetGiftCertificateBalance = guard.ensure(['https', 'get'], getGiftCertificateBalance);
/** Selects a customer credit card and returns the details of the credit card as JSON response.
* @see module:controllers/COBilling~selectCreditCard */
exports.SelectCreditCard = guard.ensure(['https', 'get'], selectCreditCard);
/** Adds the currently selected credit card to the billing form and initializes the credit card selection list.
* @see module:controllers/COBilling~updateCreditCardSelection */
exports.UpdateCreditCardSelection = guard.ensure(['https', 'get'], updateCreditCardSelection);
/** Form handler for the billing form.
* @see module:controllers/COBilling~billing */
exports.Billing = guard.ensure(['https', 'csrf'], billing);
/** Form handler for the returnToForm form.
* @see module:controllers/COBilling~editBillingAddress */
exports.EditBillingAddress = guard.ensure(['https', 'post'], editBillingAddress);
/*
* Local methods
*/
/** Saves the credit card used in the billing form in the customer payment instruments.
* @see module:controllers/COBilling~saveCreditCard */
exports.SaveCreditCard = saveCreditCard;
/** Revalidates existing payment instruments in later checkout steps.
* @see module:controllers/COBilling~validatePayment */
exports.ValidatePayment = validatePayment;
/** Handles the selection of the payment method and performs payment method specific validation and verification upon the entered form fields.
* @see module:controllers/COBilling~handlePaymentSelection */
exports.HandlePaymentSelection = handlePaymentSelection;