diff --git a/src/app/pages/cart/cart.component.html b/src/app/pages/cart/cart.component.html
index 94f4864..ac35420 100644
--- a/src/app/pages/cart/cart.component.html
+++ b/src/app/pages/cart/cart.component.html
@@ -147,8 +147,8 @@
diff --git a/src/app/pages/cart/cart.component.ts b/src/app/pages/cart/cart.component.ts
index 26ad593..470a9ce 100644
--- a/src/app/pages/cart/cart.component.ts
+++ b/src/app/pages/cart/cart.component.ts
@@ -149,11 +149,6 @@ export class CartComponent implements OnDestroy {
alert(this.i18n.t('cart.acceptTerms'));
return;
}
- // Auth gate: require Telegram login before payment
- if (!this.authService.isAuthenticated()) {
- this.authService.requestLogin();
- return;
- }
this.openPaymentPopup();
}
@@ -203,10 +198,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,
@@ -227,22 +218,17 @@ 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,
amount: Number(this.totalPrice()),
currency: 'RUB' as const,
- partnerqrID: partnerQrId,
- qrDescription: `Order ${this.generateOrderId()}, total: ${this.totalPrice().toFixed(2)} RUB`,
- Userid: userIdValue ?? this.getPaymentUserId(),
- Reference: this.getUrlParam('ref') || (typeof window !== 'undefined' ? window.location.hostname : ''),
- RedirectUrl: 'https://fastcheck.store?id=fast-c202-4062-bcfb-8b4c8cc59adc',
+ ...(partnerQrId && { partnerqrID: partnerQrId }),
+ qrDescription: this.buildQrDescription(this.generateOrderId()),
};
syncCart$
.pipe(
- switchMap(() => this.apiService.createPayment(qrPayload, { authorizationKey, userIdValue }))
+ switchMap(() => this.apiService.createSbpPayment(qrPayload))
)
.subscribe({
next: (response) => {
@@ -261,11 +247,6 @@ export class CartComponent implements OnDestroy {
this.qrCodeUrl.set(qrUrl);
this.paymentUrl.set(paymentLink);
- if (paymentLink && typeof window !== 'undefined' && window.innerWidth < 768) {
- window.location.href = paymentLink;
- return;
- }
-
this.paymentStatus.set('waiting');
this.startPolling();
},
@@ -278,7 +259,7 @@ export class CartComponent implements OnDestroy {
startPolling(): void {
this.stopPolling();
- if (!this.qrPartnerId || !this.paymentId()) {
+ if (!this.paymentId()) {
this.setPaymentError();
return;
}
@@ -287,7 +268,7 @@ export class CartComponent implements OnDestroy {
.pipe(
take(this.maxChecks), // maximum 36 checks (3 minutes)
exhaustMap(() => {
- return this.apiService.checkPaymentStatus(this.qrPartnerId, this.paymentId()).pipe(
+ return this.apiService.checkSbpPaymentStatus(this.paymentId()).pipe(
timeout(8000),
catchError((err) => {
console.error('Error checking payment status:', err);
@@ -302,10 +283,9 @@ export class CartComponent implements OnDestroy {
return;
}
- const paymentStatus = response.paymentStatus?.toUpperCase();
- const paymentCode = response.code?.toUpperCase();
+ const paymentStatus = (response.paymentStatus || response.status || response.code || '').toUpperCase();
- if (paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
+ if (paymentStatus === 'FAILED' || paymentStatus === 'EXPIRED' || paymentStatus === 'CANCELLED' || paymentStatus === 'REJECTED') {
this.paymentStatus.set('timeout');
this.stopPolling();
if (this.closeTimeout) clearTimeout(this.closeTimeout);
@@ -316,7 +296,7 @@ export class CartComponent implements OnDestroy {
}
// Check if payment is successful
- if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED') {
+ if (paymentStatus === 'COMPLETED' || paymentStatus === 'APPROVED' || paymentStatus === 'PAID') {
this.paymentStatus.set('success');
this.stopPolling();
// Clear cart but don't close popup - wait for email submission
@@ -471,6 +451,20 @@ export class CartComponent implements OnDestroy {
return `order_${timestamp}_${random}`;
}
+ private buildQrDescription(orderId: string): string {
+ const items = this.items()
+ .map((item: CartItem) => {
+ const name = this.itemName(item).trim() || `Item ${item.itemID}`;
+ const details = [item.colour, item.size].filter(Boolean).join(', ');
+ const label = details ? `${name} (${details})` : name;
+ return `${item.quantity} x ${label}`;
+ })
+ .join('; ');
+
+ const description = `Order ${orderId}; items: ${items}; total: ${this.totalPrice().toFixed(2)} RUB`;
+ return description.length > 500 ? `${description.slice(0, 497)}...` : description;
+ }
+
onPhoneInput(event: Event): void {
const input = event.target as HTMLInputElement;
let value = input.value.replace(/\D/g, ''); // Remove all non-digits
diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts
index 699306d..54af297 100644
--- a/src/app/services/api.service.ts
+++ b/src/app/services/api.service.ts
@@ -9,7 +9,7 @@ export interface QrCreateRequest {
qrtype: 'QRDynamic';
amount: number;
currency: 'RUB';
- partnerqrID: string;
+ partnerqrID?: string;
qrDescription?: string;
Userid?: string;
Reference?: string;
@@ -49,12 +49,19 @@ export interface QrDynamicStatusResponse {
qrExpirationDate: string;
}
+export interface QrPaymentStatusResponse {
+ status?: string;
+ paymentStatus?: string;
+ code?: string;
+}
+
@Injectable({
providedIn: 'root'
})
export class ApiService {
private readonly baseUrl = environment.apiUrl;
private readonly qrBaseUrl = (environment as any).qrApiUrl as string;
+ private readonly sbpQrUrl = 'https://qr.vitanova.network:567/qr';
private readonly retryConfig = {
count: 2,
@@ -404,6 +411,15 @@ export class ApiService {
return this.http.post(`${this.qrBaseUrl}/qr`, payload, { headers: httpHeaders });
}
+ createSbpPayment(payload: QrCreateRequest): Observable {
+ return this.http.post(this.sbpQrUrl, payload);
+ }
+
+ checkSbpPaymentStatus(paymentId: string): Observable {
+ const params = new HttpParams().set('id', paymentId);
+ return this.http.get(this.sbpQrUrl, { params });
+ }
+
checkPaymentStatus(partnerQrId: string, qrId: string): Observable {
return this.http.get(
`${this.qrBaseUrl}/qr/dynamic/${encodeURIComponent(partnerQrId)}/${encodeURIComponent(qrId)}`