diff --git a/Yandex.Checkout.V3.Tests/SerializerTests.cs b/Yandex.Checkout.V3.Tests/SerializerTests.cs index e2429c5..5c42b42 100644 --- a/Yandex.Checkout.V3.Tests/SerializerTests.cs +++ b/Yandex.Checkout.V3.Tests/SerializerTests.cs @@ -383,8 +383,29 @@ public void CancelPaymentTimeoutNotificationDeserializedCorrectly() Assert.AreEqual(false, payment.Refundable); // check cancellation details - Assert.AreEqual("yoo_money", payment.CancellationDetails.Party); - Assert.AreEqual("expired_on_confirmation", payment.CancellationDetails.Reason); + Assert.AreEqual(CancellationParty.YooMoney, payment.CancellationDetails.Party); + Assert.AreEqual(CancellationReason.ExpiredOnConfirmation, payment.CancellationDetails.Reason); + } + + [TestMethod] + public void ThreeDSecureFailedSerializedCorrectly() + { + var details = new CancellationDetails + { + Reason = CancellationReason.ThreeDSecureFailed + }; + + string json = Serializer.SerializeObject(details); + + Assert.IsTrue(json.Contains("\"reason\":\"3d_secure_failed\""), json); + } + + [TestMethod] + public void ThreeDSecureFailedDeserializedCorrectly() + { + var details = Serializer.DeserializeObject("{\"reason\":\"3d_secure_failed\"}"); + + Assert.AreEqual(CancellationReason.ThreeDSecureFailed, details.Reason); } [TestMethod] @@ -470,8 +491,8 @@ public void CancelPaymentManualNotificationDeserializedCorrectly() Assert.AreEqual("632756", payment.AuthorizationDetails.AuthCode); // check cancellation details - Assert.AreEqual("merchant", payment.CancellationDetails.Party); - Assert.AreEqual("canceled_by_merchant", payment.CancellationDetails.Reason); + Assert.AreEqual(CancellationParty.Merchant, payment.CancellationDetails.Party); + Assert.AreEqual(CancellationReason.CanceledByMerchant, payment.CancellationDetails.Reason); // check payment method Assert.IsNotNull(payment.PaymentMethod); diff --git a/Yandex.Checkout.V3/CancellationDetails.cs b/Yandex.Checkout.V3/CancellationDetails.cs index 06ae0e4..1740050 100644 --- a/Yandex.Checkout.V3/CancellationDetails.cs +++ b/Yandex.Checkout.V3/CancellationDetails.cs @@ -1,10 +1,13 @@ -// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global namespace Yandex.Checkout.V3; +/// +/// See https://yookassa.ru/developers/payment-acceptance/after-the-payment/refunds#declined-refunds-cancellation-details-party +/// public class CancellationDetails { - public string Party { get; set; } - public string Reason { get; set; } -} \ No newline at end of file + public CancellationParty Party { get; set; } + public CancellationReason Reason { get; set; } +} diff --git a/Yandex.Checkout.V3/CancellationParty.cs b/Yandex.Checkout.V3/CancellationParty.cs new file mode 100644 index 0000000..c12f289 --- /dev/null +++ b/Yandex.Checkout.V3/CancellationParty.cs @@ -0,0 +1,25 @@ +namespace Yandex.Checkout.V3; + +[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))] +public enum CancellationParty +{ + /// + /// ЮKassa + /// + YooMoney, + + /// + /// Продавец товаров и услуг + /// + Merchant, + + /// + /// Любые участники процесса платежа, кроме ЮKassa и вас (например, эмитент банковской карты) + /// + PaymentNetwork, + + /// + /// Любые участники процесса возврата, кроме ЮKassa и вас (например, эмитент банковской карты) + /// + RefundNetwork +} diff --git a/Yandex.Checkout.V3/CancellationReason.cs b/Yandex.Checkout.V3/CancellationReason.cs index f88f6bf..07aa71b 100644 --- a/Yandex.Checkout.V3/CancellationReason.cs +++ b/Yandex.Checkout.V3/CancellationReason.cs @@ -1,99 +1,143 @@ -// ReSharper disable UnusedType.Global +// ReSharper disable UnusedMember.Global + +using System.Runtime.Serialization; namespace Yandex.Checkout.V3; /// /// Причина отмены платежа /// -public static class CancellationReason +[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))] +public enum CancellationReason { /// /// Не пройдена аутентификация по 3-D Secure. При новой попытке оплаты пользователю следует пройти аутентификацию, использовать другое платежное средство или обратиться в банк за уточнениями /// - public const string ThreeDSecureFailed = "3d_secure_failed"; - + [EnumMember(Value = "3d_secure_failed")] + ThreeDSecureFailed, + /// /// Оплата данным платежным средством отклонена по неизвестным причинам. Пользователю следует обратиться в организацию, выпустившую платежное средство /// - public const string CallIssuer = "call_issuer"; - + CallIssuer, + /// /// Платеж отменен по API при оплате в две стадии /// - public const string CanceledByMerchant = "canceled_by_merchant"; - + CanceledByMerchant, + /// /// Истек срок действия банковской карты. При новой попытке оплаты пользователю следует использовать другое платежное средство /// - public const string CardExpired = "card_expired"; - + CardExpired, + /// /// Нельзя заплатить банковской картой, выпущенной в этой стране. При новой попытке оплаты пользователю следует использовать другое платежное средство. /// - public const string CountryForbidden = "country_forbidden"; - + CountryForbidden, + /// /// Истек срок списания оплаты у двухстадийного платежа. Если вы еще хотите принять оплату, повторите платеж с новым ключом идемпотентности и спишите деньги после подтверждения платежа пользователем /// - public const string ExpiredOnCapture = "expired_on_capture"; - + ExpiredOnCapture, + /// /// Истек срок оплаты: пользователь не подтвердил платеж за время, отведенное на оплату выбранным способом. Если пользователь еще хочет оплатить, вам необходимо повторить платеж с новым ключом идемпотентности, а пользователю — подтвердить его /// - public const string ExpiredOnConfirmation = "expired_on_confirmation"; - + ExpiredOnConfirmation, + /// /// Платеж заблокирован из-за подозрения в мошенничестве. При новой попытке оплаты пользователю следует использовать другое платежное средство /// - public const string FraudSuspected = "fraud_suspected"; - + FraudSuspected, + /// /// Причина не детализирована. Пользователю следует обратиться к инициатору отмены платежа за уточнением подробностей /// - public const string GeneralDecline = "general_decline"; - + GeneralDecline, + /// /// Превышены ограничения на платежи для кошелька в Яндекс.Деньгах. При новой попытке оплаты пользователю следует идентифицировать кошелек или выбрать другое платежное средство /// - public const string IdentificationRequired = "identification_required"; - + IdentificationRequired, + /// /// Не хватает денег для оплаты. Пользователю следует пополнить баланс или использовать другое платежное средство /// - public const string InsufficientFunds = "insufficient_funds"; - + InsufficientFunds, + /// /// Технические неполадки на стороне Яндекс.Кассы: не удалось обработать запрос в течение 30 секунд. Повторите платеж с новым ключом идемпотентности /// - public const string InternalTimeout = "internal_timeout"; - + InternalTimeout, + /// /// Неправильно указан номер карты. При новой попытке оплаты пользователю следует ввести корректные данные /// - public const string InvalidCardNumber = "invalid_card_number"; - + InvalidCardNumber, + /// /// Неправильно указан код CVV2 (CVC2, CID). При новой попытке оплаты пользователю следует ввести корректные данные /// - public const string InvalidCsc = "invalid_csc"; - + InvalidCsc, + /// /// Организация, выпустившая платежное средство, недоступна. При новой попытке оплаты пользователю следует использовать другое платежное средство или повторить оплату позже /// - public const string IssuerUnavailable = "issuer_unavailable"; - + IssuerUnavailable, + /// /// Исчерпан лимит платежей для данного платежного средства или вашего магазина. При новой попытке оплаты пользователю следует использовать другое платежное средство или повторить оплату на следующий день /// - public const string PaymentMethodLimitExceeded = "payment_method_limit_exceeded"; - + PaymentMethodLimitExceeded, + /// /// Запрещены операции данным платежным средством (например, карта заблокирована из-за утери, кошелек — из-за взлома мошенниками). Пользователю следует обратиться в организацию, выпустившую платежное средство /// - public const string PaymentMethodRestricted = "payment_method_restricted"; - + PaymentMethodRestricted, + /// /// Нельзя провести безакцептное списание: пользователь отозвал разрешение на автоплатежи. Если пользователь еще хочет оплатить, вам необходимо создать новый платеж, а пользователю — подтвердить оплату /// - public const string PermissionRevoked = "permission_revoked"; + PermissionRevoked, + + /// + /// Эмитент платежного средства или другой участник процесса возврата отклонил операцию по неизвестным причинам + /// + RejectedByPayee, + + /// + /// Технические неполадки на стороне инициатора отмены возврата. Повторите запрос с новым ключом идемпотентности + /// + RejectedByTimeout, + + /// + /// Пользователь закрыл кошелек ЮMoney, на который вы пытаетесь вернуть платеж + /// + YooMoneyAccountClosed, + + /// + /// Указаны товары, для оплаты которых не использовался электронный сертификат: значение payment_article_number отсутствует в одобренной корзине покупки + /// + PaymentArticleNumberNotFound, + + /// + /// НСПК не нашла для этого возврата одобренную корзину покупки + /// + PaymentBasketIdNotFound, + + /// + /// Указаны товары, для оплаты которых не использовался электронный сертификат: значение tru_code отсутствует в одобренной корзине покупки + /// + PaymentTruCodeNotFound, + + /// + /// Некоторые товары уже возвращены + /// + SomeArticlesAlreadyRefunded, + + /// + /// Для одного или нескольких товаров количество возвращаемых единиц больше, чем указано в одобренной корзине покупки + /// + TooManyRefundingArticles }