NestJS، gRPC، اور Docker کا استعمال کرتے ہوئے مائیکرو سروسز فن تعمیر میں پے پال کو کیسے نافذ کیا جائے

اس ٹیوٹوریل میں، آپ NestJS مائیکرو سروسز کا استعمال کرتے ہوئے پیداوار کے لیے تیار پے پال ادائیگی کی خدمت بنائیں گے۔ راستے میں، آپ سیکھیں گے کہ کس طرح ادائیگی کی منطق کو اس کی اپنی سروس میں الگ کرنا ہے، gRPC کا استعمال کرتے ہوئے خدمات کے درمیان بات چیت کرنا، RabbitMQ کے ساتھ ادائیگی کے واقعات شائع کرنا، اور Docker کے ساتھ ہر چیز کو تعینات کرنا۔

بالآخر، آپ کے پاس ایک قابل توسیع ادائیگیوں کا فن تعمیر ہوگا جسے متعدد کاروباری ڈومینز میں دوبارہ استعمال کیا جا سکتا ہے۔

انڈیکس

تعارف

ادائیگی کی منطق ہر مائیکرو سروس سے تعلق نہیں رکھتی۔ پے پال API کالز کو متعدد مقامات پر تقسیم کرنا user-service, order-serviceاور billing-serviceنتائج درج ذیل ہیں:

  • ڈپلیکیٹ پے پال اسناد اور SDK کوڈ

  • متضاد خرابی کو سنبھالنا اور قابلیت

  • ادائیگی کے ریکارڈ جن کا آڈٹ کرنا مشکل ہے۔

  • تکلیف دہ ماحول کی منتقلی (سینڈ باکس سے زندہ تک)

حل ایک وقف شدہ ادائیگیوں کی مائیکرو سروس ہے جو پے پال کے تمام تعاملات کا مالک ہے۔ دوسری سروسز اسے gRPC کے ذریعے کال کرتی ہیں اور ادائیگی کے نتائج RabbitMQ کے ذریعے نشر کیے جاتے ہیں، جس سے ڈومین سروس کو اپنا ڈیٹا اپ ڈیٹ کرنے کی اجازت ملتی ہے۔

یہ گائیڈ آپ کو اصل اسٹیک کا استعمال کرتے ہوئے پیٹرن کے ذریعے لے جاتا ہے۔

فرش ٹیکنالوجی
ادائیگی کی خدمت NestJS
انٹر سروس مواصلات جی آر پی سی
واقعہ بس خرگوش ایم کیو
ڈیٹا بیس پوسٹگری ایس کیو ایل
API کی نمائش API گیٹ وے (HTTP)
کنٹینرائزیشن docker-compose
پے پال API آرڈرز v2 (تخلیق کریں، منظور کریں، کیپچر کریں)

ایک وقف شدہ ادائیگی کی خدمت کیوں استعمال کریں؟

ایک وقف شدہ ادائیگی کی خدمت ادائیگی سے متعلقہ تمام ذمہ داریوں کو ایک جگہ پر مرکزیت دیتی ہے۔ کسی بھی مائیکرو سروس کے بجائے PayPal سے براہ راست بات کرنے کے، آپ صرف اپنی ادائیگی کی خدمت سے ادائیگی کے آپریشن کی درخواست کرتے ہیں۔

سروس پے پال کی تصدیق، آرڈر کی تخلیق، ادائیگی کی گرفتاری، والیٹ اپ ڈیٹس، لیجر ریکارڈز، اور ویب ہک پروسیسنگ کا انتظام کرتی ہے۔ دریں اثنا، ڈومین سروسز کاروباری منطق پر توجہ مرکوز کرتی رہتی ہیں جیسے کہ طلباء کی درخواستیں یا سبسکرپشنز۔

آپ کی ڈومین سروس کو صرف درج ذیل جاننے کی ضرورت ہے:

  1. کتنا چارج کرنا ہے۔

  2. کون ادا کر رہا ہے

  3. ادائیگی کے اہل کاروبار (referenceId)

  4. ادائیگی کے بعد صارفین کو کہاں ری ڈائریکٹ کرنا ہے (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 تین مراحل کی پیروی کرتا ہے:

  1. آرڈر بنائیں: پسدید رقم اور واپسی URL کے ساتھ ایک آرڈر بناتا ہے۔

  2. منظور کرنا: صارف کو پے پال پر بھیج دیا جاتا ہے اور ادائیگی کی اجازت دیتا ہے۔

  3. قبضہ: پسدید منظور شدہ فنڈز حاصل کرتا ہے۔

یہ گزشتہ ادائیگیوں کے 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() درج ذیل کام کریں:

  1. چیکر بے ضمیر کلید موجودہ آرڈر کو لوٹاتا ہے اگر یہ پہلے ہی بن چکا ہے۔

  2. نسل payment_events ادائیگی کی تاریخ

  3. نسل payment_orders حیثیت کے ساتھ قطاریں NOT_STARTED

  4. کال PayPalService.createOrder()

  5. اپنے آرڈر کی حیثیت کو اس پر اپ ڈیٹ کریں: EXECUTING

  6. رپورٹ 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() ڈیٹا بیس کے لین دین میں چلتا ہے۔

  1. اپنے آرڈر کی حیثیت کو اس پر اپ ڈیٹ کریں: SUCCESS

  2. مرچنٹ والیٹ کا بیلنس اپ ڈیٹ کریں۔

  3. لیجر اندراجات بنائیں (آڈٹ ٹریل)

  4. چیک آؤٹ ایونٹ کو مکمل طور پر نشان زد کریں۔

  5. پوسٹ payment.{domain}.completed RabbitMQ کے واقعات

مرحلہ 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",...}

ادائیگی کے بہاؤ کی جانچ

  1. کال POST /applications/:id/pay/applicationfee کے ساتھ { "domain": "http://localhost:3000" }

  2. لوٹا ہوا مواد کھولیں۔ approveUrl آپ کے براؤزر میں

  3. اپنے پے پال سینڈ باکس خریدار اکاؤنٹ کے ساتھ لاگ ان کریں۔

  4. براہ کرم منظوری کے بعد مجھے کال کریں۔ POST /applications/:id/pay/applicationfee/capture کے ساتھ paypalOrderId

  5. اپنی درخواست کی حیثیت چیک کریں۔ PAID

مرحلہ 10 – پیداوار کی تعیناتی۔

مقامی طور پر ہر چیز کی تصدیق کرنے کے بعد، اگلا مرحلہ پیمنٹ سروس کو پروڈکشن میں تعینات کرنا ہے۔ بنیادی فرق یہ ہے کہ یہ پے پال لائیو اسناد، پیداواری ماحول کے متغیرات، اور پیداوار کے لیے تیار ڈاکر امیج کا استعمال کرتا ہے۔

پے پال لائیو اسناد

  1. پے پال ڈیولپر ڈیش بورڈ → لائیو ایپ پر جائیں۔

  2. ایک لائیو REST API ایپ بنائیں

  3. کلائنٹ آئی ڈی اور پاس ورڈ کاپی کریں۔

پیداوار .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 /health 200 لوٹاتا ہے۔

  • [ ] پے پال لاگز دکھائیں۔ credentialsPresent: true

  • [ ] ڈیٹا بیس ٹیبل اسٹارٹ اپ کے بعد موجود ہے (payment_orders, payment_eventsوغیرہ)

  • [ ] ایک درست ادائیگی کی واپسی بنائیں approveUrl

  • [ ] سینڈ باکس کے خریدار اپنی ادائیگی مکمل کر سکتے ہیں۔

  • [ ] واپسی کیپچر payment_order_status: SUCCESS

  • [ ] درخواستوں کو بطور نشان زد کیا گیا ہے۔ PAID ڈومین سروس میں

  • [ ] RabbitMQ واقعات payment.application.completed کھایا جاتا ہے

  • [ ] ڈپلیکیٹ کیپچر کو خوبصورتی سے سنبھالا جاتا ہے (آدمی)۔

  • [ ] کوپن 100% ڈسکاؤنٹ پے پال کو چھوڑ دیتا ہے۔

  • [ ] پیداوار کا استعمال https://api-m.paypal.com (لائیو)

ختم

پے پال کو مائیکرو سروسز فن تعمیر میں ضم کرنے کے کئی اصول ہیں۔

  1. ایک ادائیگی کی خدمت تمام PayPal API کالوں کی مالک ہے۔

  2. gRPC آپ کی ڈومین سروس کو اندرونی طور پر آپ کی ادائیگی کی خدمت سے جوڑتا ہے۔

  3. RabbitMQ ادائیگی کے نتائج کو نشر کرتا ہے، اس لیے ڈومین کی خدمات ڈی جوپل رہتی ہیں۔

  4. غیرمعمولی چابیاں کے ساتھ ڈپلیکیٹ بلنگ سے گریز کریں۔

  5. ماحولیاتی متغیرات سینڈ باکس اور لائیو کے درمیان ٹوگل ہوتے ہیں — کوڈ میں کوئی تبدیلی نہیں ہوتی ہے۔

  6. آپ کو اپنی پروڈکشن ڈوکر امیج کے لیے اپنی منتقلی کو مرتب کرنا ہوگا۔

  7. سامنے کے آخر میں نقل و حمل domain لہذا واپسی کا URL تمام ماحول میں کام کرے گا۔

اس پیٹرن کو وسعت دی گئی ہے۔ ادائیگی کا ایک مختلف طریقہ بھیج کر ادائیگی کی نئی قسم (سبسکرپشن، ایجنسی فیس، یونیورسٹی سروس فیس) ​​شامل کریں۔ domain اور payment_category - پے پال انٹیگریشن کوڈ میں کوئی تبدیلی نہیں ہوئی ہے۔

اضافی وسائل

اوپر تک سکرول کریں۔