Skip to content

Commit

Permalink
Add the method sendInvoice (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
rojvv committed Jun 8, 2024
1 parent 6218b56 commit dee51f2
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 4 deletions.
1 change: 1 addition & 0 deletions 3_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export * from "./types/0_dice.ts";
export * from "./types/0_file_source.ts";
export * from "./types/0_giveaway_parameters.ts";
export * from "./types/0_id.ts";
export * from "./types/0_invoice.ts";
export * from "./types/0_keyboard_button_poll_type.ts";
export * from "./types/0_link_preview.ts";
export * from "./types/0_live_stream_channel.ts";
Expand Down
19 changes: 19 additions & 0 deletions client/0_params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,25 @@ export interface SendPollParams extends _SendCommon {
isClosed?: boolean;
}

export interface SendInvoiceParams extends _SendCommon {
providerToken?: string;
maxTipAmount?: number;
suggestedTipAmounts?: number[];
startParameter: string;
providerData?: string;
photoUrl?: string;
photoSize?: number;
photoWidth?: number;
photoHeight?: number;
needName?: boolean;
needPhoneNumber?: boolean;
needEmail?: boolean;
needShippingAddress?: boolean;
sendPhoneNumberToProvider?: boolean;
sendEmailToProvider?: boolean;
flexible?: boolean;
}

export interface DownloadParams {
/** Size of each download chunk in bytes. */
chunkSize?: number;
Expand Down
62 changes: 60 additions & 2 deletions client/3_message_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import { contentType, unreachable } from "../0_deps.ts";
import { InputError } from "../0_errors.ts";
import { getLogger, getRandomId, Logger, toUnixTimestamp } from "../1_utilities.ts";
import { Api, as, getChannelChatId, is, peerToChatId } from "../2_tl.ts";
import { constructChatMemberUpdated, constructInviteLink, deserializeFileId, FileId, InputMedia, PollOption, SelfDestructOption, selfDestructOptionToInt } from "../3_types.ts";
import { constructChatMemberUpdated, constructInviteLink, deserializeFileId, FileId, InputMedia, PollOption, PriceTag, SelfDestructOption, selfDestructOptionToInt } from "../3_types.ts";
import { assertMessageType, ChatAction, chatMemberRightsToTlObject, constructChatMember, constructMessage as constructMessage_, deserializeInlineMessageId, FileSource, FileType, ID, Message, MessageEntity, messageEntityToTlObject, ParseMode, Reaction, reactionEqual, reactionToTlObject, replyMarkupToTlObject, Update, UsernameResolver } from "../3_types.ts";
import { messageSearchFilterToTlObject } from "../types/0_message_search_filter.ts";
import { parseHtml } from "./0_html.ts";
import { parseMarkdown } from "./0_markdown.ts";
import { _SendCommon, _SpoilCommon, AddReactionParams, BanChatMemberParams, CreateInviteLinkParams, DeleteMessagesParams, EditMessageLiveLocationParams, EditMessageMediaParams, EditMessageParams, EditMessageReplyMarkupParams, ForwardMessagesParams, GetCreatedInviteLinksParams, GetHistoryParams, PinMessageParams, SearchMessagesParams, SendAnimationParams, SendAudioParams, SendChatActionParams, SendContactParams, SendDiceParams, SendDocumentParams, SendLocationParams, SendMessageParams, SendPhotoParams, SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, SendVideoParams, SendVoiceParams, SetChatMemberRightsParams, SetChatPhotoParams, SetReactionsParams, StopPollParams } from "./0_params.ts";
import { _SendCommon, _SpoilCommon, AddReactionParams, BanChatMemberParams, CreateInviteLinkParams, DeleteMessagesParams, EditMessageLiveLocationParams, EditMessageMediaParams, EditMessageParams, EditMessageReplyMarkupParams, ForwardMessagesParams, GetCreatedInviteLinksParams, GetHistoryParams, PinMessageParams, SearchMessagesParams, SendAnimationParams, SendAudioParams, SendChatActionParams, SendContactParams, SendDiceParams, SendDocumentParams, SendInvoiceParams, SendLocationParams, SendMessageParams, SendPhotoParams, SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, SendVideoParams, SendVoiceParams, SetChatMemberRightsParams, SetChatPhotoParams, SetReactionsParams, StopPollParams } from "./0_params.ts";
import { C as C_ } from "./1_types.ts";
import { checkMessageId } from "./0_utilities.ts";
import { checkArray } from "./0_utilities.ts";
Expand Down Expand Up @@ -1274,4 +1274,62 @@ export class MessageManager {
const id = deserializeInlineMessageId(inlineMessageId);
await this.#c.invoke({ _: "messages.editInlineBotMessage", id, media: ({ _: "inputMediaGeoLive", geo_point: ({ _: "inputGeoPoint", lat: latitude, long: longitude, accuracy_radius: params?.horizontalAccuracy }), heading: params?.heading, proximity_notification_radius: params?.proximityAlertRadius }), reply_markup: await this.#constructReplyMarkup(params) });
}

async sendInvoice(chatId: ID, title: string, description: string, payload: string, currency: string, prices: PriceTag[], params?: SendInvoiceParams) {
if (title.length < 1) {
throw new InputError("Invoice title cannot be empty.");
}
if (description.length < 1) {
throw new InputError("Invoice description cannot be empty.");
}
if (title.length > 32) {
throw new InputError("Invoice title is too long.");
}
if (description.length > 255) {
throw new InputError("Invoice description is too long.");
}
const invoice: Api.invoice = {
_: "invoice",
currency,
prices: prices.map((v) => ({ _: "labeledPrice", label: v.label, amount: BigInt(v.amount) })),
max_tip_amount: params?.maxTipAmount ? BigInt(params.maxTipAmount) : undefined,
suggested_tip_amounts: params?.suggestedTipAmounts?.map(BigInt),
name_requested: params?.needName || undefined,
phone_requested: params?.needPhoneNumber || undefined,
email_requested: params?.needEmail || undefined,
shipping_address_requested: params?.needShippingAddress || undefined,
email_to_provider: params?.sendEmailToProvider || undefined,
phone_to_provider: params?.sendPhoneNumberToProvider || undefined,
flexible: params?.flexible || undefined,
};

const message = await this.#sendMedia(
chatId,
{
_: "inputMediaInvoice",
title,
description,
invoice,
start_param: params?.startParameter,
payload: new TextEncoder().encode(payload),
provider_data: { _: "dataJSON", data: params?.providerData ?? "null" },
provider: params?.providerToken ?? "",
photo: params?.photoUrl
? {
_: "inputWebDocument",
url: params.photoUrl,
size: params.photoSize ?? 0,
mime_type: "image/jpeg", // TODO: guess from URL
attributes: [{
_: "documentAttributeImageSize",
w: params?.photoWidth ?? 0,
h: params?.photoHeight ?? 0,
}],
}
: undefined,
},
params,
);
return assertMessageType(message, "invoice");
}
}
69 changes: 67 additions & 2 deletions client/5_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,59 @@ import { Api, as, chatIdToPeerId, getChatIdPeerType, is, peerToChatId } from "..
import { Storage, StorageMemory } from "../2_storage.ts";
import { DC } from "../3_transport.ts";
import { Invoke } from "./1_types.ts";
import { BotCommand, BusinessConnection, CallbackQueryAnswer, CallbackQueryQuestion, Chat, ChatAction, ChatListItem, ChatMember, ChatP, ConnectionState, constructUser, FileSource, ID, InactiveChat, InlineQueryAnswer, InlineQueryResult, InputMedia, InputStoryContent, InviteLink, LiveStreamChannel, Message, MessageAnimation, MessageAudio, MessageContact, MessageDice, MessageDocument, MessageLocation, MessagePhoto, MessagePoll, MessageSticker, MessageText, MessageVenue, MessageVideo, MessageVideoNote, MessageVoice, NetworkStatistics, ParseMode, Poll, Reaction, Sticker, Story, Update, User, VideoChat, VideoChatActive, VideoChatScheduled } from "../3_types.ts";
import { BotCommand, BusinessConnection, CallbackQueryAnswer, CallbackQueryQuestion, Chat, ChatAction, ChatListItem, ChatMember, ChatP, ConnectionState, constructUser, FileSource, ID, InactiveChat, InlineQueryAnswer, InlineQueryResult, InputMedia, InputStoryContent, InviteLink, LiveStreamChannel, Message, MessageAnimation, MessageAudio, MessageContact, MessageDice, MessageDocument, MessageInvoice, MessageLocation, MessagePhoto, MessagePoll, MessageSticker, MessageText, MessageVenue, MessageVideo, MessageVideoNote, MessageVoice, NetworkStatistics, ParseMode, Poll, PriceTag, Reaction, Sticker, Story, Update, User, VideoChat, VideoChatActive, VideoChatScheduled } from "../3_types.ts";
import { APP_VERSION, DEVICE_MODEL, LANG_CODE, LANG_PACK, LAYER, MAX_CHANNEL_ID, MAX_CHAT_ID, PublicKeys, SYSTEM_LANG_CODE, SYSTEM_VERSION, USERNAME_TTL } from "../4_constants.ts";
import { AuthKeyUnregistered, ConnectionNotInited, FloodWait, Migrate, PasswordHashInvalid, PhoneNumberInvalid, SessionPasswordNeeded } from "../4_errors.ts";
import { _SendCommon, AddReactionParams, AnswerCallbackQueryParams, AnswerInlineQueryParams, BanChatMemberParams, CreateInviteLinkParams, CreateStoryParams, DeleteMessageParams, DeleteMessagesParams, DownloadLiveStreamChunkParams, DownloadParams, EditMessageLiveLocationParams, EditMessageMediaParams, EditMessageParams, EditMessageReplyMarkupParams, ForwardMessagesParams, GetChatsParams, GetCreatedInviteLinksParams, GetHistoryParams, GetMyCommandsParams, JoinVideoChatParams, PinMessageParams, ReplyParams, ScheduleVideoChatParams, SearchMessagesParams, SendAnimationParams, SendAudioParams, SendContactParams, SendDiceParams, SendDocumentParams, SendInlineQueryParams, SendLocationParams, SendMessageParams, SendPhotoParams, SendPollParams, SendStickerParams, SendVenueParams, SendVideoNoteParams, SendVideoParams, SendVoiceParams, SetChatMemberRightsParams, SetChatPhotoParams, SetMyCommandsParams, SetReactionsParams, SignInParams, StartVideoChatParams, StopPollParams } from "./0_params.ts";
import {
_SendCommon,
AddReactionParams,
AnswerCallbackQueryParams,
AnswerInlineQueryParams,
BanChatMemberParams,
CreateInviteLinkParams,
CreateStoryParams,
DeleteMessageParams,
DeleteMessagesParams,
DownloadLiveStreamChunkParams,
DownloadParams,
EditMessageLiveLocationParams,
EditMessageMediaParams,
EditMessageParams,
EditMessageReplyMarkupParams,
ForwardMessagesParams,
GetChatsParams,
GetCreatedInviteLinksParams,
GetHistoryParams,
GetMyCommandsParams,
JoinVideoChatParams,
PinMessageParams,
ReplyParams,
ScheduleVideoChatParams,
SearchMessagesParams,
SendAnimationParams,
SendAudioParams,
SendContactParams,
SendDiceParams,
SendDocumentParams,
SendInlineQueryParams,
SendInvoiceParams,
SendLocationParams,
SendMessageParams,
SendPhotoParams,
SendPollParams,
SendStickerParams,
SendVenueParams,
SendVideoNoteParams,
SendVideoParams,
SendVoiceParams,
SetChatMemberRightsParams,
SetChatPhotoParams,
SetMyCommandsParams,
SetReactionsParams,
SignInParams,
StartVideoChatParams,
StopPollParams,
} from "./0_params.ts";
import { checkPassword } from "./0_password.ts";
import { getUsername, isMtprotoFunction, resolve } from "./0_utilities.ts";
import { AccountManager } from "./2_account_manager.ts";
Expand Down Expand Up @@ -1822,6 +1871,22 @@ export class Client<C extends Context = Context> extends Composer<C> {
return await this.#messageManager.sendPoll(chatId, question, options, params);
}

/**
* Send an invoice.
*
* @method ms
* @param chatId The chat to send the invoice to.
* @param title The invoice's title.
* @param description The invoice's description.
* @param payload The invoice's payload.
* @param currency The invoice's currency.
* @param prices The invoice's price tags.
* @returns The sent invoice.
*/
async sendInvoice(chatId: ID, title: string, description: string, payload: string, currency: string, prices: PriceTag[], params?: SendInvoiceParams): Promise<MessageInvoice> {
return await this.#messageManager.sendInvoice(chatId, title, description, payload, currency, prices, params);
}

/**
* Edit a message's text.
*
Expand Down
19 changes: 19 additions & 0 deletions types/0_invoice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Api } from "../2_tl.ts";

export interface Invoice {
title: string;
description: string;
startParameter: string;
currency: string;
totalAmount: number;
}

export function constructInvoice(invoice: Api.messageMediaInvoice): Invoice {
return {
title: invoice.title,
description: invoice.description,
startParameter: invoice.start_param,
currency: invoice.currency,
totalAmount: Number(invoice.total_amount),
};
}
19 changes: 19 additions & 0 deletions types/4_message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { serializeFileId } from "./_file_id.ts";
import { EntityGetter } from "./_getters.ts";
import { constructContact, Contact } from "./0_contact.ts";
import { constructDice, Dice } from "./0_dice.ts";
import { constructInvoice, Invoice } from "./0_invoice.ts";
import { constructLinkPreview, LinkPreview } from "./0_link_preview.ts";
import { constructLocation, Location } from "./0_location.ts";
import { constructMessageEntity, MessageEntity } from "./0_message_entity.ts";
Expand Down Expand Up @@ -295,6 +296,18 @@ export interface MessagePoll extends _MessageBase {
poll: Poll;
}

/**
* An invoice message.
* @unlisted
*/
export interface MessageInvoice extends _MessageBase {
/**
* The invoice included in the message
* @discriminator
*/
invoice: Invoice;
}

/**
* A venue message.
* @unlisted
Expand Down Expand Up @@ -576,6 +589,7 @@ export interface MessageTypes {
contact: MessageContact;
game: MessageGame;
poll: MessagePoll;
invoice: MessageInvoice;
venue: MessageVenue;
location: MessageLocation;
newChatMembers: MessageNewChatMembers;
Expand Down Expand Up @@ -618,6 +632,7 @@ const keys: Record<keyof MessageTypes, [string, ...string[]]> = {
contact: ["contact"],
game: ["game"],
poll: ["poll"],
invoice: ["invoice"],
venue: ["venue"],
location: ["location"],
newChatMembers: ["newChatMembers"],
Expand Down Expand Up @@ -669,6 +684,7 @@ export type Message =
| MessageContact
| MessageGame
| MessagePoll
| MessageInvoice
| MessageVenue
| MessageLocation
| MessageNewChatMembers
Expand Down Expand Up @@ -1109,6 +1125,9 @@ export async function constructMessage(
} else if (is("messageMediaGiveaway", message_.media)) {
const giveaway = constructGiveaway(message_.media);
m = { ...message, giveaway };
} else if (is("messageMediaInvoice", message_.media)) {
const invoice = constructInvoice(message_.media);
m = { ...message, invoice };
}

if (m == null) {
Expand Down

0 comments on commit dee51f2

Please sign in to comment.