Source: item.js

/**
 * The Item module
 * @module item
 * @copyright CHECKROOM NV 2015
 */
define([
    'jquery',
    'common',
    'base'], /** @lends Base */ function ($, common, Base) {

    var FLAG = "cheqroom.prop.Custom",
        DEFAULT_LAT = 0.0,
        DEFAULT_LONG = 0.0,
        DEFAULTS = {
            name: "",
            status: "",
            codes: [],
            brand: "",
            model: "",
            warrantyDate: null,
            purchaseDate: null,
            purchasePrice: null,
            residualValue: null,
            location: "",
            category: "",
            geo: [DEFAULT_LAT,DEFAULT_LONG],
            address: "",
            order: null,
            kit: null,
            custody: null,
            cover: "",
            catalog: null
        };

    // Allow overriding the ctor during inheritance
    // http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain
    var tmp = function() {};
    tmp.prototype = Base.prototype;

    /**
     * Item represents a single piece of equipment
     * @name Item
     * @class Item
     * @constructor
     * @property {string} name              the name of the item
     * @property {string} status            the status of the item in an order, or expired
     * @property {string} brand             the item brand
     * @property {string} model             the item model
     * @property {moment} warrantyDate      the item warranty date
     * @property {moment} purchaseDate      the item purchase date
     * @property {string} purchasePrice     the item purchase price
     * @property {Array} codes              the item qr codes
     * @property {string} location          the item location primary key (empty if in_custody)
     * @property {string} category          the item category primary key
     * @property {Array} geo                the item geo position in lat lng array
     * @property {string} address           the item geo position address
     * @property {string} order             the order pk, if the item is currently in an order
     * @property {string} kit               the kit pk, if the item is currently in a kit
     * @property {string} custody           the customer pk, if the item is currently in custody of someone
     * @property {string} cover             the attachment pk of the main image
     * @property {string} catalog           the catalog pk, if the item was made based on a product in the catalog
     * @extends Base
     */
    var Item = function(opt) {
        var spec = $.extend({
            _fields: ['*'],
            crtype: 'cheqroom.types.item'
        }, opt);
        Base.call(this, spec);

        this.name = spec.name || DEFAULTS.name;
        this.status = spec.status || DEFAULTS.status;
        this.brand = spec.brand || DEFAULTS.brand;
        this.model = spec.model || DEFAULTS.model;
        this.warrantyDate = spec.warrantyDate || DEFAULTS.warrantyDate;
        this.purchaseDate = spec.purchaseDate || DEFAULTS.purchaseDate;
        this.purchasePrice = spec.purchasePrice || DEFAULTS.purchasePrice;
        this.residualValue = spec.residualValue || DEFAULTS.residualValue;
        this.codes = spec.codes || DEFAULTS.codes;
        this.location = spec.location || DEFAULTS.location;     // location._id
        this.category = spec.category || DEFAULTS.category;     // category._id
        this.geo = spec.geo || DEFAULTS.geo.slice();            // null or an array with 2 floats
        this.address = spec.address || DEFAULTS.address;
        this.order = spec.order || DEFAULTS.order;
        this.kit = spec.kit || DEFAULTS.kit;
        this.custody = spec.custody || DEFAULTS.custody;
        this.cover = spec.cover || DEFAULTS.cover;
        this.catalog = spec.catalog || DEFAULTS.catalog;
    };

    Item.prototype = new tmp();
    Item.prototype.constructor = Item;

    //
    // Base overrides
    //
    Item.prototype.isValidName = function() {
        this.name = $.trim(this.name);
        return (this.name.length>=3);
    };

    Item.prototype.isValidCategory = function() {
        return ($.trim(this.category).length>0);
    };

    Item.prototype.isValidLocation = function() {
        return ($.trim(this.location).length>0);
    };

    Item.prototype.isValid = function() {
        return (
            this.isValidName() &&
            this.isValidCategory() &&
            ((this.status=="in_custody") ? true : this.isValidLocation())
        );
    };

    /**
     * Checks if the item is empty
     * @name Item#isEmpty
     * @returns {boolean}
     */
    Item.prototype.isEmpty = function() {
        // Checks for: name, status, brand, model, purchaseDate, purchasePrice, codes, location, category
        return (
        (Base.prototype.isEmpty.call(this)) &&
        (this.name==DEFAULTS.name) &&
        (this.status==DEFAULTS.status) &&
        (this.brand==DEFAULTS.brand) &&
        (this.model==DEFAULTS.model) &&
        (this.warrantyDate==DEFAULTS.warrantyDate) &&
        (this.purchaseDate==DEFAULTS.purchaseDate) &&
        (this.purchasePrice==DEFAULTS.purchasePrice) &&
        (this.residualValue==DEFAULTS.residualValue) &&
        (this.codes.length==0) &&  // not DEFAULTS.codes? :)
        (this.location==DEFAULTS.location) &&
        (this.category==DEFAULTS.category));
    };

    /**
     * Checks if the item is dirty and needs saving
     * @name Item#isDirty
     * @returns {boolean}
     */
    Item.prototype.isDirty = function() {
        return (
            Base.prototype.isDirty.call(this) ||
            this._isDirtyName() ||
            this._isDirtyBrand() ||
            this._isDirtyModel() ||
            this._isDirtyWarrantyDate() ||
            this._isDirtyPurchaseDate() ||
            this._isDirtyPurchasePrice() ||
            this._isDirtyResidualValue() ||
            this._isDirtyCategory() ||
            this._isDirtyLocation() ||
            this._isDirtyGeo() || 
            this._isDirtyFlag()
        );
    };

    Item.prototype._getDefaults = function() {
        return DEFAULTS;
    };

    Item.prototype._toJson = function(options) {
        // Writes out: id, name,
        //             brand, model, purchaseDate, purchasePrice
        //             category, location, catalog
        var data = Base.prototype._toJson.call(this, options);
        data.name = this.name || DEFAULTS.name;
        data.brand = this.brand || DEFAULTS.brand;
        data.model = this.model || DEFAULTS.model;
        data.warrantyDate = this.warrantyDate || DEFAULTS.warrantyDate;
        data.purchaseDate = this.purchaseDate || DEFAULTS.purchaseDate;
        data.purchasePrice = this.purchasePrice || DEFAULTS.purchasePrice;
        data.residualValue = this.residualValue || DEFAULTS.residualValue;
        data.category = this.category || DEFAULTS.category;
        data.location = this.location || DEFAULTS.location;
        data.catalog = this.catalog || DEFAULTS.catalog;

        // Remove values of null during create
        // Avoids: 422 Unprocessable Entity
        // ValidationError (Item:TZe33wVKWwkKkpACp6Xy5T) (FloatField only accepts float values: ['purchasePrice'])
        for (var k in data) {
            if (data[k] == null) {
                delete data[k];
            }
        }

        return data;
    };

    Item.prototype._fromJson = function(data, options) {
        var that = this;
        return Base.prototype._fromJson.call(this, data, options)
            .then(function() {
                that.name = data.name || DEFAULTS.name;
                that.status = data.status || DEFAULTS.status;
                that.brand = data.brand || DEFAULTS.brand;
                that.model = data.model || DEFAULTS.model;
                that.warrantyDate = data.warrantyDate || DEFAULTS.warrantyDate;
                that.purchaseDate = data.purchaseDate || DEFAULTS.purchaseDate;
                that.purchasePrice = data.purchasePrice || DEFAULTS.purchasePrice;
                that.residualValue = data.residualValue || DEFAULTS.residualValue;
                that.codes = data.codes || DEFAULTS.codes;
                that.address = data.address || DEFAULTS.address;
                that.geo = data.geo || DEFAULTS.geo.slice();
                that.cover = data.cover || DEFAULTS.cover;
                that.catalog = data.catalog || DEFAULTS.catalog;

                // Depending on the fields we'll need to get the _id directly or from the dicts
                var locId = DEFAULTS.location;
                if (data.location) {
                    locId = (data.location._id) ? data.location._id : data.location;
                }
                that.location = locId;

                var catId = DEFAULTS.category;
                if (data.category) {
                    catId = (data.category._id) ? data.category._id : data.category;
                }
                that.category = catId;

                var orderId = DEFAULTS.order;
                if (data.order) {
                    orderId = (data.order._id) ? data.order._id : data.order;
                }
                that.order = orderId;

                var kitId = DEFAULTS.kit;
                if (data.kit) {
                    kitId = (data.kit._id) ? data.kit._id : data.kit;
                }
                that.kit = kitId;

                var custodyId = DEFAULTS.custody;
                if (data.custody) {
                    custodyId = (data.custody._id) ? data.custody._id : data.custody;
                }
                that.custody = custodyId;

                $.publish('item.fromJson', data);
                return data;
            });
    };

    // Deprecated
    Item.prototype._toJsonKeyValues = function(){
        var that = this;
        var params = {};

        if( (this.keyValues!=null) &&
            (this.keyValues.length>0)) {
            $.each(this.keyValues, function(i, kv) {
                var param = 'keyValues__' + kv.key;
                params[param + "__kind"] = kv.kind;
                params[param + "__value"] = kv.value;
            });
        }

        return params;
    };

    // Deprecated
    Item.prototype._isDirtyName = function() {
        return this._isDirtyStringProperty("name");
    };

    Item.prototype._isDirtyBrand = function() {
        return this._isDirtyStringProperty("brand");
    };

    Item.prototype._isDirtyModel = function() {
        return this._isDirtyStringProperty("model");
    };

    Item.prototype._isDirtyWarrantyDate = function() {
        return this._isDirtyMomentProperty("warrantyDate");
    };

    Item.prototype._isDirtyPurchaseDate = function() {
        return this._isDirtyMomentProperty("purchaseDate");
    };

    Item.prototype._isDirtyPurchasePrice = function() {
        return this._isDirtyProperty("purchasePrice");
    };

    Item.prototype._isDirtyResidualValue = function() {
        return this._isDirtyProperty("residualValue");
    };

    Item.prototype._isDirtyLocation = function() {
        if (this.raw && this.status != 'in_custody') {
            var locId = DEFAULTS.location;
            if (this.raw.location) {
                locId = (this.raw.location._id) ? this.raw.location._id : this.raw.location;
            }
            return (this.location!=locId);
        } else {
            return false;
        }
    };

    Item.prototype._isDirtyCategory = function() {
        if (this.raw) {
            var catId = DEFAULTS.category;
            if (this.raw.category) {
                catId = (this.raw.category._id) ? this.raw.category._id : this.raw.category;
            }
            return (this.category!=catId);
        } else {
            return false;
        }
    };

    Item.prototype._isDirtyGeo = function() {
        if (this.raw) {
            var address = this.raw.address || DEFAULTS.address;
            var geo = this.raw.geo || DEFAULTS.geo.slice();
            return (
            (this.address!=address) ||
            (this.geo[0]!=geo[0]) ||
            (this.geo[1]!=geo[1]));
        } else {
            return false;
        }
    };

    Item.prototype._isDirtyFlag = function() {
        return this._isDirtyStringProperty("flag");
    };

    //
    // Business logic
    //
    /**
     * Checks if the Item is unavailable between from / to dates (optional)
     * @name Item#getAvailabilities
     * @param {Moment} from       the from date (optional)
     * @param {Moment} to         the to date (optional)
     * @returns {promise}
     */
    Item.prototype.getAvailabilities = function(from, to) {
        return this.ds.call(this.id, 'getAvailability', {fromDate: from, toDate: to});
    };

    /**
     * updates the Item
     * We override because Item.update does not support updating categories
     * @param skipRead
     * @returns {*}
     */
    Item.prototype.update = function(skipRead) {
        if (this.isEmpty()) {
            return $.Deferred().reject(new Error("Cannot update to empty document"));
        }
        if (!this.existsInDb()) {
            return $.Deferred().reject(new Error("Cannot update document without id"));
        }
        if (!this.isValid()) {
            return $.Deferred().reject(new Error("Cannot update, invalid document"));
        }

        var that = this,
            dfdCheck = $.Deferred(),
            dfdCategory = $.Deferred(),
            dfdLocation = $.Deferred(),
            dfdFields = $.Deferred(),
            dfdFlags = $.Deferred(),
            dfdBasic = $.Deferred();

        if (this._isDirtyCategory()) {
            this.canChangeCategory(this.category)
                .done(function(data) {
                    if (data.result) {
                        dfdCheck.resolve();
                    } else {
                        dfdCheck.reject(new Error("Unable to change item category"));
                    }
                });
        } else {
            dfdCheck.resolve();
        }

        return dfdCheck
            .then(function() {
                if (that._isDirtyCategory()) {
                    dfdCategory = that.changeCategory(that.category);
                } else {
                    dfdCategory.resolve();
                }

                // Skip update location if item is in custody
                if (that._isDirtyLocation() && that.status != "in_custody") {
                    dfdLocation = that.changeLocation(that.location);
                } else {
                    dfdLocation.resolve();
                }

                if (that._isDirtyFields()) {
                    dfdFields = that._updateFields();
                } else {
                    dfdFields.resolve();
                }

                if (that._isDirtyFlag()) {
                    if ((that.flag=="") || (that.flag==null)) {
                        dfdFlags = that.clearFlag();
                    } else {                        
                        dfdFlags = that.setFlag(that.flag);
                    }
                } else {
                    dfdFlags.resolve();
                }

                if( (that._isDirtyName()) ||
                    (that._isDirtyBrand()) ||
                    (that._isDirtyModel()) ||
                    (that._isDirtyWarrantyDate()) ||
                    (that._isDirtyPurchaseDate()) ||
                    (that._isDirtyPurchasePrice()) ||
                    (that._isDirtyResidualValue())) {
                    dfdBasic = that.updateBasicFields(that.name, that.brand, that.model, that.warrantyDate, that.purchaseDate, that.purchasePrice, that.residualValue);
                } else {
                    dfdBasic.resolve();
                }

                return $.when(dfdCategory, dfdLocation, dfdFields, dfdFlags, dfdBasic);
            });
    };

    /**
     * Creates an Item
     * @name  Item#create
     * @method
     * @param skipRead skips reading the response via _fromJson (false)
     * @returns {promise}
     */
    Item.prototype.create = function(skipRead) {
        if (this.existsInDb()) {
            return $.Deferred().reject(new Error("Cannot create document, already exists in database"));
        }
        if (this.isEmpty()) {
            return $.Deferred().reject(new Error("Cannot create empty document"));
        }
        if (!this.isValid()) {
            return $.Deferred().reject(new Error("Cannot create, invalid document"));
        }

        var that = this,
            data = $.extend(this._toJson(), this._toJsonFields());

        delete data.id;

        return this.ds.create(data, this._fields)
            .then(function(data) {
                return (skipRead==true) ? data : that._fromJson(data);
            });
    };

    /**
     * Creates multiple instances of the same item
     * @name  Item#createMultiple
     * @method
     * @param  times
     * @param  autoNumber
     * @param  startFrom
     * @return {promise}
     */
    Item.prototype.createMultiple = function(times, autoNumber, startFrom, skipRead){
        if (this.existsInDb()) {
            return $.Deferred().reject(new Error("Cannot create document, already exists in database"));
        }
        if (this.isEmpty()) {
            return $.Deferred().reject(new Error("Cannot create empty document"));
        }
        if (!this.isValid()) {
            return $.Deferred().reject(new Error("Cannot create, invalid document"));
        }

        var that = this;
        var data = $.extend(this._toJson(), this._toJsonFields(), {
            times: times || 1,
            autoNumber: autoNumber || false,
            startFrom: startFrom
        });
        delete data.id;

        // BUGFFIX model name clash issue
        // model == Item property
        // model == database model
        if (data.model != null) {
            data.brandModel = data.model;
            delete data.model;
        }

        return this._doApiCall({
            method: 'createMultiple',
            params: data
        }).then(function(data) {
            var dfd = (skipRead==true) ? $.Deferred().resolve(data[0]) : that._fromJson(data[0]);
            return dfd.then(function(){
                return data;
            });
        });
    };

    /**
     * Duplicates an item a number of times
     * @name Item#duplicate
     * @param times
     * @param location
     * @returns {promise}
     */
    Item.prototype.duplicate = function(times, location, autoNumber, startFrom) {
        return this._doApiCall({
            method: 'duplicate',
            params: {
                times: times,
                location: location,
                autoNumber: autoNumber,
                startFrom: startFrom
            },
            skipRead: true  // response is an array of new Item objects!!
        });
    };

    /**
     * Checks if an item can be reserved (based on status)
     * @name Item#canReserve
     * @returns {boolean}
     */
    Item.prototype.canReserve = function() {
        return common.itemCanReserve(this);
    };

    /**
     * Checks if an item can be checked out (based on status)
     * @name Item#canCheckout
     * @returns {boolean}
     */
    Item.prototype.canCheckout = function() {
        return common.itemCanCheckout(this);
    };

    /**
     * Checks if we can go to the checkout of an item (based on status)
     * @name Item#canGoToCheckout
     * @returns {boolean}
     */
    Item.prototype.canGoToCheckout = function() {
        return common.itemCanGoToCheckout(this) && !$.isEmptyObject(this.order);
    };

    /**
     * Checks if an item can be checked in (based on status)
     * @name Item#canCheckin
     * @returns {boolean}
     */
    Item.prototype.canCheckin = function() {
        return common.itemCanCheckin(this);
    };

    /**
     * Checks if an item can be expired (based on status)
     * @name Item#canExpire
     * @returns {boolean}
     */
    Item.prototype.canExpire = function() {
        return common.itemCanExpire(this);
    };

    /**
     * Checks if an item can be made available again (based on status)
     * @name Item#canUndoExpire
     * @returns {boolean}
     */
    Item.prototype.canUndoExpire = function() {
        return common.itemCanUndoExpire(this);
    };

    /**
     * Checks if an item can be deleted
     * @name Item#canDelete
     * @returns {boolean}
     */
    Item.prototype.canDelete = function() {
        var can = Base.prototype.canDelete.call(this);
        return can && common.itemCanDelete(this);
    };

    /**
     * Expires an item, puts it in the *expired* status
     * @name Item#expire
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.expire = function(skipRead) {
        return this._doApiCall({method: 'expire', skipRead: skipRead});
    };

    /**
     * Un-expires an item, puts it in the *available* status again
     * @name Item#undoExpire
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.undoExpire = function(skipRead) {
        return this._doApiCall({method: 'undoExpire', skipRead: skipRead});
    };

    /**
     * Change the location of an item
     * @name Item#changeLocation
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.changeLocation = function(locationId, skipRead) {
        return this._doApiCall({method: 'changeLocation', params: {location: locationId}, skipRead: skipRead});
    };

    /**
     * Adds a QR code to the item
     * @name Item#addCode
     * @param code
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.addCode = function(code, skipRead) {
        return this._doApiCall({method: 'addCodes', params: {codes: [code]}, skipRead: skipRead});
    };

    /**
     * Removes a QR code from the item
     * @name Item#removeCode
     * @param code
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.removeCode = function(code, skipRead) {
        return this._doApiCall({method: 'removeCodes', params: {codes: [code]}, skipRead: skipRead});
    };

    /**
     * Updates the geo position of an item
     * @name Item#updateGeo
     * @param lat
     * @param lng
     * @param address
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.updateGeo = function(lat, lng, address, skipRead) {
        return this._doApiCall({method: 'updateGeo', params: {lat: lat, lng: lng, address: address}, skipRead: skipRead});
    };

    /**
     * Gets the last number for items with this name
     * @name Item#getLastNumber
     * @returns {promise}
     */
    Item.prototype.getLastNumber = function() {
        // Do a collection API call to get the last number for items with this name
        return this.ds.call(null, "getLastItemNumber", {name: this.name});
    };

    /**
     * Updates the basic fields of an item
     * @name Item#updateBasicFields
     * @param name
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.updateBasicFields = function(name, brand, model, warrantyDate, purchaseDate, purchasePrice, residualValue, skipRead) {
        var that = this,
            params = {};

        if( (name!=null) &&
            (name!=this.raw.name)) {
            params["name"] = name;
        }
        if( (brand!=null) &&
            (brand!=this.raw.brand)) {
            params["brand"] = brand;
        }
        if( (model!=null) &&
            (model!=this.raw.model)) {
            params["model"] = model;
        }
        if( (warrantyDate!=null)){
            // Update date or clear date?
            if(typeof(warrantyDate) === "object" && warrantyDate.isValid()){
                // Only update if date changed
                if(!warrantyDate.isSame(this.raw.warrantyDate)){
                    params["warrantyDate"] = warrantyDate;
                }
            }else{
                params["warrantyDate"] = "";  
            }
        }
        if( (purchaseDate!=null)) {
            // Update date or clear date
            if(typeof(purchaseDate) === "object" && purchaseDate.isValid()){
                // Only update if date changed
                if(!purchaseDate.isSame(this.raw.purchaseDate)){
                    params["purchaseDate"] = purchaseDate;
                }
            }else{
                params["purchaseDate"] = "";
            }
        }
        if( (purchasePrice!=null) &&
            (purchasePrice!=this.raw.purchasePrice)) {
            params["purchasePrice"] = purchasePrice;
        }
        if( (residualValue!=null) &&
            (residualValue!=this.raw.residualValue)) {
            params["residualValue"] = residualValue;
        }

        // Remove values of null during create
        // Avoids: 422 Unprocessable Entity
        // ValidationError (Item:TZe33wVKWwkKkpACp6Xy5T) (FloatField only accepts float values: ['purchasePrice'])
        //for (var k in params) {
        //    if (params[k] == null) {
        //        delete params[k];
        //    }
        //}

        return this.ds.update(this.id, params, this._fields)
            .then(function(data) {
                return (skipRead==true) ? data : that._fromJson(data);
            });
    };

    /**
     * Checks if the item can be moved to another category
     * @name Item#canChangeCategory
     * @param category
     * @returns {promise}
     */
    Item.prototype.canChangeCategory = function(category) {
        return this._doApiCall({
            collectionCall: true,  // it's a collection call, not an Item call
            method: 'canChangeCategory',
            params: {pks:[this.id], category: category},
            skipRead: true,  // the response is a hash with results and conflicts
            _fields: "*"
        });
    };

    /**
     * Moves the item to another category
     * @name Item#changeCategory
     * @param category
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.changeCategory = function(category, skipRead) {
        var that = this;
        return this._doApiCall({
            collectionCall: true,  // it's a collection call, not an Item call
            method: 'changeCategory',
            params: {pks:[this.id], category: category},
            skipRead: true  // the response is a list of changed Items
        })
            .then(function(data) {
                return (skipRead==true) ? data : that._fromJson(data[0]);
            });
    };

    /**
     * Checks if custody can be taken for an item (based on status)
     * @name Item#canTakeCustody
     * @returns {boolean}
     */
    Item.prototype.canTakeCustody = function() {
        return common.itemCanTakeCustody(this);
    };

    /**
     * Checks if custody can be released for an item (based on status)
     * @name Item#canReleaseCustody
     * @returns {boolean}
     */
    Item.prototype.canReleaseCustody = function() {
        return common.itemCanReleaseCustody(this);
    };

    /**
     * Checks if custody can be transferred for an item (based on status)
     * @name Item#canTransferCustody
     * @returns {boolean}
     */
    Item.prototype.canTransferCustody = function() {
        return common.itemCanTransferCustody(this);
    };

    /**
     * Takes custody of an item
     * Puts it in the *in_custody* status
     * @name Item#takeCustody
     * @param customerId (when null, we'll take the customer of the user making the API call)
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.takeCustody = function(customerId, skipRead) {
        return this._doApiCall({method: 'takeCustody', params: {customer: customerId}, skipRead: skipRead});
    };

    /**
     * Releases custody of an item at a certain location
     * Puts it in the *available* status again
     * @name Item#releaseCustody
     * @param locationId
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.releaseCustody = function(locationId, skipRead) {
        return this._doApiCall({method: 'releaseCustody', params: {location: locationId}, skipRead: skipRead});
    };

    /**
     * Transfers custody of an item
     * Keeps it in the *in_custody* status
     * @name Item#transferCustody
     * @param customerId (when null, we'll take the customer of the user making the API call)
     * @param skipRead
     * @returns {promise}
     */
    Item.prototype.transferCustody = function(customerId, skipRead) {
        return this._doApiCall({method: 'transferCustody', params: {customer: customerId}, skipRead: skipRead});
    };

    /**
     * Get a list depreciations 
     * 
     * @name Item#getDepreciation
     * @param frequancy
     * @returns {promise}
     */
    Item.prototype.getDepreciation = function(frequency) {
        return this.ds.call(this.id, 'getDepreciation', {frequency: frequency || "quarterly" });
    };

    return Item;
});