const { EmbedBuilder, SelectMenuBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js'); const { Invoice, addInvoiceList, addInvoice } = require('../structures/invoice'); module.exports = { name: "invoice", debug: false, description: "handle invoices", usage: "[cmd] [opt]", permissions: { channel: ["VIEW_CHANNEL", "SEND_MESSAGES", "EMBED_LINKS"], member: [], }, options: [ { name: "list", description: "list invoices that have been sent to you", value: "list", type: 1, }, { name: "create", description: "send an invoice to a user", value: "create", type: 1, options: [ { name: "title", description: "title of the invoice", value: "title", type: 3, required: true, }, { name: "description", description: "description of the invoice", value: "description", type: 3, required: true, }, { name: "user", description: "user to send invoice to", value: "user", type: 6, required: true, }, { name: "fee", description: "the amount due for this invoice", value: "fee", type: 10, min_value: 0.01, required: true, } ] } ], SlashCommand: { /** * * @param {require("../structures/QuarksBot")} client * @param {import("discord.js").MessageCreate} message * @param {string[]} args * @param {*} param3 */ run: async (client, interaction, args, { GuildDB }) => { if (GuildDB.customChannelStatus && !GuildDB.allowedChannels.includes(interaction.channel_id)) { return interaction.send({ content: `You are not allowed to use the bot in this channel.`, flags: (1 << 6) }); } if (args[0].name == 'list') { let invoices = await client.dbo.collection("invoices").findOne({"invoiceDB.userID": interaction.member.user.id}).then(invoices => invoices); if (!invoices) { invoices = { userID: interaction.member.user.id, guilds: {} }; invoices.guilds[GuildDB.serverID] = { invoices: [] }; // Register invoiceDB for user let newInvoice = new Invoice(); newInvoice.createInvoiceDB(interaction.member.user.id, GuildDB.serverID); await newInvoice.save().catch(err => { if (err) return client.sendInternalError(interaction, err); }); } else invoices = invoices.invoiceDB; if (!client.exists(invoices.guilds[GuildDB.serverID])) { let success = addInvoiceList(invoices.guilds, GuildDB.serverID, interaction.member.user.id, client); if (!success) return client.sendInternalError(interaction, 'Failed to add invoice list'); } if (invoices.guilds[GuildDB.serverID].invoices.length == 0) { let embed = new EmbedBuilder() .setTitle('No invoices') .setDescription('You have no invoices to view') .setColor(client.config.Colors.Default); return interaction.send({ embeds: [embed] }); } let invoiceMenu = new SelectMenuBuilder() .setCustomId(`ShowInvoice`) .setPlaceholder('Select the invoice to view') invoices.guilds[GuildDB.serverID].invoices.map((invoice) => { invoiceMenu.addOptions({ label: `${invoice.id} - ${invoice.name}`, description: invoice.description, value: invoice.id, }) }) const invoiceSelect = new ActionRowBuilder().addComponents(invoiceMenu); interaction.send({ components: [invoiceSelect], flags: (1 << 6) }); } else if (args[0].name == 'create') { if (!client.exists(GuildDB.commercialRole)) { let embed = new EmbedBuilder() .setColor(client.config.Colors.Yellow) .setTitle("Notice:") .setDescription("An admin needs to configure the commercial role in order for this command to be used."); return interaction.send({ embeds: [embed] }); } if (!interaction.member.roles.includes(GuildDB.commercialRole)) { let embed = new EmbedBuilder() .setColor(client.config.Colors.Yellow) .setDescription(`**Notice:** You require the <@&${GuildDB.commercialRole}> role`) return interaction.send({ embeds: [embed] }); } if (args[0].options[2] == interaction.member.user.id) { let embed = new EmbedBuilder() .setColor(client.config.Colors.Yellow) .setDescription('**Notice:** You can\'t create an invoice on yourself'); return interaction.send({ embeds: [embed] }); } let invoices = await client.dbo.collection("invoices").findOne({"invoiceDB.userID": args[0].options[2].value}).then(invoices => invoices); if (!invoices) { invoices = { userID: args[0].options[2].value, guilds: {} }; invoices.guilds[GuildDB.serverID] = { invoices: [] }; // Register invoiceDB for user let newInvoice = new Invoice(); newInvoice.createInvoiceDB(args[0].options[2].value, GuildDB.serverID); await newInvoice.save().catch(err => { if (err) return client.sendInternalError(interaction, err); }); } else invoices = invoices.invoiceDB; if (!client.exists(invoices.guilds[GuildDB.serverID])) { let success = addInvoiceList(invoices.guilds, GuildDB.serverID, args[0].options[2].value, client); if (!success) return client.sendInternalError(interaction, 'Failed to add invoice list'); } let ID = Math.floor(100000 + Math.random() * 900000); let invoice = { id: `${ID}`, name: args[0].options[0].value, description: args[0].options[1].value, amount: args[0].options[3].value, to: args[0].options[2].value, from: interaction.member.user.id, paid: false }; let success = addInvoice(GuildDB.serverID, args[0].options[2].value, invoice, client); if (!success) return client.sendInternalError(interaction, 'Failed to add invoice to user'); let successEmbed = new EmbedBuilder() .setTitle("Success") .setDescription(`Successfully sent invoice **#${ID}** to <@${args[0].options[2].value}>`) .setColor(client.config.Colors.Green); return interaction.send({ embeds: [successEmbed] }); } }, }, Interactions: { ShowInvoice: { run: async (client, interaction, GuildDB) => { let invoices = await client.dbo.collection("invoices").findOne({"invoiceDB.userID": interaction.member.user.id}).then(invoices => invoices); let invoice = invoices.invoiceDB.guilds[GuildDB.serverID].invoices.find(invoice => invoice.id == interaction.values[0]); let invoiceData = `**ID** #${invoice.id}\n**Name** ${invoice.name}\n**Description** ${invoice.description}\n**From** <@${invoice.from}>\n**Amount Due** ${invoice.amount.toFixed(2)}`; let banking = await client.dbo.collection("banks").findOne({"banking.userID": interaction.member.user.id}).then(banking => banking); if (!banking) { banking = { userID: interaction.member.user.id, guilds: { [GuildDB.serverID]: { account: { balance: GuildDB.startingBalance, cash: 0.00, } } } } // Register bank for user let newBank = new Bank(); newBank.createBank(interaction.member.user.id, GuildDB.serverID, GuildDB.startingBalance, 0); newBank.save().catch(err => { if (err) return client.sendInternalError(interaction, err); }); } else banking = banking.banking; if (!client.exists(banking.guilds[GuildDB.serverID])) { const success = addBank(banking.guilds, GuildDB.serverID, interaction.member.user.id, client, GuildDB.startingBalance); if (!success) return client.sendInternalError(interaction, 'Failed to add bank'); } let invoiceEmbed = new EmbedBuilder() .setColor(client.config.Colors.Default) .setTitle(`${invoice.id} - ${invoice.name}`) .setDescription(invoiceData); let payButton = new ButtonBuilder() .setCustomId(`PayInvoice-${invoice.id}`) // pass invoice id to search for invoice in pay handler .setLabel("Pay") .setStyle(ButtonStyle.Primary); if (banking.guilds[GuildDB.serverID].account.balance < invoice.amount) payButton.setDisabled(true); let opt = new ActionRowBuilder() .addComponents(payButton); if (GuildDB.canDismissInvoices) { opt.addComponents( new ButtonBuilder() .setCustomId(`DeleteInvoice-${invoice.id}`) .setLabel("Dismiss & Delete") .setStyle(ButtonStyle.Secondary) ); } return interaction.update({ embeds: [invoiceEmbed], components: [opt] }); } }, PayInvoice: { run: async (client, interaction, GuildDB) => { let invoices = await client.dbo.collection("invoices").findOne({"invoiceDB.userID": interaction.member.user.id}).then(invoices => invoices); let invoice = invoices.invoiceDB.guilds[GuildDB.serverID].invoices.find(invoice => invoice.id == interaction.customId.split('-')[1]); let banking = await client.dbo.collection("banks").findOne({"banking.userID": invoice.to}).then(banking => banking); banking = banking.banking; // we don't have to check for bank exisiting since its handled in the above function. let newBalance = banking.guilds[GuildDB.serverID].account.balance - invoice.amount; client.dbo.collection("banks").updateOne({"banking.userID": invoice.to}, {$set: {[`banking.guilds.${GuildDB.serverID}.account.balance`]: newBalance}}, function (err, res) { if (err) return client.sendInternalError(interaction, err); }); banking = await client.dbo.collection("banks").findOne({"banking.userID": invoice.from}).then(banking => banking); // check if user who sent invoice has bank records if (!banking) { banking = { userID: invoice.from, guilds: { [GuildDB.serverID]: { account: { balance: GuildDB.startingBalance, cash: 0.00, } } } } // Register inventory for user let newBank = new Bank(); newBank.createBank(invoice.from, GuildDB.serverID, GuildDB.startingBalance, 0); newBank.save().catch(err => { if (err) return client.sendInternalError(interaction, err); }); } else banking = banking.banking; newBalance = banking.guilds[GuildDB.serverID].account.balance + invoice.amount; client.dbo.collection("banks").updateOne({"banking.userID": invoice.from}, {$set: {[`banking.guilds.${GuildDB.serverID}.account.balance`]: newBalance}}, function (err, res) { if (err) return client.sendInternalError(interaction, err); }); client.dbo.collection("invoices").updateOne({"invoiceDB.userID": invoice.to}, {$pull: {[`invoiceDB.guilds.${GuildDB.serverID}.invoices`]: invoice}}, function (err, res) { if (err) return client.sendInternalError(interaction, err); }); let successEmbed = new EmbedBuilder() .setColor(client.config.Colors.Green) .setTitle(`Successfully payed invoice #${invoice.id}`); return interaction.update({ embeds: [successEmbed], components: [] }); } }, DeleteInvoice: { run: async (client, interaction, GuildDB) => { let invoices = await client.dbo.collection("invoices").findOne({"invoiceDB.userID": interaction.member.user.id}).then(invoices => invoices); let invoice = invoices.invoiceDB.guilds[GuildDB.serverID].invoices.find(invoice => invoice.id == interaction.customId.split('-')[1]); client.dbo.collection("invoices").updateOne({"invoiceDB.userID": invoice.to}, {$pull: {[`invoiceDB.guilds.${GuildDB.serverID}.invoices`]: invoice}}, function (err, res) { if (err) return client.sendInternalError(interaction, err); }); let successEmbed = new EmbedBuilder() .setColor(client.config.Colors.Green) .setTitle(`Dismissed and Deleted invoice #${invoice.id}`); return interaction.update({ embeds: [successEmbed], components: [] }); } } } }