Search code examples
javascriptnode.jsmongoosediscord.jsmongoose-schema

Discord.js .methods.purchase is not a function


I'm trying to do a Purchase command with mongoose, but apparently it's getting this TypeError error: cardPack.purchase is not a function I'm using discord.js, discord.js-commando, and Mongoose.

The command has to get cardPackSchema.methods.purchase in my Schema, and use the function, but it is not working properly.

My Command:

const { Command } = require('discord.js-commando');
const { MessageEmbed } = require('discord.js');
const mongoose = require('mongoose');
const Fuse = require('fuse.js');

const Profile = mongoose.model('Profile');
const CardPack = mongoose.model('CardPack');

module.exports = class PurchaseCommand extends Command {
  constructor(client) {
    super(client, {
      name: 'purchase',
      guildOnly: true,
      aliases: [],
      group: 'misc',
      memberName: 'puchase',
      description: 'Purchase a card pack',
      examples: ['purchase'],
      args: [
        {
          key: 'packName',
          prompt: 'Qual é o nome do CardPack que você quer comprar?',
          type: 'string'
        }
      ]
    });
  }

  async run(msg, { packName, }) {
    const profile = await Profile.findOne({
        memberID: msg.member.id
    }).exec();

    const cardPacks = await CardPack.find({}).exec();

    if (!profile){
        return msg.embed(
            new MessageEmbed()
                .setTitle('Perfil não registrado')
                .setDescription("O seu perfil não foi encontrado. Antes de utilizar este comando, usa o comando `register` para se registrar!")
                .setColor('#f44336')
        );
    };

    const fuse = new Fuse(cardPacks, {
        keys: ['name'],
        threshold: 0.1
    });

    const results = fuse.search(packName);

    if(results.length > 1){
        return msg.embed(
            new MessageEmbed()
                .setTitle('Seja específico')
                .setDescription('Seja mais especifico no que você quer comprar')
                .setColor('#f44336')
        );
    };

    if (results.length === 0){
        return msg.embed(
            new MessageEmbed()
                .setTitle('Nenhum CardPack encontrando')
                .setDescription('Não foi encontrado nenhum Cardpack com este nome')
                .setColor('#f44336')
        );
    };


    const cardPack = results[0];

    const response = cardPack.purchase(msg.member.id);

    if(response === 'err'){
        return msg.embed(
            new MessageEmbed()
                .setTitle(response.title)
                .setDescription(response.desc)
                .setColor('#f44336')
        );
    };

    msg.embed(
        new MessageEmbed()
            .setTitle('Abrindo o CardPack')
            .setDescription('CardPack está sendo aberto...')
            .setColor('#f44336')
    );

    setTimeout(() => {
        response.cards.forEach(async card => {
            if(card.type === 'character'){
                const embeda = new MessageEmbed()
                .setTitle(card.name)
                .setDescription(card.description)
                .addField('Código da Carta:', card.codC)
                .addField('Atributos:', card.attributes)
                .addField('Status:', `ATK: ${card.attack} \\ DEF: ${card.defense}`)
                .setThumbnail(card.pictureUrl)

                return msg.embed(embeda);
            }
        })
    }, 3000);

  }
};

My Schema:

const { model, Schema } = require('mongoose');
const Probability = require('probability-node');
const _ = require('lodash');

const cardPackSchema = new Schema({
    name: {
        type: String,
        unique: true
    },
    description: String,
    cards: Number, //Número de cartas dentro desse pack
    type: String, //Se é um Personagem, Feitiço, Item, Todos
    tier: Number,
    probability: {
        //Probabilidade de pegar cartas de especifico tier
        1: Number,
        2: Number,
        3: Number,
        4: Number,
        5: Number,
        6: Number,
        7: Number
    },
    price: Number,
    discount: Number, //Desconto em porcentagem %
    stock: Number, // -1 é infinito no estoque
    guaranteedTier: Number //Se refere ao tier da descriçao do pack
});

cardPackSchema.methods.purchase = async function(memberID){
    const profile = await this.model('Profile')
        .findOne({ memberID })
        .exec();

        if (this.stock === 0){
            return {
                res: 'err',
                title: "Não está disponível",
                desc: 'O CardPack que você está tentando comprar está esgotado'
            }
        };

        if(profile.coins < this.price - this.price * this.discount){
            return {
                res: 'err',
                title: 'Dinheiro insuficiente',
                desc: 'Você não tem dinheiro o suficiente para comprar este pacote!'
            }
        };

        //Comando
        const cards = [];

        //Add a carta garantida do tier
        if (this.guaranteedTier > 1) {
            addCard.call(this, this.guaranteedTier);
            this.cards--;
        };

        const addRandomCard = new Probability(
            {
                p: this.probability['1'],
                f: () => addCard.call(this, 1)
            },
            {
                p: this.probability['2'],
                f: () => addCard.call(this, 2)
            },
            {
                p: this.probability['3'],
                f: () => addCard.call(this, 3)
            },
            {
                p: this.probability['4'],
                f: () => addCard.call(this, 4)
            },
            {
                p: this.probability['5'],
                f: () => addCard.call(this, 5)
            },
            {
                p: this.probability['6'],
                f: () => addCard.call(this, 6)
            },
            {
                p: this.probability['7'],
                f: () => addCard.call(this, 7)
            }
        );

        //Adicionando o resto das cartas
        for (var i = 1 + cards.length; 1 <= this.cards; i++){
            await addRandomCard();
        }

        //Adicionando as cartas no inventario
        const deck = await this.model('Deck')
            .findOne({ memberID })
            .exec();

        profile.deductCoins(this.price - this.price * this.discount);
        profile.addExp(this.tier ** this.tier + this.price / 20);

        await deck.addCards(cards);
        //Voltando com os nomes da carta
        return {
            res: 'Sucesso',
            cards,
            coins: profile.coins - (this.price - this.price * this.discount)
        };

        //função de adicionar a carta
        async function addCard(tier){
            const randomTypeCard = Math.floor(Math.random() * 1) * 1;

            //Adicionando a carta do Personagem
            if (
                (randomTypeCard === 1 && this.type === 'all') || this.type === 'character'
            ) {
                const cardToAdd = _.sample(await model('Character').find({ tier }));
                cardToAdd.type = 'character';
                if (
                    !_.includes(cards.map(card => card.name), cardToAdd.name) ||
                    cardToAdd.sold >= cardToAdd.stock
                ) {
                    await cardToAdd.sell();
                    cards.push(cardToAdd);
                } else addCard.call(this, tier);
            }


        }


};

model('CardPack', cardPackSchema);

Solution

  • It seems, results[0] is not an instance of cardPack. It seems you're using fuse.js to search, and according to its examples it returns an array of objects that have the following keys: item, refIndex, and score.

    It seems, item is the instance you're looking for, so try to modify cardPack to:

    const cardPack = results[0].item
    

    Or if it doesn't work, you could use the refIndex that returns the result's index in the original list:

    const cardPack = cardPacks[results[0].refIndex]