menu

SiteGenesis / Server-side JS / Source: app_storefront_controllers/cartridge/controllers/COShippingMultiple.js

'use strict';

/**
 * Controller for the multishipping scenario. Multishipping involves more
 * than one shipment, shipping address, and/or shipping method per order.
 *
 * @module controllers/COShippingMultiple
 */

/* API Includes */
var ShippingMgr = require('dw/order/ShippingMgr');
var Transaction = require('dw/system/Transaction');
var UUIDUtils = require('dw/util/UUIDUtils');
var URLUtils = require('dw/web/URLUtils');

/* Script Modules */
var app = require('~/cartridge/scripts/app');
var guard = require('~/cartridge/scripts/guard');

var Cart = app.getModel('Cart');
var TransientAddress = app.getModel('TransientAddress');

/**
 * Starting point for multishipping scenario. Renders a page providing address selection for each product line item.
 *
 * @transaction
 */
function start() {
    var cart = Cart.get();

    if (cart) {

        // Stores session and customer addresses in sessionAddressBook attribute.
        Transaction.wrap(function () {
            cart.initAddressBook(customer);
        });

        // Creates for each quantity of ProductLineItems new QuantityLineItems helper objects.
        var quantityLineItems = null;
        var plis = cart.getProductLineItems();
        for (var i = 0; i < plis.length; i++) {
            quantityLineItems = cart.separateQuantities(plis[i], quantityLineItems);
        }

        initAddressForms(cart, quantityLineItems);

        app.getController('COShipping').PrepareShipments();
        Transaction.wrap(function () {
            cart.calculate();
        });

        app.getView({
            Basket: cart.object,
            ContinueURL: URLUtils.https('COShippingMultiple-MultiShippingAddresses')
        }).render('checkout/shipping/multishipping/multishippingaddresses');
    } else {
        app.getController('Cart').Show();
        return;
    }
}

/**
 * Form handler for multishipping form. Handles the save action. Updates the cart calculation, creates shipments
 * and renders the multishippingaddress template.
 */
function multiShippingAddresses() {
    var multiShippingForm = app.getForm('multishipping');

    multiShippingForm.handleAction({
        save: function () {
            var cart = Cart.get();

            var result = Transaction.wrap(function () {
                var MergeQuantities = require('app_storefront_core/cartridge/scripts/checkout/multishipping/MergeQuantities');
                var ScriptResult = MergeQuantities.execute({
                    CBasket: cart.object,
                    QuantityLineItems: session.forms.multishipping.addressSelection.quantityLineItems
                });
                return ScriptResult;
            });

            if (result) {
                Transaction.wrap(function () {
                    cart.calculate();
                });

                multiShippingForm.setValue('addressSelection.fulfilled', true);

                startShipments();
                return;
            } else {
                app.getView({
                    Basket: cart.object,
                    ContinueURL: URLUtils.https('COShippingMultiple-MultiShippingAddresses')
                }).render('checkout/shipping/multishipping/multishippingaddresses');
                return;
            }
        }
    });
}

/**
 * The second step of multishipping: renders a page for each shipment, providing a shipping method selection per shipment.
 * If a basket exists, renders the multishippingshipments template. If no basket exists, calls the
 * {@link module:controllers/Cart~Show|Cart controller Show function}.
 * @transaction
 */
function startShipments() {
    var cart = Cart.get();

    if (cart) {

        app.getController('COShipping').PrepareShipments();

        // Initializes the forms for the multishipment setting.
        session.forms.multishipping.shippingOptions.clearFormElement();

        app.getForm(session.forms.multishipping.shippingOptions.shipments).copyFrom(cart.getShipments());

        // Initializes the shipping method list for each shipment.
        var count = session.forms.multishipping.shippingOptions.shipments.childCount;
        for (var i = 0; i < count; i++) {
            var shipmentForm = session.forms.multishipping.shippingOptions.shipments[i];
            var shippingMethods = ShippingMgr.getShipmentShippingModel(shipmentForm.object).applicableShippingMethods;

            shipmentForm.shippingMethodID.setOptions(shippingMethods.iterator());
        }

        Transaction.wrap(function () {
            cart.calculate();
        });

        app.getView({
            Basket: cart.object,
            ContinueURL: URLUtils.https('COShippingMultiple-MultiShippingMethods')
        }).render('checkout/shipping/multishipping/multishippingshipments');
    } else {
        app.getController('Cart').Show();
        return;
    }
}

/**
 * Form handler for the multishipping form. Handles the save action.
 * Sets the shipping method for each shipment and copies it to the shipmentForm.
 * If the copy fails, it renders the multishippingshipments template. If it succeeds,
 * it calls the {@link module:controllers/COBilling~Start|COBilling controller Start function}.
 * @transaction
 */
function multiShippingMethods() {
    var multiShippingForm = app.getForm('multishipping');

    multiShippingForm.handleAction({
        save: function () {
            Transaction.wrap(function () {
                var count = session.forms.multishipping.shippingOptions.shipments.childCount;
                for (var i = 0; i < count; i++) {
                    var shipmentForm = session.forms.multishipping.shippingOptions.shipments[i];

                    if (shipmentForm.shippingMethodID.selectedOptionObject !== null) {
                        shipmentForm.getObject().setShippingMethod(shipmentForm.shippingMethodID.selectedOptionObject);
                    }

                    if (!app.getForm(shipmentForm).copyTo(shipmentForm.object)) {
                        app.getView({
                            Basket: Cart.get().object,
                            ContinueURL: URLUtils.https('COShippingMultiple-MultiShippingMethods')
                        }).render('checkout/shipping/multishipping/multishippingshipments');
                        return;
                    }
                }
            });

            // Mark step as fulfilled.
            session.forms.multishipping.shippingOptions.fulfilled.value = true;

            app.getController('COBilling').Start();
            return;
        }
    });
}

/**
 * Initializes the forms for the multiaddress selection.
 */
function initAddressForms(cart, quantityLineItems) {

    // Set flag, that customer has entered the multi shipping scenario.
    session.forms.multishipping.entered.value = true;

    if (!session.forms.multishipping.addressSelection.fulfilled.value) {
        session.forms.multishipping.addressSelection.clearFormElement();
        app.getForm(session.forms.multishipping.addressSelection.quantityLineItems).copyFrom(quantityLineItems);
    }

    var addresses = cart.getAddressBookAddresses();

    if (!addresses) {
        start();
        return;
    } else {
        for (var i = 0; i < session.forms.multishipping.addressSelection.quantityLineItems.childCount; i++) {
            var quantityLineItem = session.forms.multishipping.addressSelection.quantityLineItems[i];
            quantityLineItem.addressList.setOptions(addresses.iterator());
        }

    }
}

/**
 * Renders a form dialog to edit an address. The dialog is opened by an Ajax request and renders templates,
 * which trigger a JavaScript event. The calling page of this dialog is responsible for handling these events.
 */
function editAddresses() {
    var cart = Cart.get();

    if (cart) {

        session.forms.multishipping.editAddress.clearFormElement();

        var addresses = cart.getAddressBookAddresses();

        if (!addresses) {
            start();
            return;
        } else {
            session.forms.multishipping.editAddress.addressList.setOptions(addresses.iterator());
            app.getView({
                Basket: cart.object,
                ContinueURL: URLUtils.https('COShippingMultiple-EditForm')
            }).render('checkout/shipping/multishipping/editaddresses');
        }

        return;
    } else {
        app.getController('Cart').Show();
        return;
    }
}

/**
 * Form handler for the multishipping form. Handles the following actions:
 * - __cancel__ - calls the {@link module:controllers/COShippingMultiple~start|start function}.
 * - __save__ - calls the {@link module:controllers/COShippingMultiple~addEditAddress|addEditAddress function}. If it returns an error, renders the editaddresses template.
 * - __selectAddress__ - clears the multishipping form and calls the {@link module:controllers/COShippingMultiple~editAddress|editAddress function}.
 */
function editForm() {
    var multiShippingForm = app.getForm('multishipping');

    multiShippingForm.handleAction({
        cancel: function () {
            start();
            return;
        },
        save: function () {
            var addEditAddressResult = addEditAddress();
            if (addEditAddressResult.error) {
                app.getView({
                    ContinueURL: URLUtils.https('COShippingMultiple-EditForm')
                }).render('checkout/shipping/multishipping/editaddresses');
                return;
            }

            start();
            return;
        },
        selectAddress: function () {
            if (!session.forms.multishipping.editAddress.addressList.selectedOption) {

                session.forms.multishipping.editAddress.clearFormElement();
                editAddresses();

                return;
            }

            app.getForm(session.forms.multishipping.editAddress.addressFields).copyFrom(session.forms.multishipping.editAddress.addressList.selectedOptionObject);
            app.getForm(session.forms.multishipping.editAddress.addressFields.states).copyFrom(session.forms.multishipping.editAddress.addressList.selectedOptionObject);
            app.getView({
                Basket: Cart.get().object,
                ContinueURL: URLUtils.https('COShippingMultiple-EditForm')
            }).render('checkout/shipping/multishipping/editaddresses');

            return;
        }
    });
}

/**
  * Creates a new transient address. Attempts to copy address information from the multishipping form to the transient address.
  * Updates the customer address book. Updates the session address book.
  * If address information cannot be saved to the transient address, returns a JSON object containing success and error information.
 * @returns {object} JSON object indicating success, error and/or address information.
 */
function addEditAddress() {
    var cart = Cart.get();

    var newAddress = new TransientAddress();
    newAddress.UUID = UUIDUtils.createUUID();

    if (!app.getForm(session.forms.multishipping.editAddress.addressFields).copyTo(newAddress) || !app.getForm(session.forms.multishipping.editAddress.addressFields.states).copyTo(newAddress)) {
        return {success: false, error: true};
    } else {

        var referenceAddress = session.forms.multishipping.editAddress.addressList.selectedOptionObject;
        var addToCustomerAddressBook = session.forms.multishipping.editAddress.addToAddressBook.checked;
        var customerAddress = null;

        // Handles customer address book update process.
        if (addToCustomerAddressBook && addToCustomerAddressBook === true) {
            if (referenceAddress) {
                // Gets address from address book.
                if (referenceAddress.ID) {
                    customerAddress = customer.addressBook.getAddress(referenceAddress.ID);
                }
            } else {
                customerAddress = Transaction.wrap(function () {
                    return app.getModel('Profile').get(customer.profile).addAddressToAddressBook(newAddress);
                });
                newAddress.ID = customerAddress.ID;
                newAddress.referenceAddressUUID = customerAddress.getUUID();
            }

            if (customerAddress) {
                var helperAddress = new TransientAddress();
                helperAddress.copyFrom(newAddress);
                Transaction.wrap(function () {
                    helperAddress.copyTo(customerAddress);
                });
            }
        }

        // Handle session address book update process
        if (referenceAddress) {
            // Update Address
            newAddress.UUID = referenceAddress.UUID;
            Transaction.wrap(function () {
                cart.updateAddressBookAddress(newAddress);
            });
        } else {
            Transaction.wrap(function () {
                cart.addAddressToAddressBook(newAddress);
            });
        }

        for (var i = 0; i < session.forms.multishipping.addressSelection.quantityLineItems.childCount; i++) {
            var quantityLineItem = session.forms.multishipping.addressSelection.quantityLineItems[i];
            quantityLineItem.addressList.setOptions(cart.getAddressBookAddresses().iterator());
        }

        return {success: true, address: newAddress};
    }
}

/**
 * Calls the {@link module:controllers/COShippingMultiple~addEditAddress|addEditAddress function} and renders a JSON message
 * with information about the address and the success of the edit.
 */
function addEditAddressJSON() {
    var addEditAddressResult = addEditAddress();

    let r = require('~/cartridge/scripts/util/Response');
    r.renderJSON({
        address: addEditAddressResult.address,
        success: addEditAddressResult.success
    });
}

/*
 * Module exports
 */

/*
 * Web exposed methods
 */
/** Starting point for multishipping scenario.
 * @see module:controllers/COShippingMultiple~start */
exports.Start = guard.ensure(['https'], start);
/** The second step of multishipping: renders a page for each shipment, providing a shipping method selection per shipment.
 * @see module:controllers/COShippingMultiple~startShipments */
exports.StartShipments = guard.ensure(['https', 'get'], startShipments);
/** Renders a form dialog to edit an address.
 * @see module:controllers/COShippingMultiple~editAddresses */
exports.EditAddresses = guard.ensure(['https', 'get'], editAddresses);
/** Edits addresses and updates the customer address book and the session address book. Renders a JSON message indicating success or failure.
 * @see module:controllers/COShippingMultiple~addEditAddressJSON */
exports.AddEditAddressJSON = guard.ensure(['https', 'get'], addEditAddressJSON);
/** Form handler for multishipping form. Handles the save action.
 * @see module:controllers/COShippingMultiple~multiShippingAddresses */
exports.MultiShippingAddresses = guard.ensure(['https', 'post'], multiShippingAddresses);
/** Form handler for multishipping form. Handles the save action.
 * @see module:controllers/COShippingMultiple~multiShippingMethods */
exports.MultiShippingMethods = guard.ensure(['https', 'post'], multiShippingMethods);
/** Form handler for multishipping form. Handles cancel, save, and selectAddress actions.
 * @see module:controllers/COShippingMultiple~editForm */
exports.EditForm = guard.ensure(['https', 'post'], editForm);

X Privacy Update: We use cookies to make interactions with our websites and services easy and meaningful, to better understand how they are used. By continuing to use this site you are giving us your consent to do this. Privacy Policy.