اس ٹیوٹوریل میں، آپ NestJS مائیکرو سروسز کا استعمال کرتے ہوئے پیداوار کے لیے تیار پے پال ادائیگی کی خدمت بنائیں گے۔ راستے میں، آپ سیکھیں گے کہ کس طرح ادائیگی کی منطق کو اس کی اپنی سروس میں الگ کرنا ہے، gRPC کا استعمال کرتے ہوئے خدمات کے درمیان بات چیت کرنا، RabbitMQ کے ساتھ ادائیگی کے واقعات شائع کرنا، اور Docker کے ساتھ ہر چیز کو تعینات کرنا۔
بالآخر، آپ کے پاس ایک قابل توسیع ادائیگیوں کا فن تعمیر ہوگا جسے متعدد کاروباری ڈومینز میں دوبارہ استعمال کیا جا سکتا ہے۔
انڈیکس
تعارف
ادائیگی کی منطق ہر مائیکرو سروس سے تعلق نہیں رکھتی۔ پے پال API کالز کو متعدد مقامات پر تقسیم کرنا user-service, order-serviceاور billing-serviceنتائج درج ذیل ہیں:
-
ڈپلیکیٹ پے پال اسناد اور SDK کوڈ
-
متضاد خرابی کو سنبھالنا اور قابلیت
-
ادائیگی کے ریکارڈ جن کا آڈٹ کرنا مشکل ہے۔
-
تکلیف دہ ماحول کی منتقلی (سینڈ باکس سے زندہ تک)
حل ایک وقف شدہ ادائیگیوں کی مائیکرو سروس ہے جو پے پال کے تمام تعاملات کا مالک ہے۔ دوسری سروسز اسے gRPC کے ذریعے کال کرتی ہیں اور ادائیگی کے نتائج RabbitMQ کے ذریعے نشر کیے جاتے ہیں، جس سے ڈومین سروس کو اپنا ڈیٹا اپ ڈیٹ کرنے کی اجازت ملتی ہے۔
یہ گائیڈ آپ کو اصل اسٹیک کا استعمال کرتے ہوئے پیٹرن کے ذریعے لے جاتا ہے۔
| فرش | ٹیکنالوجی |
|---|---|
| ادائیگی کی خدمت | NestJS |
| انٹر سروس مواصلات | جی آر پی سی |
| واقعہ بس | خرگوش ایم کیو |
| ڈیٹا بیس | پوسٹگری ایس کیو ایل |
| API کی نمائش | API گیٹ وے (HTTP) |
| کنٹینرائزیشن | docker-compose |
| پے پال API | آرڈرز v2 (تخلیق کریں، منظور کریں، کیپچر کریں) |
ایک وقف شدہ ادائیگی کی خدمت کیوں استعمال کریں؟
ایک وقف شدہ ادائیگی کی خدمت ادائیگی سے متعلقہ تمام ذمہ داریوں کو ایک جگہ پر مرکزیت دیتی ہے۔ کسی بھی مائیکرو سروس کے بجائے PayPal سے براہ راست بات کرنے کے، آپ صرف اپنی ادائیگی کی خدمت سے ادائیگی کے آپریشن کی درخواست کرتے ہیں۔
سروس پے پال کی تصدیق، آرڈر کی تخلیق، ادائیگی کی گرفتاری، والیٹ اپ ڈیٹس، لیجر ریکارڈز، اور ویب ہک پروسیسنگ کا انتظام کرتی ہے۔ دریں اثنا، ڈومین سروسز کاروباری منطق پر توجہ مرکوز کرتی رہتی ہیں جیسے کہ طلباء کی درخواستیں یا سبسکرپشنز۔
آپ کی ڈومین سروس کو صرف درج ذیل جاننے کی ضرورت ہے:
-
کتنا چارج کرنا ہے۔
-
کون ادا کر رہا ہے
-
ادائیگی کے اہل کاروبار (
referenceId) -
ادائیگی کے بعد صارفین کو کہاں ری ڈائریکٹ کرنا ہے (
returnUrl/cancelUrl)
وہ ہیں ~ نہیں پے پال کی اسناد درکار ہیں۔
فن تعمیر کا جائزہ
صارف فرنٹ اینڈ پر ادائیگی شروع کرتا ہے اور درخواست کو API گیٹ وے کے ذریعے طلباء کی خدمات تک پہنچایا جاتا ہے۔ یہ سروس ادائیگی کی خدمت کے ساتھ بات چیت کرنے کے لیے gRPC کا استعمال کرتی ہے، جو PayPal کے ساتھ تمام تعاملات کو سنبھالتی ہے۔
جب کوئی ادائیگی مکمل ہو جاتی ہے، ادائیگی کی خدمت RabbitMQ پر ایک واقعہ شائع کرتی ہے، جس سے طالب علم کی خدمت کو ادائیگی کی صورتحال کو متضاد طور پر اپ ڈیٹ کرنے کی اجازت ملتی ہے۔
┌────────────────────────────────────────────────────────────┐
│ PRESENTATION LAYER │
├────────────────────────────────────────────────────────────┤
│ Frontend (React) │
└───────────────────────┬────────────────────────────────────┘
│ HTTP
▼
┌────────────────────────────────────────────────────────────┐
│ GATEWAY LAYER │
├────────────────────────────────────────────────────────────┤
│ student-apigw │
└───────────────────────┬────────────────────────────────────┘
│ gRPC
▼
┌────────────────────────────────────────────────────────────┐
│ DOMAIN LAYER │
├────────────────────────────────────────────────────────────┤
│ students-service │
└───────────────────────┬────────────────────────────────────┘
│ gRPC
▼
┌────────────────────────────────────────────────────────────┐
│ PAYMENT LAYER │
├────────────────────────────────────────────────────────────┤
│ payment-service │
│ │
│ • Create Payment │
│ • Capture Payment │
│ • Wallet Management │
│ • Ledger │
│ • Webhooks │
│ • Event Publishing │
└──────────────┬───────────────────────┬─────────────────────┘
│ │
│ REST │ RabbitMQ
▼ ▼
┌───────────────┐ ┌────────────────────┐
│ PayPal │ │ payment_events │
│ Checkout │ │ Queue │
└───────────────┘ └─────────┬──────────┘
│
▼
┌────────────────────┐
│ students-service │
│ Event Consumer │
└────────────────────┘
ادائیگی ریاست مشین
ادائیگی کی حالت کی مشین ادائیگی کے لائف سائیکل کی نمائندگی کرتی ہے اور تخلیق سے لے کر تکمیل (یا ناکامی) تک اس کی پیشرفت کو ٹریک کرتی ہے۔ ہر حیثیت ادائیگی کی موجودہ حالت کی عکاسی کرتی ہے، جس سے نگرانی کرنا، دوبارہ کوشش کرنا اور غلط کارروائیوں کو روکنا آسان ہو جاتا ہے۔
NOT_STARTED → EXECUTING → SUCCESS
└→ FAILED
-
NOT_STARTED – ڈی بی میں آرڈر ریکارڈ بنایا گیا۔
-
چل رہا ہے۔ – آپ کا پے پال آرڈر بنا دیا گیا ہے اور صارف کی منظوری کا انتظار کر رہا ہے۔
-
کامیابی – فنڈز جمع کریں، لیجر کو اپ ڈیٹ کریں، ایونٹس پوسٹ کریں۔
-
ناکام — کیپچر ناکام ہو گیا یا صارف کے ذریعے منسوخ کر دیا گیا۔
شرطیں
شروع کرنے سے پہلے، درج ذیل کو چیک کریں:
پے پال کے تصورات جو آپ کو جاننے کی ضرورت ہے۔
PayPal کو مربوط کرنے سے پہلے، چند اہم تصورات کو سمجھنا مددگار ہے۔ PayPal ایک آرڈر پر مبنی ادائیگی کے ورک فلو کے ساتھ ترقی اور پیداوار کے لیے الگ ماحول فراہم کرتا ہے جس کی ایپلی کیشن پیروی کرتی ہے۔
سینڈ باکس بمقابلہ لائیو
| ماحول | API بیس یو آر ایل | ادائیگی کا URL |
|---|---|---|
| سینڈ باکس (ڈیولپر) | https://api-m.sandbox.paypal.com |
https://www.sandbox.paypal.com/checkoutnow?token=... |
| لائیو (پیداوار) | https://api-m.paypal.com |
https://www.paypal.com/checkoutnow?token=... |
ہمیشہ ترقی پذیر سینڈ باکس. صرف پیداوار میں لائیو جاؤ.
آرڈرز API فلو (جو ہم استعمال کرتے ہیں)
پے پال کے آرڈرز v2 API تین مراحل کی پیروی کرتا ہے:
-
آرڈر بنائیں: پسدید رقم اور واپسی URL کے ساتھ ایک آرڈر بناتا ہے۔
-
منظور کرنا: صارف کو پے پال پر بھیج دیا جاتا ہے اور ادائیگی کی اجازت دیتا ہے۔
-
قبضہ: پسدید منظور شدہ فنڈز حاصل کرتا ہے۔
یہ گزشتہ ادائیگیوں کے REST API سے مختلف ہے۔ آرڈرز v2 نئے انضمام کے لیے تجویز کردہ طریقہ ہے۔
ماحولیاتی متغیرات
پے پال سروس ماحولیاتی متغیرات سے اپنی ترتیب پڑھتی ہے۔ یہ آپ کو اپنے سورس کوڈ میں حساس اسناد کی حفاظت کرنے اور سینڈ باکس اور پروڈکشن ماحول کے درمیان آسانی سے منتقلی کی اجازت دیتا ہے۔
PAYPAL_CLIENT_ID=your_client_id
PAYPAL_CLIENT_SECRET=your_client_secret
PAYPAL_API_BASE=https://api-m.sandbox.paypal.com # or https://api-m.paypal.com for live
اپنی اصل اسناد Git کے ساتھ نہ دیں۔ استعمال کریں .env فائل اور ڈوکر ماحول کا انجیکشن۔
منصوبے کی ساخت
apps/
├── core/
│ └── payment-service/ # Owns all PayPal logic
│ ├── src/
│ │ ├── app/payment/
│ │ │ ├── paypal/paypal.service.ts
│ │ │ ├── payment.service.ts
│ │ │ ├── payment.grpc.controller.ts
│ │ │ ├── payment.http.controller.ts
│ │ │ └── events/payment-events.publisher.ts
│ │ ├── migrations/ # DB schema
│ │ └── routes/health.routes.ts
│ └── Dockerfile
├── services/
│ └── students-service/ # Domain service example
│ └── src/app/payment/
│ ├── payment-client.service.ts # gRPC client
│ ├── application-payment.service.ts # business logic
│ └── payment-events.consumer.ts # RabbitMQ listener
└── gateways/
└── student-apigw/ # HTTP API for frontend
libs/
└── shared/dto/src/lib/payment/
└── payment.proto # Shared gRPC contract
مرحلہ 1 – ادائیگی کی خدمت بنائیں
ادائیگی کی خدمت ایک عمل میں دو سرور چلاتی ہے۔
| کوڈ | بندرگاہ | مقصد |
|---|---|---|
| HTTP | 3003 | ہیلتھ چیکس، ویب ہکس، اور مینجمنٹ APIs |
| جی آر پی سی | 50061 | اندرونی خدمات کے درمیان کالز |
ادائیگی کی خدمت ایک ہی NestJS ایپلیکیشن کے لیے HTTP سرور اور ایک gRPC سرور دونوں کو ظاہر کرتی ہے۔ ایچ ٹی ٹی پی سرورز ہیلتھ چیکس، ویب ہکس اور بیرونی درخواستوں کو ہینڈل کرتے ہیں، جب کہ جی آر پی سی سرور دیگر مائیکرو سروسز سے داخلی درخواستیں قبول کرتے ہیں۔
// apps/core/payment-service/src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Health route (outside /api prefix)
app.use('/health', healthRouter);
// gRPC microservice
app.connectMicroservice({
transport: Transport.GRPC,
options: {
package: 'payment',
protoPath: join(process.cwd(), 'libs/shared/dto/src/lib/payment/payment.proto'),
url: `0.0.0.0:${process.env.GRPC_PORT || '50061'}`,
},
});
app.setGlobalPrefix('api');
await app.startAllMicroservices();
await app.listen(process.env.PORT || 3003);
}
آغاز کے دوران، NestJS دونوں سرورز کو شروع کرتا ہے تاکہ بیرونی کلائنٹس اور اندرونی خدمات مناسب پروٹوکول کے ذریعے بات چیت کر سکیں۔
کلیدی ڈیزائن کے انتخاب: HTTP بیرونی/ویب ہُک ٹریفک کے لیے ہے۔ gRPC خدمات کے درمیان تیز ان پٹ اندرونی کالوں کے لیے ہے۔
مرحلہ 2 – ایک gRPC معاہدہ کی وضاحت کریں۔
اگلا، ایک حصہ بنائیں. .proto ایک فائل لکھیں تاکہ تمام خدمات ایک ہی زبان استعمال کریں۔
gRPC معاہدے مائیکرو سروسز کے درمیان اشتراک کردہ APIs کی وضاحت کرتے ہیں۔ استعمال کرتے ہوئے .proto فائل اس بات کو یقینی بناتی ہے کہ تمام خدمات، پروگرامنگ زبان سے قطع نظر، ایک ہی درخواست اور جوابی ڈھانچے کا استعمال کرتے ہوئے ادائیگی کی خدمت کے ساتھ بات چیت کریں۔
// libs/shared/dto/src/lib/payment/payment.proto
syntax = "proto3";
package payment;
service PaymentService {
rpc CreatePayment(CreatePaymentRequest) returns (CreatePaymentResponse) {}
rpc CapturePayment(CapturePaymentRequest) returns (CapturePaymentResponse) {}
rpc GetPaymentStatus(GetPaymentStatusRequest) returns (GetPaymentStatusResponse) {}
rpc ListPayments(ListPaymentsRequest) returns (ListPaymentsResponse) {}
}
message CreatePaymentRequest {
string checkout_id = 1;
string payment_order_id = 2;
string domain = 3; // e.g. "application", "subscription"
string reference_id = 4; // business entity ID
string payer_id = 5;
string amount = 6;
string currency = 7;
string buyer_email = 8;
string seller_account = 9;
string payment_category = 10;
string return_url = 11; // PayPal redirect on success
string cancel_url = 12; // PayPal redirect on cancel
string idempotency_key = 13;
string metadata = 14;
string description = 15;
}
message CreatePaymentResponse {
int32 status = 1;
string message = 2;
string payment_order_id = 3;
string paypal_order_id = 4;
string approve_url = 5; // Redirect user here
string payment_order_status = 6;
}
کہ domain + reference_id جوڑا ایک ادائیگی کی خدمت کو کسی ایک کاروباری ماڈل میں یکجا کیے بغیر درخواستوں، سبسکرپشنز، کالج ٹیوشن وغیرہ کے لیے ادائیگیوں پر کارروائی کرنے کی اجازت دیتا ہے۔
مرحلہ 3 – پے پال سروسز کو لاگو کریں۔
اب صرف PayPalService یہ PayPal REST API کو لپیٹ دیتا ہے۔
اپنی پوری درخواست میں PayPal APIs کو کال کرنے کے بجائے، آپ تمام PayPal کمیونیکیشن کو ایک وقف سروس کے اندر سمیٹ لیتے ہیں۔ یہ تصدیق، آرڈر کی تخلیق، اور ادائیگی کی گرفت کی منطق کو مرکزی بناتا ہے اور انہیں برقرار رکھنا آسان بناتا ہے۔
// apps/core/payment-service/src/app/payment/paypal/paypal.service.ts
@Injectable()
export class PayPalService {
private accessToken: string | null = null;
private tokenExpiresAt = 0;
private get apiBase(): string {
return this.configService.get('PAYPAL_API_BASE')
|| 'https://api-m.sandbox.paypal.com';
}
// Step 1: Get OAuth access token (cached until expiry)
private async getAccessToken(): Promise {
const now = Date.now();
if (this.accessToken && now < this.tokenExpiresAt) {
return this.accessToken;
}
const response = await axios.post(
`${this.apiBase}/v1/oauth2/token`,
'grant_type=client_credentials',
{
auth: {
username: this.configService.get('PAYPAL_CLIENT_ID'),
password: this.configService.get('PAYPAL_CLIENT_SECRET'),
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}
);
this.accessToken = response.data.access_token;
this.tokenExpiresAt = now + (response.data.expires_in - 60) * 1000;
return this.accessToken;
}
// Step 2: Create PayPal checkout order
async createOrder(input: PayPalCreateOrderInput) {
const token = await this.getAccessToken();
const response = await axios.post(
`${this.apiBase}/v2/checkout/orders`,
{
intent: 'CAPTURE',
purchase_units: [{
custom_id: input.paymentOrderId,
description: input.description,
amount: {
currency_code: input.currency,
value: input.amount,
},
}],
application_context: {
return_url: input.returnUrl,
cancel_url: input.cancelUrl,
brand_name: 'YourApp',
user_action: 'PAY_NOW',
},
},
{
headers: {
Authorization: `Bearer ${token}`,
'PayPal-Request-Id': input.idempotencyKey,
},
}
);
const paypalOrderId = response.data.id;
const approveUrl = response.data.links
?.find((l) => l.rel === 'approve')?.href;
return { paypalOrderId, approveUrl };
}
// Step 3: Capture approved order
async captureOrder(paypalOrderId: string) {
const token = await this.getAccessToken();
const response = await axios.post(
`${this.apiBase}/v2/checkout/orders/${paypalOrderId}/capture`,
{},
{ headers: { Authorization: `Bearer ${token}` } }
);
const capture = response.data.purchase_units?.[0]?.payments?.captures?.[0];
return { status: response.data.status, captureId: capture?.id || '' };
}
}
اپنی کنفیگریشن (بشمول نقاب پوش راز) ریکارڈ کریں تاکہ آپ ایک نظر میں دیکھ سکیں کہ آپ کا سینڈ باکس اور لائیو شروع ہونے پر کیا ہے۔
PayPal configuration check:
PAYPAL_API_BASE: https://api-m.paypal.com
PAYPAL_CLIENT_ID: AQb2...aq1M (80 chars)
credentialsPresent: true
environment: live
رسائی ٹوکن کی میعاد ختم ہونے تک کیش کیے جاتے ہیں۔ یہ کارکردگی کو بہتر بناتا ہے اور ہر بار جب آپ ادائیگی کرتے ہیں تو نئے OAuth ٹوکن کی درخواست کرنے کی ضرورت کو ختم کرکے غیر ضروری API کالز کو کم کرتا ہے۔
مرحلہ 4 – ادائیگی کا بہاؤ بنائیں (تخلیق کریں، منظور کریں، کیپچر کریں)
ادائیگی بنائیں
PaymentService.createPayment() درج ذیل کام کریں:
-
چیکر بے ضمیر کلید موجودہ آرڈر کو لوٹاتا ہے اگر یہ پہلے ہی بن چکا ہے۔
-
نسل
payment_eventsادائیگی کی تاریخ -
نسل
payment_ordersحیثیت کے ساتھ قطاریںNOT_STARTED -
کال
PayPalService.createOrder() -
اپنے آرڈر کی حیثیت کو اس پر اپ ڈیٹ کریں:
EXECUTING -
رپورٹ
approveUrlبھیجنے والے کو
async createPayment(input: CreatePaymentPayload) {
// Idempotency: prevent duplicate charges
const existing = await this.paymentOrderModel.findOne({
where: { idempotencyKey: input.idempotencyKey },
});
if (existing) return this.buildCreateResponse(existing);
const order = await this.paymentOrderModel.create({
paymentOrderId: input.paymentOrderId,
amount: input.amount,
currency: input.currency,
paymentOrderStatus: PaymentOrderStatus.NOT_STARTED,
domain: input.domain,
referenceId: input.referenceId,
// ...
});
const paypalOrder = await this.paypalService.createOrder({
paymentOrderId: order.paymentOrderId,
amount: input.amount,
currency: input.currency,
returnUrl: input.returnUrl,
cancelUrl: input.cancelUrl,
idempotencyKey: input.idempotencyKey,
});
await order.update({
paymentOrderStatus: PaymentOrderStatus.EXECUTING,
paypalOrderId: paypalOrder.paypalOrderId,
});
return {
approveUrl: paypalOrder.approveUrl,
paypalOrderId: paypalOrder.paypalOrderId,
paymentOrderStatus: PaymentOrderStatus.EXECUTING,
};
}
پے پال کے ذریعہ منظور شدہ صارف
فرنٹ اینڈ صارف کو ری ڈائریکٹ کرتا ہے: approveUrl. پے پال تصدیق اور اجازت پر کارروائی کرے گا اور پھر آپ کو دوبارہ بھیجے گا۔ returnUrl.
ادائیگی کی گرفتاری
براہ کرم منظوری کے بعد مجھے کال کریں۔ capturePayment() کسی بھی طرح paymentOrderId یا paypalOrderId:
async capturePayment(paymentOrderId?: string, paypalOrderId?: string) {
const order = await this.findOrder(paymentOrderId, paypalOrderId);
if (order.paymentOrderStatus === PaymentOrderStatus.SUCCESS) {
return this.buildCaptureResponse(order); // already captured
}
const capture = await this.paypalService.captureOrder(order.paypalOrderId);
if (capture.status !== 'COMPLETED') {
throw new Error(`PayPal capture status: ${capture.status}`);
}
await this.finalizeSuccessfulPayment(order, capture.captureId);
return this.buildCaptureResponse(order);
}
finalizeSuccessfulPayment() ڈیٹا بیس کے لین دین میں چلتا ہے۔
-
اپنے آرڈر کی حیثیت کو اس پر اپ ڈیٹ کریں:
SUCCESS -
مرچنٹ والیٹ کا بیلنس اپ ڈیٹ کریں۔
-
لیجر اندراجات بنائیں (آڈٹ ٹریل)
-
چیک آؤٹ ایونٹ کو مکمل طور پر نشان زد کریں۔
-
پوسٹ
payment.{domain}.completedRabbitMQ کے واقعات
مرحلہ 5 – ڈومین سروسز کو gRPC کے ذریعے مربوط کریں۔
ڈومین سروسز، جیسے students-service) کبھی بھی پے پال سے براہ راست بات نہ کریں۔ جی آر پی سی کلائنٹ استعمال کریں۔
طالب علم کی خدمت جی آر پی سی کلائنٹ کے ذریعے ادائیگی کی خدمت کے ساتھ بات چیت کرتی ہے۔ PayPal API کو براہ راست کال کرنے کے بجائے، آپ ادائیگی کی خدمت کے ذریعہ فراہم کردہ سختی سے ٹائپ شدہ ریموٹ طریقہ کار کو کال کرتے ہیں۔
// apps/services/students-service/src/app/payment/payment.module.ts
ClientsModule.registerAsync([{
name: 'PAYMENT_SERVICE',
useFactory: () => ({
transport: Transport.GRPC,
options: {
package: 'payment',
protoPath: 'libs/shared/dto/src/lib/payment/payment.proto',
url: process.env.PAYMENT_SERVICE_URL || 'payment-service:50061',
},
}),
}])
// payment-client.service.ts
@Injectable()
export class PaymentClientService implements OnModuleInit {
private paymentService: PaymentGrpcService;
constructor(@Inject('PAYMENT_SERVICE') private client: ClientGrpc) {}
onModuleInit() {
this.paymentService = this.client.getService('PaymentService');
}
async createPayment(data: CreatePaymentRequest) {
return firstValueFrom(this.paymentService.CreatePayment(data));
}
async capturePayment(data: { payment_order_id?: string; paypal_order_id?: string }) {
return firstValueFrom(this.paymentService.CapturePayment(data));
}
}
ڈومین سروس بزنس منطق کی مثال:
یہ مثال دکھاتی ہے کہ کس طرح ایک ڈومین سروس ادائیگی کی سروس کو ادائیگی کی کارروائی سونپنے سے پہلے کاروبار سے متعلق ڈیٹا تیار کرتی ہے۔
// application-payment.service.ts
async initiateTuitionPayment(applicationId: number, options: { domain: string }) {
const application = await this.applicationModel.findByPk(applicationId);
// Build PayPal return URLs from frontend domain
const frontendBase = options.domain; // e.g. https://crm.yourapp.com
const returnUrl = `${frontendBase}/payment/successful?applicationId=${application.applicationId}`;
const cancelUrl = `${frontendBase}/payment/failure?applicationId=${application.applicationId}`;
const result = await this.paymentClient.createPayment({
checkout_id: `checkout-app-${application.id}`,
payment_order_id: uuidv4(),
domain: 'application',
reference_id: String(application.id),
payer_id: application.studentId,
amount: finalAmount.toFixed(2),
currency: 'USD',
buyer_email: buyerEmail,
seller_account: `university-${application.universityId}`,
payment_category: 'tuition_deposit',
return_url: returnUrl,
cancel_url: cancelUrl,
idempotency_key: `app-${application.id}-tuition-${uuidv4()}`,
});
return {
approveUrl: result.approve_url,
paypalOrderId: result.paypal_order_id,
paymentOrderId: result.payment_order_id,
};
}
ڈومین سروس کاروباری قوانین کے لیے ذمہ دار ہے، اور ادائیگی کی خدمت ادائیگی کے ورک فلو کو خود ہینڈل کرتی ہے۔
اہم: فرنٹ اینڈ کو اپنا اصل اس طرح بھیجنا چاہیے: domain لہذا واپسی یو آر ایل درست ماحول کی طرف اشارہ کرتا ہے (ڈیو پر لوکل ہوسٹ، پروڈکشن یو آر ایل)۔
مرحلہ 6 – API گیٹ وے پرت شامل کریں۔
API گیٹ وے ایک HTTP اینڈ پوائنٹ کو فرنٹ اینڈ پر ظاہر کرتا ہے اور اسے ڈومین سروس کو آگے بھیج دیتا ہے۔
POST /applications/:id/pay/applicationfee
Body: { "domain": "https://crm.yourapp.com", "couponCode": "SAVE10" }
// student-apigw → students-service (gRPC) → payment-service (gRPC) → PayPal
گیٹ وے کی ذمہ داریاں:
-
تصدیق (JWT)
-
تصدیق کی درخواست
-
میرے پاس پے پال کی اسناد نہیں ہیں۔
پے پال ری ڈائریکٹ کے بعد اختتامی نقطہ پر قبضہ کریں۔
POST /applications/:id/pay/applicationfee/capture
Body: { "paypalOrderId": "PAYPAL_ORDER_ID_FROM_URL" }
مرحلہ 7 – RabbitMQ کا استعمال کرتے ہوئے ادائیگی کی تقریب شائع کریں۔
RabbitMQ خدمات کے درمیان غیر مطابقت پذیر مواصلات کو قابل بناتا ہے۔ کامیاب ادائیگی کے بعد تمام سروسز کا پروسیسنگ مکمل ہونے کا انتظار کرنے کے بجائے، ادائیگی کی سروس صرف ایک ایونٹ شائع کرتی ہے اور دلچسپی رکھنے والی خدمات کو آزادانہ طور پر اس پر کارروائی کرنے دیتی ہے۔
کامیاب گرفتاری کے بعد، ادائیگی کی خدمت ایک واقعہ شائع کرتی ہے۔
// payment-events.publisher.ts
async publishCompleted(event: PaymentCompletedEvent) {
const pattern = `payment.${event.domain}.completed`; // e.g. payment.application.completed
this.eventsClient.emit(pattern, { ...event, eventId: uuidv4() });
}
ہر ڈومین سروس آپ کے کاروباری ڈومین سے متعلق ادائیگی کے واقعات کو سبسکرائب کرتی ہے۔ مثال کے طور پر، طلباء کی خدمات حاصل کرتی ہیں: payment.application.completed آپ طالب علم کی درخواست کو کسی تقریب کے ذریعے ادا شدہ کے بطور نشان زد کر سکتے ہیں۔
// payment-events.consumer.ts (students-service)
@EventPattern('payment.application.completed')
async handlePaymentCompleted(@Payload() data: PaymentCompletedPayload) {
await this.applicationPaymentService.handlePaymentCompletedEvent(data);
// Marks application as PAID, records payment history
}
یہ آپ کی ادائیگی کو آپ کے ڈومین کو اپ ڈیٹ کرنے سے الگ کرتا ہے۔ اسہال students-service اگر یہ عارضی طور پر بند ہے، تو آپ قطار سے ایونٹس کو دوبارہ چلا سکتے ہیں۔
آرڈر کو بطور ادا شدہ نشان زد کرنے کے دو راستے
| سڑک | استعمال کرتے وقت |
|---|---|
| ہم وقت ساز گرفت | پے پال ری ڈائریکٹ API کے بعد فرنٹ اینڈ کالز کیپچر کریں۔ |
| متضاد واقعہ | RabbitMQ صارف ادائیگی کی خدمت کے ایونٹ شائع کرنے کے بعد ڈومین کی حالت کو اپ ڈیٹ کرتا ہے۔ |
دونوں کو ایک ساتھ استعمال کرنے سے استقلال حاصل ہوتا ہے۔ Sync Path فوری UX فیڈ بیک فراہم کرتا ہے۔ غیر مطابقت پذیر راستے ایک حفاظتی جال ہیں۔
مرحلہ 8 – ڈیٹا بیس اسکیما اور ہجرت
ادائیگی کی خدمت اپنا ڈیٹا بیس اسکیما برقرار رکھتی ہے۔ ہر ٹیبل کی مخصوص ذمہ داریاں ہوتی ہیں، اس بات کو یقینی بنانا کہ ادائیگی کے ریکارڈ، مالی لین دین، اور ویب ہک پروسیسنگ دیگر کاروباری خدمات سے الگ تھلگ رہیں۔
| میز | مقصد |
|---|---|
payment_events |
ادائیگی کا سیشن (خریدار/بیچنے والے کی معلومات) |
payment_orders |
PayPal ID کے ذریعے ادائیگی کی انفرادی کوشش |
ledger_entries |
فنانشل آڈٹ ٹریل |
wallets |
بیچنے والے بیلنس سے باخبر رہنا |
processed_webhooks |
ویب ہُک ڈیپلیکیشن |
coupons / coupon_redemptions |
ڈسکاؤنٹ کوڈ (اختیاری) |
sequelize_meta |
مائیگریشن ٹریکنگ |
پیداوار کی منتقلی کے مسائل
پروڈکشن ڈوکر امیج سے ہجرت کریں۔ .ts فائل ہے۔ ~ نہیں آپ اسے اس وقت تک استعمال کرسکتے ہیں جب تک کہ آپ اسے جاوا اسکرپٹ پر مرتب کرتے ہیں اور اسے تصویر میں کاپی نہیں کرتے ہیں۔
# Dockerfile — compile migrations for production
RUN pnpm exec tsc --project apps/core/payment-service/tsconfig.migrations.json
COPY --from=builder /app/dist/apps/core/payment-service/migrations ./migrations
اگر آپ کے پاس یہ نہیں ہے تو آپ اسے دیکھ سکتے ہیں۔ Executed 0 migrations لاگ اور ٹیبل نہیں بنایا گیا ہے۔.
ابتدائی تعیناتی سے پہلے ڈیٹا بیس کے صارفین بنائیں۔
CREATE USER payment_user WITH PASSWORD 'payment_pass';
CREATE DATABASE payment_db;
GRANT ALL PRIVILEGES ON DATABASE payment_db TO payment_user;
مرحلہ 9 – مقامی ترقی قائم کریں (ڈوکر)
ماحولیاتی متغیرات (.env)
PAYPAL_CLIENT_ID=your_sandbox_client_id
PAYPAL_CLIENT_SECRET=your_sandbox_client_secret
PAYPAL_API_BASE=https://api-m.sandbox.paypal.com
اس سیکشن میں، آپ ڈوکر کمپوز کا استعمال کرتے ہوئے مقامی ترقی کے لیے ادائیگی کی سروس تشکیل دیتے ہیں۔ یہ سیٹ اپ پروڈکشن میں تعینات کیے بغیر ادائیگیوں کی جانچ کے لیے ایک بہترین ماحول فراہم کرتا ہے۔
ڈاکر کمپوز (مقامی)
درج ذیل کنفیگریشن پوسٹگری ایس کیو ایل اور ریبٹ ایم کیو سمیت مطلوبہ انحصار کے ساتھ ادائیگی کی خدمت شروع کرتی ہے۔
payment-service:
build:
dockerfile: apps/core/payment-service/Dockerfile.dev
ports:
- '3003:3003' # HTTP
- '50061:50061' # gRPC
environment:
- PAYPAL_API_BASE=https://api-m.sandbox.paypal.com
- PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}
- PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}
- DB_HOST=postgres
- DB_NAME=payment_db
- DB_USER=payment_user
- DB_PASSWORD=payment_pass
- RABBITMQ_URL=amqp://rabbitmq:5672
students-service:
environment:
- PAYMENT_SERVICE_URL=payment-service:50061
depends_on:
payment-service:
condition: service_healthy
سروس شروع کریں۔
کنفیگریشن مکمل ہونے کے بعد، کنٹینر شروع کریں اور ادائیگی کے بہاؤ کو جانچنے سے پہلے یقینی بنائیں کہ تمام سروسز صحیح طریقے سے چل رہی ہیں۔
docker compose up -d payment-service students-service student-apigw
اسٹیٹس چیک کریں۔
curl http://localhost:3003/health
# {"status":"healthy","service":"payment-service",...}
ادائیگی کے بہاؤ کی جانچ
-
کال
POST /applications/:id/pay/applicationfeeکے ساتھ{ "domain": "http://localhost:3000" } -
لوٹا ہوا مواد کھولیں۔
approveUrlآپ کے براؤزر میں -
اپنے پے پال سینڈ باکس خریدار اکاؤنٹ کے ساتھ لاگ ان کریں۔
-
براہ کرم منظوری کے بعد مجھے کال کریں۔
POST /applications/:id/pay/applicationfee/captureکے ساتھpaypalOrderId -
اپنی درخواست کی حیثیت چیک کریں۔
PAID
مرحلہ 10 – پیداوار کی تعیناتی۔
مقامی طور پر ہر چیز کی تصدیق کرنے کے بعد، اگلا مرحلہ پیمنٹ سروس کو پروڈکشن میں تعینات کرنا ہے۔ بنیادی فرق یہ ہے کہ یہ پے پال لائیو اسناد، پیداواری ماحول کے متغیرات، اور پیداوار کے لیے تیار ڈاکر امیج کا استعمال کرتا ہے۔
پے پال لائیو اسناد
-
پے پال ڈیولپر ڈیش بورڈ → لائیو ایپ پر جائیں۔
-
ایک لائیو REST API ایپ بنائیں
-
کلائنٹ آئی ڈی اور پاس ورڈ کاپی کریں۔
پیداوار .env (سرور پر – کوئی عہد نہیں)
PAYPAL_CLIENT_ID=your_live_client_id
PAYPAL_CLIENT_SECRET=your_live_secret
PAYPAL_API_BASE=https://api-m.paypal.com
ڈاکر کمپوز (پروڈکشن)
payment-service:
build:
dockerfile: apps/core/payment-service/Dockerfile
environment:
- NODE_ENV=production
- PAYPAL_API_BASE=${PAYPAL_API_BASE:-https://api-m.paypal.com}
- PAYPAL_CLIENT_ID=${PAYPAL_CLIENT_ID}
- PAYPAL_CLIENT_SECRET=${PAYPAL_CLIENT_SECRET}
- DB_HOST=${DB_HOST}
- DB_NAME=payment_db
- DB_USER=payment_user
- DB_PASSWORD=payment_pass
- RABBITMQ_URL=amqp://${RABBITMQ_USER}:${RABBITMQ_PASS}@rabbitmq:5672
labels:
- 'traefik.http.routers.payment.rule=Host(`payment-service.yourapp.com`)'
students-service:
environment:
- PAYMENT_SERVICE_URL=payment-service:50061
depends_on:
payment-service:
condition: service_healthy
تعیناتی کا حکم
docker compose -f docker-compose.prod.yml build --no-cache payment-service
docker compose -f docker-compose.prod.yml up -d payment-service students-service
پیداوار کی تصدیق
curl https://payment-service.yourapp.com/health
docker logs -f apply-goal-payment-service
# Look for:
# environment: live
# Found 8 pending migrations
# Executed 8 migrations
پیداوار میں فرنٹ اینڈ ڈومین
فرنٹ اینڈ کو ادائیگی شروع کرتے وقت پروڈکشن CRM URL بھیجنا چاہیے۔
{ "domain": "https://crm.yourapp.com" }
نہیں localhost. کنٹرول کریں کہ ادائیگی کے بعد پے پال کو کہاں ری ڈائریکٹ کیا جاتا ہے۔
مرحلہ 11 – حالت کی جانچ اور نگرانی کریں۔
ہیلتھ چیک آرکیسٹریشن ٹولز جیسے Docker اور Traefik کو اس بات کی تصدیق کرنے کی اجازت دیتے ہیں کہ آپ کی ادائیگی کی سروس صحیح طریقے سے چل رہی ہے۔ ان اختتامی نکات کی نگرانی سے غلطیوں کا جلد پتہ لگانے اور ایپلیکیشن کی بھروسے کو بہتر بنانے میں مدد ملتی ہے۔
// GET /health
{ "status": "healthy", "service": "payment-service", "timestamp": "...", "version": "1.0.0" }
کہاں استعمال کرنا ہے:
-
ڈاکر
HEALTHCHECK -
ٹریفک لوڈ بیلنسر
-
اپ ٹائم نگرانی
پے پال کی اسناد کی توثیق آغاز پر چلائی جاتی ہے بذریعہ: PayPalService.logConfiguration().
مکمل درخواست کا بہاؤ (حقیقی دنیا کی مثال)
سکرپٹ: طلباء کالج میں درخواست دینے کے لیے ٹیوشن ادا کرتے ہیں۔
1. Frontend
POST /applications/42/pay/applicationfee
Body: { "domain": "https://crm.yourapp.com" }
│
▼
2. student-apigw (HTTP → gRPC)
InitiateApplicationTuitionPayment(applicationId: 42)
│
▼
3. students-service
- Validates application not already paid
- Resolves tuition amount
- Optionally validates coupon via payment-service gRPC
- Builds returnUrl / cancelUrl from domain
- Calls payment-service CreatePayment (gRPC)
│
▼
4. payment-service
- Creates payment_orders record (EXECUTING)
- Calls PayPal POST /v2/checkout/orders
- Returns approveUrl
│
▼
5. Frontend redirects user to approveUrl (PayPal checkout)
│
▼
6. User approves → PayPal redirects to returnUrl
│
▼
7. Frontend
POST /applications/42/pay/applicationfee/capture
Body: { "paypalOrderId": "PAYPAL_ORDER_ID" }
│
▼
8. payment-service
- POST /v2/checkout/orders/{id}/capture
- Updates order → SUCCESS
- Updates wallet + ledger
- Publishes payment.application.completed → RabbitMQ
│
▼
9. students-service (event consumer)
- Marks application paymentStatus = PAID
- Records payment in application_payments table
کوپن سپورٹ (اختیاری)
پے پال آرڈر بنانے سے پہلے جی آر پی سی کے ذریعے کوپن چیک کریں۔
const validation = await this.paymentClient.validateCoupon({
code: 'SAVE20',
universityId: application.universityId,
originalAmount: 500,
paymentType: 'application_fee',
});
const finalAmount = validation.data.finalAmount;
// If coupon covers 100% — skip PayPal entirely
if (finalAmount <= 0) {
await this.markApplicationPaid(applicationId, { amount: 0, source: 'coupon' });
return { paymentOrderStatus: 'COMPLETED' };
}
کوپن منطق زندہ اور اچھی ہے۔ payment-service اس لیے رعایت کے قوانین مرکزی ہیں۔
پے پال ویب ہک (اختیاری، لیکن تجویز کردہ)
اپنے پے پال ڈیش بورڈ میں ویب ہک URL کو رجسٹر کریں۔
https://payment-service.yourapp.com/api/v1/payments/webhooks/paypal
ادائیگی کی خدمت ہینڈل کرتی ہے:
| واقعہ | کارروائی |
|---|---|
CHECKOUT.ORDER.APPROVED |
آرڈرز کی خودکار گرفتاری۔ |
PAYMENT.CAPTURE.COMPLETED |
براہ کرم ادائیگی مکمل کریں اگر آپ نے پہلے ہی ایسا نہیں کیا ہے۔ |
ویب ہک ایونٹس کی نقل کی جاتی ہے بذریعہ: processed_webhooks یہ میز ڈبل پروسیسنگ کو روکنے کے لئے ہے.
جانچ پڑتال کی فہرست
-
[ ]
GET /health200 لوٹاتا ہے۔ -
[ ] پے پال لاگز دکھائیں۔
credentialsPresent: true -
[ ] ڈیٹا بیس ٹیبل اسٹارٹ اپ کے بعد موجود ہے (
payment_orders,payment_eventsوغیرہ) -
[ ] ایک درست ادائیگی کی واپسی بنائیں
approveUrl -
[ ] سینڈ باکس کے خریدار اپنی ادائیگی مکمل کر سکتے ہیں۔
-
[ ] واپسی کیپچر
payment_order_status: SUCCESS -
[ ] درخواستوں کو بطور نشان زد کیا گیا ہے۔
PAIDڈومین سروس میں -
[ ] RabbitMQ واقعات
payment.application.completedکھایا جاتا ہے -
[ ] ڈپلیکیٹ کیپچر کو خوبصورتی سے سنبھالا جاتا ہے (آدمی)۔
-
[ ] کوپن 100% ڈسکاؤنٹ پے پال کو چھوڑ دیتا ہے۔
-
[ ] پیداوار کا استعمال
https://api-m.paypal.com(لائیو)
ختم
پے پال کو مائیکرو سروسز فن تعمیر میں ضم کرنے کے کئی اصول ہیں۔
-
ایک ادائیگی کی خدمت تمام PayPal API کالوں کی مالک ہے۔
-
gRPC آپ کی ڈومین سروس کو اندرونی طور پر آپ کی ادائیگی کی خدمت سے جوڑتا ہے۔
-
RabbitMQ ادائیگی کے نتائج کو نشر کرتا ہے، اس لیے ڈومین کی خدمات ڈی جوپل رہتی ہیں۔
-
غیرمعمولی چابیاں کے ساتھ ڈپلیکیٹ بلنگ سے گریز کریں۔
-
ماحولیاتی متغیرات سینڈ باکس اور لائیو کے درمیان ٹوگل ہوتے ہیں — کوڈ میں کوئی تبدیلی نہیں ہوتی ہے۔
-
آپ کو اپنی پروڈکشن ڈوکر امیج کے لیے اپنی منتقلی کو مرتب کرنا ہوگا۔
-
سامنے کے آخر میں نقل و حمل
domainلہذا واپسی کا URL تمام ماحول میں کام کرے گا۔
اس پیٹرن کو وسعت دی گئی ہے۔ ادائیگی کا ایک مختلف طریقہ بھیج کر ادائیگی کی نئی قسم (سبسکرپشن، ایجنسی فیس، یونیورسٹی سروس فیس) شامل کریں۔ domain اور payment_category - پے پال انٹیگریشن کوڈ میں کوئی تبدیلی نہیں ہوئی ہے۔