payment
This commit is contained in:
@@ -800,14 +800,6 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// ── GET /qr/settings
|
||||
if (url.endsWith('/qr/settings') && req.method === 'GET') {
|
||||
return respond({
|
||||
minAmount: 30,
|
||||
maxAmount: 200000,
|
||||
});
|
||||
}
|
||||
|
||||
// ── POST /qr (create payment QR directly)
|
||||
if (url.endsWith('/qr') && req.method === 'POST') {
|
||||
return respond({
|
||||
@@ -866,27 +858,7 @@ export const mockDataInterceptor: HttpInterceptorFn = (req, next) => {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// ── GET /qr/dynamic/:partnerID/:qrID (dynamic QR status)
|
||||
if (url.match(/\/qr\/dynamic\/[^/]+\/[^/]+$/) && req.method === 'GET') {
|
||||
return respond({
|
||||
status: 'APPROVED',
|
||||
paymentStatus: 'COMPLETED',
|
||||
code: 'SUCCESS',
|
||||
amount: 0,
|
||||
currency: 'RUB',
|
||||
qrId: 'mock',
|
||||
transactionId: 999,
|
||||
transactionDate: new Date().toISOString(),
|
||||
additionalInfo: '',
|
||||
paymentPurpose: '',
|
||||
createDate: new Date().toISOString(),
|
||||
order: 'mock-order',
|
||||
qrExpirationDate: new Date().toISOString(),
|
||||
phoneNumber: '+70000000000'
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// ── GET /qr/payment/:qrId (legacy/direct payment status)
|
||||
// ── GET /qr/payment/:qrId (payment status)
|
||||
if (url.match(/\/qr\/payment\/[^/]+$/) && req.method === 'GET') {
|
||||
return respond({
|
||||
paymentStatus: 'COMPLETED',
|
||||
|
||||
@@ -58,7 +58,6 @@ export class CartComponent implements OnDestroy {
|
||||
maxChecks = PAYMENT_MAX_CHECKS;
|
||||
private pollingSubscription?: Subscription;
|
||||
private closeTimeout?: ReturnType<typeof setTimeout>;
|
||||
private qrPartnerId = '';
|
||||
|
||||
constructor(
|
||||
private cartService: CartService,
|
||||
@@ -160,7 +159,6 @@ export class CartComponent implements OnDestroy {
|
||||
openPaymentPopup(): void {
|
||||
this.showPaymentPopup.set(true);
|
||||
this.paymentStatus.set('creating');
|
||||
this.qrPartnerId = '';
|
||||
this.paymentId.set('');
|
||||
this.qrCodeUrl.set('');
|
||||
this.paymentUrl.set('');
|
||||
@@ -192,7 +190,6 @@ export class CartComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
this.paymentStatus.set('creating');
|
||||
this.qrPartnerId = '';
|
||||
this.paymentId.set('');
|
||||
this.qrCodeUrl.set('');
|
||||
this.paymentUrl.set('');
|
||||
@@ -202,12 +199,6 @@ export class CartComponent implements OnDestroy {
|
||||
|
||||
createPayment(): void {
|
||||
const sessionId = this.authService.session()?.sessionId || '';
|
||||
const partnerQrId = this.getPartnerQrId();
|
||||
if (!partnerQrId) {
|
||||
this.setPaymentError();
|
||||
return;
|
||||
}
|
||||
|
||||
const cartItems = this.items().map((item: CartItem) => ({
|
||||
itemID: item.itemID,
|
||||
quantity: item.quantity,
|
||||
@@ -227,22 +218,26 @@ export class CartComponent implements OnDestroy {
|
||||
)
|
||||
: of(null);
|
||||
|
||||
const userIdValue = this.getUrlParam('userid-value') || undefined;
|
||||
const authorizationKey = this.getUrlParam('authorization-key') || undefined;
|
||||
const qrPayload = {
|
||||
qrtype: 'QRDynamic' as const,
|
||||
const paymentPayload = {
|
||||
amount: Number(this.totalPrice()),
|
||||
currency: 'RUB' as const,
|
||||
partnerqrID: partnerQrId,
|
||||
qrDescription: `Order ${this.generateOrderId()}, total: ${this.totalPrice().toFixed(2)} ${this.currentCurrency}`,
|
||||
Userid: userIdValue ?? this.getPaymentUserId(),
|
||||
Reference: this.getUrlParam('ref') || (typeof window !== 'undefined' ? window.location.hostname : ''),
|
||||
RedirectUrl: typeof window !== 'undefined' ? window.location.origin : undefined,
|
||||
currency: this.currentCurrency,
|
||||
siteuserID: this.getPaymentUserId(),
|
||||
siteorderID: this.generateOrderId(),
|
||||
redirectUrl: '',
|
||||
telegramUsername: this.getTelegramUsername(),
|
||||
items: this.items().map((item: CartItem) => ({
|
||||
itemID: item.itemID,
|
||||
price: item.discount > 0
|
||||
? item.price * (1 - item.discount / 100)
|
||||
: item.price,
|
||||
name: item.name,
|
||||
quantity: item.quantity,
|
||||
})),
|
||||
};
|
||||
|
||||
syncCart$
|
||||
.pipe(
|
||||
switchMap(() => this.apiService.createPayment(qrPayload, { authorizationKey, userIdValue }))
|
||||
switchMap(() => this.apiService.createPayment(paymentPayload))
|
||||
)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
@@ -256,7 +251,6 @@ export class CartComponent implements OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
this.qrPartnerId = partnerQrId;
|
||||
this.paymentId.set(qrId);
|
||||
this.qrCodeUrl.set(qrUrl);
|
||||
this.paymentUrl.set(paymentLink);
|
||||
@@ -278,7 +272,7 @@ export class CartComponent implements OnDestroy {
|
||||
|
||||
startPolling(): void {
|
||||
this.stopPolling();
|
||||
if (!this.qrPartnerId || !this.paymentId()) {
|
||||
if (!this.paymentId()) {
|
||||
this.setPaymentError();
|
||||
return;
|
||||
}
|
||||
@@ -287,7 +281,7 @@ export class CartComponent implements OnDestroy {
|
||||
.pipe(
|
||||
take(this.maxChecks), // maximum 36 checks (3 minutes)
|
||||
switchMap(() => {
|
||||
return this.apiService.checkPaymentStatus(this.qrPartnerId, this.paymentId()).pipe(
|
||||
return this.apiService.checkPaymentStatus(this.paymentId()).pipe(
|
||||
catchError((err) => {
|
||||
console.error('Error checking payment status:', err);
|
||||
return of(null);
|
||||
@@ -348,7 +342,6 @@ export class CartComponent implements OnDestroy {
|
||||
private setPaymentError(): void {
|
||||
this.paymentStatus.set('error');
|
||||
this.stopPolling();
|
||||
this.qrPartnerId = '';
|
||||
if (this.closeTimeout) {
|
||||
clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = undefined;
|
||||
@@ -452,24 +445,6 @@ export class CartComponent implements OnDestroy {
|
||||
return this.getTelegramUserId() ?? `web_${Date.now()}`;
|
||||
}
|
||||
|
||||
private getPartnerQrId(): string {
|
||||
const fromQuery = this.getUrlParam('id');
|
||||
if (fromQuery) {
|
||||
return fromQuery;
|
||||
}
|
||||
|
||||
const envValue = (environment as unknown as Record<string, unknown>)['partnerqrID'];
|
||||
return typeof envValue === 'string' ? envValue : '';
|
||||
}
|
||||
|
||||
private getUrlParam(name: string): string | null {
|
||||
if (typeof window === 'undefined') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new URLSearchParams(window.location.search).get(name);
|
||||
}
|
||||
|
||||
private generateOrderId(): string {
|
||||
const timestamp = Date.now();
|
||||
const random = Math.random().toString(36).substring(2, 8);
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable, timer } from 'rxjs';
|
||||
import { map, retry } from 'rxjs/operators';
|
||||
import { Category, Item, Subcategory } from '../models';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
export interface QrCreateRequest {
|
||||
qrtype: 'QRDynamic';
|
||||
export interface PaymentCreateRequest {
|
||||
amount: number;
|
||||
currency: 'RUB';
|
||||
partnerqrID: string;
|
||||
qrDescription?: string;
|
||||
Userid?: string;
|
||||
Reference?: string;
|
||||
RedirectUrl?: string;
|
||||
currency: string;
|
||||
siteuserID: string;
|
||||
siteorderID: string;
|
||||
redirectUrl: string;
|
||||
telegramUsername: string;
|
||||
items: Array<{ itemID: number; price: number; name: string; quantity?: number }>;
|
||||
}
|
||||
|
||||
export interface QrCreateResponse {
|
||||
@@ -34,8 +33,7 @@ export interface QrCreateResponse {
|
||||
PartnerID?: string | number;
|
||||
}
|
||||
|
||||
export interface QrStatusResponse {
|
||||
status?: string;
|
||||
export interface PaymentStatusResponse {
|
||||
additionalInfo: string;
|
||||
paymentPurpose: string;
|
||||
amount: number;
|
||||
@@ -393,23 +391,12 @@ export class ApiService {
|
||||
return this.http.post<{ message: string }>(`${this.baseUrl}/items/${itemID}/questiion`, body);
|
||||
}
|
||||
|
||||
createPayment(payload: QrCreateRequest, headers?: { authorizationKey?: string; userIdValue?: string }): Observable<QrCreateResponse> {
|
||||
let httpHeaders = new HttpHeaders();
|
||||
|
||||
if (headers?.authorizationKey) {
|
||||
httpHeaders = httpHeaders.set('authorization-key', headers.authorizationKey);
|
||||
}
|
||||
if (headers?.userIdValue) {
|
||||
httpHeaders = httpHeaders.set('userid-value', headers.userIdValue);
|
||||
}
|
||||
|
||||
return this.http.post<QrCreateResponse>(`${this.baseUrl}/qr`, payload, { headers: httpHeaders });
|
||||
createPayment(payload: PaymentCreateRequest): Observable<QrCreateResponse> {
|
||||
return this.http.post<QrCreateResponse>(`${this.baseUrl}/cart`, payload);
|
||||
}
|
||||
|
||||
checkPaymentStatus(partnerQrId: string, qrId: string): Observable<QrStatusResponse> {
|
||||
return this.http.get<QrStatusResponse>(
|
||||
`${this.baseUrl}/qr/dynamic/${encodeURIComponent(partnerQrId)}/${encodeURIComponent(qrId)}`
|
||||
);
|
||||
checkPaymentStatus(qrId: string): Observable<PaymentStatusResponse> {
|
||||
return this.http.get<PaymentStatusResponse>(`${this.baseUrl}/qr/payment/${encodeURIComponent(qrId)}`);
|
||||
}
|
||||
|
||||
resolvePaymentQrId(response: QrCreateResponse): string {
|
||||
|
||||
Reference in New Issue
Block a user