OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/payments/payment_sheet_view_controller.h" | 5 #include "chrome/browser/ui/views/payments/payment_sheet_view_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <memory> | 8 #include <memory> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #include "ui/views/layout/grid_layout.h" | 48 #include "ui/views/layout/grid_layout.h" |
49 #include "ui/views/vector_icons.h" | 49 #include "ui/views/vector_icons.h" |
50 #include "ui/views/view.h" | 50 #include "ui/views/view.h" |
51 | 51 |
52 namespace payments { | 52 namespace payments { |
53 namespace { | 53 namespace { |
54 | 54 |
55 constexpr int kFirstTagValue = static_cast<int>( | 55 constexpr int kFirstTagValue = static_cast<int>( |
56 payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX); | 56 payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX); |
57 | 57 |
| 58 // Tags for the buttons in the payment sheet |
58 enum class PaymentSheetViewControllerTags { | 59 enum class PaymentSheetViewControllerTags { |
59 // The tag for the button that navigates to the Order Summary sheet. | 60 SHOW_ORDER_SUMMARY_BUTTON = kFirstTagValue, // Navigate to order summary |
60 SHOW_ORDER_SUMMARY_BUTTON = kFirstTagValue, | 61 SHOW_SHIPPING_BUTTON, // Navigate to the shipping address screen |
61 SHOW_SHIPPING_BUTTON, | 62 ADD_SHIPPING_BUTTON, // Navigate to the shipping address editor |
62 SHOW_PAYMENT_METHOD_BUTTON, | 63 SHOW_PAYMENT_METHOD_BUTTON, // Navigate to the payment method screen |
63 SHOW_CONTACT_INFO_BUTTON, | 64 ADD_PAYMENT_METHOD_BUTTON, // Navigate to the payment method editor |
64 SHOW_SHIPPING_OPTION_BUTTON, | 65 SHOW_CONTACT_INFO_BUTTON, // Navigate to the contact info screen |
| 66 ADD_CONTACT_INFO_BUTTON, // Navigate to the contact info editor |
| 67 SHOW_SHIPPING_OPTION_BUTTON, // Navigate to the shipping options screen |
65 PAY_BUTTON | 68 PAY_BUTTON |
66 }; | 69 }; |
67 | 70 |
68 // A class that ensures proper elision of labels in the form | 71 // A class that ensures proper elision of labels in the form |
69 // "[preview] and N more" where preview might be elided to allow "and N more" to | 72 // "[preview] and N more" where preview might be elided to allow "and N more" to |
70 // be always visible. | 73 // be always visible. |
71 class PreviewEliderLabel : public views::Label { | 74 class PreviewEliderLabel : public views::Label { |
72 public: | 75 public: |
73 // Creates a PreviewEliderLabel where |preview_text| might be elided, | 76 // Creates a PreviewEliderLabel where |preview_text| might be elided, |
74 // |format_string| is the string with format argument numbers in ICU syntax | 77 // |format_string| is the string with format argument numbers in ICU syntax |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 switch (sender->tag()) { | 481 switch (sender->tag()) { |
479 case static_cast<int>( | 482 case static_cast<int>( |
480 PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON): | 483 PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON): |
481 dialog()->ShowOrderSummary(); | 484 dialog()->ShowOrderSummary(); |
482 break; | 485 break; |
483 | 486 |
484 case static_cast<int>(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON): | 487 case static_cast<int>(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON): |
485 dialog()->ShowShippingProfileSheet(); | 488 dialog()->ShowShippingProfileSheet(); |
486 break; | 489 break; |
487 | 490 |
| 491 case static_cast<int>(PaymentSheetViewControllerTags::ADD_SHIPPING_BUTTON): |
| 492 dialog()->ShowShippingAddressEditor( |
| 493 /*on_edited=*/base::OnceClosure(), // This is always an add. |
| 494 /*on_added=*/ |
| 495 base::BindOnce(&PaymentRequestState::AddAutofillShippingProfile, |
| 496 base::Unretained(state()), /*selected=*/true), |
| 497 nullptr); |
| 498 break; |
| 499 |
488 case static_cast<int>( | 500 case static_cast<int>( |
489 PaymentSheetViewControllerTags::SHOW_PAYMENT_METHOD_BUTTON): | 501 PaymentSheetViewControllerTags::SHOW_PAYMENT_METHOD_BUTTON): |
490 dialog()->ShowPaymentMethodSheet(); | 502 dialog()->ShowPaymentMethodSheet(); |
491 break; | 503 break; |
492 | 504 |
493 case static_cast<int>( | 505 case static_cast<int>( |
| 506 PaymentSheetViewControllerTags::ADD_PAYMENT_METHOD_BUTTON): |
| 507 dialog()->ShowCreditCardEditor( |
| 508 /*on_edited=*/base::OnceClosure(), // This is always an add. |
| 509 /*on_added=*/ |
| 510 base::BindOnce(&PaymentRequestState::AddAutofillPaymentInstrument, |
| 511 base::Unretained(state()), /*selected=*/true), |
| 512 /*credit_card=*/nullptr); |
| 513 |
| 514 break; |
| 515 |
| 516 case static_cast<int>( |
494 PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON): | 517 PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON): |
495 dialog()->ShowContactProfileSheet(); | 518 dialog()->ShowContactProfileSheet(); |
496 break; | 519 break; |
497 | 520 |
498 case static_cast<int>( | 521 case static_cast<int>( |
| 522 PaymentSheetViewControllerTags::ADD_CONTACT_INFO_BUTTON): |
| 523 dialog()->ShowContactInfoEditor(); |
| 524 break; |
| 525 |
| 526 case static_cast<int>( |
499 PaymentSheetViewControllerTags::SHOW_SHIPPING_OPTION_BUTTON): | 527 PaymentSheetViewControllerTags::SHOW_SHIPPING_OPTION_BUTTON): |
500 dialog()->ShowShippingOptionSheet(); | 528 dialog()->ShowShippingOptionSheet(); |
501 break; | 529 break; |
502 | 530 |
503 default: | 531 default: |
504 PaymentRequestSheetController::ButtonPressed(sender, event); | 532 PaymentRequestSheetController::ButtonPressed(sender, event); |
505 break; | 533 break; |
506 } | 534 } |
507 } | 535 } |
508 | 536 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 std::unique_ptr<views::Button> section; | 647 std::unique_ptr<views::Button> section; |
620 PaymentSheetRowBuilder builder( | 648 PaymentSheetRowBuilder builder( |
621 this, GetShippingAddressSectionString(spec()->shipping_type()), | 649 this, GetShippingAddressSectionString(spec()->shipping_type()), |
622 widest_name_column_view_width_); | 650 widest_name_column_view_width_); |
623 builder.Tag(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON); | 651 builder.Tag(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON); |
624 if (state()->selected_shipping_profile()) { | 652 if (state()->selected_shipping_profile()) { |
625 builder.Id(DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION); | 653 builder.Id(DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION); |
626 return builder.CreateWithChevron(CreateShippingSectionContent(), nullptr); | 654 return builder.CreateWithChevron(CreateShippingSectionContent(), nullptr); |
627 } else { | 655 } else { |
628 builder.Id(DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION_BUTTON); | 656 builder.Id(DialogViewID::PAYMENT_SHEET_SHIPPING_ADDRESS_SECTION_BUTTON); |
629 base::string16 button_string = state()->shipping_profiles().size() | |
630 ? l10n_util::GetStringUTF16(IDS_CHOOSE) | |
631 : l10n_util::GetStringUTF16(IDS_ADD); | |
632 if (state()->shipping_profiles().empty()) { | 657 if (state()->shipping_profiles().empty()) { |
633 return builder.CreateWithButton(base::ASCIIToUTF16(""), button_string, | 658 // If the button is "Add", clicking it should navigate to the editor |
| 659 // instead of the list. |
| 660 builder.Tag(PaymentSheetViewControllerTags::ADD_SHIPPING_BUTTON); |
| 661 return builder.CreateWithButton(base::ASCIIToUTF16(""), |
| 662 l10n_util::GetStringUTF16(IDS_ADD), |
634 /*button_enabled=*/true); | 663 /*button_enabled=*/true); |
635 } else if (state()->shipping_profiles().size() == 1) { | 664 } else if (state()->shipping_profiles().size() == 1) { |
636 base::string16 truncated_content = | 665 base::string16 truncated_content = |
637 state()->shipping_profiles()[0]->ConstructInferredLabel( | 666 state()->shipping_profiles()[0]->ConstructInferredLabel( |
638 { | 667 { |
639 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, | 668 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, |
640 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, | 669 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, |
641 autofill::ADDRESS_HOME_COUNTRY, | 670 autofill::ADDRESS_HOME_COUNTRY, |
642 }, | 671 }, |
643 6, state()->GetApplicationLocale()); | 672 6, state()->GetApplicationLocale()); |
644 return builder.CreateWithButton(truncated_content, button_string, | 673 return builder.CreateWithButton(truncated_content, |
| 674 l10n_util::GetStringUTF16(IDS_CHOOSE), |
645 /*button_enabled=*/true); | 675 /*button_enabled=*/true); |
646 } else { | 676 } else { |
647 base::string16 format = l10n_util::GetPluralStringFUTF16( | 677 base::string16 format = l10n_util::GetPluralStringFUTF16( |
648 IDS_PAYMENT_REQUEST_SHIPPING_ADDRESSES_PREVIEW, | 678 IDS_PAYMENT_REQUEST_SHIPPING_ADDRESSES_PREVIEW, |
649 state()->shipping_profiles().size() - 1); | 679 state()->shipping_profiles().size() - 1); |
650 base::string16 label = | 680 base::string16 label = |
651 state()->shipping_profiles()[0]->ConstructInferredLabel( | 681 state()->shipping_profiles()[0]->ConstructInferredLabel( |
652 { | 682 { |
653 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, | 683 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, |
654 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, | 684 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, |
655 autofill::ADDRESS_HOME_COUNTRY, | 685 autofill::ADDRESS_HOME_COUNTRY, |
656 }, | 686 }, |
657 6, state()->GetApplicationLocale()); | 687 6, state()->GetApplicationLocale()); |
658 return builder.CreateWithButton( | 688 return builder.CreateWithButton(label, format, |
659 label, format, state()->shipping_profiles().size() - 1, button_string, | 689 state()->shipping_profiles().size() - 1, |
660 /*button_enabled=*/true); | 690 l10n_util::GetStringUTF16(IDS_CHOOSE), |
| 691 /*button_enabled=*/true); |
661 } | 692 } |
662 } | 693 } |
663 } | 694 } |
664 | 695 |
665 // Creates the Payment Method row, which contains a "Payment" label, the user's | 696 // Creates the Payment Method row, which contains a "Payment" label, the user's |
666 // masked Credit Card details, the icon for the selected card, and a chevron. | 697 // masked Credit Card details, the icon for the selected card, and a chevron. |
667 // If no option is selected or none is available, the Chevron and icon are | 698 // If no option is selected or none is available, the Chevron and icon are |
668 // replaced with a button | 699 // replaced with a button |
669 // +----------------------------------------------+ | 700 // +----------------------------------------------+ |
670 // | Payment Visa ****0000 | | 701 // | Payment Visa ****0000 | |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
704 layout->AddView(selected_instrument_sublabel.release()); | 735 layout->AddView(selected_instrument_sublabel.release()); |
705 | 736 |
706 std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView( | 737 std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView( |
707 selected_instrument->icon_resource_id(), selected_instrument->label()); | 738 selected_instrument->icon_resource_id(), selected_instrument->label()); |
708 card_icon_view->SetImageSize(gfx::Size(32, 20)); | 739 card_icon_view->SetImageSize(gfx::Size(32, 20)); |
709 | 740 |
710 return builder.Id(DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION) | 741 return builder.Id(DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION) |
711 .CreateWithChevron(std::move(content_view), std::move(card_icon_view)); | 742 .CreateWithChevron(std::move(content_view), std::move(card_icon_view)); |
712 } else { | 743 } else { |
713 builder.Id(DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION_BUTTON); | 744 builder.Id(DialogViewID::PAYMENT_SHEET_PAYMENT_METHOD_SECTION_BUTTON); |
714 base::string16 button_string = state()->available_instruments().size() | |
715 ? l10n_util::GetStringUTF16(IDS_CHOOSE) | |
716 : l10n_util::GetStringUTF16(IDS_ADD); | |
717 | |
718 if (state()->available_instruments().empty()) { | 745 if (state()->available_instruments().empty()) { |
719 return builder.CreateWithButton(base::ASCIIToUTF16(""), button_string, | 746 // If the button is "Add", navigate to the editor directly. |
| 747 builder.Tag(PaymentSheetViewControllerTags::ADD_PAYMENT_METHOD_BUTTON); |
| 748 return builder.CreateWithButton(base::ASCIIToUTF16(""), |
| 749 l10n_util::GetStringUTF16(IDS_ADD), |
720 /*button_enabled=*/true); | 750 /*button_enabled=*/true); |
721 } else if (state()->available_instruments().size() == 1) { | 751 } else if (state()->available_instruments().size() == 1) { |
722 return builder.CreateWithButton( | 752 return builder.CreateWithButton( |
723 state()->available_instruments()[0]->label(), button_string, | 753 state()->available_instruments()[0]->label(), |
| 754 l10n_util::GetStringUTF16(IDS_CHOOSE), |
724 /*button_enabled=*/true); | 755 /*button_enabled=*/true); |
725 } else { | 756 } else { |
726 base::string16 format = l10n_util::GetPluralStringFUTF16( | 757 base::string16 format = l10n_util::GetPluralStringFUTF16( |
727 IDS_PAYMENT_REQUEST_PAYMENT_METHODS_PREVIEW, | 758 IDS_PAYMENT_REQUEST_PAYMENT_METHODS_PREVIEW, |
728 state()->available_instruments().size() - 1); | 759 state()->available_instruments().size() - 1); |
729 return builder.CreateWithButton( | 760 return builder.CreateWithButton( |
730 state()->available_instruments()[0]->label(), format, | 761 state()->available_instruments()[0]->label(), format, |
731 state()->available_instruments().size() - 1, button_string, | 762 state()->available_instruments().size() - 1, |
| 763 l10n_util::GetStringUTF16(IDS_CHOOSE), |
732 /*button_enabled=*/true); | 764 /*button_enabled=*/true); |
733 } | 765 } |
734 } | 766 } |
735 } | 767 } |
736 | 768 |
737 std::unique_ptr<views::View> | 769 std::unique_ptr<views::View> |
738 PaymentSheetViewController::CreateContactInfoSectionContent() { | 770 PaymentSheetViewController::CreateContactInfoSectionContent() { |
739 autofill::AutofillProfile* profile = state()->selected_contact_profile(); | 771 autofill::AutofillProfile* profile = state()->selected_contact_profile(); |
740 return profile | 772 return profile |
741 ? payments::GetContactInfoLabel( | 773 ? payments::GetContactInfoLabel( |
(...skipping 15 matching lines...) Expand all Loading... |
757 this, | 789 this, |
758 l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME), | 790 l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME), |
759 widest_name_column_view_width_); | 791 widest_name_column_view_width_); |
760 builder.Tag(PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON); | 792 builder.Tag(PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON); |
761 | 793 |
762 if (state()->selected_contact_profile()) { | 794 if (state()->selected_contact_profile()) { |
763 return builder.Id(DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION) | 795 return builder.Id(DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION) |
764 .CreateWithChevron(CreateContactInfoSectionContent(), nullptr); | 796 .CreateWithChevron(CreateContactInfoSectionContent(), nullptr); |
765 } else { | 797 } else { |
766 builder.Id(DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION_BUTTON); | 798 builder.Id(DialogViewID::PAYMENT_SHEET_CONTACT_INFO_SECTION_BUTTON); |
767 base::string16 button_string = state()->contact_profiles().size() | |
768 ? l10n_util::GetStringUTF16(IDS_CHOOSE) | |
769 : l10n_util::GetStringUTF16(IDS_ADD); | |
770 | |
771 if (state()->contact_profiles().empty()) { | 799 if (state()->contact_profiles().empty()) { |
772 return builder.CreateWithButton(base::ASCIIToUTF16(""), button_string, | 800 // If the button is "Add", navigate directly to the editor. |
| 801 builder.Tag(PaymentSheetViewControllerTags::ADD_CONTACT_INFO_BUTTON); |
| 802 return builder.CreateWithButton(base::ASCIIToUTF16(""), |
| 803 l10n_util::GetStringUTF16(IDS_ADD), |
773 /*button_enabled=*/true); | 804 /*button_enabled=*/true); |
774 } else if (state()->contact_profiles().size() == 1) { | 805 } else if (state()->contact_profiles().size() == 1) { |
775 base::string16 truncated_content = | 806 base::string16 truncated_content = |
776 state()->contact_profiles()[0]->ConstructInferredLabel( | 807 state()->contact_profiles()[0]->ConstructInferredLabel( |
777 { | 808 { |
778 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, | 809 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, |
779 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, | 810 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, |
780 autofill::ADDRESS_HOME_COUNTRY, | 811 autofill::ADDRESS_HOME_COUNTRY, |
781 }, | 812 }, |
782 6, state()->GetApplicationLocale()); | 813 6, state()->GetApplicationLocale()); |
783 return builder.CreateWithButton(truncated_content, button_string, | 814 return builder.CreateWithButton(truncated_content, |
| 815 l10n_util::GetStringUTF16(IDS_CHOOSE), |
784 /*button_enabled=*/true); | 816 /*button_enabled=*/true); |
785 } else { | 817 } else { |
786 base::string16 preview = | 818 base::string16 preview = |
787 state()->contact_profiles()[0]->ConstructInferredLabel( | 819 state()->contact_profiles()[0]->ConstructInferredLabel( |
788 { | 820 { |
789 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, | 821 autofill::ADDRESS_HOME_LINE1, autofill::ADDRESS_HOME_LINE2, |
790 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, | 822 autofill::ADDRESS_HOME_CITY, autofill::ADDRESS_HOME_STATE, |
791 autofill::ADDRESS_HOME_COUNTRY, | 823 autofill::ADDRESS_HOME_COUNTRY, |
792 }, | 824 }, |
793 6, state()->GetApplicationLocale()); | 825 6, state()->GetApplicationLocale()); |
794 base::string16 format = l10n_util::GetPluralStringFUTF16( | 826 base::string16 format = l10n_util::GetPluralStringFUTF16( |
795 IDS_PAYMENT_REQUEST_CONTACTS_PREVIEW, | 827 IDS_PAYMENT_REQUEST_CONTACTS_PREVIEW, |
796 state()->contact_profiles().size() - 1); | 828 state()->contact_profiles().size() - 1); |
797 return builder.CreateWithButton(preview, format, | 829 return builder.CreateWithButton( |
798 state()->contact_profiles().size() - 1, | 830 preview, format, state()->contact_profiles().size() - 1, |
799 button_string, /*button_enabled=*/true); | 831 l10n_util::GetStringUTF16(IDS_CHOOSE), /*button_enabled=*/true); |
800 } | 832 } |
801 } | 833 } |
802 } | 834 } |
803 | 835 |
804 std::unique_ptr<views::Button> | 836 std::unique_ptr<views::Button> |
805 PaymentSheetViewController::CreateShippingOptionRow() { | 837 PaymentSheetViewController::CreateShippingOptionRow() { |
806 // The Shipping Options row has many different ways of being displayed | 838 // The Shipping Options row has many different ways of being displayed |
807 // depending on the state of the dialog and Payment Request. | 839 // depending on the state of the dialog and Payment Request. |
808 // 1. There is a selected shipping address. The website updated the shipping | 840 // 1. There is a selected shipping address. The website updated the shipping |
809 // options. | 841 // options. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
856 } else { | 888 } else { |
857 return builder | 889 return builder |
858 .Id(DialogViewID::PAYMENT_SHEET_SHIPPING_OPTION_SECTION_BUTTON) | 890 .Id(DialogViewID::PAYMENT_SHEET_SHIPPING_OPTION_SECTION_BUTTON) |
859 .CreateWithButton( | 891 .CreateWithButton( |
860 l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_CHOOSE_AN_ADDRESS), | 892 l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_CHOOSE_AN_ADDRESS), |
861 l10n_util::GetStringUTF16(IDS_CHOOSE), /*button_enabled=*/false); | 893 l10n_util::GetStringUTF16(IDS_CHOOSE), /*button_enabled=*/false); |
862 } | 894 } |
863 } | 895 } |
864 | 896 |
865 } // namespace payments | 897 } // namespace payments |
OLD | NEW |