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

ไลบรารี Python (omise-python)

ไลบรารี omise-python ให้อินเทอร์เฟซแบบ Pythonic กับ Omise API พร้อมการสนับสนุน Django และ Flask การทำงานแบบ async คำแนะนำประเภท และการจัดการข้อผิดพลาดอย่างครอบคลุม

การติดตั้ง

การใช้ pip (แนะนำ)

pip install omise

การใช้ pip with requirements.txt

# requirements.txt
omise>=0.11.0
pip install -r requirements.txt

การใช้ Poetry

poetry add omise

ข้อกำหนด

  • Python 3.6 ขึ้นไป (รวมถึง Python 3.11+)
  • ไลบรารี requests (ติดตั้งโดยอัตโนมัติ)
  • ตัวเลือก: aiohttp สำหรับการสนับสนุนแบบ async

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

การกำหนดค่าพื้นฐาน

import omise

# กำหนดค่าด้วย API key ของคุณ
omise.api_secret = 'skey_test_123456789'
omise.api_version = '2019-05-29'

# ตัวเลือก: ตั้งค่า API endpoint
# omise.api_url = 'https://api.omise.co'

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

เพิ่มไปยังการตั้งค่า Django ของคุณ:

# settings.py
import os

OMISE_SECRET_KEY = os.environ.get('OMISE_SECRET_KEY')
OMISE_PUBLIC_KEY = os.environ.get('OMISE_PUBLIC_KEY')
OMISE_API_VERSION = '2019-05-29'

# เริ่มต้นใน apps.py หรือ __init__.py
import omise
omise.api_secret = OMISE_SECRET_KEY
omise.api_version = OMISE_API_VERSION

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

# config.py
import os

class Config:
OMISE_SECRET_KEY = os.environ.get('OMISE_SECRET_KEY')
OMISE_PUBLIC_KEY = os.environ.get('OMISE_PUBLIC_KEY')
OMISE_API_VERSION = '2019-05-29'

# app.py
from flask import Flask
import omise

app = Flask(__name__)
app.config.from_object('config.Config')

omise.api_secret = app.config['OMISE_SECRET_KEY']
omise.api_version = app.config['OMISE_API_VERSION']

ตัวแปรสภาพแวดล้อม

เพิ่มไปยังไฟล์ .env ของคุณ:

# การพัฒนา/ทดสอบ
OMISE_SECRET_KEY=skey_test_123456789
OMISE_PUBLIC_KEY=pkey_test_123456789

# ผลิตภาพ
# OMISE_SECRET_KEY=skey_live_123456789
# OMISE_PUBLIC_KEY=pkey_live_123456789

การตรวจสอบสิทธิ์

ไลบรารีใช้ secret key ของคุณสำหรับการดำเนินการ API ทั้งหมด:

import omise

# ตัวเลือกที่ 1: การกำหนดค่าแบบ Global (แนะนำ)
omise.api_secret = os.environ['OMISE_SECRET_KEY']

# ตัวเลือกที่ 2: การกำหนดค่าแบบแต่ละ request
charge = omise.Charge.retrieve('chrg_test_123', key='skey_test_alternate')

การดำเนินการทั่วไป

การสร้างค่าธรรมเนียม

ด้วย Token

import omise

# สร้างค่าธรรมเนียมด้วย card token
charge = omise.Charge.create(
amount=100000, # 1,000.00 บาท (ในหน่วยสกุลเงินที่เล็กที่สุด)
currency='THB',
card='tokn_test_123',
description='Order #1234',
metadata={
'order_id': '1234',
'customer_name': 'John Doe'
}
)

if charge.paid:
print(f"เรียกเก็บเงินสำเร็จ: {charge.id}")
else:
print(f"เรียกเก็บเงินล้มเหลว: {charge.failure_message}")

ด้วย Type Hints

from typing import Dict, Any
import omise

def create_charge(
amount: int,
currency: str,
token: str,
metadata: Dict[str, Any]
) -> omise.Charge:
"""สร้างค่าธรรมเนียมด้วยพารามิเตอร์ที่กำหนด"""
charge = omise.Charge.create(
amount=amount,
currency=currency,
card=token,
metadata=metadata
)
return charge

# การใช้
charge = create_charge(
amount=100000,
currency='THB',
token='tokn_test_123',
metadata={'order_id': '1234'}
)

ด้วยลูกค้า

# สร้างค่าธรรมเนียมสำหรับลูกค้าที่มีอยู่
charge = omise.Charge.create(
amount=50000,
currency='THB',
customer='cust_test_123',
description='Subscription payment'
)

ด้วย 3D Secure

# สร้างค่าธรรมเนียมที่อาจต้องใช้ 3D Secure
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123',
return_uri='https://example.com/payment/callback'
)

if charge.authorized:
if charge.authorize_uri:
# เปลี่ยนเส้นทางลูกค้าไปยัง authorize_uri สำหรับ 3D Secure
return redirect(charge.authorize_uri)
else:
# เรียกเก็บเงินเสร็จสมบูรณ์โดยไม่ต้องใช้ 3D Secure
process_successful_payment(charge)

การดึงค่าธรรมเนียม

# ดึงข้อมูลค่าธรรมเนียมด้วย ID
charge = omise.Charge.retrieve('chrg_test_123')

print(f"จำนวนเงิน: {charge.amount}")
print(f"สกุลเงิน: {charge.currency}")
print(f"สถานะ: {charge.status}")
print(f"ชำระแล้ว: {charge.paid}")

การแสดงรายชื่อค่าธรรมเนียม

from datetime import datetime, timedelta

# แสดงรายการค่าธรรมเนียมทั้งหมดพร้อม pagination
charges = omise.Charge.list(
limit=20,
offset=0,
order='reverse_chronological'
)

for charge in charges:
print(f"{charge.id}: {charge.amount} {charge.currency}")

# แสดงรายการค่าธรรมเนียมพร้อมตัวกรอง
week_ago = (datetime.now() - timedelta(days=7)).date().isoformat()
today = datetime.now().date().isoformat()

recent_charges = omise.Charge.list(
from_date=week_ago,
to_date=today
)

การสร้างลูกค้า

# สร้างลูกค้าโดยไม่มีบัตร
customer = omise.Customer.create(
email='customer@example.com',
description='John Doe',
metadata={
'user_id': '12345',
'account_type': 'premium'
}
)

print(f"สร้างลูกค้าแล้ว: {customer.id}")

การบันทึกบัตรเข้าไปในลูกค้า

# อัปเดตลูกค้าด้วย card token
customer = omise.Customer.retrieve('cust_test_123')
customer.update(card='tokn_test_456')

print(f"บันทึกบัตรแล้ว: {customer.default_card}")

# หรือสร้างลูกค้าพร้อมบัตรในขั้นตอนเดียว
customer = omise.Customer.create(
email='customer@example.com',
description='John Doe',
card='tokn_test_123'
)

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

customer = omise.Customer.retrieve('cust_test_123')

for card in customer.cards:
print(f"{card.brand} ลงท้ายด้วย {card.last_digits}")
print(f"หมดอายุ: {card.expiration_month}/{card.expiration_year}")

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

# คืนเงินเต็มจำนวน
refund = omise.Refund.create(
charge='chrg_test_123',
amount=None # None สำหรับคืนเงินเต็มจำนวน
)

# คืนเงินบางส่วน
refund = omise.Refund.create(
charge='chrg_test_123',
amount=25000, # 250.00 บาท
metadata={
'reason': 'customer_request',
'ticket_id': 'TICKET-123'
}
)

print(f"คืนเงิน {refund.id}: {refund.amount} {refund.currency}")

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

# สร้างการโอนไปยังบัญชีธนาคารของคุณ
transfer = omise.Transfer.create(
amount=500000, # 5,000.00 บาท
recipient='recp_test_123',
metadata={
'payout_id': 'PAYOUT-456'
}
)

print(f"โอน {transfer.id}: {transfer.amount}")

วิธีการชำระเงินแบบอื่น

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

# QR PromptPay
source = omise.Source.create(
type='promptpay',
amount=100000,
currency='THB'
)

# แสดง QR code ให้ลูกค้า
print(f"URL QR Code: {source.scannable_code.image.download_uri}")

# สร้างค่าธรรมเนียมด้วย source
charge = omise.Charge.create(
amount=100000,
currency='THB',
source=source.id,
return_uri='https://example.com/payment/callback'
)

ธนาคารอินเทอร์เน็ต

# ธนาคารอินเทอร์เน็ต
source = omise.Source.create(
type='internet_banking_scb',
amount=100000,
currency='THB'
)

charge = omise.Charge.create(
amount=100000,
currency='THB',
source=source.id,
return_uri='https://example.com/payment/callback'
)

# เปลี่ยนเส้นทางลูกค้าไปยัง authorize_uri
return redirect(charge.authorize_uri)

โมบายแบงก์กิ้ง

# โมบายแบงก์กิ้ง (SCB Easy)
source = omise.Source.create(
type='mobile_banking_scb',
amount=100000,
currency='THB'
)

charge = omise.Charge.create(
amount=100000,
currency='THB',
source=source.id,
return_uri='https://example.com/payment/callback'
)

การผ่อนชำระ

# การชำระเงินแบบผ่อน
source = omise.Source.create(
type='installment_kbank',
amount=100000,
currency='THB',
installment_term=6 # 6 เดือน
)

charge = omise.Charge.create(
amount=100000,
currency='THB',
source=source.id,
return_uri='https://example.com/payment/callback'
)

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

ไลบรารีส่งประเภท exception ที่เฉพาะเจาะจงสำหรับข้อผิดพลาดแต่ละประเภท:

import omise
from omise.errors import (
OmiseError,
การตรวจสอบสิทธิ์Error,
InvalidRequestError,
CardError,
APIError,
ConnectionError
)

try:
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123'
)
except การตรวจสอบสิทธิ์Error as e:
# API key ไม่ถูกต้อง
print(f"การตรวจสอบสิทธิ์ล้มเหลว: {e}")

except InvalidRequestError as e:
# พารามิเตอร์ไม่ถูกต้อง
print(f"คำขอไม่ถูกต้อง: {e}")
print(f"รหัสสถานะ: {e.http_status}")

except CardError as e:
# บัตรถูกปฏิเสธ
print(f"ข้อผิดพลาดบัตร: {e}")
print(f"รหัสความล้มเหลว: {e.code}")

except APIError as e:
# ข้อผิดพลาด API ทั่วไป
print(f"ข้อผิดพลาด API: {e}")

except ConnectionError as e:
# ข้อผิดพลาดเครือข่าย
print(f"การเชื่อมต่อล้มเหลว: {e}")

except OmiseError as e:
# จับข้อผิดพลาด Omise ทั้งหมด
print(f"ข้อผิดพลาด Omise: {e}")

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

from omise.errors import CardError

try:
charge = omise.Charge.create(amount=100000, currency='THB', card=token)

except CardError as e:
error_messages = {
'insufficient_fund': 'เงินในบัตรไม่เพียงพอ',
'stolen_or_lost_card': 'บัตรถูกรายงานว่าถูกขโมยหรือสูญหาย',
'invalid_security_code': 'รหัส CVV ไม่ถูกต้อง',
'payment_cancelled': 'การชำระเงินถูกยกเลิก'
}

message = error_messages.get(e.code, f"ข้อผิดพลาดบัตร: {e}")
return {'error': message}, 400

การผสานรวม Django

ตัวอย่าง Views

# views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.views.decorators.http import require_http_methods
import omise
from omise.errors import OmiseError

from .models import Order, Payment

@require_http_methods(["POST"])
def create_payment(request, order_id):
"""สร้างค่าธรรมเนียมการชำระเงินสำหรับคำสั่งซื้อ"""
order = get_object_or_404(Order, id=order_id)
token = request.POST.get('omise_token')

try:
charge = omise.Charge.create(
amount=int(order.total * 100), # แปลงเป็นหน่วยที่เล็กที่สุด
currency='THB',
card=token,
description=f"Order #{order.id}",
metadata={
'order_id': str(order.id),
'customer_email': order.email
},
return_uri=request.build_absolute_uri(
reverse('payment_callback')
)
)

# บันทึกข้อมูลการชำระเงิน
payment = Payment.objects.create(
order=order,
charge_id=charge.id,
amount=order.total,
status=charge.status,
paid=charge.paid
)

if charge.paid:
order.payment_status = 'paid'
order.save()
messages.success(request, 'ชำระเงินสำเร็จ!')
return redirect('order_detail', order_id=order.id)
elif charge.authorize_uri:
# ต้องใช้ 3D Secure
return redirect(charge.authorize_uri)
else:
messages.error(request, charge.failure_message)
return redirect('payment_form', order_id=order.id)

except OmiseError as e:
logger.error(f"ข้อผิดพลาด Omise: {e}")
messages.error(request, 'การชำระเงินล้มเหลว กรุณาลองอีกครั้ง')
return redirect('payment_form', order_id=order.id)

@require_http_methods(["GET"])
def payment_callback(request):
"""จัดการ callback การชำระเงินหลังจาก 3D Secure"""
charge_id = request.GET.get('id')

try:
charge = omise.Charge.retrieve(charge_id)
payment = Payment.objects.get(charge_id=charge.id)

payment.status = charge.status
payment.paid = charge.paid
payment.save()

if charge.paid:
payment.order.payment_status = 'paid'
payment.order.save()
messages.success(request, 'ชำระเงินสำเร็จ!')
return redirect('order_detail', order_id=payment.order.id)
else:
messages.error(request, charge.failure_message)
return redirect('payment_form', order_id=payment.order.id)

except omise.OmiseError as e:
messages.error(request, 'การยืนยันการชำระเงินล้มเหลว')
return redirect('home')

การผสานรวม Models

# models.py
from django.db import models
from django.core.exceptions import ValidationError
import omise
from omise.errors import OmiseError

class Payment(models.Model):
"""โมเดลการชำระเงินสำหรับติดตามค่าธรรมเนียม Omise"""

STATUS_CHOICES = [
('pending', 'รอดำเนินการ'),
('successful', 'สำเร็จ'),
('failed', 'ล้มเหลว'),
('refunded', 'คืนเงินแล้ว'),
]

order = models.ForeignKey('Order', on_delete=models.CASCADE)
charge_id = models.CharField(max_length=100, unique=True, null=True)
amount = models.DecimalField(max_digits=10, decimal_places=2)
currency = models.CharField(max_length=3, default='THB')
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
paid = models.BooleanField(default=False)
failure_code = models.CharField(max_length=100, blank=True)
failure_message = models.TextField(blank=True)
refund_id = models.CharField(max_length=100, blank=True)
refund_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
ordering = ['-created_at']

def charge(self, token: str) -> omise.Charge:
"""สร้างค่าธรรมเนียมด้วย token ที่กำหนด"""
charge = omise.Charge.create(
amount=int(self.amount * 100),
currency=self.currency,
card=token,
description=f"Order #{self.order.id}",
metadata=self.get_charge_metadata()
)

self.charge_id = charge.id
self.status = charge.status
self.paid = charge.paid
self.save()

return charge

def refund(self, refund_amount: float = None) -> omise.Refund:
"""สร้างการคืนเงินสำหรับการชำระเงินนี้"""
if not self.charge_id:
raise ValueError("ไม่สามารถคืนเงินได้หากไม่มี charge_id")

refund = omise.Refund.create(
charge=self.charge_id,
amount=int(refund_amount * 100) if refund_amount else None
)

self.refund_id = refund.id
self.refund_amount = refund.amount / 100
self.status = 'refunded'
self.save()

return refund

def refresh_status(self) -> None:
"""รีเฟรชสถานะการชำระเงินจาก Omise"""
if not self.charge_id:
return

charge = omise.Charge.retrieve(self.charge_id)
self.status = charge.status
self.paid = charge.paid
self.failure_code = charge.failure_code or ''
self.failure_message = charge.failure_message or ''
self.save()

def get_charge_metadata(self) -> dict:
"""รับ metadata สำหรับค่าธรรมเนียม"""
return {
'order_id': str(self.order.id),
'customer_email': self.order.email,
'customer_name': self.order.customer_name
}

งาน Celery สำหรับการประมวลผลแบบ Async

# tasks.py
from celery import shared_task
from django.core.mail import send_mail
import omise
from omise.errors import OmiseError, CardError

from .models import Payment

@shared_task(bind=True, max_retries=3)
def process_charge(self, payment_id: int, token: str):
"""ประมวลผลค่าธรรมเนียมแบบอะซิงโครนัส"""
try:
payment = Payment.objects.get(id=payment_id)
charge = payment.charge(token)

if charge.paid:
# ส่งอีเมลแจ้งความสำเร็จ
send_mail(
'ยืนยันการชำระเงิน',
f'การชำระเงินของคุณจำนวน {payment.amount} {payment.currency} สำเร็จ',
'noreply@example.com',
[payment.order.email],
fail_silently=False,
)
else:
# ส่งอีเมลแจ้งความล้มเหลว
send_mail(
'การชำระเงินล้มเหลว',
f'การชำระเงินของคุณล้มเหลว: {charge.failure_message}',
'noreply@example.com',
[payment.order.email],
fail_silently=False,
)

except CardError as e:
payment.status = 'failed'
payment.failure_message = str(e)
payment.save()

except OmiseError as e:
# ลองใหม่เมื่อเกิดข้อผิดพลาดเครือข่าย
raise self.retry(exc=e, countdown=60)

@shared_task
def refresh_payment_statuses():
"""รีเฟรชสถานะการชำระเงินที่รอดำเนินการ"""
pending_payments = Payment.objects.filter(status='pending')

for payment in pending_payments:
try:
payment.refresh_status()
except OmiseError:
continue

การผสานรวม Flask

การตั้งค่าแอปพลิเคชัน

# app.py
from flask import Flask, request, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
import omise
from omise.errors import OmiseError, CardError
import os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://localhost/myapp'
db = SQLAlchemy(app)

# กำหนดค่า Omise
omise.api_secret = os.environ.get('OMISE_SECRET_KEY')
omise.api_version = '2019-05-29'

@app.route('/payment/<int:order_id>', methods=['GET'])
def payment_form(order_id):
"""แสดงฟอร์มการชำระเงิน"""
order = Order.query.get_or_404(order_id)
return render_template('payment.html', order=order)

@app.route('/payment/<int:order_id>', methods=['POST'])
def create_payment(order_id):
"""ประมวลผลการชำระเงิน"""
order = Order.query.get_or_404(order_id)
token = request.form.get('omise_token')

try:
charge = omise.Charge.create(
amount=int(order.total * 100),
currency='THB',
card=token,
description=f"Order #{order.id}",
metadata={
'order_id': str(order.id),
'customer_email': order.email
},
return_uri=url_for('payment_callback', _external=True)
)

# บันทึกการชำระเงิน
payment = Payment(
order_id=order.id,
charge_id=charge.id,
amount=order.total,
status=charge.status,
paid=charge.paid
)
db.session.add(payment)
db.session.commit()

if charge.paid:
flash('ชำระเงินสำเร็จ!', 'success')
return redirect(url_for('order_detail', order_id=order.id))
elif charge.authorize_uri:
return redirect(charge.authorize_uri)
else:
flash(charge.failure_message, 'error')
return redirect(url_for('payment_form', order_id=order.id))

except CardError as e:
flash(f'ข้อผิดพลาดบัตร: {e}', 'error')
return redirect(url_for('payment_form', order_id=order.id))

except OmiseError as e:
app.logger.error(f"ข้อผิดพลาด Omise: {e}")
flash('การชำระเงินล้มเหลว กรุณาลองอีกครั้ง', 'error')
return redirect(url_for('payment_form', order_id=order.id))

@app.route('/payment/callback')
def payment_callback():
"""จัดการ callback การชำระเงิน"""
charge_id = request.args.get('id')

try:
charge = omise.Charge.retrieve(charge_id)
payment = Payment.query.filter_by(charge_id=charge.id).first_or_404()

payment.status = charge.status
payment.paid = charge.paid
db.session.commit()

if charge.paid:
flash('ชำระเงินสำเร็จ!', 'success')
return redirect(url_for('order_detail', order_id=payment.order_id))
else:
flash(charge.failure_message, 'error')
return redirect(url_for('payment_form', order_id=payment.order_id))

except OmiseError as e:
flash('การยืนยันการชำระเงินล้มเหลว', 'error')
return redirect(url_for('home'))

การสนับสนุนแบบ Async

การใช้ asyncio

import asyncio
import aiohttp
import omise

async def create_charge_async(amount: int, currency: str, token: str):
"""สร้างค่าธรรมเนียมแบบอะซิงโครนัส"""
# หมายเหตุ: omise-python ไม่มีการสนับสนุน async แบบดั้งเดิม
# ใช้ run_in_executor สำหรับการดำเนินการพร้อมกัน
loop = asyncio.get_event_loop()
charge = await loop.run_in_executor(
None,
omise.Charge.create,
amount,
currency,
token
)
return charge

async def process_multiple_charges(charges_data):
"""ประมวลผลค่าธรรมเนียมหลายรายการพร้อมกัน"""
tasks = [
create_charge_async(
data['amount'],
data['currency'],
data['token']
)
for data in charges_data
]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results

# การใช้
async def main():
charges_data = [
{'amount': 100000, 'currency': 'THB', 'token': 'tokn_test_1'},
{'amount': 200000, 'currency': 'THB', 'token': 'tokn_test_2'},
]
results = await process_multiple_charges(charges_data)

asyncio.run(main())

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

1. ใช้ตัวแปรสภาพแวดล้อมสำหรับ Keys

import os
from dotenv import load_dotenv

load_dotenv()

# แสดงข้อผิดพลาดหาก key หายไป
OMISE_SECRET_KEY = os.environ['OMISE_SECRET_KEY']
if not OMISE_SECRET_KEY:
raise ValueError("ตัวแปรสภาพแวดล้อม OMISE_SECRET_KEY ไม่ได้ถูกตั้งค่า")

omise.api_secret = OMISE_SECRET_KEY

2. จัดการ Idempotency

import uuid
import omise

def create_idempotent_charge(amount: int, currency: str, token: str, order_id: str):
"""สร้างค่าธรรมเนียมด้วย idempotency key"""
idempotency_key = f"order-{order_id}-{uuid.uuid4()}"

charge = omise.Charge.create(
amount=amount,
currency=currency,
card=token,
headers={'Idempotency-Key': idempotency_key}
)
return charge

3. ใช้ Connection Pooling

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

# กำหนดค่ากลยุทธ์การลองใหม่
retry_strategy = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE", "POST"],
backoff_factor=1
)

adapter = HTTPAdapter(max_retries=retry_strategy, pool_connections=10, pool_maxsize=10)
session = requests.Session()
session.mount("https://", adapter)

# ใช้ session แบบกำหนดเองกับ omise
omise.api_session = session

4. เก็บข้อมูลขั้นต่ำ

class Payment:
"""เก็บเฉพาะ ID ไม่ใช่ออบเจ็กต์ทั้งหมด"""

def __init__(self, charge_id: str):
self.charge_id = charge_id
self._charge = None

@property
def charge(self):
"""โหลดค่าธรรมเนียมแบบ lazy เมื่อจำเป็น"""
if self._charge is None and self.charge_id:
self._charge = omise.Charge.retrieve(self.charge_id)
return self._charge

def refresh(self):
"""รีเฟรชข้อมูลค่าธรรมเนียม"""
self._charge = None
return self.charge

5. ตรวจสอบความถูกต้องก่อนเรียก API

from decimal import Decimal

def validate_charge_params(amount: Decimal, currency: str):
"""ตรวจสอบพารามิเตอร์ค่าธรรมเนียมก่อนเรียก API"""
if amount < Decimal('20.00'):
raise ValueError("จำนวนเงินต้องไม่น้อยกว่า 20 บาท")

if currency not in ['THB', 'USD', 'SGD', 'JPY']:
raise ValueError(f"สกุลเงิน {currency} ไม่รองรับ")

return True

def create_validated_charge(amount: Decimal, currency: str, token: str):
"""สร้างค่าธรรมเนียมพร้อมการตรวจสอบความถูกต้อง"""
validate_charge_params(amount, currency)

charge = omise.Charge.create(
amount=int(amount * 100),
currency=currency,
card=token
)
return charge

6. ใช้งาน Logging

import logging
import omise

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def create_charge_with_logging(amount: int, currency: str, token: str):
"""สร้างค่าธรรมเนียมพร้อมการบันทึกล็อกที่ครอบคลุม"""
logger.info(f"กำลังสร้างค่าธรรมเนียม: amount={amount}, currency={currency}")

try:
charge = omise.Charge.create(
amount=amount,
currency=currency,
card=token
)
logger.info(f"สร้างค่าธรรมเนียมแล้ว: {charge.id}, paid={charge.paid}")
return charge

except omise.OmiseError as e:
logger.error(f"เรียกเก็บเงินล้มเหลว: {e}", exc_info=True)
raise

การทดสอบ

ตัวอย่าง Pytest

# test_payments.py
import pytest
import omise
from unittest.mock import patch, Mock

@pytest.fixture
def mock_charge():
"""ออบเจ็กต์ค่าธรรมเนียมจำลอง"""
charge = Mock()
charge.id = 'chrg_test_123'
charge.amount = 100000
charge.currency = 'THB'
charge.paid = True
charge.status = 'successful'
return charge

def test_create_charge(mock_charge):
"""ทดสอบการสร้างค่าธรรมเนียม"""
with patch('omise.Charge.create', return_value=mock_charge):
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123'
)

assert charge.id == 'chrg_test_123'
assert charge.paid is True

def test_create_charge_with_error():
"""ทดสอบการสร้างค่าธรรมเนียมที่มีข้อผิดพลาด"""
with patch('omise.Charge.create', side_effect=omise.CardError('insufficient_fund', 'Insufficient funds')):
with pytest.raises(omise.CardError) as exc_info:
omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123'
)

assert 'insufficient_fund' in str(exc_info.value)

@pytest.fixture
def payment_service():
"""Payment service fixture"""
return PaymentService()

def test_process_payment(payment_service, mock_charge):
"""ทดสอบการประมวลผลการชำระเงิน"""
with patch('omise.Charge.create', return_value=mock_charge):
result = payment_service.process_payment(
amount=1000.00,
token='tokn_test_123'
)

assert result['success'] is True
assert result['charge_id'] == 'chrg_test_123'

การใช้ VCR.py สำหรับการทดสอบ API

# test_integration.py
import pytest
import vcr
import omise

# กำหนดค่า VCR
my_vcr = vcr.VCR(
cassette_library_dir='tests/fixtures/vcr_cassettes',
record_mode='once',
filter_headers=['authorization'],
)

@my_vcr.use_cassette('create_charge.yaml')
def test_create_charge_integration():
"""การทดสอบการผสานรวมด้วย VCR"""
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123'
)

assert charge.paid is True
assert charge.amount == 100000

รูปแบบ Mock Decorator

from unittest.mock import patch
from functools import wraps

def mock_omise(func):
"""Decorator สำหรับจำลองการเรียก Omise API"""
@wraps(func)
def wrapper(*args, **kwargs):
with patch('omise.Charge.create') as mock_create:
mock_charge = Mock()
mock_charge.id = 'chrg_test_123'
mock_charge.paid = True
mock_create.return_value = mock_charge

return func(*args, **kwargs)
return wrapper

@mock_omise
def test_payment_flow():
"""ทดสอบการไหลของการชำระเงินด้วย decorator"""
charge = omise.Charge.create(amount=100000, currency='THB', card='tokn_test_123')
assert charge.paid is True

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

ข้อผิดพลาดใบรับรอง SSL

import certifi
import omise

# ใช้ certifi สำหรับการตรวจสอบ SSL
omise.ca_bundle = certifi.where()

# หรือปิดการตรวจสอบ SSL (ไม่แนะนำสำหรับการใช้งานจริง)
# omise.verify_ssl = False

หมดเวลาการเชื่อมต่อ

import omise

# ตั้งค่า timeout แบบกำหนดเอง (เป็นวินาที)
omise.timeout = 60

# หรือแบบแต่ละ request
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_123',
timeout=60
)

โหมดดีบัก

import logging
import omise

# เปิดใช้งานการบันทึกล็อกแบบดีบัก
logging.basicConfig(level=logging.DEBUG)
omise.debug = True

# สิ่งนี้จะแสดงผล:
# - URL และ method ของ request
# - Headers ของ request
# - Body ของ request
# - สถานะของ response
# - Body ของ response

การตรวจสอบลายเซ็นเว็บฮุก

import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
"""ตรวจสอบลายเซ็น webhook"""
expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()

return hmac.compare_digest(signature, expected_signature)

# ตัวอย่าง Flask
@app.route('/webhooks/omise', methods=['POST'])
def omise_webhook():
"""จัดการ Omise webhook"""
payload = request.get_data()
signature = request.headers.get('Omise-Signature')

if not verify_webhook_signature(payload, signature, os.environ['OMISE_WEBHOOK_SECRET']):
return {'error': 'Invalid signature'}, 401

event = request.get_json()
# ประมวลผล event
return {'status': 'ok'}

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

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

# views.py
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json
import hmac
import hashlib

@csrf_exempt
def omise_webhook(request):
"""จัดการ Omise webhook"""
if request.method != 'POST':
return JsonResponse({'error': 'ไม่อนุญาตให้ใช้เมธอดนี้'}, status=405)

# ตรวจสอบลายเซ็น
payload = request.body
signature = request.headers.get('Omise-Signature')

expected_signature = hmac.new(
settings.OMISE_WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()

if not hmac.compare_digest(signature, expected_signature):
return JsonResponse({'error': 'ลายเซ็นไม่ถูกต้อง'}, status=401)

# ประมวลผล event
event = json.loads(payload)

if event['key'] == 'charge.complete':
handle_charge_complete(event['data'])
elif event['key'] == 'refund.create':
handle_refund_create(event['data'])

return JsonResponse({'status': 'ok'})

def handle_charge_complete(charge_data):
"""จัดการการเรียกเก็บเงินที่เสร็จสมบูรณ์"""
charge = omise.Charge.retrieve(charge_data['id'])
payment = Payment.objects.get(charge_id=charge.id)
payment.status = charge.status
payment.paid = charge.paid
payment.save()

ฉันจะทดสอบการชำระเงินโดยไม่มีการเรียกเก็บเงินจริงได้อย่างไร?

import os
import omise

# ใช้ API keys แบบทดสอบ
omise.api_secret = 'skey_test_123456789'

# ใช้ card tokens แบบทดสอบ
# สำเร็จ: tokn_test_5086xl7ddjbases4sq3i
# ปฏิเสธ: tokn_test_no1

# สร้างค่าธรรมเนียมทดสอบ
charge = omise.Charge.create(
amount=100000,
currency='THB',
card='tokn_test_5086xl7ddjbases4sq3i'
)

# ตรวจสอบโหมดทดสอบ
print(f"โหมดทดสอบ: {not charge.livemode}")

ฉันจะจัดการการแปลงสกุลเงินได้อย่างไร?

from decimal import Decimal

class Payment:
"""การชำระเงินพร้อมการแปลงสกุลเงิน"""

def __init__(self, amount_baht: Decimal):
self.amount_baht = amount_baht

@property
def amount_satang(self) -> int:
"""แปลงบาทเป็นสตางค์"""
return int(self.amount_baht * 100)

@staticmethod
def from_satang(amount_satang: int) -> 'Payment':
"""สร้างการชำระเงินจากสตางค์"""
amount_baht = Decimal(amount_satang) / 100
return Payment(amount_baht)

# การใช้
payment = Payment(Decimal('1000.00')) # 1000.00 บาท
charge = omise.Charge.create(
amount=payment.amount_satang, # 100000 สตางค์
currency='THB',
card='tokn_test_123'
)

ฉันจะใช้งานตรรกะการลองใหม่ได้อย่างไร?

import time
from typing import Optional
import omise
from omise.errors import ConnectionError

def create_charge_with_retry(
amount: int,
currency: str,
token: str,
max_retries: int = 3
) -> Optional[omise.Charge]:
"""สร้างค่าธรรมเนียมพร้อมการลองใหม่แบบ exponential backoff"""
for attempt in range(max_retries):
try:
charge = omise.Charge.create(
amount=amount,
currency=currency,
card=token
)
return charge

except ConnectionError as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # 1, 2, 4 วินาที
time.sleep(wait_time)
else:
raise

# หรือใช้ไลบรารี tenacity
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def create_charge_tenacity(amount: int, currency: str, token: str):
"""สร้างค่าธรรมเนียมพร้อมการลองใหม่ด้วย tenacity"""
return omise.Charge.create(amount=amount, currency=currency, card=token)

ฉันจะจัดการการคืนเงินบางส่วนได้อย่างไร?

import omise

def refund_charge(charge_id: str, refund_amount: float = None):
"""คืนเงินค่าธรรมเนียม (บางส่วนหรือเต็มจำนวน)"""
# รับข้อมูลค่าธรรมเนียมปัจจุบัน
charge = omise.Charge.retrieve(charge_id)

# คำนวณจำนวนเงินที่สามารถคืนได้
refundable = charge.amount - charge.refunded

if refund_amount:
refund_amount_satang = int(refund_amount * 100)
if refund_amount_satang > refundable:
raise ValueError(f"จำนวนเงินที่คืนเกินจำนวนที่สามารถคืนได้: {refundable / 100}")
else:
refund_amount_satang = None # คืนเงินเต็มจำนวน

# สร้างการคืนเงิน
refund = omise.Refund.create(
charge=charge_id,
amount=refund_amount_satang
)

return refund

# การใช้
refund = refund_charge('chrg_test_123', refund_amount=250.00)

ฉันจะบันทึกบัตรหลายใบสำหรับลูกค้าได้อย่างไร?

import omise

def add_card_to_customer(customer_id: str, token: str) -> omise.Card:
"""เพิ่มบัตรให้กับลูกค้า"""
customer = omise.Customer.retrieve(customer_id)
customer.update(card=token)
return customer.default_card

def list_customer_cards(customer_id: str):
"""แสดงรายการบัตรทั้งหมดของลูกค้า"""
customer = omise.Customer.retrieve(customer_id)
return list(customer.cards)

def charge_specific_card(customer_id: str, card_id: str, amount: int):
"""เรียกเก็บเงินจากบัตรที่เฉพาะเจาะจง"""
charge = omise.Charge.create(
amount=amount,
currency='THB',
customer=customer_id,
card=card_id # ID บัตรที่เฉพาะเจาะจง
)
return charge

ฉันจะใช้งานการเรียกเก็บเงินแบบสมาชิกได้อย่างไร?

from datetime import datetime, timedelta
import omise

class SubscriptionManager:
"""จัดการการเรียกเก็บเงินแบบสมาชิก"""

def __init__(self, customer_id: str, plan_amount: int):
self.customer_id = customer_id
self.plan_amount = plan_amount

def charge_monthly(self) -> omise.Charge:
"""เรียกเก็บเงินสมาชิกรายเดือน"""
charge = omise.Charge.create(
amount=self.plan_amount,
currency='THB',
customer=self.customer_id,
description=f"สมาชิก {datetime.now().strftime('%B %Y')}"
)
return charge

def handle_failed_payment(self, charge: omise.Charge):
"""จัดการการชำระเงินสมาชิกที่ล้มเหลว"""
# ส่งการแจ้งเตือน
# อัปเดตสถานะสมาชิก
# ลองใหม่หลังจากช่วงเวลาผ่อนผัน
pass

# การใช้กับ Celery
from celery import shared_task

@shared_task
def charge_subscriptions():
"""เรียกเก็บเงินสมาชิกที่ใช้งานอยู่ทั้งหมด"""
from myapp.models import Subscription

subscriptions = Subscription.objects.filter(status='active')

for subscription in subscriptions:
manager = SubscriptionManager(
subscription.customer_id,
subscription.plan_amount
)
try:
charge = manager.charge_monthly()
subscription.last_charge_date = datetime.now()
subscription.save()
except omise.CardError as e:
manager.handle_failed_payment(charge)

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

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

การสนับสนุน

หากคุณพบปัญหากับไลบรารี Python:

  1. ตรวจสอบ GitHub Issues
  2. ตรวจสอบ เอกสาร API
  3. ติดต่อ support@omise.co พร้อม:
    • เวอร์ชัน Python
    • เวอร์ชันไลบรารี omise-python
    • ข้อความข้อผิดพลาดและ traceback
    • ขั้นตอนในการสร้างซ้ำ