yoctore/yocto-orika

View on GitHub
src/api/modules/orkaisse/schema.js

Summary

Maintainability
F
5 days
Test Coverage
'use strict';

var logger    = require('yocto-logger');
var _         = require('lodash');
var joi       = require('joi');
var moment    = require('moment');

/**
 * Default orkaisse module - Provide request to orkaisse endpoint
 */
function OrkaisseSchema (l) {
  /**
   * Default logger instance
   */
  this.logger   = l;
  /**
   * List of status codes
   */
  this.statusCodes  = [ {
    code      : 0,
    message   : 'Ok'
  }, {
    code      : 2,
    message   : 'Ticket non calculé'
  }, {
    code      : 1,
    message   : 'Erreur inconnue / interne'
  }, {
    code      : 100,
    message   : 'Les formats des données reçues en entrée n\'est pas celui attendu.'
  }, {
    code      : 101,
    message   : 'Article inconnu'
  }, {
    code      : 102,
    message   : 'Numéro de client inconnu'
  }, {
    code      : 103,
    message   : 'Coupon inconnu'
  }, {
    code      : 104,
    message   : 'Code ticket inconnu'
  }, {
    code      : 105,
    message   : [ 'Problème de montant, le montant reçu ne correspond',
                              'pas à celui attendu pour le ticket' ].join(' ')
  } ];
}

/**
 * An utlity method to get only message from a status code number
 *
 * @param {Number} code current code to use to retreive default message
 * @return {String} retreive message
 */
OrkaisseSchema.prototype.getStatusCodesMessage = function (code) {
  // default statement
  return _.get(_.find(this.statusCodes, function (s) {
    // is wanted code ?
    return s.code === code;
  }), 'message') || [ 'Unkown message with given code :', code ].join(' ');
};
/**
 * An utility method to get current defined status code on yocto orikaisse
 *
 * @param {Boolean} list if true return complete list
 * @return {Array} list of status codes or only code is list
 */
OrkaisseSchema.prototype.getStatusCodes = function (list) {
  // whant only list
  if (list) {
    // default statement for list request
    return _.map(this.statusCodes, function (s) {
      // return only code
      return s.code;
    });
  }
  // default statement
  return this.statusCodes;
};

/**
 * Default method to retrieve validation schema
 *
 * @param {String} name default name to use to get wanted schema
 * @return {Object|Boolean} valid object founded
 */
OrkaisseSchema.prototype.get = function (name) {
  // list of complete schema
  var schemas = {
    request   : {
      idm       : joi.number().required().min(1),
      dt        : joi.date().default(moment().format('YYYY-MM-DD')),
      idtrs     : joi.string().required().trim().empty(),
      idcli     : joi.string().optional().trim().empty().min(13).max(14),
      idtkt     : joi.string().required().trim().empty().min(24).max(24),
      items     : joi.array().optional().items(joi.object().optional().keys({
        ean         : joi.string().required().trim().empty().min(13).max(13),
        qte         : joi.number().required().min(0),
        replacement : joi.array().min(1).items(joi.object().optional().keys({
          ean     : joi.string().required().trim().empty().min(13).max(13),
          puvttc  : joi.number().optional().min(0).precision(2),
          qte     : joi.number().required().min(0)
        })),
        puvttc      : joi.number().optional().min(0).precision(2)
      })),
      vouchers  : joi.array().optional().items(joi.object().required().keys({
        ean         : joi.string().required().trim().empty().min(8).max(128),
        typ         : joi.number().required().valid([ 0, 1 ])
      })),
      netttc    : joi.number().required().positive().precision(2),
      payments  : joi.array().required().items(joi.object().required().keys({
        idreg   : joi.number().required().min(1),
        mntttc  : joi.number().required().min(0).precision(2)
      })),
      itemscond : joi.array().optional().items(
        joi.object().required().keys({
          ean     : joi.string().required().trim().empty().min(13).max(13),
          qte     : joi.number().required().min(0),
          cond    : joi.string().required().empty(),
          mntcond : joi.number().optional().min(0).precision(2)
        })
      )
    },
    response  : {
      status    : joi.number().required().valid(this.getStatusCodes(true)),
      idm       : joi.number().required().min(1),
      dt        : joi.date().required().format('YYYY-MM-DD'),
      idtrs     : joi.string().required().trim().empty(),
      idcli     : joi.string().optional().trim().empty().min(13).max(14),
      idtkt     : joi.string().required().trim().empty().min(24).max(24),
      netttc    : joi.number().required().min(0).precision(2),
      netht     : joi.number().required().min(0).precision(2),
      mntavg    : joi.number().required().min(0).precision(2),
      mntavgf   : joi.number().required().min(0).precision(2),
      items     : joi.array().optional().items(joi.object().optional().keys({
        ean     : joi.string().required().trim().empty().min(13).max(13),
        qte     : joi.number().required().min(0),
        puvttc  : joi.number().optional().min(0).precision(2),
        netttc  : joi.number().required().min(0).precision(2),
        netht   : joi.number().required().min(0).precision(2),
        mntavg  : joi.number().required().min(0).precision(2),
        txtva   : joi.number().required().min(0).precision(2),
        mnttva  : joi.number().required().min(0).precision(2)
      })),
      itemscond : joi.array().optional().items(
        joi.object().required().keys({
          ean     : joi.string().required().trim().empty().min(13).max(13),
          qte     : joi.number().required().min(0),
          cond    : joi.string().required().empty(),
          mntcond : joi.number().optional().min(0).precision(2)
        })
      ),
      lots      : joi.array().optional().items(joi.object().required().keys({
        idlot   : joi.string().required().trim().empty(),
        ean     : joi.string().required().trim().empty().min(13).max(13),
        qte     : joi.number().required().min(0)
      })),
      tva       : joi.array().optional().items(joi.object().optional().keys({
        taux      : joi.number().required().min(0).precision(2),
        totalTTC  : joi.number().required().min(0).precision(2),
        totalHT   : joi.number().required().min(0).precision(2),
        montant   : joi.number().required().min(0).precision(2)
      })),
      vouchers  : joi.array().optional().items(joi.object().required().keys({
        ean         : joi.string().required().trim().empty().min(8).max(128),
        typ         : joi.number().optional().valid([ 0, 1 ]),
        mnt         : joi.number().optional().min(0).precision(2)
      })),
    },
    rules     : {
      order   : {
        request   : [ 'idm', 'dt', 'idtrs', 'idcli', 'items', 'vouchers', 'itemscond' ],
        response  : [ 'status', 'idm', 'dt', 'idtrs', 'idcli',
                      'idtkt', 'netttc', 'netht', 'mntavg', 'mntavgf', 'items', 'lots', 'vouchers',
                      'itemscond', 'tva' ]
      },
      prepare : {
        request   : [ 'idm', 'dt', 'idtrs', 'idcli', 'items', 'vouchers' ],
        response  : [ 'status', 'idm', 'dt', 'idtrs', 'idcli',
                      'idtkt', 'netttc', 'netht', 'mntavg', 'mntavgf',
                      'items', 'lots', 'vouchers', 'tva' ]
      },
      paid    : {
        request   : [ 'idm', 'dt', 'idtrs', 'idtkt', 'netttc', 'payments' ],
        response  : [ 'status' ]
      },
      cancel  : {
        request   : [ 'idm', 'dt', 'idtrs', 'idcli', 'idtkt' ],
        response  : [ 'status' ]
      }
    }
  };

  // optionnal list rules for item
  this.optionnalSchema = {
    response : {
      prepare : {
        items     : joi.array().required().items(joi.object().required().keys({
          ean     : joi.string().required().trim().empty().min(13).max(13),
          qte     : joi.number().required(),
          puvttc  : joi.number().optional().min(0).precision(2),
          netttc  : joi.number().required().precision(2),
          netht   : joi.number().required().precision(2),
          mntavg  : joi.number().required().min(0).precision(2),
          txtva   : joi.number().required().min(0).precision(2),
          mnttva  : joi.number().required().min(0).precision(2)
        }))
      }
    }
  };

  // now find correct schema and build data
  if (!_.has(schemas.rules, name)) {
    // error message
    this.logger.error([ '[ YoctoOrika.OrkaisseSchema.get ] - cannot find schema rules for ',
                        name || '"an empty name"', 'please provide a valid name' ].join(''));
    // invalid statement
    return false;
  }

  // default object
  var obj = {
    data   : joi.object().required().keys(
      _.pick(schemas.response, _.difference(_.values(schemas.rules[name].response), [ 'status' ])))
  };

  // we need to do this to override default schema with optionnal schema for a specific name rules
  if (this.optionnalSchema.response[name]) {
    // get picked
    var picked = _.pick(schemas.response,
                  _.difference(_.values(schemas.rules[name].response), [ 'status' ]));
    // Merge picked data
    _.merge(picked, this.optionnalSchema.response[name]);
    // change object
    obj.data = joi.object().required().keys(picked);
  }

  // extend correct object
  _.extend(obj, _.pick(schemas.response,
                _.intersection(schemas.rules[name].response, [ 'status' ])));

  // is for cancel and paid request
  if (name === 'cancel' || name === 'paid') {
    // remove unused object
    delete obj.data;
  }

  // has key so process next process
  var schema = {
    request   : _.pick(schemas.request, schemas.rules[name].request),
    response  : joi.object().required().keys(obj),
    optional  : joi.object().required().keys().unknown()
  };

  // default statement
  return schema;
};

// Default export
module.exports = function (l) {
  // is a valid logger ?
  if (_.isUndefined(l) || _.isNull(l)) {
    // warning message
    logger.warning([ '[ YoctoOrika.OrkaisseSchema.constructor ] -',
                     'Invalid logger given. Use internal logger' ].join(' '));
    // assign
    l = logger;
  }

  // default statement
  return new (OrkaisseSchema)(l);
};