diff --git a/lib/nadia.ex b/lib/nadia.ex index 03c5d77..bf6468b 100644 --- a/lib/nadia.ex +++ b/lib/nadia.ex @@ -6,7 +6,7 @@ defmodule Nadia do https://core.telegram.org/bots/api#available-methods """ - alias Nadia.Model.{User, Message, Update, UserProfilePhotos, File, Error, WebhookInfo} + alias Nadia.Model.{User, Message, Update, UserProfilePhotos, File, Error, WebhookInfo, LabeledPrice} import Nadia.API @@ -897,4 +897,103 @@ defmodule Nadia do def unpin_chat_message(chat_id) do request("unpinChatMessage", chat_id: chat_id) end + + @doc """ + Use this method to send invoices. On success, the sent Message is returned. + + Args: + * `chat_id` - Unique identifier for the target chat or username of the target + * `title` - Product name, 1-32 characters + * `description` - Product description, 1-255 characters + * `payload` - Bot-defined invoice payload, 1-128 bytes. This will not be displayed to + the user, use for your internal processes. + * `provider_token` - Payments provider token, obtained via Botfather + * `start_parameter` - Unique deep-linking parameter that can be used to generate + this invoice when used as a start parameter + * `currency` - Three-letter ISO 4217 currency code + * `prices` - Array of `LabeledPrice`. Price breakdown (e.g. product price, tax, + discount, delivery cost, delivery tax, bonus, etc.) + + Options: + * `provider_data` - A JSON-serialized data about the invoice, which will be shared + with the payment provider. A detailed description of required fields should be provided + by the payment provider. + * `photo_url` - URL of the product photo for the invoice. Can be a photo of the goods + or a marketing image for a service. People like it better when they see what they are paying for. + * `photo_size` - Photo size + * `photo_width` - Photo width + * `photo_height` - Photo height + * `need_name` - Pass True, if you require the user's full name to complete the order + * `need_phone_number` - Pass True, if you require the user's phone number to complete the order + * `need_email` - Pass True, if you require the user's email address to complete the order + * `need_shipping_address` - Pass True, if you require the user's shipping address to complete the order + * `send_phone_number_to_provider` - Pass True, if user's phone number should be sent to provider + * `send_email_to_provider` - Pass True, if user's email address should be sent to provider + * `is_flexible` - Pass True, if the final price depends on the shipping method + * `disable_notification` - Sends the message silently. Users will receive a notification with no sound. + * `reply_to_message_id` - If the message is a reply, ID of the original message + * `allow_sending_without_reply` - Pass True, if the message should be sent even if the + specified replied-to message is not found + * `reply_markup` - A JSON-serialized object for an inline keyboard - `Nadia.Model.InlineKeyboardMarkup` + """ + @spec send_invoice(integer | binary, binary, binary, binary, binary, binary, binary, [LabeledPrice.t()], [{atom, any}]) :: + {:ok, Message.t()} | {:error, Error.t()} + def send_invoice(chat_id, title, description, payload, provider_token, start_parameter, currency, prices, options \\ []) do + request("sendInvoice", + [ + chat_id: chat_id, + title: title, + description: description, + payload: payload, + provider_token: provider_token, + start_parameter: start_parameter, + currency: currency, + prices: prices, + ] ++ options + ) + end + + @doc """ + If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, + the Bot API will send an Update with a shipping_query field to the bot. Use this method to reply + to shipping queries. On success, True is returned. + + Args: + * `shipping_query_id` - Unique identifier for the query to be answered + * `ok` - Specify True if delivery to the specified address is possible and False if there are any + problems (for example, if delivery to the specified address is not possible) + + Options: + * `shipping_address` - Required if ok is True. A list of `Nadia.Model.ShippingOption` + * `error_message` - Required if ok is False. Error message in human readable form that explains + why it is impossible to complete the order (e.g. "Sorry, delivery to your desired address is + unavailable'). Telegram will display this message to the user. + """ + @spec answer_shipping_query(integer | binary, boolean, [{atom, any}]) :: :ok | {:error, Error.t()} + def answer_shipping_query(shipping_query_id, ok, options \\ []) do + request("answerShippingQuery", [shipping_query_id: shipping_query_id, ok: ok] ++ options) + end + + @doc """ + Once the user has confirmed their payment and shipping details, the Bot API sends the final + confirmation in the form of an Update with the field pre_checkout_query. Use this method to + respond to such pre-checkout queries. On success, True is returned. Note: The Bot API must receive + an answer within 10 seconds after the pre-checkout query was sent. + + Args: + * `pre_checkout_query_id` - Unique identifier for the query to be answered + * `ok` - Specify True if everything is alright (goods are available, etc.) and the bot + is ready to proceed with the order. Use False if there are any problems. + + Options: + * `error_message` - Required if ok is False. Error message in human readable form that explains + the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of + our amazing black T-shirts while you were busy filling out your payment details. Please choose + a different color or garment!"). Telegram will display this message to the user. + """ + @spec answer_pre_checkout_query(integer | binary, boolean, [{atom, any}]) :: :ok | {:error, Error.t()} + def answer_pre_checkout_query(pre_checkout_query_id, ok, options \\ []) do + request("answerPreCheckoutQuery", + [pre_checkout_query_id: pre_checkout_query_id, ok: ok] ++ options) + end end diff --git a/lib/nadia/api.ex b/lib/nadia/api.ex index df6db00..932f336 100644 --- a/lib/nadia/api.ex +++ b/lib/nadia/api.ex @@ -47,12 +47,14 @@ defmodule Nadia.API do defp build_request(params, file_field) when is_list(params) do params |> Keyword.update(:reply_markup, nil, &Jason.encode!(&1)) + |> Keyword.update(:prices, nil, &Jason.encode!(&1)) |> map_params(file_field) end defp build_request(params, file_field) when is_map(params) do params |> Map.update(:reply_markup, nil, &Jason.encode!(&1)) + |> Map.update(:prices, nil, &Jason.encode!(&1)) |> map_params(file_field) end diff --git a/lib/nadia/behaviour.ex b/lib/nadia/behaviour.ex index 4d2aaf6..903f86c 100644 --- a/lib/nadia/behaviour.ex +++ b/lib/nadia/behaviour.ex @@ -46,4 +46,10 @@ defmodule Nadia.Behaviour do {:ok, Message.t()} | {:error, Error.t()} @callback answer_inline_query(binary, [Nadia.Model.InlineQueryResult.t()], [{atom, any}]) :: :ok | {:error, Error.t()} + @callback send_invoice(integer | binary, binary, binary, binary, binary, binary, binary, [Nadia.Model.LabeledPrice.t()], [{atom, any}]) :: + {:ok, Message.t()} | {:error, Error.t()} + @callback answer_shipping_query(integer | binary, boolean, [{atom, any}]) :: + :ok | {:error, Error.t()} + @callback answer_pre_checkout_query(integer | binary, boolean, [{atom, any}]) :: + :ok | {:error, Error.t()} end diff --git a/lib/nadia/model.ex b/lib/nadia/model.ex index 1a1b831..230de1d 100644 --- a/lib/nadia/model.ex +++ b/lib/nadia/model.ex @@ -349,6 +349,118 @@ defmodule Nadia.Model do } end + defmodule LabeledPrice do + @derive Jason.Encoder + defstruct label: nil, amount: nil + + @type t :: %LabeledPrice{label: binary, amount: integer} + end + + defmodule Invoice do + @derive Jason.Encoder + defstruct title: nil, description: nil, start_parameter: nil, currency: nil, total_amount: nil + + @type t :: %Invoice{ + title: binary, + description: binary, + start_parameter: binary, + currency: binary, + total_amount: integer + } + end + + defmodule ShippingAddress do + @derive Jason.Encoder + defstruct id: nil, title: nil, prices: [] + + @type t :: %ShippingAddress{ + id: binary, + title: binary, + prices: [ LabeledPrice.t() ] + } + end + + defmodule OrderInfo do + @derive Jason.Encoder + defstruct name: nil, phone_number: nil, email: nil, shipping_address: nil + + @type t :: %OrderInfo{ + name: binary, + phone_number: binary, + email: binary, + shipping_address: ShippingAddress.t() + } + end + + defmodule ShippingOption do + @derive Jason.Encoder + defstruct id: nil, title: nil, prices: [] + + @type t :: %ShippingOption{ + id: binary, + title: binary, + prices: [ LabeledPrice.t() ] + } + end + + defmodule SuccessfulPayment do + @derive Jason.Encoder + defstruct [ + currency: "USD", + total_amount: nil, + invoice_payload: nil, + shipping_option_id: nil, + order_info: nil, + telegram_payment_charge_id: nil, + provider_payment_charge_id: nil + ] + + @type t :: %SuccessfulPayment{ + currency: binary, + total_amount: non_neg_integer, + invoice_payload: binary, + shipping_option_id: binary, + order_info: OrderInfo.t(), + telegram_payment_charge_id: binary, + provider_payment_charge_id: binary + } + end + + defmodule ShippingQuery do + @derive Jason.Encoder + defstruct id: nil, from: nil, invoice_payload: nil, shipping_address: nil + + @type t :: %ShippingQuery{ + id: binary, + from: User.t(), + invoice_payload: binary, + shipping_address: ShippingAddress.t() + } + end + + defmodule PreCheckoutQuery do + @derive Jason.Encoder + defstruct [ + id: nil, + from: nil, + currency: nil, + total_amount: nil, + invoice_payload: nil, + shipping_option_id: nil, + order_info: nil + ] + + @type t :: %PreCheckoutQuery{ + id: binary, + from: User.t(), + currency: binary, + total_amount: integer, + invoice_payload: binary, + shipping_option_id: binary, + order_info: OrderInfo.t() + } + end + defmodule CallbackQuery do defstruct id: nil, from: nil, message: nil, inline_message_id: nil, data: nil