| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "payments/payments_form.h"
- #include "main/main_session.h"
- #include "data/data_channel.h"
- #include "data/data_session.h"
- #include "data/data_media_types.h"
- #include "data/data_user.h"
- #include "data/data_photo.h"
- #include "data/data_photo_media.h"
- #include "data/data_file_origin.h"
- #include "countries/countries_instance.h"
- #include "history/history_item.h"
- #include "history/history_item_components.h"
- #include "stripe/stripe_api_client.h"
- #include "stripe/stripe_error.h"
- #include "stripe/stripe_token.h"
- #include "stripe/stripe_card_validator.h"
- #include "smartglocal/smartglocal_api_client.h"
- #include "smartglocal/smartglocal_error.h"
- #include "smartglocal/smartglocal_token.h"
- #include "storage/storage_account.h"
- #include "ui/image/image.h"
- #include "ui/text/format_values.h"
- #include "ui/text/text_entity.h"
- #include "apiwrap.h"
- #include "api/api_text_entities.h"
- #include "core/core_cloud_password.h"
- #include "window/themes/window_theme.h"
- #include "webview/webview_interface.h"
- #include "styles/style_payments.h" // paymentsThumbnailSize.
- #include <QtCore/QJsonDocument>
- #include <QtCore/QJsonObject>
- #include <QtCore/QJsonValue>
- namespace Payments {
- namespace {
- constexpr auto kPasswordPeriod = 15 * TimeId(60);
- [[nodiscard]] Ui::Address ParseAddress(const MTPPostAddress &address) {
- return address.match([](const MTPDpostAddress &data) {
- return Ui::Address{
- .address1 = qs(data.vstreet_line1()),
- .address2 = qs(data.vstreet_line2()),
- .city = qs(data.vcity()),
- .state = qs(data.vstate()),
- .countryIso2 = qs(data.vcountry_iso2()),
- .postcode = qs(data.vpost_code()),
- };
- });
- }
- [[nodiscard]] int64 ParsePriceAmount(uint64 value) {
- return *reinterpret_cast<const int64*>(&value);
- }
- [[nodiscard]] std::vector<Ui::LabeledPrice> ParsePrices(
- const MTPVector<MTPLabeledPrice> &data) {
- return ranges::views::all(
- data.v
- ) | ranges::views::transform([](const MTPLabeledPrice &price) {
- return price.match([&](const MTPDlabeledPrice &data) {
- return Ui::LabeledPrice{
- .label = qs(data.vlabel()),
- .price = ParsePriceAmount(data.vamount().v),
- };
- });
- }) | ranges::to_vector;
- }
- [[nodiscard]] MTPPaymentRequestedInfo Serialize(
- const Ui::RequestedInformation &information) {
- using Flag = MTPDpaymentRequestedInfo::Flag;
- return MTP_paymentRequestedInfo(
- MTP_flags((information.name.isEmpty() ? Flag(0) : Flag::f_name)
- | (information.email.isEmpty() ? Flag(0) : Flag::f_email)
- | (information.phone.isEmpty() ? Flag(0) : Flag::f_phone)
- | (information.shippingAddress
- ? Flag::f_shipping_address
- : Flag(0))),
- MTP_string(information.name),
- MTP_string(information.phone),
- MTP_string(information.email),
- MTP_postAddress(
- MTP_string(information.shippingAddress.address1),
- MTP_string(information.shippingAddress.address2),
- MTP_string(information.shippingAddress.city),
- MTP_string(information.shippingAddress.state),
- MTP_string(information.shippingAddress.countryIso2),
- MTP_string(information.shippingAddress.postcode)));
- }
- [[nodiscard]] QString CardTitle(const Stripe::Card &card) {
- // Like server stores saved_credentials title.
- return Stripe::CardBrandToString(card.brand()).toLower()
- + " *"
- + card.last4();
- }
- [[nodiscard]] QString CardTitle(const SmartGlocal::Card &card) {
- // Like server stores saved_credentials title.
- return card.type().toLower()
- + " *"
- + SmartGlocal::Last4(card);
- }
- } // namespace
- not_null<Main::Session*> SessionFromId(const InvoiceId &id) {
- if (const auto message = std::get_if<InvoiceMessage>(&id.value)) {
- return &message->peer->session();
- } else if (const auto slug = std::get_if<InvoiceSlug>(&id.value)) {
- return slug->session;
- } else if (const auto slug = std::get_if<InvoiceCredits>(&id.value)) {
- return slug->session;
- } else if (const auto gift = std::get_if<InvoiceStarGift>(&id.value)) {
- return &gift->recipient->session();
- }
- const auto &giftCode = v::get<InvoicePremiumGiftCode>(id.value);
- const auto users = std::get_if<InvoicePremiumGiftCodeUsers>(
- &giftCode.purpose);
- if (users) {
- Assert(!users->users.empty());
- return &users->users.front()->session();
- }
- const auto &giveaway = v::get<InvoicePremiumGiftCodeGiveaway>(
- giftCode.purpose);
- return &giveaway.boostPeer->session();
- }
- MTPinputStorePaymentPurpose InvoicePremiumGiftCodeGiveawayToTL(
- const InvoicePremiumGiftCode &invoice) {
- const auto &giveaway = v::get<InvoicePremiumGiftCodeGiveaway>(
- invoice.purpose);
- using Flag = MTPDinputStorePaymentPremiumGiveaway::Flag;
- return MTP_inputStorePaymentPremiumGiveaway(
- MTP_flags(Flag()
- | (giveaway.onlyNewSubscribers
- ? Flag::f_only_new_subscribers
- : Flag())
- | (giveaway.additionalChannels.empty()
- ? Flag()
- : Flag::f_additional_peers)
- | (giveaway.countries.empty()
- ? Flag()
- : Flag::f_countries_iso2)
- | (giveaway.showWinners
- ? Flag::f_winners_are_visible
- : Flag())
- | (giveaway.additionalPrize.isEmpty()
- ? Flag()
- : Flag::f_prize_description)),
- giveaway.boostPeer->input,
- MTP_vector_from_range(ranges::views::all(
- giveaway.additionalChannels
- ) | ranges::views::transform([](not_null<ChannelData*> c) {
- return MTPInputPeer(c->input);
- })),
- MTP_vector_from_range(ranges::views::all(
- giveaway.countries
- ) | ranges::views::transform([](QString value) {
- return MTP_string(value);
- })),
- MTP_string(giveaway.additionalPrize),
- MTP_long(invoice.randomId),
- MTP_int(giveaway.untilDate),
- MTP_string(invoice.currency),
- MTP_long(invoice.amount));
- }
- MTPinputStorePaymentPurpose InvoiceCreditsGiveawayToTL(
- const InvoicePremiumGiftCode &invoice) {
- Expects(invoice.giveawayCredits.has_value());
- const auto &giveaway = v::get<InvoicePremiumGiftCodeGiveaway>(
- invoice.purpose);
- using Flag = MTPDinputStorePaymentStarsGiveaway::Flag;
- return MTP_inputStorePaymentStarsGiveaway(
- MTP_flags(Flag()
- | (giveaway.onlyNewSubscribers
- ? Flag::f_only_new_subscribers
- : Flag())
- | (giveaway.additionalChannels.empty()
- ? Flag()
- : Flag::f_additional_peers)
- | (giveaway.countries.empty()
- ? Flag()
- : Flag::f_countries_iso2)
- | (giveaway.showWinners
- ? Flag::f_winners_are_visible
- : Flag())
- | (giveaway.additionalPrize.isEmpty()
- ? Flag()
- : Flag::f_prize_description)),
- MTP_long(*invoice.giveawayCredits),
- giveaway.boostPeer->input,
- MTP_vector_from_range(ranges::views::all(
- giveaway.additionalChannels
- ) | ranges::views::transform([](not_null<ChannelData*> c) {
- return MTPInputPeer(c->input);
- })),
- MTP_vector_from_range(ranges::views::all(
- giveaway.countries
- ) | ranges::views::transform([](QString value) {
- return MTP_string(value);
- })),
- MTP_string(giveaway.additionalPrize),
- MTP_long(invoice.randomId),
- MTP_int(giveaway.untilDate),
- MTP_string(invoice.currency),
- MTP_long(invoice.amount),
- MTP_int(invoice.users));
- }
- bool IsPremiumForStarsInvoice(const InvoiceId &id) {
- const auto giftCode = std::get_if<InvoicePremiumGiftCode>(&id.value);
- return giftCode
- && !giftCode->giveawayCredits
- && (giftCode->currency == ::Ui::kCreditsCurrency);
- }
- Form::Form(InvoiceId id, bool receipt)
- : _id(id)
- , _session(SessionFromId(id))
- , _api(&_session->mtp())
- , _receiptMode(receipt) {
- fillInvoiceFromMessage();
- if (_receiptMode) {
- _invoice.receipt.paid = true;
- requestReceipt();
- } else {
- requestForm();
- }
- }
- Form::~Form() = default;
- void Form::fillInvoiceFromMessage() {
- const auto message = std::get_if<InvoiceMessage>(&_id.value);
- if (!message) {
- return;
- }
- const auto id = FullMsgId(message->peer->id, message->itemId);
- if (const auto item = _session->data().message(id)) {
- const auto media = [&] {
- if (const auto payment = item->Get<HistoryServicePayment>()) {
- if (const auto invoice = payment->msg) {
- return invoice->media();
- }
- }
- return item->media();
- }();
- if (const auto invoice = media ? media->invoice() : nullptr) {
- _invoice.isTest = invoice->isTest;
- _invoice.cover = Ui::Cover{
- .title = invoice->title,
- .description = invoice->description,
- };
- if (const auto photo = invoice->photo) {
- loadThumbnail(photo);
- }
- }
- }
- }
- void Form::showProgress() {
- _updates.fire(ToggleProgress{ true });
- }
- void Form::hideProgress() {
- _updates.fire(ToggleProgress{ false });
- }
- void Form::loadThumbnail(not_null<PhotoData*> photo) {
- Expects(!_thumbnailLoadProcess);
- auto view = photo->createMediaView();
- if (auto good = prepareGoodThumbnail(view); !good.isNull()) {
- _invoice.cover.thumbnail = std::move(good);
- return;
- }
- _thumbnailLoadProcess = std::make_unique<ThumbnailLoadProcess>();
- if (auto blurred = prepareBlurredThumbnail(view); !blurred.isNull()) {
- _invoice.cover.thumbnail = std::move(blurred);
- _thumbnailLoadProcess->blurredSet = true;
- } else {
- _invoice.cover.thumbnail = prepareEmptyThumbnail();
- }
- _thumbnailLoadProcess->view = std::move(view);
- photo->load(Data::PhotoSize::Thumbnail, thumbnailFileOrigin());
- _session->downloaderTaskFinished(
- ) | rpl::start_with_next([=] {
- const auto &view = _thumbnailLoadProcess->view;
- if (auto good = prepareGoodThumbnail(view); !good.isNull()) {
- _invoice.cover.thumbnail = std::move(good);
- _thumbnailLoadProcess = nullptr;
- } else if (_thumbnailLoadProcess->blurredSet) {
- return;
- } else if (auto blurred = prepareBlurredThumbnail(view)
- ; !blurred.isNull()) {
- _invoice.cover.thumbnail = std::move(blurred);
- _thumbnailLoadProcess->blurredSet = true;
- } else {
- return;
- }
- _updates.fire(ThumbnailUpdated{ _invoice.cover.thumbnail });
- }, _thumbnailLoadProcess->lifetime);
- }
- Data::FileOrigin Form::thumbnailFileOrigin() const {
- if (const auto message = std::get_if<InvoiceMessage>(&_id.value)) {
- return FullMsgId(message->peer->id, message->itemId);
- }
- return Data::FileOrigin();
- }
- QImage Form::prepareGoodThumbnail(
- const std::shared_ptr<Data::PhotoMedia> &view) const {
- using Size = Data::PhotoSize;
- if (const auto large = view->image(Size::Large)) {
- return prepareThumbnail(large);
- } else if (const auto thumbnail = view->image(Size::Thumbnail)) {
- return prepareThumbnail(thumbnail);
- }
- return QImage();
- }
- QImage Form::prepareBlurredThumbnail(
- const std::shared_ptr<Data::PhotoMedia> &view) const {
- if (const auto small = view->image(Data::PhotoSize::Small)) {
- return prepareThumbnail(small, true);
- } else if (const auto blurred = view->thumbnailInline()) {
- return prepareThumbnail(blurred, true);
- }
- return QImage();
- }
- QImage Form::prepareThumbnail(
- not_null<const Image*> image,
- bool blurred) const {
- auto result = image->original().scaled(
- st::paymentsThumbnailSize * style::DevicePixelRatio(),
- Qt::KeepAspectRatio,
- Qt::SmoothTransformation);
- result = Images::Round(std::move(result), ImageRoundRadius::Large);
- result.setDevicePixelRatio(style::DevicePixelRatio());
- return result;
- }
- QImage Form::prepareEmptyThumbnail() const {
- auto result = QImage(
- st::paymentsThumbnailSize * style::DevicePixelRatio(),
- QImage::Format_ARGB32_Premultiplied);
- result.setDevicePixelRatio(style::DevicePixelRatio());
- result.fill(Qt::transparent);
- return result;
- }
- MTPInputInvoice Form::inputInvoice() const {
- if (const auto message = std::get_if<InvoiceMessage>(&_id.value)) {
- return MTP_inputInvoiceMessage(
- message->peer->input,
- MTP_int(message->itemId.bare));
- } else if (const auto slug = std::get_if<InvoiceSlug>(&_id.value)) {
- return MTP_inputInvoiceSlug(MTP_string(slug->slug));
- } else if (const auto credits = std::get_if<InvoiceCredits>(&_id.value)) {
- if (const auto userId = peerToUser(credits->giftPeerId)) {
- if (const auto user = _session->data().user(userId)) {
- return MTP_inputInvoiceStars(
- MTP_inputStorePaymentStarsGift(
- user->inputUser,
- MTP_long(credits->credits),
- MTP_string(credits->currency),
- MTP_long(credits->amount)));
- }
- }
- return MTP_inputInvoiceStars(
- MTP_inputStorePaymentStarsTopup(
- MTP_long(credits->credits),
- MTP_string(credits->currency),
- MTP_long(credits->amount)));
- } else if (const auto gift = std::get_if<InvoiceStarGift>(&_id.value)) {
- using Flag = MTPDinputInvoiceStarGift::Flag;
- return MTP_inputInvoiceStarGift(
- MTP_flags((gift->anonymous ? Flag::f_hide_name : Flag(0))
- | (gift->message.empty() ? Flag(0) : Flag::f_message)
- | (gift->upgraded ? Flag::f_include_upgrade : Flag(0))),
- gift->recipient->input,
- MTP_long(gift->giftId),
- MTP_textWithEntities(
- MTP_string(gift->message.text),
- Api::EntitiesToMTP(
- &gift->recipient->session(),
- gift->message.entities,
- Api::ConvertOption::SkipLocal)));
- }
- const auto &giftCode = v::get<InvoicePremiumGiftCode>(_id.value);
- if (giftCode.giveawayCredits) {
- return MTP_inputInvoiceStars(InvoiceCreditsGiveawayToTL(giftCode));
- }
- using Flag = MTPDpremiumGiftCodeOption::Flag;
- const auto option = MTP_premiumGiftCodeOption(
- MTP_flags((giftCode.storeQuantity ? Flag::f_store_quantity : Flag())
- | (giftCode.storeProduct.isEmpty()
- ? Flag()
- : Flag::f_store_product)),
- MTP_int(giftCode.users),
- MTP_int(giftCode.months),
- MTP_string(giftCode.storeProduct),
- MTP_int(giftCode.storeQuantity),
- MTP_string(giftCode.currency),
- MTP_long(giftCode.amount));
- const auto users = std::get_if<InvoicePremiumGiftCodeUsers>(
- &giftCode.purpose);
- auto message = (users && !users->message.empty())
- ? MTP_textWithEntities(
- MTP_string(users->message.text),
- Api::EntitiesToMTP(
- &users->users.front()->session(),
- users->message.entities,
- Api::ConvertOption::SkipLocal))
- : std::optional<MTPTextWithEntities>();
- if (users
- && users->users.size() == 1
- && giftCode.currency == ::Ui::kCreditsCurrency) {
- using Flag = MTPDinputInvoicePremiumGiftStars::Flag;
- return MTP_inputInvoicePremiumGiftStars(
- MTP_flags(message ? Flag::f_message : Flag()),
- users->users.front()->inputUser,
- MTP_int(giftCode.months),
- message.value_or(MTPTextWithEntities()));
- } else if (users) {
- using Flag = MTPDinputStorePaymentPremiumGiftCode::Flag;
- return MTP_inputInvoicePremiumGiftCode(
- MTP_inputStorePaymentPremiumGiftCode(
- MTP_flags((users->boostPeer ? Flag::f_boost_peer : Flag())
- | (message ? Flag::f_message : Flag())),
- MTP_vector_from_range(ranges::views::all(
- users->users
- ) | ranges::views::transform([](not_null<UserData*> user) {
- return MTPInputUser(user->inputUser);
- })),
- users->boostPeer ? users->boostPeer->input : MTPInputPeer(),
- MTP_string(giftCode.currency),
- MTP_long(giftCode.amount),
- message.value_or(MTPTextWithEntities())),
- option);
- } else {
- return MTP_inputInvoicePremiumGiftCode(
- InvoicePremiumGiftCodeGiveawayToTL(giftCode),
- option);
- }
- }
- void Form::requestForm() {
- showProgress();
- _api.request(MTPpayments_GetPaymentForm(
- MTP_flags(MTPpayments_GetPaymentForm::Flag::f_theme_params),
- inputInvoice(),
- MTP_dataJSON(MTP_bytes(Window::Theme::WebViewParams().json))
- )).done([=](const MTPpayments_PaymentForm &result) {
- hideProgress();
- result.match([&](const MTPDpayments_paymentForm &data) {
- processForm(data);
- }, [&](const MTPDpayments_paymentFormStars &data) {
- _session->data().processUsers(data.vusers());
- const auto currency = qs(data.vinvoice().data().vcurrency());
- const auto &tlPrices = data.vinvoice().data().vprices().v;
- const auto amount = tlPrices.empty()
- ? 0
- : tlPrices.front().data().vamount().v;
- const auto subscriptionPeriod
- = data.vinvoice().data().vsubscription_period().value_or(0);
- if (currency != ::Ui::kCreditsCurrency || !amount) {
- using Type = Error::Type;
- _updates.fire(Error{ Type::Form, u"Bad Stars Form."_q });
- return;
- }
- const auto invoice = InvoiceCredits{
- .session = _session,
- .randomId = 0,
- .credits = amount,
- .currency = currency,
- .amount = amount,
- .subscriptionPeriod = subscriptionPeriod,
- };
- const auto formData = CreditsFormData{
- .id = _id,
- .formId = data.vform_id().v,
- .botId = data.vbot_id().v,
- .title = qs(data.vtitle()),
- .description = qs(data.vdescription()),
- .photo = data.vphoto()
- ? _session->data().photoFromWeb(
- *data.vphoto(),
- ImageLocation())
- : nullptr,
- .invoice = invoice,
- .inputInvoice = inputInvoice(),
- };
- _updates.fire(CreditsPaymentStarted{ .data = formData });
- }, [&](const MTPDpayments_paymentFormStarGift &data) {
- const auto currency = qs(data.vinvoice().data().vcurrency());
- const auto &tlPrices = data.vinvoice().data().vprices().v;
- const auto amount = tlPrices.empty()
- ? 0
- : tlPrices.front().data().vamount().v;
- if (currency != ::Ui::kCreditsCurrency || !amount) {
- using Type = Error::Type;
- _updates.fire(Error{ Type::Form, u"Bad Stars Form."_q });
- return;
- }
- const auto invoice = InvoiceCredits{
- .session = _session,
- .randomId = 0,
- .credits = amount,
- .currency = currency,
- .amount = amount,
- };
- const auto gift = std::get_if<InvoiceStarGift>(&_id.value);
- const auto formData = CreditsFormData{
- .id = _id,
- .formId = data.vform_id().v,
- .invoice = invoice,
- .inputInvoice = inputInvoice(),
- .starGiftLimitedCount = gift ? gift->limitedCount : 0,
- .starGiftForm = true,
- };
- _updates.fire(CreditsPaymentStarted{ .data = formData });
- });
- }).fail([=](const MTP::Error &error) {
- hideProgress();
- _updates.fire(Error{ Error::Type::Form, error.type() });
- }).send();
- }
- void Form::requestReceipt() {
- Expects(v::is<InvoiceMessage>(_id.value));
- const auto message = v::get<InvoiceMessage>(_id.value);
- showProgress();
- _api.request(MTPpayments_GetPaymentReceipt(
- message.peer->input,
- MTP_int(message.itemId.bare)
- )).done([=](const MTPpayments_PaymentReceipt &result) {
- hideProgress();
- result.match([&](const auto &data) {
- processReceipt(data);
- });
- }).fail([=](const MTP::Error &error) {
- hideProgress();
- _updates.fire(Error{ Error::Type::Form, error.type() });
- }).send();
- }
- void Form::processForm(const MTPDpayments_paymentForm &data) {
- _session->data().processUsers(data.vusers());
- data.vinvoice().match([&](const auto &data) {
- processInvoice(data);
- });
- processDetails(data);
- if (const auto info = data.vsaved_info()) {
- info->match([&](const auto &data) {
- processSavedInformation(data);
- });
- }
- _paymentMethod.savedCredentials.clear();
- _paymentMethod.savedCredentialsIndex = 0;
- if (const auto credentials = data.vsaved_credentials()) {
- _paymentMethod.savedCredentials.reserve(credentials->v.size());
- for (const auto &saved : credentials->v) {
- _paymentMethod.savedCredentials.push_back({
- .id = qs(saved.data().vid()),
- .title = qs(saved.data().vtitle()),
- });
- }
- refreshPaymentMethodDetails();
- }
- if (const auto additional = data.vadditional_methods()) {
- processAdditionalPaymentMethods(additional->v);
- }
- fillPaymentMethodInformation();
- _updates.fire(FormReady{});
- }
- void Form::processReceipt(const MTPDpayments_paymentReceipt &data) {
- _session->data().processUsers(data.vusers());
- data.vinvoice().match([&](const auto &data) {
- processInvoice(data);
- });
- processDetails(data);
- if (const auto info = data.vinfo()) {
- info->match([&](const auto &data) {
- processSavedInformation(data);
- });
- }
- if (const auto shipping = data.vshipping()) {
- processShippingOptions({ *shipping });
- if (!_shippingOptions.list.empty()) {
- _shippingOptions.selectedId = _shippingOptions.list.front().id;
- }
- }
- _paymentMethod.savedCredentials = { {
- .id = "(used)",
- .title = qs(data.vcredentials_title()),
- } };
- _paymentMethod.savedCredentialsIndex = 0;
- fillPaymentMethodInformation();
- _updates.fire(FormReady{});
- }
- void Form::processReceipt(const MTPDpayments_paymentReceiptStars &data) {
- _session->data().processUsers(data.vusers());
- const auto receiptData = CreditsReceiptData{
- .id = qs(data.vtransaction_id()),
- .title = qs(data.vtitle()),
- .description = qs(data.vdescription()),
- .photo = data.vphoto()
- ? _session->data().photoFromWeb(
- *data.vphoto(),
- ImageLocation())
- : nullptr,
- .peerId = peerFromUser(data.vbot_id().v),
- .credits = StarsAmount(data.vtotal_amount().v),
- .date = data.vdate().v,
- };
- _updates.fire(CreditsReceiptReady{ .data = receiptData });
- }
- void Form::processInvoice(const MTPDinvoice &data) {
- const auto suggested = data.vsuggested_tip_amounts().value_or_empty();
- _invoice = Ui::Invoice{
- .cover = std::move(_invoice.cover),
- .prices = ParsePrices(data.vprices()),
- .suggestedTips = ranges::views::all(
- suggested
- ) | ranges::views::transform(
- &MTPlong::v
- ) | ranges::views::transform(
- ParsePriceAmount
- ) | ranges::to_vector,
- .tipsMax = ParsePriceAmount(data.vmax_tip_amount().value_or_empty()),
- .currency = qs(data.vcurrency()),
- .isNameRequested = data.is_name_requested(),
- .isPhoneRequested = data.is_phone_requested(),
- .isEmailRequested = data.is_email_requested(),
- .isShippingAddressRequested = data.is_shipping_address_requested(),
- .isRecurring = data.is_recurring(),
- .isFlexible = data.is_flexible(),
- .isTest = data.is_test(),
- .termsUrl = qs(data.vterms_url().value_or_empty()),
- .phoneSentToProvider = data.is_phone_to_provider(),
- .emailSentToProvider = data.is_email_to_provider(),
- };
- }
- void Form::processDetails(const MTPDpayments_paymentForm &data) {
- const auto nativeParams = data.vnative_params();
- auto nativeParamsJson = nativeParams
- ? nativeParams->match(
- [&](const MTPDdataJSON &data) { return data.vdata().v; })
- : QByteArray();
- _details = FormDetails{
- .formId = data.vform_id().v,
- .url = qs(data.vurl()),
- .nativeProvider = qs(data.vnative_provider().value_or_empty()),
- .nativeParamsJson = std::move(nativeParamsJson),
- .botId = data.vbot_id().v,
- .providerId = data.vprovider_id().v,
- .canSaveCredentials = data.is_can_save_credentials(),
- .passwordMissing = data.is_password_missing(),
- };
- _invoice.cover.title = qs(data.vtitle());
- _invoice.cover.description = TextUtilities::ParseEntities(
- qs(data.vdescription()),
- TextParseLinks | TextParseMultiline);
- if (_invoice.cover.thumbnail.isNull() && !_thumbnailLoadProcess) {
- if (const auto photo = data.vphoto()) {
- loadThumbnail(
- _session->data().photoFromWeb(*photo, ImageLocation()));
- }
- }
- if (const auto botId = _details.botId) {
- if (const auto bot = _session->data().userLoaded(botId)) {
- _invoice.cover.seller = bot->name();
- _details.termsBotUsername = bot->username();
- }
- }
- if (const auto providerId = _details.providerId) {
- if (const auto bot = _session->data().userLoaded(providerId)) {
- _invoice.provider = bot->name();
- }
- }
- }
- void Form::processDetails(const MTPDpayments_paymentReceipt &data) {
- _invoice.receipt = Ui::Receipt{
- .date = data.vdate().v,
- .totalAmount = ParsePriceAmount(data.vtotal_amount().v),
- .currency = qs(data.vcurrency()),
- .paid = true,
- };
- _details = FormDetails{
- .botId = data.vbot_id().v,
- .providerId = data.vprovider_id().v,
- };
- if (_invoice.cover.title.isEmpty()
- && _invoice.cover.description.empty()
- && _invoice.cover.thumbnail.isNull()
- && !_thumbnailLoadProcess) {
- _invoice.cover = Ui::Cover{
- .title = qs(data.vtitle()),
- .description = { qs(data.vdescription()) },
- };
- if (const auto web = data.vphoto()) {
- if (const auto photo = _session->data().photoFromWeb(*web, {})) {
- loadThumbnail(photo);
- }
- }
- }
- if (_details.botId) {
- if (const auto bot = _session->data().userLoaded(_details.botId)) {
- _invoice.cover.seller = bot->name();
- }
- }
- }
- void Form::processDetails(const MTPDpayments_paymentReceiptStars &data) {
- _invoice.receipt = Ui::Receipt{
- .date = data.vdate().v,
- .totalAmount = ParsePriceAmount(data.vtotal_amount().v),
- .currency = qs(data.vcurrency()),
- .paid = true,
- };
- _details = FormDetails{
- .botId = data.vbot_id().v,
- };
- if (_invoice.cover.title.isEmpty()
- && _invoice.cover.description.empty()
- && _invoice.cover.thumbnail.isNull()
- && !_thumbnailLoadProcess) {
- _invoice.cover = Ui::Cover{
- .title = qs(data.vtitle()),
- .description = { qs(data.vdescription()) },
- };
- if (const auto web = data.vphoto()) {
- if (const auto photo = _session->data().photoFromWeb(*web, {})) {
- loadThumbnail(photo);
- }
- }
- }
- if (_details.botId) {
- if (const auto bot = _session->data().userLoaded(_details.botId)) {
- _invoice.cover.seller = bot->name();
- }
- }
- }
- void Form::processSavedInformation(const MTPDpaymentRequestedInfo &data) {
- const auto address = data.vshipping_address();
- _savedInformation = _information = Ui::RequestedInformation{
- .defaultPhone = defaultPhone(),
- .defaultCountry = defaultCountry(),
- .name = qs(data.vname().value_or_empty()),
- .phone = qs(data.vphone().value_or_empty()),
- .email = qs(data.vemail().value_or_empty()),
- .shippingAddress = address ? ParseAddress(*address) : Ui::Address(),
- };
- }
- void Form::processAdditionalPaymentMethods(
- const QVector<MTPPaymentFormMethod> &list) {
- _paymentMethod.ui.additionalMethods = ranges::views::all(
- list
- ) | ranges::views::transform([](const MTPPaymentFormMethod &method) {
- return Ui::PaymentMethodAdditional{
- .title = qs(method.data().vtitle()),
- .url = qs(method.data().vurl()),
- };
- }) | ranges::to_vector;
- }
- void Form::refreshPaymentMethodDetails() {
- refreshSavedPaymentMethodDetails();
- _paymentMethod.ui.provider = _invoice.provider;
- _paymentMethod.ui.native.defaultCountry = defaultCountry();
- _paymentMethod.ui.canSaveInformation
- = _paymentMethod.ui.native.canSaveInformation
- = _details.canSaveCredentials || _details.passwordMissing;
- }
- void Form::refreshSavedPaymentMethodDetails() {
- const auto &list = _paymentMethod.savedCredentials;
- const auto index = _paymentMethod.savedCredentialsIndex;
- const auto &entered = _paymentMethod.newCredentials;
- _paymentMethod.ui.savedMethods.clear();
- if (entered) {
- _paymentMethod.ui.savedMethods.push_back({ .title = entered.title });
- }
- for (const auto &item : list) {
- _paymentMethod.ui.savedMethods.push_back({
- .id = item.id,
- .title = item.title,
- });
- }
- _paymentMethod.ui.savedMethodIndex = (index < list.size())
- ? (index + (entered ? 1 : 0))
- : 0;
- }
- QString Form::defaultPhone() const {
- return _session->user()->phone();
- }
- QString Form::defaultCountry() const {
- return Countries::Instance().countryISO2ByPhone(defaultPhone());
- }
- void Form::fillPaymentMethodInformation() {
- _paymentMethod.native = NativePaymentMethod();
- _paymentMethod.ui.native = Ui::NativeMethodDetails();
- _paymentMethod.ui.url = _details.url;
- //AssertIsDebug();
- //static auto counter = 0; // #TODO payments test both native and webview.
- if (!_details.nativeProvider.isEmpty()/* && ((++counter) % 2)*/) {
- auto error = QJsonParseError();
- auto document = QJsonDocument::fromJson(
- _details.nativeParamsJson,
- &error);
- if (error.error != QJsonParseError::NoError) {
- LOG(("Payment Error: Could not decode native_params, error %1: %2"
- ).arg(error.error
- ).arg(error.errorString()));
- } else if (!document.isObject()) {
- LOG(("Payment Error: Not an object in native_params."));
- } else {
- const auto object = document.object();
- if (_details.nativeProvider == "stripe") {
- fillStripeNativeMethod(object);
- } else if (_details.nativeProvider == "smartglocal") {
- fillSmartGlocalNativeMethod(object);
- } else {
- LOG(("Payment Error: Unknown native provider '%1'."
- ).arg(_details.nativeProvider));
- }
- }
- }
- refreshPaymentMethodDetails();
- }
- void Form::fillStripeNativeMethod(QJsonObject object) {
- const auto value = [&](QStringView key) {
- return object.value(key);
- };
- const auto key = value(u"publishable_key").toString();
- if (key.isEmpty()) {
- LOG(("Payment Error: No publishable_key in stripe native_params."));
- return;
- }
- _paymentMethod.native = NativePaymentMethod{
- .data = StripePaymentMethod{
- .publishableKey = key,
- },
- };
- _paymentMethod.ui.native = Ui::NativeMethodDetails{
- .supported = true,
- .needCountry = value(u"need_country").toBool(),
- .needZip = value(u"need_zip").toBool(),
- .needCardholderName = value(u"need_cardholder_name").toBool(),
- };
- }
- void Form::fillSmartGlocalNativeMethod(QJsonObject object) {
- const auto value = [&](QStringView key) {
- return object.value(key);
- };
- const auto key = value(u"public_token").toString();
- if (key.isEmpty()) {
- LOG(("Payment Error: "
- "No public_token in smartglocal native_params."));
- return;
- }
- _paymentMethod.native = NativePaymentMethod{
- .data = SmartGlocalPaymentMethod{
- .publicToken = key,
- .tokenizeUrl = value(u"tokenize_url").toString(),
- },
- };
- _paymentMethod.ui.native = Ui::NativeMethodDetails{
- .supported = true,
- .needCountry = false,
- .needZip = false,
- .needCardholderName = false,
- };
- }
- void Form::submit() {
- Expects(_paymentMethod.newCredentials
- || (_paymentMethod.savedCredentialsIndex
- < _paymentMethod.savedCredentials.size()));
- const auto index = _paymentMethod.savedCredentialsIndex;
- const auto &list = _paymentMethod.savedCredentials;
- const auto password = (index < list.size())
- ? _session->validTmpPassword()
- : QByteArray();
- if (index < list.size() && password.isEmpty()) {
- _updates.fire(TmpPasswordRequired{});
- return;
- } else if (!_session->local().isPeerTrustedPayment(_details.botId)) {
- _updates.fire(BotTrustRequired{
- .bot = _session->data().user(_details.botId),
- .provider = _session->data().user(_details.providerId),
- });
- return;
- }
- using Flag = MTPpayments_SendPaymentForm::Flag;
- showProgress();
- _api.request(MTPpayments_SendPaymentForm(
- MTP_flags((_requestedInformationId.isEmpty()
- ? Flag(0)
- : Flag::f_requested_info_id)
- | (_shippingOptions.selectedId.isEmpty()
- ? Flag(0)
- : Flag::f_shipping_option_id)
- | (_invoice.tipsMax > 0 ? Flag::f_tip_amount : Flag(0))),
- MTP_long(_details.formId),
- inputInvoice(),
- MTP_string(_requestedInformationId),
- MTP_string(_shippingOptions.selectedId),
- (index < list.size()
- ? MTP_inputPaymentCredentialsSaved(
- MTP_string(list[index].id),
- MTP_bytes(password))
- : MTP_inputPaymentCredentials(
- MTP_flags((_paymentMethod.newCredentials.saveOnServer
- && _details.canSaveCredentials)
- ? MTPDinputPaymentCredentials::Flag::f_save
- : MTPDinputPaymentCredentials::Flag(0)),
- MTP_dataJSON(MTP_bytes(_paymentMethod.newCredentials.data)))),
- MTP_long(_invoice.tipsSelected)
- )).done([=](const MTPpayments_PaymentResult &result) {
- hideProgress();
- result.match([&](const MTPDpayments_paymentResult &data) {
- _updates.fire(PaymentFinished{ data.vupdates() });
- }, [&](const MTPDpayments_paymentVerificationNeeded &data) {
- _updates.fire(VerificationNeeded{ qs(data.vurl()) });
- });
- }).fail([=](const MTP::Error &error) {
- hideProgress();
- _updates.fire(Error{ Error::Type::Send, error.type() });
- }).send();
- }
- void Form::submit(const Core::CloudPasswordResult &result) {
- if (_passwordRequestId) {
- return;
- }
- _passwordRequestId = _api.request(MTPaccount_GetTmpPassword(
- result.result,
- MTP_int(kPasswordPeriod)
- )).done([=](const MTPaccount_TmpPassword &result) {
- _passwordRequestId = 0;
- result.match([&](const MTPDaccount_tmpPassword &data) {
- _session->setTmpPassword(
- data.vtmp_password().v,
- data.vvalid_until().v);
- submit();
- });
- }).fail([=](const MTP::Error &error) {
- _passwordRequestId = 0;
- _updates.fire(Error{ Error::Type::TmpPassword, error.type() });
- }).send();
- }
- std::optional<QDate> Form::overrideExpireDateThreshold() const {
- const auto phone = _session->user()->phone();
- return phone.startsWith('7')
- ? QDate(2022, 2, 1)
- : std::optional<QDate>();
- }
- void Form::validateInformation(const Ui::RequestedInformation &information) {
- if (_validateRequestId) {
- if (_validatedInformation == information) {
- return;
- }
- hideProgress();
- _api.request(base::take(_validateRequestId)).cancel();
- }
- _validatedInformation = information;
- if (!validateInformationLocal(information)) {
- return;
- }
- Assert(!_invoice.isShippingAddressRequested
- || information.shippingAddress);
- Assert(!_invoice.isNameRequested || !information.name.isEmpty());
- Assert(!_invoice.isEmailRequested || !information.email.isEmpty());
- Assert(!_invoice.isPhoneRequested || !information.phone.isEmpty());
- showProgress();
- using Flag = MTPpayments_ValidateRequestedInfo::Flag;
- _validateRequestId = _api.request(MTPpayments_ValidateRequestedInfo(
- MTP_flags(information.save ? Flag::f_save : Flag(0)),
- inputInvoice(),
- Serialize(information)
- )).done([=](const MTPpayments_ValidatedRequestedInfo &result) {
- hideProgress();
- _validateRequestId = 0;
- const auto oldSelectedId = _shippingOptions.selectedId;
- result.match([&](const MTPDpayments_validatedRequestedInfo &data) {
- _requestedInformationId = data.vid().value_or_empty();
- processShippingOptions(
- data.vshipping_options().value_or_empty());
- });
- _shippingOptions.selectedId = ranges::contains(
- _shippingOptions.list,
- oldSelectedId,
- &Ui::ShippingOption::id
- ) ? oldSelectedId : QString();
- if (_shippingOptions.selectedId.isEmpty()
- && _shippingOptions.list.size() == 1) {
- _shippingOptions.selectedId = _shippingOptions.list.front().id;
- }
- _information = _validatedInformation;
- if (_information.save) {
- _savedInformation = _information;
- }
- _updates.fire(ValidateFinished{});
- }).fail([=](const MTP::Error &error) {
- hideProgress();
- _validateRequestId = 0;
- _updates.fire(Error{ Error::Type::Validate, error.type() });
- }).send();
- }
- bool Form::hasChanges() const {
- const auto &information = _validateRequestId
- ? _validatedInformation
- : _information;
- return (information != _savedInformation)
- || (_stripe != nullptr)
- || (_smartglocal != nullptr)
- || (!_paymentMethod.newCredentials.empty()
- && (_paymentMethod.savedCredentialsIndex
- >= _paymentMethod.savedCredentials.size()));
- }
- bool Form::validateInformationLocal(
- const Ui::RequestedInformation &information) const {
- if (const auto error = informationErrorLocal(information)) {
- _updates.fire_copy(error);
- return false;
- }
- return true;
- }
- Error Form::informationErrorLocal(
- const Ui::RequestedInformation &information) const {
- auto errors = QStringList();
- const auto push = [&](const QString &id) {
- errors.push_back(id);
- };
- if (_invoice.isShippingAddressRequested) {
- if (information.shippingAddress.address1.isEmpty()) {
- push(u"ADDRESS_STREET_LINE1_INVALID"_q);
- }
- if (information.shippingAddress.city.isEmpty()) {
- push(u"ADDRESS_CITY_INVALID"_q);
- }
- if (information.shippingAddress.countryIso2.isEmpty()) {
- push(u"ADDRESS_COUNTRY_INVALID"_q);
- }
- }
- if (_invoice.isNameRequested && information.name.isEmpty()) {
- push(u"REQ_INFO_NAME_INVALID"_q);
- }
- if (_invoice.isEmailRequested && information.email.isEmpty()) {
- push(u"REQ_INFO_EMAIL_INVALID"_q);
- }
- if (_invoice.isPhoneRequested && information.phone.isEmpty()) {
- push(u"REQ_INFO_PHONE_INVALID"_q);
- }
- if (!errors.isEmpty()) {
- return Error{ Error::Type::Validate, errors.front() };
- }
- return Error();
- }
- void Form::validateCard(
- const Ui::UncheckedCardDetails &details,
- bool saveInformation) {
- Expects(!v::is_null(_paymentMethod.native.data));
- if (!validateCardLocal(details, overrideExpireDateThreshold())) {
- return;
- }
- const auto &native = _paymentMethod.native.data;
- if (const auto smartglocal = std::get_if<SmartGlocalPaymentMethod>(
- &native)) {
- validateCard(*smartglocal, details, saveInformation);
- } else if (const auto stripe = std::get_if<StripePaymentMethod>(&native)) {
- validateCard(*stripe, details, saveInformation);
- } else {
- Unexpected("Native payment provider in Form::validateCard.");
- }
- }
- bool Form::validateCardLocal(
- const Ui::UncheckedCardDetails &details,
- const std::optional<QDate> &overrideExpireDateThreshold) const {
- if (auto error = cardErrorLocal(details, overrideExpireDateThreshold)) {
- _updates.fire(std::move(error));
- return false;
- }
- return true;
- }
- Error Form::cardErrorLocal(
- const Ui::UncheckedCardDetails &details,
- const std::optional<QDate> &overrideExpireDateThreshold) const {
- using namespace Stripe;
- auto errors = QStringList();
- const auto push = [&](const QString &id) {
- errors.push_back(id);
- };
- const auto kValid = ValidationState::Valid;
- if (ValidateCard(details.number).state != kValid) {
- push(u"LOCAL_CARD_NUMBER_INVALID"_q);
- }
- if (ValidateParsedExpireDate(
- details.expireMonth,
- details.expireYear,
- overrideExpireDateThreshold
- ) != kValid) {
- push(u"LOCAL_CARD_EXPIRE_DATE_INVALID"_q);
- }
- if (ValidateCvc(details.number, details.cvc).state != kValid) {
- push(u"LOCAL_CARD_CVC_INVALID"_q);
- }
- if (_paymentMethod.ui.native.needCardholderName
- && details.cardholderName.isEmpty()) {
- push(u"LOCAL_CARD_HOLDER_NAME_INVALID"_q);
- }
- if (_paymentMethod.ui.native.needCountry
- && details.addressCountry.isEmpty()) {
- push(u"LOCAL_CARD_BILLING_COUNTRY_INVALID"_q);
- }
- if (_paymentMethod.ui.native.needZip
- && details.addressZip.isEmpty()) {
- push(u"LOCAL_CARD_BILLING_ZIP_INVALID"_q);
- }
- if (!errors.isEmpty()) {
- return Error{ Error::Type::Validate, errors.front() };
- }
- return Error();
- }
- void Form::validateCard(
- const StripePaymentMethod &method,
- const Ui::UncheckedCardDetails &details,
- bool saveInformation) {
- Expects(!method.publishableKey.isEmpty());
- if (_stripe) {
- return;
- }
- auto configuration = Stripe::PaymentConfiguration{
- .publishableKey = method.publishableKey,
- .companyName = "Telegram",
- };
- _stripe = std::make_unique<Stripe::APIClient>(std::move(configuration));
- auto card = Stripe::CardParams{
- .number = details.number,
- .expMonth = details.expireMonth,
- .expYear = details.expireYear,
- .cvc = details.cvc,
- .name = details.cardholderName,
- .addressZip = details.addressZip,
- .addressCountry = details.addressCountry,
- };
- showProgress();
- _stripe->createTokenWithCard(std::move(card), crl::guard(this, [=](
- Stripe::Token token,
- Stripe::Error error) {
- hideProgress();
- _stripe = nullptr;
- if (error) {
- LOG(("Stripe Error %1: %2 (%3)"
- ).arg(int(error.code())
- ).arg(error.description(), error.message()));
- _updates.fire(Error{ Error::Type::Stripe, error.description() });
- } else {
- setPaymentCredentials({
- .title = CardTitle(token.card()),
- .data = QJsonDocument(QJsonObject{
- { "type", "card" },
- { "id", token.tokenId() },
- }).toJson(QJsonDocument::Compact),
- .saveOnServer = saveInformation,
- });
- }
- }));
- }
- void Form::validateCard(
- const SmartGlocalPaymentMethod &method,
- const Ui::UncheckedCardDetails &details,
- bool saveInformation) {
- Expects(!method.publicToken.isEmpty());
- if (_smartglocal) {
- return;
- }
- auto configuration = SmartGlocal::PaymentConfiguration{
- .publicToken = method.publicToken,
- .tokenizeUrl = method.tokenizeUrl,
- .isTest = _invoice.isTest,
- };
- _smartglocal = std::make_unique<SmartGlocal::APIClient>(
- std::move(configuration));
- auto card = Stripe::CardParams{
- .number = details.number,
- .expMonth = details.expireMonth,
- .expYear = details.expireYear,
- .cvc = details.cvc,
- .name = details.cardholderName,
- .addressZip = details.addressZip,
- .addressCountry = details.addressCountry,
- };
- showProgress();
- _smartglocal->createTokenWithCard(std::move(card), crl::guard(this, [=](
- SmartGlocal::Token token,
- SmartGlocal::Error error) {
- hideProgress();
- _smartglocal = nullptr;
- if (error) {
- LOG(("SmartGlocal Error %1: %2 (%3)"
- ).arg(int(error.code())
- ).arg(error.description(), error.message()));
- _updates.fire(Error{
- Error::Type::SmartGlocal,
- error.description(),
- });
- } else {
- setPaymentCredentials({
- .title = CardTitle(token.card()),
- .data = QJsonDocument(QJsonObject{
- { "token", token.tokenId() },
- { "type", "card" },
- }).toJson(QJsonDocument::Compact),
- .saveOnServer = saveInformation,
- });
- }
- }));
- }
- void Form::setPaymentCredentials(const NewCredentials &credentials) {
- Expects(!credentials.empty());
- _paymentMethod.newCredentials = credentials;
- _paymentMethod.savedCredentialsIndex
- = _paymentMethod.savedCredentials.size();
- refreshSavedPaymentMethodDetails();
- const auto requestNewPassword = credentials.saveOnServer
- && !_details.canSaveCredentials
- && _details.passwordMissing;
- _updates.fire(PaymentMethodUpdate{ requestNewPassword });
- }
- void Form::chooseSavedMethod(const QString &id) {
- auto &index = _paymentMethod.savedCredentialsIndex;
- const auto &list = _paymentMethod.savedCredentials;
- if (id.isEmpty() && _paymentMethod.newCredentials) {
- index = list.size();
- } else {
- const auto i = ranges::find(list, id, &SavedCredentials::id);
- index = (i != end(list)) ? (i - begin(list)) : 0;
- }
- refreshSavedPaymentMethodDetails();
- const auto requestNewPassword = (index == list.size())
- && _paymentMethod.newCredentials
- && _paymentMethod.newCredentials.saveOnServer
- && !_details.canSaveCredentials
- && _details.passwordMissing;
- _updates.fire(PaymentMethodUpdate{ requestNewPassword });
- }
- void Form::setHasPassword(bool has) {
- if (_details.passwordMissing) {
- _details.canSaveCredentials = has;
- }
- }
- void Form::setShippingOption(const QString &id) {
- _shippingOptions.selectedId = id;
- }
- void Form::setTips(int64 value) {
- _invoice.tipsSelected = std::min(value, _invoice.tipsMax);
- }
- void Form::acceptTerms() {
- _details.termsAccepted = true;
- }
- void Form::trustBot() {
- _session->local().markPeerTrustedPayment(_details.botId);
- }
- void Form::processShippingOptions(const QVector<MTPShippingOption> &data) {
- const auto currency = _invoice.currency;
- _shippingOptions = Ui::ShippingOptions{ currency, ranges::views::all(
- data
- ) | ranges::views::transform([](const MTPShippingOption &option) {
- return option.match([](const MTPDshippingOption &data) {
- return Ui::ShippingOption{
- .id = qs(data.vid()),
- .title = qs(data.vtitle()),
- .prices = ParsePrices(data.vprices()),
- };
- });
- }) | ranges::to_vector };
- _shippingOptions.currency = _invoice.currency;
- }
- } // namespace Payments
|