index.js

"use strict";
/**
 *  @module     @magic.batua/points
 *  @overview   Defines the `Ledger` class that manages loyalty points logic across the
 *              application.
 *
 *  @author     Animesh Mishra <hello@animesh.ltd>
 *  @copyright  © 2018 Animesh Ltd. All Rights Reserved.
 */
Object.defineProperty(exports, "__esModule", { value: true });
const Points = require("./Source/Points");
exports.Points = Points;
const error_1 = require("@magic.batua/error");
const error_2 = require("@magic.batua/error");
const Transaction_1 = require("./Source/Transaction");
exports.Transaction = Transaction_1.Transaction;
/**
 *  The Points Ledger keeps track of a user's Magic Points, their status, their availability
 *  and other points related arithmetic.
 *
 *  Magic Points are awarded to users as rewards for continued usage and word-of-mouth publicity.
 *  The points are rewarded as following:
 *
 *  -   600 points at signup. These points aren't redeemable until you've spent ₹1,000 or more on the
 *      Magic Batua platform.
 *
 *  -   400 points if somebody signs up using your referral code. These points become redeemable once
 *      you've amassed 10 or more referrals, and each of those referrals have spent ₹1,000 or more.
 *
 *  -   1 point for mobile recharge. Redeemable immediately. If were referred by someone, their account
 *      is credited with a point too.
 *
 *  -   20 points for tuition fee payments. Redeemable immediately. If were referred by someone, their
 *      account is credited with 20 points too.
 *
 *  To manage the points logic, we make use of three buckets: Signup, Referrals and Available. As points
 *  earned through Signup and Referrals become redeemable they are emptied into the Available bucket.
 *  Points earned through other activities such as mobile recharge or tuition fee payment are credited to
 *  the Available bucket straightaway.
 */
class Ledger {
    constructor(transactions) {
        /** Number of points available for redemption */
        this.available = 0;
        /**
         *  Points earned at signup. Becomes redeemable once the account has spent
         *  ₹1,000 or more on the Magic Batua platform.
         */
        this.signup = 0;
        /**
         *  Points earned through referrals. Becomes redeemable once the account has accrued
         *  10 or more referrals.
         */
        this.referral = 0;
        /** Number of points accured since the creation of account */
        this.redeemable = 0;
        /** Points that have expired. */
        this.expired = 0;
        /** Points that have been redeemed since the creation of account */
        this.redeemed = 0;
        /** Points that have been refunded */
        this.refunded = 0;
        /** Points transactions listing all the issuance, redemption and refund transactions. */
        this.transactions = new Array();
        for (var entry of transactions) {
            this.transactions.push(new Transaction_1.Transaction(entry));
        }
        // Count all points
        this.count();
    }
    /**
     *  Goes over all point transactions one by one and separates all the points
     *  in their respective baskets.
     *
     *  @param transactions     An array of Points `Transaction`
     */
    count() {
        this.signup = 0;
        this.referral = 0;
        this.expired = 0;
        this.redeemable = 0;
        this.refunded = 0;
        this.redeemed = 0;
        for (var transaction of this.transactions) {
            switch (transaction.type) {
                case "Issue":
                    if (transaction.expiryDate.valueOf() <= Date.now()) {
                        this.expired += transaction.points;
                        break;
                    }
                    if (transaction.notes == "Signup") {
                        this.signup += transaction.points;
                        break;
                    }
                    if (transaction.notes == "Referral") {
                        this.referral += transaction.points;
                        break;
                    }
                    else {
                        this.redeemable += transaction.points;
                        break;
                    }
                case "Redeem":
                    this.redeemed += transaction.points;
                    break;
                case "Refund":
                    this.refunded += transaction.points;
            }
        }
        this.available = this.redeemable - this.redeemed;
    }
    /** Issues a Magic Point for the given `reason` */
    Issue(points, reason) {
        let transaction = new Transaction_1.Transaction({
            points: points,
            type: "Issue",
            notes: reason
        });
        // Add this transaction to the transactions array and count
        // the points again
        this.transactions.push(transaction);
        this.count();
        return transaction;
    }
    /** Redeems `points` from the balance */
    Redeem(points, reason) {
        if (points > this.available) {
            throw new error_1.ClientError(error_2.Code.BadRequest, "Trying to redeem " + points + " points, but the account has " + this.redeemable + " redeemable points only.");
        }
        let transaction = new Transaction_1.Transaction({
            points: points,
            type: "Redeem",
            notes: reason
        });
        // Add this transaction to the transactions array and count
        // the points again
        this.transactions.push(transaction);
        this.count();
        return transaction;
    }
    /**
     *  This method will be called by the `Account` module when the condition for
     *  unlocking signup bonus is met.
     *  To move points from Signup bucket `this.signup` to Redeemable bucket `this.redeemable`,
     *  we change the `notes` property of signup points issuance from "Signup" to
     *  "Signup Points become active".
     */
    MakeSignupRedeemable() {
        for (var transaction of this.transactions) {
            if (transaction.notes == "Signup" && transaction.expiryDate.valueOf() >= Date.now()) {
                transaction.notes = "Signup points can be redeemed now.";
            }
        }
        this.count();
    }
    /**
     *  This method will be called by the `Account` module when the condition for
     *  unlocking signup bonus is met.
     *  To move points from Referrals bucket `this.signup` to Redeemable bucket `this.redeemable`,
     *  we change the `notes` property of signup points issuance from "Signup" to
     *  "Referral points can be redeemed now.".
     */
    MakeReferralsRedeemable() {
        for (var transaction of this.transactions) {
            if (transaction.notes == "Referral" && transaction.expiryDate.valueOf() >= Date.now()) {
                transaction.notes = "Referral points can now be redeemed.";
            }
        }
        this.count();
    }
}
exports.Ledger = Ledger;
//# sourceMappingURL=index.js.map