ViURShopClient.js

import {getSkey, request} from './HttpClient.js';

// Note: Order of functions should always be RCUD (this is NOT a typo of CRUD!)

/**
 * ViUR Shop Client
 */
export class ViURShopClient {

    /**
     * URL to the shop-backend (ViUR server)
     */
    host_url;

    /**
     * Name of the shop root module
     */
    shop_module;

    /**
     * URL to shop root module with the default renderer
     */
    shop_url;

    /**
     * URL to shop root module with the json renderer
     */
    shop_json_url;

    /**
     * URL to shop API module with the default renderer
     */
    shop_api_url;

    constructor({
                    host_url = null,
                    shop_module = 'shop',
                } = {}) {
        if (host_url === null) {
            try {
                this.host_url = import.meta.env.VITE_API_URL ? import.meta.env.VITE_API_URL : window.location.origin;
            } catch (e) {
                // The import crashes in a bundled runtime
                this.host_url = window.location.origin;
            }
        } else {
            this.host_url = host_url;
        }
        this.shop_module = shop_module;
        this.shop_url = `${this.host_url}/${this.shop_module}`;
        this.shop_json_url = `${this.host_url}/json/${this.shop_module}`;
        this.shop_api_url = `${this.shop_url}/api`;
        this.getStructure_url = `${this.host_url}/vi/getStructure`;
    }


    // --- Article ------------------------------------------------------------

    article_view({
                     article_key,
                     parent_cart_key,
                 } = {}) {
        return request(`${this.shop_api_url}/article_view`, {
            params: {
                'article_key': article_key,
                'parent_cart_key': parent_cart_key,
            },
        })
            .then(req => req.json());
    }


    article_add({
                    article_key,
                    parent_cart_key,
                    quantity = 1,
                    quantity_mode = 'increase',
                } = {}) {
        return request(`${this.shop_api_url}/article_add`, {
            method: 'POST',
            params: {
                article_key,
                parent_cart_key,
                quantity,
                quantity_mode,
            },
        })
            .then(req => req.json());
    }

    article_update({
                       article_key,
                       parent_cart_key,
                       quantity = 1,
                       quantity_mode = 'increase',
                   } = {}) {
        return request(`${this.shop_api_url}/article_update`, {
            method: 'POST',
            params: {
                article_key,
                parent_cart_key,
                quantity,
                quantity_mode,
            },
        })
            .then(req => req.json());
    }


    article_remove({
                       article_key,
                       parent_cart_key,
                   } = {}) {
        return request(`${this.shop_api_url}/article_remove`, {
            method: 'POST',
            params: {
                article_key,
                parent_cart_key,
            },
        })
            .then(req => req.json());
    }

    // --- Basket ---------------------------------------------------------------
    basket_list() {
        return request(`${this.shop_api_url}/basket_list`).then(req => req.json());
    }

    // --- Cart ---------------------------------------------------------------

    /**
     * List root nodes or children of a cart
     *
     * If a cart key is provided, the direct children (nodes and leafs) will
     * be returned.
     * Otherwise (without a key), the root nodes will be returned.
     *
     * @param {string} cart_key list direct children (nodes and leafs) of this parent node
     * @returns {Promise<Response>}
     */
    cart_list({cart_key = null} = {}) {
        const self = this;
        return request(`${this.shop_api_url}/cart_list`, {
            params: cart_key === null ? {} : {cart_key},
        })
            .then(req => req.json());
    }

    /**
     * Add a new cart node
     *
     * @param {string} parent_cart_key Key of the parent cart
     * @param {CartType} cart_type Type of the cart node, see `CartType`
     * @param {string=} name Optional. Name of the cart node
     * @param {string=} customer_comment Optional. Comment to this node, by customer.
     * @param {string=} shipping_address_key Optional. Key of the address
     * @param {string=} shipping_key Optional. Key of the shipping
     * @param {string=} discount_key Optional. Key of the discount
     * @returns {Promise<Response>}
     */
    cart_add({
                 parent_cart_key,
                 cart_type,
                 name,
                 customer_comment,
                 shipping_address_key,
                 shipping_key,
                 discount_key,
             } = {}) {
        return request(`${this.shop_api_url}/cart_add`, {
            method: 'POST',
            params: this.removeUndefinedValues({
                parent_cart_key,
                name,
                cart_type,
                customer_comment,
                shipping_address_key,
                shipping_key,
                discount_key,
            }),
        })
            .then(req => req.json());
    }

    /**
     * Update an existing cart node
     *
     * @param {string} cart_key Key of the cart node to be updated
     * @param {CartType} cart_type Type of the cart node, see `CartType`
     * @param {string=} name Optional. Name of the cart node
     * @param {string=} customer_comment Optional. Comment to this node, by customer.
     * @param {string=} shipping_address_key Optional. Key of the address
     * @param {string=} shipping_key Optional. Key of the shipping
     * @param {string=} discount_key Optional. Key of the discount
     * @returns {Promise<Response>}
     */
    cart_update({
                    cart_key,
                    cart_type,
                    name,
                    customer_comment,
                    shipping_address_key,
                    shipping_key,
                    discount_key,
                } = {}) {
        return request(`${this.shop_api_url}/cart_update`, {
            method: 'POST',
            params: this.removeUndefinedValues({
                cart_key,
                cart_type,
                name,
                customer_comment,
                shipping_address_key,
                shipping_key,
                discount_key,
            }),
        })
            .then(req => req.json());
    }

    /**
     * Remove a cart node.
     * Removes itself and all children
     *
     * @param {string} cart_key Key of the cart node to be removed
     * @returns {Promise<Response>}
     */
    cart_remove({cart_key} = {}) {
        return request(`${this.shop_api_url}/cart_remove`, {
            method: 'POST',
            params: {
                cart_key,
            },
        })
            .then(req => req.json());
    }

    cart_structure() {
        return request(`${this.getStructure_url}/${this.shop_module}.cart`, {
            method: 'GET',
        })
            .then(req => req.json());
    }

    // --- Address ------------------------------------------------------------

    address_list({} = {}) {
        const self = this;
        return request(`${this.shop_json_url}/address/list`, {
            params: {
                limit: 100,
            },
        })
            .then(req => req.json())
            .then(response => response.skellist);
    }

    address_add({
                    customer_type,
                    salutation,
                    company_name,
                    firstname,
                    lastname,
                    street_name,
                    street_number,
                    address_addition,
                    zip_code,
                    city,
                    country,
                    customer_key,
                    is_default,
                    address_type,
                } = {}) {
        return getSkey()
            .then(skey => {
                return request(`${this.shop_json_url}/address/add`, {
                    method: 'POST',
                    params: this.removeUndefinedValues({
                        skey,
                        customer_type,
                        salutation,
                        company_name,
                        firstname,
                        lastname,
                        street_name,
                        street_number,
                        address_addition,
                        zip_code,
                        city,
                        country,
                        customer: customer_key,
                        is_default,
                        address_type,
                    }),
                })
                    .then(req => req.json())
                    .then(response => response.values);
            });
    }

    address_structure() {
        return request(`${this.getStructure_url}/${this.shop_module}.address`, {
            method: 'GET',
        })
            .then(req => req.json());
    }

    // --- Order --------------------------------------------------------------

    payment_providers_list({} = {}) {
        return request(`${this.shop_url}/order/payment_providers_list`)
            .then(req => req.json());
    }

    order_add({
                  cart_key,
                  payment_provider,
                  billing_address_key,
                  email,
                  customer_key,
                  state_ordered,
                  state_paid,
                  state_rts,
              } = {}) {
        return request(`${this.shop_api_url}/order_add`, {
            method: 'POST',
            params: this.removeUndefinedValues({
                cart_key,
                payment_provider,
                billing_address_key,
                email,
                customer_key,
                state_ordered,
                state_paid,
                state_rts,
            }),
        })
            .then(req => req.json());
    }

    order_update({
                     order_key,
                     payment_provider,
                     billing_address_key,
                     email,
                     customer_key,
                     state_ordered,
                     state_paid,
                     state_rts,
                 } = {}) {
        return request(`${this.shop_api_url}/order_update`, {
            method: 'POST',
            params: this.removeUndefinedValues({
                order_key,
                payment_provider,
                billing_address_key,
                email,
                customer_key,
                state_ordered,
                state_paid,
                state_rts,
            }),
        })
            .then(req => req.json());
    }

    order_checkout_start({
                             order_key,
                         } = {}) {
        return request(`${this.shop_url}/order/checkout_start`, {
            method: 'POST',
            params: {order_key},
        })
            .then(req => req.json());
    }

    order_checkout_order({
                             order_key,
                         } = {}) {
        return request(`${this.shop_url}/order/checkout_order`, {
            method: 'POST',
            params: {order_key},
        })
            .then(req => req.json());
    }

    order_pp_get_settings({
                              order_key,
                          } = {}) {
        return request(`${this.shop_url}/order/checkout_order`, {
            method: 'POST',
            params: {order_key},
        })
            .then(req => req.json());
    }


    // --- User ---------------------------------------------------------------

    user_view({
                  user_key = 'self',
              } = {}) {
        return request(`${this.host_url}/json/user/view/${user_key}`)
            .then(req => req.json())
            .then(response => response.values);
    }


    // --- Discount -----------------------------------------------------------
    /**
     * Add a Discount to the current Cart.
     * @param {string} code Human readable Discount Code
     * @param {string} discount_key Database Key from a Discount.
     * @returns {Response<Response>}
     */
    discount_add({
                     code,
                     discount_key,
                 } = {}) {
        return request(`${this.shop_api_url}/discount_add`, {
            method: 'POST',
            params: this.removeUndefinedValues({
                code,
                discount_key,
            }),
        })
            .then(req => req.json());
    }

    /**
     * Removes a Discount by the Database Key
     * @param {string} discount_key Database Key from a Discount.
     * @returns {Promise<Response>}
     */
    discount_remove({
                        discount_key,
                    } = {}) {
        return request(`${this.shop_api_url}/discount_remove`, {
            method: 'POST',
            params: {discount_key},
        })
            .then(req => req.json());
    }


    // --- Shipping -----------------------------------------------------------

    /**
     * Lists available shipping options for a (sub)cart
     * @param {string} cart_key Key of the parent cart
     * @returns {Promise<Response>} List of ShippingsSkels
     */
    shipping_list({
                      cart_key,
                  } = {}) {
        return request(`${this.shop_api_url}/shipping_list`, {
            method: 'GET',
            params: {cart_key},
        })
            .then(req => req.json());
    }


    // --- Utils -------------------------------------------------------------

    removeUndefinedValues(obj) {
        return Object.fromEntries(
            Object.entries(obj)
                .filter(([key, value]) => value !== undefined),
        );
    }
}