Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions Yandex.Checkout.V3.Tests/SerializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CancellationDetails>("{\"reason\":\"3d_secure_failed\"}");

Assert.AreEqual(CancellationReason.ThreeDSecureFailed, details.Reason);
}

[TestMethod]
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 7 additions & 4 deletions Yandex.Checkout.V3/CancellationDetails.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable ClassNeverInstantiated.Global

namespace Yandex.Checkout.V3;

/// <remarks>
/// See https://yookassa.ru/developers/payment-acceptance/after-the-payment/refunds#declined-refunds-cancellation-details-party
/// </remarks>
public class CancellationDetails
{
public string Party { get; set; }
public string Reason { get; set; }
}
public CancellationParty Party { get; set; }
public CancellationReason Reason { get; set; }
}
25 changes: 25 additions & 0 deletions Yandex.Checkout.V3/CancellationParty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace Yandex.Checkout.V3;

[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))]
public enum CancellationParty
{
/// <summary>
/// ЮKassa
/// </summary>
YooMoney,

/// <summary>
/// Продавец товаров и услуг
/// </summary>
Merchant,

/// <summary>
/// Любые участники процесса платежа, кроме ЮKassa и вас (например, эмитент банковской карты)
/// </summary>
PaymentNetwork,

/// <summary>
/// Любые участники процесса возврата, кроме ЮKassa и вас (например, эмитент банковской карты)
/// </summary>
RefundNetwork
}
118 changes: 81 additions & 37 deletions Yandex.Checkout.V3/CancellationReason.cs
Original file line number Diff line number Diff line change
@@ -1,99 +1,143 @@
// ReSharper disable UnusedType.Global
// ReSharper disable UnusedMember.Global

using System.Runtime.Serialization;

namespace Yandex.Checkout.V3;

/// <summary>
/// Причина отмены платежа
/// </summary>
public static class CancellationReason
[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))]
public enum CancellationReason
{
/// <summary>
/// Не пройдена аутентификация по 3-D Secure. При новой попытке оплаты пользователю следует пройти аутентификацию, использовать другое платежное средство или обратиться в банк за уточнениями
/// </summary>
public const string ThreeDSecureFailed = "3d_secure_failed";

[EnumMember(Value = "3d_secure_failed")]
ThreeDSecureFailed,

/// <summary>
/// Оплата данным платежным средством отклонена по неизвестным причинам. Пользователю следует обратиться в организацию, выпустившую платежное средство
/// </summary>
public const string CallIssuer = "call_issuer";
CallIssuer,

/// <summary>
/// Платеж отменен по API при оплате в две стадии
/// </summary>
public const string CanceledByMerchant = "canceled_by_merchant";
CanceledByMerchant,

/// <summary>
/// Истек срок действия банковской карты. При новой попытке оплаты пользователю следует использовать другое платежное средство
/// </summary>
public const string CardExpired = "card_expired";
CardExpired,

/// <summary>
/// Нельзя заплатить банковской картой, выпущенной в этой стране. При новой попытке оплаты пользователю следует использовать другое платежное средство.
/// </summary>
public const string CountryForbidden = "country_forbidden";
CountryForbidden,

/// <summary>
/// Истек срок списания оплаты у двухстадийного платежа. Если вы еще хотите принять оплату, повторите платеж с новым ключом идемпотентности и спишите деньги после подтверждения платежа пользователем
/// </summary>
public const string ExpiredOnCapture = "expired_on_capture";
ExpiredOnCapture,

/// <summary>
/// Истек срок оплаты: пользователь не подтвердил платеж за время, отведенное на оплату выбранным способом. Если пользователь еще хочет оплатить, вам необходимо повторить платеж с новым ключом идемпотентности, а пользователю — подтвердить его
/// </summary>
public const string ExpiredOnConfirmation = "expired_on_confirmation";
ExpiredOnConfirmation,

/// <summary>
/// Платеж заблокирован из-за подозрения в мошенничестве. При новой попытке оплаты пользователю следует использовать другое платежное средство
/// </summary>
public const string FraudSuspected = "fraud_suspected";
FraudSuspected,

/// <summary>
/// Причина не детализирована. Пользователю следует обратиться к инициатору отмены платежа за уточнением подробностей
/// </summary>
public const string GeneralDecline = "general_decline";
GeneralDecline,

/// <summary>
/// Превышены ограничения на платежи для кошелька в Яндекс.Деньгах. При новой попытке оплаты пользователю следует идентифицировать кошелек или выбрать другое платежное средство
/// </summary>
public const string IdentificationRequired = "identification_required";
IdentificationRequired,

/// <summary>
/// Не хватает денег для оплаты. Пользователю следует пополнить баланс или использовать другое платежное средство
/// </summary>
public const string InsufficientFunds = "insufficient_funds";
InsufficientFunds,

/// <summary>
/// Технические неполадки на стороне Яндекс.Кассы: не удалось обработать запрос в течение 30 секунд. Повторите платеж с новым ключом идемпотентности
/// </summary>
public const string InternalTimeout = "internal_timeout";
InternalTimeout,

/// <summary>
/// Неправильно указан номер карты. При новой попытке оплаты пользователю следует ввести корректные данные
/// </summary>
public const string InvalidCardNumber = "invalid_card_number";
InvalidCardNumber,

/// <summary>
/// Неправильно указан код CVV2 (CVC2, CID). При новой попытке оплаты пользователю следует ввести корректные данные
/// </summary>
public const string InvalidCsc = "invalid_csc";
InvalidCsc,

/// <summary>
/// Организация, выпустившая платежное средство, недоступна. При новой попытке оплаты пользователю следует использовать другое платежное средство или повторить оплату позже
/// </summary>
public const string IssuerUnavailable = "issuer_unavailable";
IssuerUnavailable,

/// <summary>
/// Исчерпан лимит платежей для данного платежного средства или вашего магазина. При новой попытке оплаты пользователю следует использовать другое платежное средство или повторить оплату на следующий день
/// </summary>
public const string PaymentMethodLimitExceeded = "payment_method_limit_exceeded";
PaymentMethodLimitExceeded,

/// <summary>
/// Запрещены операции данным платежным средством (например, карта заблокирована из-за утери, кошелек — из-за взлома мошенниками). Пользователю следует обратиться в организацию, выпустившую платежное средство
/// </summary>
public const string PaymentMethodRestricted = "payment_method_restricted";
PaymentMethodRestricted,

/// <summary>
/// Нельзя провести безакцептное списание: пользователь отозвал разрешение на автоплатежи. Если пользователь еще хочет оплатить, вам необходимо создать новый платеж, а пользователю — подтвердить оплату
/// </summary>
public const string PermissionRevoked = "permission_revoked";
PermissionRevoked,

/// <summary>
/// Эмитент платежного средства или другой участник процесса возврата отклонил операцию по неизвестным причинам
/// </summary>
RejectedByPayee,

/// <summary>
/// Технические неполадки на стороне инициатора отмены возврата. Повторите запрос с новым ключом идемпотентности
/// </summary>
RejectedByTimeout,

/// <summary>
/// Пользователь закрыл кошелек ЮMoney, на который вы пытаетесь вернуть платеж
/// </summary>
YooMoneyAccountClosed,

/// <summary>
/// Указаны товары, для оплаты которых не использовался электронный сертификат: значение payment_article_number отсутствует в одобренной корзине покупки
/// </summary>
PaymentArticleNumberNotFound,

/// <summary>
/// НСПК не нашла для этого возврата одобренную корзину покупки
/// </summary>
PaymentBasketIdNotFound,

/// <summary>
/// Указаны товары, для оплаты которых не использовался электронный сертификат: значение tru_code отсутствует в одобренной корзине покупки
/// </summary>
PaymentTruCodeNotFound,

/// <summary>
/// Некоторые товары уже возвращены
/// </summary>
SomeArticlesAlreadyRefunded,

/// <summary>
/// Для одного или нескольких товаров количество возвращаемых единиц больше, чем указано в одобренной корзине покупки
/// </summary>
TooManyRefundingArticles
}