@sahabaplus/moyasar
Version:
A comprehensive TypeScript SDK for integrating with the Moyasar payment gateway
277 lines • 9.16 kB
JavaScript
import { API_ENDPOINTS } from "../../shared/constants/index";
import { PaymentStatus } from "./enums";
import { PaymentUtils } from "./utils";
import { PaymentError } from "./errors";
import { MoyasarError } from "../../shared/errors";
export class PaymentService {
constructor(p) {
this.apiClient = p.apiClient;
}
/**
* Create a new payment
*/
async create(params) {
// Validate input
const validation = PaymentUtils.validateCreatePaymentRequest(params);
if (!validation.success) {
throw new PaymentError(`Validation failed: ${validation.errors.join(", ")}`, 400);
}
try {
const response = await this.apiClient.request({
method: "POST",
url: API_ENDPOINTS.payments,
data: params,
});
return PaymentUtils.parsePayment(response);
}
catch (error) {
const paymentError = this.handleError(error, `Failed to create payment`);
throw paymentError;
}
}
/**
* List payments with optional filtering
*/
async list(options = {}) {
try {
// Convert metadata filters to proper query format
const queryParams = this.parseBody(options);
const response = await this.apiClient.request({
method: "GET",
url: API_ENDPOINTS.payments,
params: queryParams,
});
const parsed = PaymentUtils.parseListPaymentsResponse(response);
return parsed;
}
catch (error) {
const paymentError = this.handleError(error, "Failed to list payments");
throw paymentError;
}
}
/**
* Retrieve a specific payment
*/
async retrieve(paymentId) {
if (!paymentId)
throw new PaymentError("Payment ID is required", 400);
try {
const response = await this.apiClient.request({
method: "GET",
url: `${API_ENDPOINTS.payments}/${paymentId}`,
});
// Parse and validate the response
const payment = PaymentUtils.parsePayment(response);
return payment;
}
catch (error) {
const paymentError = this.handleError(error, `Failed to retrieve payment ${paymentId}`);
throw paymentError;
}
}
/**
* Update a payment
*/
async update({ paymentId, update, }) {
if (!paymentId) {
throw new PaymentError("Payment ID is required", 400);
}
// Validate input
const validation = PaymentUtils.validateUpdatePaymentRequest(update);
if (!validation.success) {
throw new PaymentError(`Validation failed: ${validation.errors.join(", ")}`, 400);
}
try {
const response = await this.apiClient.request({
method: "PUT",
url: `${API_ENDPOINTS.payments}/${paymentId}`,
data: update,
});
return response;
}
catch (error) {
const paymentError = this.handleError(error, `Failed to update payment ${paymentId}`);
throw paymentError;
}
}
/**
* Refund a payment (full or partial)
*/
async refund({ paymentId, refund, }) {
if (!paymentId) {
throw new PaymentError("Payment ID is required", 400);
}
refund.amount;
// Validate input
const validation = PaymentUtils.validateRefundRequest(refund);
if (!validation.success) {
throw new PaymentError(`Validation failed: ${validation.errors.join(", ")}`, 400);
}
try {
const response = await this.apiClient.request({
method: "POST",
url: `${API_ENDPOINTS.payments}/${paymentId}/refund`,
data: refund,
});
// Parse and validate the response
const payment = PaymentUtils.parsePayment(response);
return payment;
}
catch (error) {
const paymentError = this.handleError(error, `Failed to refund payment ${paymentId}`);
throw paymentError;
}
}
/**
* Capture an authorized payment (full or partial)
*/
async capture({ paymentId, capture, }) {
if (!paymentId)
throw new PaymentError("Payment ID is required", 400);
// Validate input
const validation = PaymentUtils.validateCaptureRequest(capture);
if (!validation.success) {
throw new PaymentError(`Validation failed: ${validation.errors}`, 400, {
errors: validation.errors,
});
}
try {
const response = await this.apiClient.request({
method: "POST",
url: `${API_ENDPOINTS.payments}/${paymentId}/capture`,
data: capture,
});
// Parse and validate the response
const payment = PaymentUtils.parsePayment(response);
return payment;
}
catch (error) {
const paymentError = this.handleError(error, `Failed to capture payment ${paymentId}`);
throw paymentError;
}
}
/**
* Void an authorized payment
*/
async void(paymentId) {
if (!paymentId)
throw new PaymentError("Payment ID is required", 400);
try {
const response = await this.apiClient.request({
method: "POST",
url: `${API_ENDPOINTS.payments}/${paymentId}/void`,
});
// Parse and validate the response
const payment = PaymentUtils.parsePayment(response);
return payment;
}
catch (error) {
const paymentError = this.handleError(error, `Failed to void payment ${paymentId}`);
throw paymentError;
}
}
/**
* Search payments by metadata
*/
async searchByMetadata({ metadata, options, }) {
const metadataQuery = PaymentUtils.buildMetadataQuery(metadata);
return this.list({
...options,
...metadataQuery,
});
}
/**
* Get payments by status
*/
async getByStatus(status, options = {}) {
return this.list({
...options,
status,
});
}
/**
* Get paid payments
*/
async getPaid(options = {}) {
return this.getByStatus(PaymentStatus.PAID, options);
}
/**
* Get failed payments
*/
async getFailed(options = {}) {
return this.getByStatus(PaymentStatus.FAILED, options);
}
/**
* Get authorized payments
*/
async getAuthorized(options = {}) {
return this.getByStatus(PaymentStatus.AUTHORIZED, options);
}
/**
* Get refunded payments
*/
async getRefunded(options = {}) {
return this.getByStatus(PaymentStatus.REFUNDED, options);
}
/**
* Get payments by card last 4 digits
*/
async getByCardLast4({ last4, options, }) {
if (!/^\d{4}$/.test(last4)) {
throw new PaymentError("Last 4 digits must be exactly 4 digits", 400);
}
return this.list({
...options,
last_4: last4,
});
}
/**
* Get payments by RRN (Retrieval Reference Number)
*/
async getByRRN({ rrn, options, }) {
if (!/^\d{12}$/.test(rrn)) {
throw new PaymentError("RRN must be exactly 12 digits", 400);
}
return this.list({
...options,
rrn,
});
}
/**
* Check payment capabilities (what actions can be performed)
*/
async getPaymentCapabilities(paymentId) {
const payment = await this.retrieve(paymentId);
return {
canRefund: PaymentUtils.canRefundPayment(payment),
canCapture: PaymentUtils.canCapturePayment(payment),
canVoid: PaymentUtils.canVoidPayment(payment),
maxRefundAmount: PaymentUtils.getMaxRefundAmount(payment),
maxCaptureAmount: PaymentUtils.getMaxCaptureAmount(payment),
};
}
handleError(error, message) {
if (error instanceof PaymentError)
return error;
if (error instanceof MoyasarError) {
return new PaymentError(`${message}: ${error.message}`, error.statusCode, { ...error.details });
}
const errorMessage = error?.message || error?.toString() || "Unknown error";
return new PaymentError(`${message}: ${errorMessage}`, 500, {
cause: errorMessage,
});
}
parseBody(p) {
const copied = { ...p };
Object.entries(copied).forEach(([key, value]) => {
if (typeof value === "object") {
if (value instanceof Date) {
// @ts-expect-error
copied[key] = value.toISOString();
}
}
});
return copied;
}
}
//# sourceMappingURL=service.js.map