ข้ามไปยังเนื้อหาหลัก

Dart SDK

Omise Dart SDK ให้บริการการรวมระบบฝั่งเซิร์ฟเวอร์ที่ครอบคลุมสำหรับ Omise payment API สร้างขึ้นสำหรับบริการแบ็กเอนด์, cloud functions และเครื่องมือ CLI โดยให้การเข้าถึง API แบบเต็มรูปแบบพร้อมโมเดล request/response ที่ปลอดภัยต่อประเภทและรองรับ async

ภาพรวม

Dart SDK ช่วยให้คุณสามารถ:

  • เข้าถึง API แบบเต็มรูปแบบ - ควบคุมอย่างสมบูรณ์การเรียกเก็บเงิน ลูกค้า บัตร และอื่นๆ
  • การดำเนินการฝั่งเซิร์ฟเวอร์ - สร้างการเรียกเก็บเงิน จัดการลูกค้า จัดการการคืนเงิน
  • โมเดลที่ปลอดภัยต่อประเภท - อ็อบเจ็กต์ request และ response ที่มีประเภทครบถ้วน
  • รองรับ Async/await - รูปแบบ async ของ Dart สมัยใหม่
  • Null safety - สร้างด้วย sound null safety
  • การจัดการ Webhook - ตรวจสอบและประมวลผลเหตุการณ์ webhook
  • การจัดการข้อผิดพลาด - ประเภท exception ที่ครอบคลุม

คุณสมบัติหลัก

  • Dart 2.12+ API ที่ปลอดภัยจาก null
  • การทำงานแบบ async ด้วย Future
  • ครอบคลุม API อย่างสมบูรณ์
  • ตัวสร้าง request ที่ปลอดภัยต่อประเภท
  • การตรวจสอบลายเซ็น webhook
  • ตรรกะการลองใหม่โดยอัตโนมัติ
  • รองรับ HTTP client แบบกำหนดเอง
  • การจัดการข้อผิดพลาดอย่างครอบคลุม

ข้อกำหนด

  • Dart 2.12 หรือใหม่กว่า (null safety)
  • แอปพลิเคชันฝั่งเซิร์ฟเวอร์หรือ CLI
  • ไม่เหมาะสำหรับใช้ฝั่ง client/browser (ต้องการ secret key)

การติดตั้ง

เพิ่มใน pubspec.yaml

dependencies:
omise_dart: ^3.0.0

ติดตั้งแพ็กเกจ

dart pub add omise_dart

หรือแบบแมนนวล:

dart pub get

เริ่มต้นอย่างรวดเร็ว

1. นำเข้าแพ็กเกจ

import 'package:omise_dart/omise_dart.dart';

2. กำหนดค่าเริ่มต้นของ Client

void main() async {
final omise = Omise(
publicKey: 'pkey_test_5xyzyx5xyzyx5xyzyx5',
secretKey: 'skey_test_5xyzyx5xyzyx5xyzyx5',
);
}

3. สร้างการเรียกเก็บเงิน

Future<void> createCharge() async {
final omise = Omise(
publicKey: 'pkey_test_5xyzyx5xyzyx5xyzyx5',
secretKey: 'skey_test_5xyzyx5xyzyx5xyzyx5',
);

try {
final charge = await omise.charges.create(
amount: 100000, // 1,000.00 บาท
currency: 'thb',
card: 'tokn_test_5xyzyx5xyzyx5xyzyx5',
description: 'Order #1234',
metadata: {
'order_id': '1234',
'customer_email': 'john@example.com',
},
);

print('Charge created: ${charge.id}');
print('Status: ${charge.status}');

if (charge.paid) {
print('Payment successful!');
}

} catch (error) {
print('Error: $error');
}
}

การกำหนดค่า

การกำหนดค่า Client

// การกำหนดค่าพื้นฐาน
final omise = Omise(
publicKey: 'pkey_test_5xyzyx5xyzyx5xyzyx5',
secretKey: 'skey_test_5xyzyx5xyzyx5xyzyx5',
);

// การกำหนดค่าขั้นสูง
final omise = Omise(
publicKey: 'pkey_test_5xyzyx5xyzyx5xyzyx5',
secretKey: 'skey_test_5xyzyx5xyzyx5xyzyx5',
apiVersion: '2019-05-29',
timeout: Duration(seconds: 60),
debugMode: true,
);

การกำหนดค่าตาม Environment

import 'dart:io';

class Config {
static String get publicKey {
return Platform.environment['OMISE_PUBLIC_KEY'] ??
'pkey_test_5xyzyx5xyzyx5xyzyx5';
}

static String get secretKey {
return Platform.environment['OMISE_SECRET_KEY'] ??
'skey_test_5xyzyx5xyzyx5xyzyx5';
}
}

final omise = Omise(
publicKey: Config.publicKey,
secretKey: Config.secretKey,
);

HTTP Client แบบกำหนดเอง

import 'package:http/http.dart' as http;

final customClient = http.Client();

final omise = Omise(
publicKey: 'pkey_test_...',
secretKey: 'skey_test_...',
httpClient: customClient,
);

// อย่าลืมปิด client เมื่อเสร็จแล้ว
void cleanup() {
customClient.close();
}

การเรียกเก็บเงิน

สร้างการเรียกเก็บเงิน

// เรียกเก็บเงินจากโทเค็นบัตร
Future<Charge> chargeCard(String tokenId, int amount) async {
return await omise.charges.create(
amount: amount,
currency: 'thb',
card: tokenId,
description: 'Payment for order',
returnUri: 'https://example.com/payment/callback',
);
}

// เรียกเก็บเงินจากบัตรเริ่มต้นของลูกค้า
Future<Charge> chargeCustomer(String customerId, int amount) async {
return await omise.charges.create(
amount: amount,
currency: 'thb',
customer: customerId,
description: 'Subscription payment',
);
}

// เรียกเก็บเงินด้วยแหล่งที่มา
Future<Charge> chargeSource(String sourceId, int amount) async {
return await omise.charges.create(
amount: amount,
currency: 'thb',
source: sourceId,
returnUri: 'https://example.com/payment/callback',
);
}

สร้างการเรียกเก็บเงินพร้อม Metadata

Future<Charge> createChargeWithMetadata() async {
return await omise.charges.create(
amount: 100000,
currency: 'thb',
card: 'tokn_test_5xyzyx5xyzyx5xyzyx5',
description: 'Order #1234',
metadata: {
'order_id': '1234',
'customer_email': 'john@example.com',
'customer_name': 'John Doe',
'shipping_method': 'express',
},
);
}

ดึงข้อมูลการเรียกเก็บเงิน

Future<Charge> getCharge(String chargeId) async {
return await omise.charges.retrieve(chargeId);
}

// ตรวจสอบสถานะการเรียกเก็บเงิน
Future<void> checkChargeStatus(String chargeId) async {
final charge = await omise.charges.retrieve(chargeId);

print('Charge ID: ${charge.id}');
print('สถานะ: ${charge.status}');
print('ชำระแล้ว: ${charge.paid}');
print('จำนวนเงิน: ${charge.amount}');

if (charge.authorized) {
print('การเรียกเก็บเงินได้รับอนุมัติแล้ว');
}

if (charge.captured) {
print('การเรียกเก็บเงินถูกจับแล้ว');
}

if (charge.reversed) {
print('การเรียกเก็บเงินถูกยกเลิกแล้ว');
}
}

แสดงรายการการเรียกเก็บเงิน

Future<ChargeList> listCharges({
int limit = 20,
int offset = 0,
}) async {
return await omise.charges.list(
limit: limit,
offset: offset,
);
}

// แสดงรายการการเรียกเก็บเงินทั้งหมด
Future<void> listAllCharges() async {
var offset = 0;
const limit = 100;

while (true) {
final charges = await omise.charges.list(
limit: limit,
offset: offset,
);

for (final charge in charges.data) {
print('การเรียกเก็บเงิน: ${charge.id} - ${charge.amount}');
}

if (charges.data.length < limit) break;
offset += limit;
}
}

อัปเดตการเรียกเก็บเงิน

Future<Charge> updateCharge(String chargeId) async {
return await omise.charges.update(
chargeId,
description: 'Updated description',
metadata: {
'updated_at': DateTime.now().toIso8601String(),
},
);
}

จับการเรียกเก็บเงิน

Future<Charge> captureCharge(String chargeId) async {
return await omise.charges.capture(chargeId);
}

// การจับบางส่วน
Future<Charge> partialCapture(String chargeId, int amount) async {
return await omise.charges.capture(
chargeId,
captureAmount: amount,
);
}

ยกเลิกการเรียกเก็บเงิน

Future<Charge> reverseCharge(String chargeId) async {
return await omise.charges.reverse(chargeId);
}

ลูกค้า

สร้างลูกค้า

Future<Customer> createCustomer({
required String email,
String? description,
Map<String, dynamic>? metadata,
}) async {
return await omise.customers.create(
email: email,
description: description,
metadata: metadata,
);
}

// การใช้งาน
final customer = await createCustomer(
email: 'john@example.com',
description: 'John Doe',
metadata: {
'phone': '+66812345678',
'address': '123 Wireless Road, Bangkok',
},
);

ดึงข้อมูลลูกค้า

Future<Customer> getCustomer(String customerId) async {
return await omise.customers.retrieve(customerId);
}

อัปเดตลูกค้า

Future<Customer> updateCustomer(String customerId) async {
return await omise.customers.update(
customerId,
email: 'newemail@example.com',
description: 'Updated customer',
metadata: {
'last_updated': DateTime.now().toIso8601String(),
},
);
}

แสดงรายการลูกค้า

Future<CustomerList> listCustomers({
int limit = 20,
int offset = 0,
}) async {
return await omise.customers.list(
limit: limit,
offset: offset,
);
}

ลบลูกค้า

Future<DeletedCustomer> deleteCustomer(String customerId) async {
return await omise.customers.delete(customerId);
}

บัตร

สร้างบัตร

Future<Card> addCardToCustomer(
String customerId,
String tokenId,
) async {
return await omise.customers.cards.create(
customerId,
card: tokenId,
);
}

แสดงรายการบัตรของลูกค้า

Future<CardList> listCustomerCards(String customerId) async {
return await omise.customers.cards.list(customerId);
}

// รับบัตรเริ่มต้น
Future<Card?> getDefaultCard(String customerId) async {
final customer = await omise.customers.retrieve(customerId);

if (customer.defaultCard != null) {
return await omise.customers.cards.retrieve(
customerId,
customer.defaultCard!,
);
}

return null;
}

อัปเดตบัตร

Future<Card> updateCard(
String customerId,
String cardId, {
String? name,
int? expirationMonth,
int? expirationYear,
}) async {
return await omise.customers.cards.update(
customerId,
cardId,
name: name,
expirationMonth: expirationMonth,
expirationYear: expirationYear,
);
}

ลบบัตร

Future<DeletedCard> deleteCard(
String customerId,
String cardId,
) async {
return await omise.customers.cards.delete(customerId, cardId);
}

การคืนเงิน

สร้างการคืนเงิน

Future<Refund> createRefund(String chargeId) async {
// คืนเงินเต็มจำนวน
return await omise.refunds.create(chargeId);
}

// คืนเงินบางส่วน
Future<Refund> partialRefund(String chargeId, int amount) async {
return await omise.refunds.create(
chargeId,
amount: amount,
);
}

// คืนเงินพร้อม metadata
Future<Refund> refundWithReason(
String chargeId,
String reason,
) async {
return await omise.refunds.create(
chargeId,
metadata: {
'reason': reason,
'refunded_by': 'system',
'refunded_at': DateTime.now().toIso8601String(),
},
);
}

ดึงข้อมูลการคืนเงิน

Future<Refund> getRefund(String chargeId, String refundId) async {
return await omise.refunds.retrieve(chargeId, refundId);
}

แสดงรายการการคืนเงิน

Future<RefundList> listRefunds(String chargeId) async {
return await omise.refunds.list(chargeId);
}

// แสดงรายการการคืนเงินทั้งหมดสำหรับการเรียกเก็บเงิน
Future<void> listAllRefunds(String chargeId) async {
final refunds = await omise.refunds.list(chargeId);

for (final refund in refunds.data) {
print('การคืนเงิน: ${refund.id}');
print('จำนวนเงิน: ${refund.amount}');
print('สถานะ: ${refund.status}');
}
}

แหล่งที่มา

สร้างแหล่งที่มา

// ธนาคารอินเทอร์เน็ต
Future<Source> createInternetBankingSource(int amount) async {
return await omise.sources.create(
amount: amount,
currency: 'thb',
type: 'internet_banking_bay',
);
}

// พร้อมเพย์
Future<Source> createPromptPaySource(int amount) async {
return await omise.sources.create(
amount: amount,
currency: 'thb',
type: 'promptpay',
);
}

// TrueMoney Wallet
Future<Source> createTrueMoneySource(
int amount,
String phoneNumber,
) async {
return await omise.sources.create(
amount: amount,
currency: 'thb',
type: 'truemoney',
phoneNumber: phoneNumber,
);
}

// การผ่อนชำระ
Future<Source> createInstallmentSource(
int amount,
int installmentTerms,
) async {
return await omise.sources.create(
amount: amount,
currency: 'thb',
type: 'installment_bay',
installmentTerms: installmentTerms,
);
}

ดึงข้อมูลแหล่งที่มา

Future<Source> getSource(String sourceId) async {
return await omise.sources.retrieve(sourceId);
}

// รอจนกว่าแหล่งที่มาจะชำระเงิน
Future<Source> waitForSourcePayment(
String sourceId, {
Duration interval = const Duration(seconds: 3),
Duration timeout = const Duration(minutes: 10),
}) async {
final deadline = DateTime.now().add(timeout);

while (DateTime.now().isBefore(deadline)) {
final source = await omise.sources.retrieve(sourceId);

if (source.status == 'successful' || source.status == 'failed') {
return source;
}

await Future.delayed(interval);
}

throw TimeoutException('Source payment timeout');
}

โทเค็น

สร้างโทเค็น

// หมายเหตุ: ควรสร้างโทเค็นฝั่ง client เพื่อความสอดคล้องกับ PCI
// นี่เป็นเพียงสำหรับสถานการณ์ server-to-server

Future<Token> createToken({
required String name,
required String number,
required int expirationMonth,
required int expirationYear,
required String securityCode,
}) async {
return await omise.tokens.create(
name: name,
number: number,
expirationMonth: expirationMonth,
expirationYear: expirationYear,
securityCode: securityCode,
);
}

ดึงข้อมูลโทเค็น

Future<Token> getToken(String tokenId) async {
return await omise.tokens.retrieve(tokenId);
}

การโอนเงิน

สร้างการโอนเงิน

Future<Transfer> createTransfer(int amount) async {
return await omise.transfers.create(
amount: amount,
);
}

// โอนเงินพร้อมผู้รับ
Future<Transfer> transferToRecipient(
String recipientId,
int amount,
) async {
return await omise.transfers.create(
amount: amount,
recipient: recipientId,
);
}

ดึงข้อมูลการโอนเงิน

Future<Transfer> getTransfer(String transferId) async {
return await omise.transfers.retrieve(transferId);
}

แสดงรายการการโอนเงิน

Future<TransferList> listTransfers({
int limit = 20,
int offset = 0,
}) async {
return await omise.transfers.list(
limit: limit,
offset: offset,
);
}

อัปเดตการโอนเงิน

Future<Transfer> updateTransfer(String transferId) async {
return await omise.transfers.update(
transferId,
amount: 50000, // อัปเดตจำนวนเงินโอน
);
}

ลบการโอนเงิน

Future<DeletedTransfer> deleteTransfer(String transferId) async {
return await omise.transfers.destroy(transferId);
}

ผู้รับเงิน

สร้างผู้รับเงิน

Future<Recipient> createRecipient({
required String name,
required String email,
required String type,
required Map<String, dynamic> bankAccount,
}) async {
return await omise.recipients.create(
name: name,
email: email,
type: type,
bankAccount: bankAccount,
);
}

// การใช้งาน
final recipient = await createRecipient(
name: 'John Doe',
email: 'john@example.com',
type: 'individual',
bankAccount: {
'brand': 'bbl',
'number': '1234567890',
'name': 'John Doe',
},
);

ดึงข้อมูลผู้รับเงิน

Future<Recipient> getRecipient(String recipientId) async {
return await omise.recipients.retrieve(recipientId);
}

แสดงรายการผู้รับเงิน

Future<RecipientList> listRecipients({
int limit = 20,
int offset = 0,
}) async {
return await omise.recipients.list(
limit: limit,
offset: offset,
);
}

อัปเดตผู้รับเงิน

Future<Recipient> updateRecipient(String recipientId) async {
return await omise.recipients.update(
recipientId,
name: 'Updated Name',
email: 'newemail@example.com',
);
}

ลบผู้รับเงิน

Future<DeletedRecipient> deleteRecipient(String recipientId) async {
return await omise.recipients.delete(recipientId);
}

เว็บฮุค

ตรวจสอบลายเซ็น Webhook

import 'dart:convert';
import 'package:crypto/crypto.dart';

class WebhookHandler {
final String secretKey;

WebhookHandler(this.secretKey);

bool verifySignature(String payload, String signature) {
final hmac = Hmac(sha256, utf8.encode(secretKey));
final digest = hmac.convert(utf8.encode(payload));
final expectedSignature = base64.encode(digest.bytes);

return signature == expectedSignature;
}

WebhookEvent parseEvent(String payload) {
final json = jsonDecode(payload);
return WebhookEvent.fromJson(json);
}
}

// การใช้งานกับ shelf (Dart web server)
import 'package:shelf/shelf.dart';

Response handleWebhook(Request request) async {
final payload = await request.readAsString();
final signature = request.headers['x-omise-signature'];

if (signature == null) {
return Response.unauthorized('Missing signature');
}

final handler = WebhookHandler('skey_test_...');

if (!handler.verifySignature(payload, signature)) {
return Response.unauthorized('Invalid signature');
}

final event = handler.parseEvent(payload);
await processWebhookEvent(event);

return Response.ok('OK');
}

จัดการเหตุการณ์ Webhook

Future<void> processWebhookEvent(WebhookEvent event) async {
print('ได้รับเหตุการณ์: ${event.key}');

switch (event.key) {
case 'charge.complete':
await handleChargeComplete(event.data as Charge);
break;

case 'charge.create':
await handleChargeCreate(event.data as Charge);
break;

case 'refund.create':
await handleRefundCreate(event.data as Refund);
break;

case 'transfer.create':
await handleTransferCreate(event.data as Transfer);
break;

default:
print('ประเภทเหตุการณ์ที่ไม่ได้จัดการ: ${event.key}');
}
}

Future<void> handleChargeComplete(Charge charge) async {
print('การเรียกเก็บเงินเสร็จสิ้น: ${charge.id}');

if (charge.paid) {
// อัปเดตสถานะคำสั่งซื้อในฐานข้อมูลของคุณ
await updateOrderStatus(
charge.metadata['order_id'],
'paid',
);

// ส่งอีเมลยืนยัน
await sendConfirmationEmail(
charge.metadata['customer_email'],
charge.id,
);
}
}

การจัดการข้อผิดพลาด

ประเภท Exception

Future<void> handlePayment() async {
try {
final charge = await omise.charges.create(
amount: 100000,
currency: 'thb',
card: 'tokn_test_...',
);


print('Charge created: ${charge.id}');

} on OmiseException catch (e) {
// ข้อผิดพลาด API จาก Omise
print('ข้อผิดพลาด API: ${e.message}');
print('รหัส: ${e.code}');
print('สถานะ: ${e.statusCode}');

} on NetworkException catch (e) {
// ข้อผิดพลาดการเชื่อมต่อเครือข่าย
print('ข้อผิดพลาดเครือข่าย: ${e.message}');

} on AuthenticationException catch (e) {
// API keys ไม่ถูกต้อง
print('ข้อผิดพลาดการยืนยันตัวตน: ${e.message}');

} catch (e) {
// ข้อผิดพลาดที่ไม่ทราบสาเหตุ
print('ข้อผิดพลาดที่ไม่ทราบ: $e');
}
}

จัดการรหัสข้อผิดพลาดเฉพาะ

Future<Charge> createChargeWithErrorHandling(
String tokenId,
int amount,
) async {
try {
return await omise.charges.create(
amount: amount,
currency: 'thb',
card: tokenId,
);

} on OmiseException catch (e) {
switch (e.code) {
case 'invalid_card':
throw PaymentException('Invalid card details');

case 'insufficient_fund':
throw PaymentException('Insufficient funds');

case 'failed_processing':
throw PaymentException('Payment processing failed');

case 'invalid_security_code':
throw PaymentException('Invalid CVV');

case 'stolen_or_lost_card':
throw PaymentException('Card reported stolen or lost');

default:
throw PaymentException('Payment failed: ${e.message}');
}
}
}

class PaymentException implements Exception {
final String message;
PaymentException(this.message);

@override
String toString() => message;
}

ตรรกะการลองใหม่

Future<Charge> createChargeWithRetry({
required String tokenId,
required int amount,
int maxAttempts = 3,
Duration delay = const Duration(seconds: 1),
}) async {
int attempts = 0;

while (attempts < maxAttempts) {
try {
return await omise.charges.create(
amount: amount,
currency: 'thb',
card: tokenId,
);


} on NetworkException catch (e) {
attempts++;

if (attempts >= maxAttempts) {
rethrow;
}

print('ความพยายามครั้งที่ $attempts ล้มเหลว กำลังลองใหม่...');
await Future.delayed(delay * attempts);

} on OmiseException catch (e) {
// ไม่ลองใหม่สำหรับข้อผิดพลาด API
rethrow;
}
}

throw Exception('Max retry attempts reached');
}

แนวทางปฏิบัติที่ดีที่สุด

ความปลอดภัย

// ✅ ควรทำ: ใช้ตัวแปรสิ่งแวดล้อม
final omise = Omise(
publicKey: Platform.environment['OMISE_PUBLIC_KEY']!,
secretKey: Platform.environment['OMISE_SECRET_KEY']!,
);

// ❌ ไม่ควรทำ: ฮาร์ดโค้ด API keys
// final omise = Omise(
// publicKey: 'pkey_...',
// secretKey: 'skey_...',
// );

// ✅ ควรทำ: ตรวจสอบข้อมูลที่ป้อน
Future<Charge> createCharge(Map<String, dynamic> data) async {
final amount = data['amount'] as int?;
if (amount == null || amount <= 0) {
throw ArgumentError('Invalid amount');
}

return await omise.charges.create(
amount: amount,
currency: 'thb',
card: data['token'] as String,
);
}

// ✅ ควรทำ: ใช้ HTTPS เท่านั้น
// SDK บังคับการเชื่อมต่อ HTTPS

// ❌ ไม่ควรทำ: บันทึกข้อมูลสำคัญ
// print('Card: ${card.number}');

// ✅ ควรทำ: ใช้การบันทึกที่ปลอดภัย
print('Charge created: ${charge.id}');

ประสิทธิภาพ

// ✅ ควรทำ: ใช้ client ซ้ำ
class Paymentบริการ {
static final Paymentบริการ _instance = Paymentบริการ._internal();
factory Paymentบริการ() => _instance;

late final Omise omise;

Paymentบริการ._internal() {
omise = Omise(
publicKey: Config.publicKey,
secretKey: Config.secretKey,
);
}
}

// ✅ ควรทำ: ใช้การแบ่งหน้าสำหรับรายการขนาดใหญ่
Future<List<Charge>> getAllCharges() async {
final allCharges = <Charge>[];
var offset = 0;
const limit = 100;

while (true) {
final charges = await omise.charges.list(
limit: limit,
offset: offset,
);

allCharges.addAll(charges.data);

if (charges.data.length < limit) break;
offset += limit;
}

return allCharges;
}

// ✅ ควรทำ: แคชข้อมูลที่เข้าถึงบ่อย
class CachedCustomerบริการ {
final Omise omise;
final Map<String, Customer> _cache = {};

CachedCustomerบริการ(this.omise);

Future<Customer> getCustomer(String id) async {
if (_cache.containsKey(id)) {
return _cache[id]!;
}

final customer = await omise.customers.retrieve(id);
_cache[id] = customer;
return customer;
}
}

การจัดการข้อผิดพลาด

// ✅ ควรทำ: จัดการข้อผิดพลาดอย่างสง่างาม
Future<Charge?> createChargeWithFallback(
String tokenId,
int amount,
) async {
try {
return await omise.charges.create(
amount: amount,
currency: 'thb',
card: tokenId,
);

} on OmiseException catch (e) {
logger.error('การชำระเงินล้มเหลว', error: e);
await notifyAdmins(e);
return null;

} on NetworkException catch (e) {
logger.error('ข้อผิดพลาดเครือข่าย', error: e);
await queueForRetry(tokenId, amount);
return null;
}
}

// ✅ ควรทำ: ตรวจสอบลายเซ็น webhook
Future<void> handleWebhook(Request request) async {
final signature = request.headers['x-omise-signature'];

if (signature == null) {
throw UnauthorizedException('Missing signature');
}

final payload = await request.readAsString();

if (!verifySignature(payload, signature)) {
throw UnauthorizedException('Invalid signature');
}

await processWebhook(payload);
}

การทดสอบ

การทดสอบหน่วย

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';

class MockOmise extends Mock implements Omise {}

void main() {
group('Payment Tests', () {
late MockOmise mockOmise;

setUp(() {
mockOmise = MockOmise();
});

test('createCharge คืนการเรียกเก็บเงินเมื่อสำเร็จ', () async {
// จัดเตรียม
final expectedCharge = Charge(
id: 'chrg_test_123',
amount: 100000,
currency: 'thb',
status: 'successful',
paid: true,
);

when(mockOmise.charges.create(
amount: anyNamed('amount'),
currency: anyNamed('currency'),
card: anyNamed('card'),
)).thenAnswer((_) async => expectedCharge);

// ทำการทดสอบ
final charge = await mockOmise.charges.create(
amount: 100000,
currency: 'thb',
card: 'tokn_test_123',
);

// ตรวจสอบ
expect(charge.id, equals('chrg_test_123'));
expect(charge.paid, isTrue);
});

test('createCharge แสดงข้อผิดพลาดเมื่อบัตรไม่ถูกต้อง', () async {
// จัดเตรียม
when(mockOmise.charges.create(
amount: anyNamed('amount'),
currency: anyNamed('currency'),
card: anyNamed('card'),
)).thenThrow(
OmiseException('invalid_card', 'Invalid card'),
);

// ทำการทดสอบและตรวจสอบ
expect(
() => mockOmise.charges.create(
amount: 100000,
currency: 'thb',
card: 'tokn_invalid',
),
throwsA(isA<OmiseException>()),
);
});
});
}

การทดสอบการรวมระบบ

import 'package:test/test.dart';

void main() {
group('Integration Tests', () {
late Omise omise;

setUp(() {
omise = Omise(
publicKey: 'pkey_test_5xyzyx5xyzyx5xyzyx5',
secretKey: 'skey_test_5xyzyx5xyzyx5xyzyx5',
);
});

test('สร้างและดึงข้อมูลการเรียกเก็บเงิน', () async {
// สร้างโทเค็น
final token = await omise.tokens.create(
name: 'Test User',
number: '4242424242424242',
expirationMonth: 12,
expirationYear: 2025,
securityCode: '123',
);

// สร้างการเรียกเก็บเงิน
final charge = await omise.charges.create(
amount: 100000,
currency: 'thb',
card: token.id,
);

expect(charge.id, isNotEmpty);
expect(charge.amount, equals(100000));

// ดึงข้อมูลการเรียกเก็บเงิน
final retrieved = await omise.charges.retrieve(charge.id);
expect(retrieved.id, equals(charge.id));
});
});
}

การแก้ไขปัญหา

ปัญหาทั่วไป

ปัญหา: ข้อผิดพลาด "Authentication failed"

// วิธีแก้: ตรวจสอบ API keys ของคุณ
final omise = Omise(
publicKey: 'pkey_test_...', // ต้องเริ่มด้วย pkey_
secretKey: 'skey_test_...', // ต้องเริ่มด้วย skey_
);

ปัญหา: ข้อผิดพลาดหมดเวลาเครือข่าย

// วิธีแก้: เพิ่มเวลาหมดเวลา
final omise = Omise(
publicKey: 'pkey_test_...',
secretKey: 'skey_test_...',
timeout: Duration(seconds: 60),
);

ปัญหา: ข้อผิดพลาดใบรับรอง SSL

// วิธีแก้: ตรวจสอบว่าใบรับรองระบบเป็นปัจจุบัน
// สำหรับการพัฒนาเท่านั้น:
// import 'dart:io';
// HttpOverrides.global = DevHttpOverrides();

ปัญหา: ข้อผิดพลาด "Invalid charge"

// วิธีแก้: ตรวจสอบว่าจำนวนเงินอยู่ในหน่วยสกุลเงินที่เล็กที่สุด
final amount = 100000; // 1,000.00 บาท (ไม่ใช่ 1000.00)

final charge = await omise.charges.create(
amount: amount,
currency: 'thb',
card: tokenId,
);

คำถามที่พบบ่อย

ฉันสามารถใช้ SDK นี้ในแอป Flutter ได้หรือไม่?

SDK นี้ออกแบบมาสำหรับใช้ฝั่งเซิร์ฟเวอร์เท่านั้น เนื่องจากต้องการ secret key ของคุณ สำหรับแอป Flutter ให้ใช้ Flutter SDK ซึ่งต้องการเพียง public key ของคุณเท่านั้น

ฉันจะจัดการ idempotency ได้อย่างไร?

ใช้พารามิเตอร์ idempotency key เพื่อให้แน่ใจว่าการดำเนินการไม่ซ้ำ:

final charge = await omise.charges.create(
amount: 100000,
currency: 'thb',
card: tokenId,
idempotencyKey: 'order_1234_payment',
);

ฉันสามารถใช้กับ cloud functions ได้หรือไม่?

ได้ครับ SDK ทำงานได้ดีกับ cloud functions (Firebase, AWS Lambda ฯลฯ):

// Firebase Cloud Function
import 'package:functions_framework/functions_framework.dart';

@CloudFunction()
Future<Response> handlePayment(Request request) async {
final omise = Omise(
publicKey: Platform.environment['OMISE_PUBLIC_KEY']!,
secretKey: Platform.environment['OMISE_SECRET_KEY']!,
);

final body = await request.readAsString();
final data = jsonDecode(body);

final charge = await omise.charges.create(
amount: data['amount'],
currency: 'thb',
card: data['token'],
);

return Response.ok(jsonEncode(charge.toJson()));
}

ฉันจะทดสอบ webhooks ในเครื่องได้อย่างไร?

ใช้เครื่องมืออย่าง ngrok เพื่อเปิดเผยเซิร์ฟเวอร์ในเครื่องของคุณ:

dart run bin/server.dart
ngrok http 8080

จากนั้นกำหนดค่า URL ของ ngrok ในแดชบอร์ด Omise ของคุณ

ฉันสามารถทำการดำเนินการแบบชุดได้หรือไม่?

SDK ไม่มีการแบทช์ในตัว แต่คุณสามารถใช้ Future.wait:

final charges = await Future.wait([
omise.charges.create(amount: 10000, currency: 'thb', card: token1),
omise.charges.create(amount: 20000, currency: 'thb', card: token2),
omise.charges.create(amount: 30000, currency: 'thb', card: token3),
]);

ฉันจะจัดการการจำกัดอัตราได้อย่างไร?

ใช้ exponential backoff:

Future<T> withRetry<T>(Future<T> Function() operation) async {
var delay = Duration(seconds: 1);
var attempts = 0;
const maxAttempts = 5;

while (attempts < maxAttempts) {
try {
return await operation();
} on OmiseException catch (e) {
if (e.statusCode == 429) { // ถูกจำกัดอัตรา
attempts++;
if (attempts >= maxAttempts) rethrow;
await Future.delayed(delay);
delay *= 2;
} else {
rethrow;
}
}
}

throw Exception('Max retries exceeded');
}

ฉันสามารถใช้ SDK นี้กับหลายบัญชีได้หรือไม่?

ได้ครับ สร้างอินสแตนซ์ client หลายตัว:

final omise1 = Omise(
publicKey: 'pkey_account1_...',
secretKey: 'skey_account1_...',
);

final omise2 = Omise(
publicKey: 'pkey_account2_...',
secretKey: 'skey_account2_...',
);

ทรัพยากรที่เกี่ยวข้อง

ขั้นตอนถัดไป

  1. ตั้งค่าบัญชีของคุณ เพื่อรับ API keys
  2. กำหนดค่า webhooks เพื่อรับการอัปเดตการชำระเงิน
  3. ทดสอบการรวมระบบของคุณ ด้วยโหมดทดสอบ
  4. เริ่มใช้งานจริง ด้วย production keys

การสนับสนุน

ต้องการความช่วยเหลือเกี่ยวกับ Dart SDK?