Integracja z przelewy24 - Nie otrzymuję potwierdzenia poprawnego wykonania operacji

0

Witam serdecznie. Integruję aplikację net. core z systemem Przelewy24 według dokumentacji https://developers.przelewy24.pl/index.php?pl#tag/Obsluga-transakcji-API/paths/~1api~1v1~1transaction~1register/post .
Napotkałem problem przy weryfikacji poprawności operacji, mianowicie po zarejestrowaniu płatności przez "sklep" i dokonanie płatności przez klienta zostaje on przekierowany na adres url podany w polu: **urlReturn ** (to działa bez zarzutów). Aby odebrać status transakcji podczas rejestrowania płatności podaję adres w polu urlStatus. Po pomyślnym wykonaniu transakcji zostanie on wywołany lecz niestety tak się nie dzieje.
Czy moglibyście obejrzeć mój kod w celu wyeliminowania pomyłek błędów?

Wartość przekazana do urlStatus:

https:/xxx.net/Home/PaymentCompleted

Kontroler Home:

        [HttpPost]
        public async Task PaymentCompleted([FromBody]ReservationPayStatusModel model)
        {
            _dbContext.DebugLogs.Add(new DebugLog() { Id = Guid.NewGuid(), CreatingTime = DateTime.Now, Log = "PaymentCompleted" });
            await _dbContext.SaveChangesAsync();
            await _paymentService.PaymentCompleted(model);
        }

ReservationPayStatusModel

public class ReservationPayStatusModel
    {
        public int p24_merchant_id { get; set; }
        public int p24_pos_id { get; set; }
        public string p24_session_id { get; set; }
        public int p24_amount { get; set; }
        public string p24_currency { get; set; }
        public int p24_order_id { get; set; }
        public int p24_method { get; set; }
        public string p24_statement { get; set; }
        public string p24_sign { get; set; }
    }

W serwisie przelewy24 transakcje są opłacone ale czekają właśnie na trnverify, niestety akcja z kontrolera nigdy nie zostaje wywołana.

1

Nie widzę żebyś nadał nazwę tej akcji.

Domyślnie będzie ona wywołana jako post dla /Home, o ile tam więcej akcji z postem nie masz w tym kontrolerze.
Dodaj w atrybucie HttpPost nazwę tej ścieżki, czyli [HttpPost("PaymentCompleted")]

Ogólnie używaj postmana do debugowania swojej apki, bo zwrotka z API powie Ci co tam źle zrobiłeś w większości przypadków.

0

Testuję twoją podpowiedź, natomiast Pomoc techniczna przelewy24 odpowiedziała mi, że podczas wysyłania metodą POST potwierdzenia z danymi na adres url podany w urlStatus otrzymują błąd 415. Google podpowiedziało mi, że błąd oznacza:

The HTTP 415 Unsupported Media Type client error response code indicates that the server refuses to accept the request because the payload format is in an unsupported format.

0

Dodanie [HttpPost("PaymentCompleted")] rozwiązało problem i poprawnie otrzymuję komunikat. Dziękuję !

0

Spróbuj wyciągnąć body przy tej odpowiedzi z kodem 415

0

@_13th_Dragon: screenshot-20200727104615.png

[HttpPost("PaymentCompleted")]
        public async Task PaymentCompleted([FromBody]ReservationPayStatusModel model)
        {
            _dbContext.DebugLogs.Add(new DebugLog() { Id = Guid.NewGuid(), CreatingTime = DateTime.Now, Log = "PaymentCompleted" });
            await _dbContext.SaveChangesAsync();
            await _paymentService.PaymentCompleted(model);
        }

Właśnie problem w tym, że nawet nie zapisuje mi do tabeli logów, że udało się wywołać akcję. Raz udało się, potem znowu to samo

0

Postman zwraca mi error 404. Czyli coś robię źle. Jak wywołać akcję kontrolera?
screenshot-20200727111521.png

0

usuń "/" na końcu.

0

Coś tu nie gra. Not Found, zaś body zamiast komunikatu o szczegółach błędu zwraca pola z wartościami 11111?

0

Ale pierwszą procedurą która ma się wykonać jest utworzenie w bazie danych nowego rekordu a go nie mam.
Dostaję Error404 przy: https://xxx.net/Home/PaymentCompleted oraz [HttpPost(Name ="PaymentCompleted")]
Natomiast przy : https://xxx.net/Home/PaymentCompleted oraz [HttpPost(Name ="Home/PaymentCompleted")] otrzymuję server internal error

screenshot-20200727114608.png

0

Zdążyłem sprawdzić zanim zamaskowałeś linki i dla pustego modelu zwraca status 200 - ok, dla jsona który wysyłasz, faktycznie wali 500.

Problem polega na tym, że wysyłasz wartości integer jako string i rzuca wyjątkiem przy bindowaniu danych, bo widocznie używasz jakiegoś głupiego serializera, co nie potrafi sprawdzić, czy string można przekonwertować w typ liczbowy.

Zrób sobie jakiegoś logowanie w tej apce, bo zwariujesz.

0

@urke: Muszę chwilę poczytać o routingu, bo coś mi się zdaje, że moja niewiedza generuje jakieś głupoty. Póki co naprawiłem błąd i wstawię rozwiązanie jak będę pewien, że to jest to

0

Aaa. bo ty masz Web API i widoki w jednym projekcie :P

0

Czy da się sprawdzić jakie dane wysyła serwis Przelewy24 do Akcji

[HttpPost(Name ="Home/PaymentCompleted")]
        public async Task PaymentCompleted([FromBody]ReservationPayStatusModel model)
        {
            _dbContext.DebugLogs.Add(new DebugLog() { Id = Guid.NewGuid(), CreatingTime = DateTime.Now, Log = "PaymentCompleted: " + model.p24_session_id });
            await _dbContext.SaveChangesAsync();
            await _paymentService.PaymentCompleted(model);
        }

Bo PostMan zwraca mi prawidłowe dane, lecz przelewy24 nadal nie wywołują owej akcji. Podejrzewam, że mam coś namieszane w modelu (zmieniłem go trochę według dokumentacji https://developers.przelewy24.pl/index.php?pl#tag/Notification)

public class ReservationPayStatusModel
    {
        public int merchantId { get; set; }
        public int posId { get; set; }
        public string sessionId { get; set; }
        public int amount { get; set; }
        public int originAmount { get; set; }
        public string currency { get; set; }
        public int orderId { get; set; }
        public int methodId { get; set; }
        public string statement { get; set; }
        public string sign { get; set; }
    }
2

Jak używasz .net core, to skorzystaj z middleware i napisz własne, co zaloguje Ci dane przychodzące, zanim zostanie wywołana akcja w kontrolerze.

0

Już wszystko jasne. Byłem pewien, że dane będą przesłane w formacie

{
     "d1":"v1",
     "d2":"v2"
}

a były przesłane w formacie:

data:d1=v1&d2=v2&d3=v3

Po pierwsze przeniosłem url_status do oddzielnego api. Następnie nieco zmodyfikowałem model oraz akcję:

ReservationPayStatusModel Model = ReservationPayStatusModel.TryParse(body);
public class ReservationPayStatusModel
    {
        public int p24_merchant_id { get; set; }
        public int p24_pos_id { get; set; }
        public string p24_session_id { get; set; }
        public int p24_amount { get; set; }
        public string p24_currency { get; set; }
        public int p24_order_id { get; set; }
        public int p24_method { get; set; }
        public string p24_statement { get; set; }
        public string p24_sign { get; set; }

        
        public static ReservationPayStatusModel TryParse(string Body)
        {
            try
            {
                string[] lines = Body.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
                if(lines.Count() == 9)
                {
                    ReservationPayStatusModel model = new ReservationPayStatusModel();
                    Dictionary<string, string> Values = MapValues(lines);
                    if (Values == null)
                        return null;
                    model.p24_session_id = Values["p24_session_id"];
                    model.p24_amount = Convert.ToInt32(Values["p24_amount"]);
                    model.p24_order_id = Convert.ToInt32(Values["p24_order_id"]);
                    model.p24_pos_id = Convert.ToInt32(Values["p24_pos_id"]);
                    model.p24_merchant_id = Convert.ToInt32(Values["p24_merchant_id"]);
                    model.p24_method = Convert.ToInt32(Values["p24_method"]);
                    model.p24_statement = Values["p24_statement"];
                    model.p24_currency = Values["p24_currency"];
                    model.p24_sign = Values["p24_sign"];
                    return model;
                }
                else
                    return null;
            }
            catch(Exception)
            {
                return null;
            }
        }
        private static Dictionary<string, string> MapValues(string[] lines)
        {
            Dictionary<string, string> Values = new Dictionary<string, string>();
            foreach(string line in lines)
            {
                string[] pair = line.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                if (pair.Count() != 2)
                    return null;
                Values.Add(pair[0], pair[1]);
            }
            return Values;
        }

1 użytkowników online, w tym zalogowanych: 0, gości: 1