# Delivery Methods

# Introduction

A delivery method defines the intricacies of how an order is price quoted pre-purchase and finally delivered post-purchase.

The simplest form of a delivery method is "pickup" as it usually costs nothing and does not require any special process post-purchase. This often referred to as click & collect.

Delivering items post-purchase is often overlooked at when starting a new business and in many cases turns out to be the more complicated part of the sales process, think amazon.

For small retailers / small businesses in general deliveries are much easier than big enterprises as stock management increases in complexity. A small business has their items stored in one location only and the owner is present and simply knows what sells out.

The delivery framework in the SalesCloud Platform aims to simplify all the complexities of coding simple & complex delivery services.

# Base definition

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
    }
}

# Concepts

# Delivery Service Instance

A delivery service instance is not to be confused with a delivery method. A delivery service is created by users after installing your app.

A delivery method only defines the behavior and logic, in itself it does not exist until a user creates an instance of your delivery method.

Like the definition of a car, a car only defines the properties & the meaning thereof but has no actual values. Properties such as color, transmission, etc.

My renault clio is an instance of a car with unique plate numbers. Its properties are color red and transmission automatic. There exist many other instances of cars all with their own values.

A delivery method is like "car", it is only the definition and has no actual values.

Delivery Service Instances have real values.

# Config Fields

Config fields are not displayed publicly to customers.

Config fields are used to allow users to configure the behavior of your delivery method. These fields and their values are mapped to "deliveryInstance.data".

The config fields below and their values will be mapped to: deliveryInstance.data.foo deliveryInstance.data.test

We can say that the configuration lies with the instance of the delivery method.

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [
        {
            key: 'foo',
            label: 'bar',
            type: 'textfield'
        },
        {
            key: 'test',
            label: '123',
            type: 'select',
            options: [
                {   
                    key: 'option1',
                    label: 'Option 1'
                }
            ]
        }
    ],
    uiFields: [],
    callbacks: {
    }
}

# UI Fields

UI Fields are displayed to customers publicly in their checkout. UI fields allow you as a developer to define fields to capture information in checkouts.

Use cases include but are not limited to asking for additional information such as a delivery date or delivery day.

# Callbacks

# Is Available

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
        isAvailable: async function(deliveryInstance, order) {

            let available = {
                isAvailable: true,
                message: null
            }

            // Determine if this is delivery method should be available for the order

            return available
        }
    }
}

# Rate Legacy Order

This callback is used to determine the price of delivery. The order object comes from the checkout. You must remember that not all checkouts are the same across merchants and so values available on order object depends on what information has been requested in previous steps in the checkout.

If your delivery method depends on certain information being present on the order in order to determine the price of delivery then we recommend to check for this information in the isAvailable callback.

Please do not return null or price.amount = 0 for when you are unable to determine the price.

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
        rateLegacyOrder: async function(deliveryInstance, order, uiValues) {
            let price = {
                amount: 0,
                currency_code: 'ISK'
            }

            // Calculate price of delivery service here

            return deliveryInstance
        }
    }
}

# Rate Order

This callback is used to determine the price of delivery. The order object comes from the checkout. You must remember that not all checkouts are the same across merchants and so values available on order object depends on what information has been requested in previous steps in the checkout.

If your delivery method depends on certain information being present on the order in order to determine the price of delivery then we recommend to check for this information in the isAvailable callback.

Please do not return null or price.amount = 0 for when you are unable to determine the price.

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
        rateOrder: async function(deliveryInstance, order, uiValues) {
            let price = {
                amount: 0,
                currency_code: 'ISK'
            }

            // Calculate price of delivery service here

            return deliveryInstance
        }
    }
}

# Process Order

This callback is used to execute logic post-purchase after completing the checkout. For example this callback should be used to communicate with an external api to register the delivery.


const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
        processOrder: async function(deliveryInstance, order) {
            // Execute logic here, no return required
        }
    }
}

# Complete Example

const deliveryMethod = {
    title: "My Custom Delivery Method",
    description: "This is my delivery method description",
    namespace: "my_custom_delivery_method",
    configFields: [],
    uiFields: [],
    callbacks: {
        rateLegacyOrder: async function(deliveryInstance, order, uiValues) {
            let price = {
                amount: 0,
                currency_code: 'ISK'
            }

            // Calculate price of delivery service here

            return deliveryInstance
        },
        rateOrder: async function(deliveryInstance, order, uiValues) {
            let price = {
                amount: 0,
                currency_code: 'ISK'
            }

            // Calculate price of delivery service here

            return deliveryInstance
        },
        processOrder: async function(deliveryInstance, order) {
            // Execute logic here, no return required
        }
    }
}

# Registration

Finally any delivery method that you define must be exported in your app like so. Apps export an array delivery method object definitions and so can define multiple delivery methods in a single app.

module.exports = {
    app : app,
    deliveryMethods: [
        deliveryMethod
    ]
}