@nehorai/payments-il 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -576,7 +576,11 @@ var CardcomWebhookHandler = class {
576
576
  const amountMinor = Math.round(amountMajor * 100);
577
577
  const parsed = {
578
578
  provider: "cardcom",
579
- eventId: `${lowProfileCode}_${internalDealNumber}_${Date.now()}`,
579
+ // Stable id (deal identifier + event type) so redelivered callbacks
580
+ // dedupe via the webhook_events (provider, provider_event_id) unique
581
+ // constraint. Never include a timestamp here — that would defeat
582
+ // idempotency and risk granting credits twice.
583
+ eventId: `${lowProfileCode || internalDealNumber}:${eventType}`,
580
584
  eventType,
581
585
  providerTransactionId: internalDealNumber || lowProfileCode,
582
586
  timestamp: /* @__PURE__ */ new Date(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/cardcom/index.ts","../../src/providers/cardcom/cardcom-provider.ts","../../src/providers/cardcom/cardcom-types.ts","../../src/providers/cardcom/cardcom-webhook-handler.ts"],"sourcesContent":["/**\r\n * Cardcom Provider Exports\r\n */\r\n\r\n// Provider and webhook handler\r\nexport { CardcomProvider, type CardcomProviderConfig } from './cardcom-provider.js';\r\nexport { CardcomWebhookHandler } from './cardcom-webhook-handler.js';\r\n\r\n// Types\r\nexport type {\r\n CardcomConfig,\r\n CardcomLowProfileRequest,\r\n CardcomLowProfileResponse,\r\n CardcomLowProfileStatusRequest,\r\n CardcomLowProfileStatusResponse,\r\n CardcomDirectChargeRequest,\r\n CardcomDirectChargeResponse,\r\n CardcomRefundRequest,\r\n CardcomRefundResponse,\r\n CardcomWebhookParams,\r\n CardcomWebhookEventType,\r\n} from './cardcom-types.js';\r\n\r\nexport {\r\n CardcomOperation,\r\n CardcomTransactionType,\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n CARDCOM_RESPONSE_CODE_MAP,\r\n CARDCOM_CURRENCY_CODES,\r\n CARDCOM_LANGUAGE_CODES,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n getCurrencyCode,\r\n} from './cardcom-types.js';\r\n\r\n// Webhook utilities\r\nexport {\r\n validateCardcomCallback,\r\n parseCardcomCallbackUrl,\r\n isCardcomCallbackSuccess,\r\n isCardcomCallbackAuthorized,\r\n getCardcomCallbackError,\r\n} from './cardcom-webhook-handler.js';\r\n","/**\r\n * Cardcom Provider Implementation\r\n *\r\n * Implements IPaymentProvider for Cardcom payment gateway (Israeli market).\r\n * Uses Low Profile (hosted page) for PCI compliance and direct API for operations.\r\n * Supports Two-Phase Commit (J5) with SuspendDealOnly operation.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport * as crypto from 'crypto';\r\nimport type {\r\n PaymentProvider,\r\n CreatePaymentIntentParams,\r\n PaymentIntentResult,\r\n AuthorizePaymentParams,\r\n AuthorizationResult,\r\n CapturePaymentParams,\r\n CaptureResult,\r\n VoidPaymentParams,\r\n VoidResult,\r\n RefundParams,\r\n RefundResult,\r\n ProviderHealthStatus,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IPaymentProvider,\r\n SavePaymentMethodParams,\r\n SavePaymentMethodResult,\r\n DeletePaymentMethodResult,\r\n CreateSetupIntentParams,\r\n SetupIntentResult,\r\n CreateCustomerParams,\r\n CreateCustomerResult,\r\n} from '@nehorai/payments/providers';\r\nimport { calculateCaptureDeadline } from '@nehorai/payments/types';\r\nimport {\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CardcomOperation,\r\n getCurrencyCode,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n type CardcomLowProfileRequest,\r\n type CardcomLowProfileResponse,\r\n type CardcomLowProfileStatusResponse,\r\n type CardcomRefundRequest,\r\n type CardcomRefundResponse,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom provider constructor config\r\n */\r\nexport interface CardcomProviderConfig {\r\n terminalNumber: string;\r\n apiName: string;\r\n apiPassword: string;\r\n webhookSecret?: string;\r\n}\r\n\r\n/**\r\n * Cardcom Payment Provider\r\n *\r\n * Full implementation of IPaymentProvider for Cardcom.\r\n */\r\nexport class CardcomProvider implements IPaymentProvider {\r\n readonly name: PaymentProvider = 'cardcom';\r\n readonly supportedCurrencies = CARDCOM_SUPPORTED_CURRENCIES;\r\n readonly supportsRecurring = true;\r\n readonly supportsSplitPayments = false;\r\n\r\n private config: CardcomProviderConfig;\r\n\r\n constructor(config: CardcomProviderConfig) {\r\n if (!config.terminalNumber || !config.apiName || !config.apiPassword) {\r\n throw new Error(\r\n 'CardcomProvider requires terminalNumber, apiName, and apiPassword in config'\r\n );\r\n }\r\n this.config = config;\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Intent Operations\r\n // ==========================================================================\r\n\r\n async createPaymentIntent(\r\n params: CreatePaymentIntentParams\r\n ): Promise<PaymentIntentResult> {\r\n try {\r\n const amountMajor = params.amount.amountMinor / 100;\r\n\r\n const operation =\r\n params.captureMethod === 'manual'\r\n ? CardcomOperation.SUSPEND_DEAL_ONLY\r\n : params.metadata?.savePaymentMethod\r\n ? CardcomOperation.BILL_AND_CREATE_TOKEN\r\n : CardcomOperation.BILL_ONLY;\r\n\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: amountMajor,\r\n CoinID: getCurrencyCode(params.amount.currency),\r\n Operation: operation,\r\n Language: 'en',\r\n ReturnUrl: params.returnUrl,\r\n ErrorUrl: params.returnUrl,\r\n ProductName: params.description ?? 'Payment',\r\n InternalDealNumber: params.idempotencyKey,\r\n SendEmail: false,\r\n };\r\n\r\n if (params.metadata?.customerName) {\r\n request.CustomerName = String(params.metadata.customerName);\r\n }\r\n if (params.metadata?.customerEmail) {\r\n request.Email = String(params.metadata.customerEmail);\r\n }\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n errorCode: String(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerIntentId: response.LowProfileCode!,\r\n redirectUrl: response.PaymentUrl,\r\n status: 'created',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async authorize(params: AuthorizePaymentParams): Promise<AuthorizationResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to check payment status',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n authorizationCode: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'authorized',\r\n captureDeadline: calculateCaptureDeadline(new Date()),\r\n };\r\n }\r\n\r\n if (status.DealResponse === 2) {\r\n return {\r\n success: false,\r\n error: 'Payment declined',\r\n status: 'failed',\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not yet completed',\r\n status: 'pending_authorization',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async capture(params: CapturePaymentParams): Promise<CaptureResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to capture payment',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n providerTransactionId: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'captured',\r\n capturedAmount: {\r\n amountMinor: Math.round((status.Amount ?? 0) * 100),\r\n currency: status.Currency ?? params.amount?.currency ?? 'ILS',\r\n },\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not authorized for capture',\r\n status: mapCardcomDealResponseToStatus(status.DealResponse ?? 3),\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async void(_params: VoidPaymentParams): Promise<VoidResult> {\r\n return {\r\n success: false,\r\n error: 'Void operation not supported via API. Please use Cardcom merchant dashboard.',\r\n };\r\n }\r\n\r\n async refund(params: RefundParams): Promise<RefundResult> {\r\n try {\r\n const refundAmount = params.amount\r\n ? params.amount.amountMinor / 100\r\n : undefined;\r\n\r\n if (!refundAmount) {\r\n return {\r\n success: false,\r\n error: 'Refund amount is required',\r\n };\r\n }\r\n\r\n const request: CardcomRefundRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n InternalDealNumber: params.providerTransactionId,\r\n Amount: refundAmount,\r\n CoinID: params.amount ? getCurrencyCode(params.amount.currency) : 1,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomRefundResponse>(\r\n CARDCOM_ENDPOINTS.REFUND,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerRefundId: response.InternalDealNumber ?? params.providerTransactionId,\r\n refundedAmount: {\r\n amountMinor: Math.round((response.Amount ?? 0) * 100),\r\n currency: params.amount?.currency ?? 'ILS',\r\n },\r\n status: 'succeeded',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Method Tokenization\r\n // ==========================================================================\r\n\r\n async createSetupIntent(\r\n params: CreateSetupIntentParams\r\n ): Promise<SetupIntentResult> {\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 0,\r\n Operation: CardcomOperation.CREATE_TOKEN_ONLY,\r\n Language: 'en',\r\n InternalDealNumber: `setup_${params.userId}_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n setupIntentId: response.LowProfileCode!,\r\n clientSecret: response.PaymentUrl,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async savePaymentMethod(\r\n params: SavePaymentMethodParams\r\n ): Promise<SavePaymentMethodResult> {\r\n try {\r\n const lowProfileCode = params.setupData.lowProfileCode as string;\r\n\r\n if (!lowProfileCode) {\r\n return {\r\n success: false,\r\n error: 'Low profile code is required',\r\n };\r\n }\r\n\r\n const statusResponse = await this.getLowProfileStatus(lowProfileCode);\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to retrieve payment method',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (!status.Token) {\r\n return {\r\n success: false,\r\n error: 'No token created',\r\n };\r\n }\r\n\r\n const [expMonth, expYear] = (status.CardExpiration ?? '/').split('/');\r\n\r\n return {\r\n success: true,\r\n paymentMethodId: status.Token,\r\n cardBrand: status.CardType ?? 'unknown',\r\n cardLast4: status.CardMask?.slice(-4),\r\n cardExpMonth: expMonth?.padStart(2, '0'),\r\n cardExpYear: expYear ? `20${expYear}` : undefined,\r\n cardBin: status.CardBin,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async deletePaymentMethod(\r\n _paymentMethodId: string\r\n ): Promise<DeletePaymentMethodResult> {\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n // ==========================================================================\r\n // Customer Management\r\n // ==========================================================================\r\n\r\n async createCustomer(params: CreateCustomerParams): Promise<CreateCustomerResult> {\r\n return {\r\n success: true,\r\n customerId: params.userId,\r\n };\r\n }\r\n\r\n async getOrCreateCustomer(\r\n userId: string,\r\n email: string\r\n ): Promise<CreateCustomerResult> {\r\n return this.createCustomer({ userId, email });\r\n }\r\n\r\n // ==========================================================================\r\n // Health & Status\r\n // ==========================================================================\r\n\r\n async getHealth(): Promise<ProviderHealthStatus> {\r\n const start = Date.now();\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 1,\r\n Operation: CardcomOperation.BILL_ONLY,\r\n InternalDealNumber: `health_check_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n const healthy = response.ResponseCode === 0 || response.ResponseCode === 1;\r\n\r\n return {\r\n provider: 'cardcom',\r\n healthy,\r\n lastChecked: new Date(),\r\n avgLatencyMs: Date.now() - start,\r\n circuitBreakerOpen: false,\r\n };\r\n } catch {\r\n return {\r\n provider: 'cardcom',\r\n healthy: false,\r\n lastChecked: new Date(),\r\n circuitBreakerOpen: false,\r\n };\r\n }\r\n }\r\n\r\n validateWebhookSignature(payload: string, signature: string): boolean {\r\n if (!this.config.webhookSecret) {\r\n return false;\r\n }\r\n\r\n try {\r\n const expectedSignature = crypto\r\n .createHmac('sha256', this.config.webhookSecret)\r\n .update(payload)\r\n .digest('hex');\r\n\r\n return crypto.timingSafeEqual(\r\n Buffer.from(signature),\r\n Buffer.from(expectedSignature)\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getPaymentIntentStatus(\r\n providerIntentId: string\r\n ): Promise<{ status: string; error?: string }> {\r\n try {\r\n const result = await this.getLowProfileStatus(providerIntentId);\r\n\r\n if (!result.success || !result.data) {\r\n return {\r\n status: 'unknown',\r\n error: result.error,\r\n };\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(\r\n result.data.DealResponse ?? 0\r\n );\r\n\r\n return { status };\r\n } catch (error) {\r\n return {\r\n status: 'unknown',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Helper Methods\r\n // ==========================================================================\r\n\r\n private async makeRequest<T>(\r\n endpoint: string,\r\n data: Record<string, unknown>\r\n ): Promise<T> {\r\n const url = `${CARDCOM_API_BASE}${endpoint}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Cardcom API error: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n private async getLowProfileStatus(\r\n lowProfileCode: string\r\n ): Promise<{\r\n success: boolean;\r\n data?: CardcomLowProfileStatusResponse;\r\n error?: string;\r\n }> {\r\n try {\r\n const params = new URLSearchParams({\r\n terminalnumber: this.config.terminalNumber,\r\n lowprofilecode: lowProfileCode,\r\n username: this.config.apiName,\r\n });\r\n\r\n const url = `${CARDCOM_API_BASE}${CARDCOM_ENDPOINTS.LOW_PROFILE_STATUS}?${params}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n });\r\n\r\n if (!response.ok) {\r\n return {\r\n success: false,\r\n error: `Status check failed: ${response.status}`,\r\n };\r\n }\r\n\r\n const data = (await response.json()) as CardcomLowProfileStatusResponse;\r\n\r\n if (data.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(data.ResponseCode),\r\n };\r\n }\r\n\r\n return { success: true, data };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Status check failed',\r\n };\r\n }\r\n }\r\n\r\n private handleError(error: unknown): {\r\n success: false;\r\n error: string;\r\n errorCode?: string;\r\n } {\r\n const errorMessage =\r\n error instanceof Error ? error.message : 'Unknown error occurred';\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n };\r\n }\r\n}\r\n","/**\r\n * Cardcom Type Definitions\r\n *\r\n * Type definitions for Cardcom payment gateway API v11.\r\n * Supports JSON API endpoints for Low Profile (hosted page) and direct transactions.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport type { TransactionStatus } from '@nehorai/payments/types';\r\n\r\n// ============================================================================\r\n// API Configuration\r\n// ============================================================================\r\n\r\nexport const CARDCOM_API_BASE = 'https://secure.cardcom.solutions';\r\n\r\nexport const CARDCOM_ENDPOINTS = {\r\n LOW_PROFILE_CREATE: '/api/v11/LowProfile/Create',\r\n LOW_PROFILE_STATUS: '/Interface/BillGoldGetLowProfileIndicator.aspx',\r\n DIRECT_CHARGE: '/api/v11/Transactions/Transaction',\r\n REFUND: '/api/v11/Transactions/RefundByTransactionId',\r\n} as const;\r\n\r\nexport const CARDCOM_SUPPORTED_CURRENCIES = ['ILS', 'USD', 'EUR', 'GBP'] as const;\r\n\r\nexport const CARDCOM_API_VERSION = 'v11';\r\n\r\n// ============================================================================\r\n// Cardcom Configuration\r\n// ============================================================================\r\n\r\nexport interface CardcomConfig {\r\n /** Terminal number (merchant ID) */\r\n terminalNumber: string;\r\n /** API username */\r\n apiName: string;\r\n /** API password */\r\n apiPassword: string;\r\n /** Webhook secret for signature validation */\r\n webhookSecret?: string;\r\n /** Environment (sandbox uses same endpoints but different credentials) */\r\n environment: 'sandbox' | 'production';\r\n}\r\n\r\n// ============================================================================\r\n// Operation Types\r\n// ============================================================================\r\n\r\nexport enum CardcomOperation {\r\n /** Charge immediately */\r\n BILL_ONLY = 1,\r\n /** Charge + save card token */\r\n BILL_AND_CREATE_TOKEN = 2,\r\n /** Save card without charging */\r\n CREATE_TOKEN_ONLY = 3,\r\n /** Authorize without capture (J5) */\r\n SUSPEND_DEAL_ONLY = 4,\r\n}\r\n\r\nexport enum CardcomTransactionType {\r\n REGULAR = 1,\r\n CREDIT = 2,\r\n INSTALLMENTS = 3,\r\n}\r\n\r\n// ============================================================================\r\n// Request Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n Sum: number;\r\n CoinID?: number;\r\n Operation?: CardcomOperation;\r\n Language?: string;\r\n ReturnUrl?: string;\r\n ErrorUrl?: string;\r\n ProductName?: string;\r\n CustomerName?: string;\r\n Email?: string;\r\n InvoiceLanguage?: string;\r\n SendEmail?: boolean;\r\n IndicatorUrl?: string;\r\n InternalDealNumber?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusRequest {\r\n terminalnumber: string;\r\n lowprofilecode: string;\r\n username: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n CardNumber: string;\r\n CVV: string;\r\n Year: string;\r\n Month: string;\r\n CardOwnerID: string;\r\n Sum: number;\r\n CoinID?: number;\r\n NumOfPayments?: number;\r\n Operation?: CardcomOperation;\r\n Token?: string;\r\n}\r\n\r\nexport interface CardcomRefundRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n InternalDealNumber: string;\r\n Amount: number;\r\n CoinID?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Response Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n LowProfileCode?: string;\r\n PaymentUrl?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n DealResponse?: number;\r\n OperationResponse?: number;\r\n InternalDealNumber?: string;\r\n Token?: string;\r\n CardMask?: string;\r\n CardType?: string;\r\n CardExpiration?: string;\r\n Amount?: number;\r\n Currency?: string;\r\n CardBin?: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n ApprovalNumber?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomRefundResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n Amount?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Webhook Types\r\n// ============================================================================\r\n\r\nexport interface CardcomWebhookParams {\r\n ResponseCode?: string;\r\n LowProfileCode?: string;\r\n DealResponse?: string;\r\n OperationResponse?: string;\r\n InternalDealNumber?: string;\r\n Amount?: string;\r\n Currency?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n}\r\n\r\nexport const CARDCOM_WEBHOOK_EVENTS = [\r\n 'payment.completed',\r\n 'payment.declined',\r\n 'payment.authorized',\r\n] as const;\r\n\r\nexport type CardcomWebhookEventType = (typeof CARDCOM_WEBHOOK_EVENTS)[number];\r\n\r\nexport const CARDCOM_DEAL_RESPONSE_ACTIONS: Record<number, string> = {\r\n 0: 'pending',\r\n 1: 'approved',\r\n 2: 'declined',\r\n 3: 'error',\r\n};\r\n\r\n// ============================================================================\r\n// Response Code Mapping\r\n// ============================================================================\r\n\r\nexport const CARDCOM_RESPONSE_CODE_MAP: Record<number, TransactionStatus> = {\r\n 0: 'created',\r\n 1: 'failed',\r\n 2: 'failed',\r\n 3: 'failed',\r\n 4: 'failed',\r\n 5: 'failed',\r\n 6: 'failed',\r\n 7: 'failed',\r\n 8: 'failed',\r\n 9: 'failed',\r\n 10: 'failed',\r\n};\r\n\r\nexport function mapCardcomDealResponseToStatus(\r\n dealResponse: number\r\n): TransactionStatus {\r\n switch (dealResponse) {\r\n case 0:\r\n return 'pending_authorization';\r\n case 1:\r\n return 'captured';\r\n case 2:\r\n return 'failed';\r\n case 3:\r\n return 'failed';\r\n default:\r\n return 'failed';\r\n }\r\n}\r\n\r\nexport function mapCardcomError(responseCode: number): string {\r\n const errorMessages: Record<number, string> = {\r\n 0: 'Success',\r\n 1: 'General error',\r\n 2: 'Invalid API credentials',\r\n 3: 'Invalid terminal number',\r\n 4: 'Invalid operation type',\r\n 5: 'Invalid card details',\r\n 6: 'Card declined by issuer',\r\n 7: 'Insufficient funds',\r\n 8: 'Invalid amount',\r\n 9: 'Transaction not found',\r\n 10: 'Duplicate transaction',\r\n 11: 'Terminal not active',\r\n 12: 'CVV validation failed',\r\n 13: 'Card expired',\r\n 14: 'Invalid currency',\r\n 15: 'Operation not supported',\r\n };\r\n\r\n return errorMessages[responseCode] ?? `Error code ${responseCode}`;\r\n}\r\n\r\nexport const CARDCOM_CURRENCY_CODES: Record<string, number> = {\r\n ILS: 1,\r\n USD: 2,\r\n EUR: 3,\r\n GBP: 4,\r\n};\r\n\r\nexport function getCurrencyCode(currency: string): number {\r\n return CARDCOM_CURRENCY_CODES[currency.toUpperCase()] ?? 1;\r\n}\r\n\r\nexport const CARDCOM_LANGUAGE_CODES = {\r\n en: 'en',\r\n he: 'he',\r\n} as const;\r\n","/**\r\n * Cardcom Webhook Handler\r\n *\r\n * Processes incoming Cardcom webhooks with idempotency.\r\n * Maps Cardcom callback events to transaction status updates.\r\n *\r\n * Cardcom uses GET callback parameters instead of POST webhooks.\r\n * Parameters are sent to ReturnUrl after payment completion.\r\n */\r\n\r\nimport type {\r\n PaymentProvider,\r\n TransactionStatus,\r\n WebhookProcessingResult,\r\n ReconciliationResult,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IWebhookHandler,\r\n ParsedWebhookEvent,\r\n ParseWebhookResult,\r\n} from '@nehorai/payments/providers';\r\nimport {\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n mapCardcomDealResponseToStatus,\r\n type CardcomWebhookEventType,\r\n type CardcomWebhookParams,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom Webhook Handler Implementation\r\n */\r\nexport class CardcomWebhookHandler implements IWebhookHandler {\r\n readonly provider: PaymentProvider = 'cardcom';\r\n readonly supportedEventTypes = CARDCOM_WEBHOOK_EVENTS;\r\n\r\n parseEvent(rawPayload: Record<string, unknown>): ParseWebhookResult {\r\n try {\r\n const params = rawPayload as unknown as CardcomWebhookParams;\r\n\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n const lowProfileCode = params.LowProfileCode ?? '';\r\n const internalDealNumber = params.InternalDealNumber ?? '';\r\n\r\n if (!lowProfileCode && !internalDealNumber) {\r\n return {\r\n success: false,\r\n error: 'Missing LowProfileCode or InternalDealNumber in callback',\r\n };\r\n }\r\n\r\n let eventType: CardcomWebhookEventType;\r\n if (dealResponse === 1) {\r\n eventType = 'payment.completed';\r\n } else if (dealResponse === 2) {\r\n eventType = 'payment.declined';\r\n } else if (dealResponse === 0 && responseCode === 0) {\r\n eventType = 'payment.authorized';\r\n } else {\r\n eventType = 'payment.declined';\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(dealResponse);\r\n\r\n const amountString = params.Amount ?? '0';\r\n const amountMajor = parseFloat(amountString);\r\n const amountMinor = Math.round(amountMajor * 100);\r\n\r\n const parsed: ParsedWebhookEvent = {\r\n provider: 'cardcom',\r\n eventId: `${lowProfileCode}_${internalDealNumber}_${Date.now()}`,\r\n eventType,\r\n providerTransactionId: internalDealNumber || lowProfileCode,\r\n timestamp: new Date(),\r\n rawPayload,\r\n newStatus: status,\r\n amountMinor,\r\n currency: params.Currency ?? 'ILS',\r\n };\r\n\r\n if (dealResponse === 2 || responseCode !== 0) {\r\n parsed.error = {\r\n code: String(responseCode),\r\n message: CARDCOM_DEAL_RESPONSE_ACTIONS[dealResponse] ?? 'Payment failed',\r\n };\r\n }\r\n\r\n return { success: true, event: parsed };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Parse error',\r\n };\r\n }\r\n }\r\n\r\n async processEvent(\r\n event: ParsedWebhookEvent\r\n ): Promise<WebhookProcessingResult> {\r\n const action = this.getActionForEvent(event.eventType);\r\n\r\n if (action === 'ignored') {\r\n return {\r\n success: true,\r\n action: 'ignored_event_type',\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n transactionId: event.providerTransactionId,\r\n action: 'status_updated',\r\n };\r\n }\r\n\r\n canHandle(eventType: string): boolean {\r\n return this.supportedEventTypes.includes(\r\n eventType as CardcomWebhookEventType\r\n );\r\n }\r\n\r\n async reconcile(\r\n _transactionId: string,\r\n _providerTransactionId: string\r\n ): Promise<ReconciliationResult> {\r\n return {\r\n reconciled: false,\r\n finalStatus: 'created',\r\n source: 'provider_query',\r\n statusChanged: false,\r\n };\r\n }\r\n\r\n mapEventType(providerEventType: string): string {\r\n return providerEventType;\r\n }\r\n\r\n mapStatus(providerStatus: string): TransactionStatus | null {\r\n const dealResponse = parseInt(providerStatus, 10);\r\n if (isNaN(dealResponse)) {\r\n return null;\r\n }\r\n return mapCardcomDealResponseToStatus(dealResponse);\r\n }\r\n\r\n private getActionForEvent(eventType: string): 'status_update' | 'ignored' {\r\n switch (eventType) {\r\n case 'payment.completed':\r\n case 'payment.declined':\r\n case 'payment.authorized':\r\n return 'status_update';\r\n default:\r\n return 'ignored';\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Callback Utility Functions\r\n// ============================================================================\r\n\r\nexport function validateCardcomCallback(\r\n params: Record<string, unknown>\r\n): { valid: boolean; error?: string } {\r\n const requiredFields = ['ResponseCode', 'LowProfileCode'];\r\n\r\n for (const field of requiredFields) {\r\n if (!params[field]) {\r\n return {\r\n valid: false,\r\n error: `Missing required field: ${field}`,\r\n };\r\n }\r\n }\r\n\r\n const responseCode = parseInt(String(params.ResponseCode), 10);\r\n if (isNaN(responseCode)) {\r\n return {\r\n valid: false,\r\n error: 'Invalid ResponseCode format',\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\nexport function parseCardcomCallbackUrl(url: string): CardcomWebhookParams {\r\n try {\r\n const urlObj = new URL(url);\r\n const params: CardcomWebhookParams = {};\r\n\r\n params.ResponseCode = urlObj.searchParams.get('ResponseCode') ?? undefined;\r\n params.LowProfileCode =\r\n urlObj.searchParams.get('LowProfileCode') ?? undefined;\r\n params.DealResponse = urlObj.searchParams.get('DealResponse') ?? undefined;\r\n params.OperationResponse =\r\n urlObj.searchParams.get('OperationResponse') ?? undefined;\r\n params.InternalDealNumber =\r\n urlObj.searchParams.get('InternalDealNumber') ?? undefined;\r\n params.Amount = urlObj.searchParams.get('Amount') ?? undefined;\r\n params.Currency = urlObj.searchParams.get('Currency') ?? undefined;\r\n params.CardMask = urlObj.searchParams.get('CardMask') ?? undefined;\r\n params.Token = urlObj.searchParams.get('Token') ?? undefined;\r\n\r\n return params;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function isCardcomCallbackSuccess(params: CardcomWebhookParams): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && dealResponse === 1;\r\n}\r\n\r\nexport function isCardcomCallbackAuthorized(\r\n params: CardcomWebhookParams\r\n): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && (dealResponse === 0 || dealResponse === 1);\r\n}\r\n\r\nexport function getCardcomCallbackError(\r\n params: CardcomWebhookParams\r\n): string | null {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n if (responseCode === 0 && dealResponse === 1) {\r\n return null;\r\n }\r\n\r\n if (dealResponse === 2) {\r\n return 'Payment declined by card issuer';\r\n }\r\n\r\n if (responseCode !== 0) {\r\n return `Payment failed with code ${responseCode}`;\r\n }\r\n\r\n return 'Payment processing error';\r\n}\r\n"],"mappings":"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","names":["CardcomOperation","CardcomTransactionType"]}
1
+ {"version":3,"sources":["../../src/providers/cardcom/index.ts","../../src/providers/cardcom/cardcom-provider.ts","../../src/providers/cardcom/cardcom-types.ts","../../src/providers/cardcom/cardcom-webhook-handler.ts"],"sourcesContent":["/**\r\n * Cardcom Provider Exports\r\n */\r\n\r\n// Provider and webhook handler\r\nexport { CardcomProvider, type CardcomProviderConfig } from './cardcom-provider.js';\r\nexport { CardcomWebhookHandler } from './cardcom-webhook-handler.js';\r\n\r\n// Types\r\nexport type {\r\n CardcomConfig,\r\n CardcomLowProfileRequest,\r\n CardcomLowProfileResponse,\r\n CardcomLowProfileStatusRequest,\r\n CardcomLowProfileStatusResponse,\r\n CardcomDirectChargeRequest,\r\n CardcomDirectChargeResponse,\r\n CardcomRefundRequest,\r\n CardcomRefundResponse,\r\n CardcomWebhookParams,\r\n CardcomWebhookEventType,\r\n} from './cardcom-types.js';\r\n\r\nexport {\r\n CardcomOperation,\r\n CardcomTransactionType,\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n CARDCOM_RESPONSE_CODE_MAP,\r\n CARDCOM_CURRENCY_CODES,\r\n CARDCOM_LANGUAGE_CODES,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n getCurrencyCode,\r\n} from './cardcom-types.js';\r\n\r\n// Webhook utilities\r\nexport {\r\n validateCardcomCallback,\r\n parseCardcomCallbackUrl,\r\n isCardcomCallbackSuccess,\r\n isCardcomCallbackAuthorized,\r\n getCardcomCallbackError,\r\n} from './cardcom-webhook-handler.js';\r\n","/**\r\n * Cardcom Provider Implementation\r\n *\r\n * Implements IPaymentProvider for Cardcom payment gateway (Israeli market).\r\n * Uses Low Profile (hosted page) for PCI compliance and direct API for operations.\r\n * Supports Two-Phase Commit (J5) with SuspendDealOnly operation.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport * as crypto from 'crypto';\r\nimport type {\r\n PaymentProvider,\r\n CreatePaymentIntentParams,\r\n PaymentIntentResult,\r\n AuthorizePaymentParams,\r\n AuthorizationResult,\r\n CapturePaymentParams,\r\n CaptureResult,\r\n VoidPaymentParams,\r\n VoidResult,\r\n RefundParams,\r\n RefundResult,\r\n ProviderHealthStatus,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IPaymentProvider,\r\n SavePaymentMethodParams,\r\n SavePaymentMethodResult,\r\n DeletePaymentMethodResult,\r\n CreateSetupIntentParams,\r\n SetupIntentResult,\r\n CreateCustomerParams,\r\n CreateCustomerResult,\r\n} from '@nehorai/payments/providers';\r\nimport { calculateCaptureDeadline } from '@nehorai/payments/types';\r\nimport {\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CardcomOperation,\r\n getCurrencyCode,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n type CardcomLowProfileRequest,\r\n type CardcomLowProfileResponse,\r\n type CardcomLowProfileStatusResponse,\r\n type CardcomRefundRequest,\r\n type CardcomRefundResponse,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom provider constructor config\r\n */\r\nexport interface CardcomProviderConfig {\r\n terminalNumber: string;\r\n apiName: string;\r\n apiPassword: string;\r\n webhookSecret?: string;\r\n}\r\n\r\n/**\r\n * Cardcom Payment Provider\r\n *\r\n * Full implementation of IPaymentProvider for Cardcom.\r\n */\r\nexport class CardcomProvider implements IPaymentProvider {\r\n readonly name: PaymentProvider = 'cardcom';\r\n readonly supportedCurrencies = CARDCOM_SUPPORTED_CURRENCIES;\r\n readonly supportsRecurring = true;\r\n readonly supportsSplitPayments = false;\r\n\r\n private config: CardcomProviderConfig;\r\n\r\n constructor(config: CardcomProviderConfig) {\r\n if (!config.terminalNumber || !config.apiName || !config.apiPassword) {\r\n throw new Error(\r\n 'CardcomProvider requires terminalNumber, apiName, and apiPassword in config'\r\n );\r\n }\r\n this.config = config;\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Intent Operations\r\n // ==========================================================================\r\n\r\n async createPaymentIntent(\r\n params: CreatePaymentIntentParams\r\n ): Promise<PaymentIntentResult> {\r\n try {\r\n const amountMajor = params.amount.amountMinor / 100;\r\n\r\n const operation =\r\n params.captureMethod === 'manual'\r\n ? CardcomOperation.SUSPEND_DEAL_ONLY\r\n : params.metadata?.savePaymentMethod\r\n ? CardcomOperation.BILL_AND_CREATE_TOKEN\r\n : CardcomOperation.BILL_ONLY;\r\n\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: amountMajor,\r\n CoinID: getCurrencyCode(params.amount.currency),\r\n Operation: operation,\r\n Language: 'en',\r\n ReturnUrl: params.returnUrl,\r\n ErrorUrl: params.returnUrl,\r\n ProductName: params.description ?? 'Payment',\r\n InternalDealNumber: params.idempotencyKey,\r\n SendEmail: false,\r\n };\r\n\r\n if (params.metadata?.customerName) {\r\n request.CustomerName = String(params.metadata.customerName);\r\n }\r\n if (params.metadata?.customerEmail) {\r\n request.Email = String(params.metadata.customerEmail);\r\n }\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n errorCode: String(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerIntentId: response.LowProfileCode!,\r\n redirectUrl: response.PaymentUrl,\r\n status: 'created',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async authorize(params: AuthorizePaymentParams): Promise<AuthorizationResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to check payment status',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n authorizationCode: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'authorized',\r\n captureDeadline: calculateCaptureDeadline(new Date()),\r\n };\r\n }\r\n\r\n if (status.DealResponse === 2) {\r\n return {\r\n success: false,\r\n error: 'Payment declined',\r\n status: 'failed',\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not yet completed',\r\n status: 'pending_authorization',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async capture(params: CapturePaymentParams): Promise<CaptureResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to capture payment',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n providerTransactionId: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'captured',\r\n capturedAmount: {\r\n amountMinor: Math.round((status.Amount ?? 0) * 100),\r\n currency: status.Currency ?? params.amount?.currency ?? 'ILS',\r\n },\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not authorized for capture',\r\n status: mapCardcomDealResponseToStatus(status.DealResponse ?? 3),\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async void(_params: VoidPaymentParams): Promise<VoidResult> {\r\n return {\r\n success: false,\r\n error: 'Void operation not supported via API. Please use Cardcom merchant dashboard.',\r\n };\r\n }\r\n\r\n async refund(params: RefundParams): Promise<RefundResult> {\r\n try {\r\n const refundAmount = params.amount\r\n ? params.amount.amountMinor / 100\r\n : undefined;\r\n\r\n if (!refundAmount) {\r\n return {\r\n success: false,\r\n error: 'Refund amount is required',\r\n };\r\n }\r\n\r\n const request: CardcomRefundRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n InternalDealNumber: params.providerTransactionId,\r\n Amount: refundAmount,\r\n CoinID: params.amount ? getCurrencyCode(params.amount.currency) : 1,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomRefundResponse>(\r\n CARDCOM_ENDPOINTS.REFUND,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerRefundId: response.InternalDealNumber ?? params.providerTransactionId,\r\n refundedAmount: {\r\n amountMinor: Math.round((response.Amount ?? 0) * 100),\r\n currency: params.amount?.currency ?? 'ILS',\r\n },\r\n status: 'succeeded',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Method Tokenization\r\n // ==========================================================================\r\n\r\n async createSetupIntent(\r\n params: CreateSetupIntentParams\r\n ): Promise<SetupIntentResult> {\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 0,\r\n Operation: CardcomOperation.CREATE_TOKEN_ONLY,\r\n Language: 'en',\r\n InternalDealNumber: `setup_${params.userId}_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n setupIntentId: response.LowProfileCode!,\r\n clientSecret: response.PaymentUrl,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async savePaymentMethod(\r\n params: SavePaymentMethodParams\r\n ): Promise<SavePaymentMethodResult> {\r\n try {\r\n const lowProfileCode = params.setupData.lowProfileCode as string;\r\n\r\n if (!lowProfileCode) {\r\n return {\r\n success: false,\r\n error: 'Low profile code is required',\r\n };\r\n }\r\n\r\n const statusResponse = await this.getLowProfileStatus(lowProfileCode);\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to retrieve payment method',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (!status.Token) {\r\n return {\r\n success: false,\r\n error: 'No token created',\r\n };\r\n }\r\n\r\n const [expMonth, expYear] = (status.CardExpiration ?? '/').split('/');\r\n\r\n return {\r\n success: true,\r\n paymentMethodId: status.Token,\r\n cardBrand: status.CardType ?? 'unknown',\r\n cardLast4: status.CardMask?.slice(-4),\r\n cardExpMonth: expMonth?.padStart(2, '0'),\r\n cardExpYear: expYear ? `20${expYear}` : undefined,\r\n cardBin: status.CardBin,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async deletePaymentMethod(\r\n _paymentMethodId: string\r\n ): Promise<DeletePaymentMethodResult> {\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n // ==========================================================================\r\n // Customer Management\r\n // ==========================================================================\r\n\r\n async createCustomer(params: CreateCustomerParams): Promise<CreateCustomerResult> {\r\n return {\r\n success: true,\r\n customerId: params.userId,\r\n };\r\n }\r\n\r\n async getOrCreateCustomer(\r\n userId: string,\r\n email: string\r\n ): Promise<CreateCustomerResult> {\r\n return this.createCustomer({ userId, email });\r\n }\r\n\r\n // ==========================================================================\r\n // Health & Status\r\n // ==========================================================================\r\n\r\n async getHealth(): Promise<ProviderHealthStatus> {\r\n const start = Date.now();\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 1,\r\n Operation: CardcomOperation.BILL_ONLY,\r\n InternalDealNumber: `health_check_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n const healthy = response.ResponseCode === 0 || response.ResponseCode === 1;\r\n\r\n return {\r\n provider: 'cardcom',\r\n healthy,\r\n lastChecked: new Date(),\r\n avgLatencyMs: Date.now() - start,\r\n circuitBreakerOpen: false,\r\n };\r\n } catch {\r\n return {\r\n provider: 'cardcom',\r\n healthy: false,\r\n lastChecked: new Date(),\r\n circuitBreakerOpen: false,\r\n };\r\n }\r\n }\r\n\r\n validateWebhookSignature(payload: string, signature: string): boolean {\r\n if (!this.config.webhookSecret) {\r\n return false;\r\n }\r\n\r\n try {\r\n const expectedSignature = crypto\r\n .createHmac('sha256', this.config.webhookSecret)\r\n .update(payload)\r\n .digest('hex');\r\n\r\n return crypto.timingSafeEqual(\r\n Buffer.from(signature),\r\n Buffer.from(expectedSignature)\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getPaymentIntentStatus(\r\n providerIntentId: string\r\n ): Promise<{ status: string; error?: string }> {\r\n try {\r\n const result = await this.getLowProfileStatus(providerIntentId);\r\n\r\n if (!result.success || !result.data) {\r\n return {\r\n status: 'unknown',\r\n error: result.error,\r\n };\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(\r\n result.data.DealResponse ?? 0\r\n );\r\n\r\n return { status };\r\n } catch (error) {\r\n return {\r\n status: 'unknown',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Helper Methods\r\n // ==========================================================================\r\n\r\n private async makeRequest<T>(\r\n endpoint: string,\r\n data: Record<string, unknown>\r\n ): Promise<T> {\r\n const url = `${CARDCOM_API_BASE}${endpoint}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Cardcom API error: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n private async getLowProfileStatus(\r\n lowProfileCode: string\r\n ): Promise<{\r\n success: boolean;\r\n data?: CardcomLowProfileStatusResponse;\r\n error?: string;\r\n }> {\r\n try {\r\n const params = new URLSearchParams({\r\n terminalnumber: this.config.terminalNumber,\r\n lowprofilecode: lowProfileCode,\r\n username: this.config.apiName,\r\n });\r\n\r\n const url = `${CARDCOM_API_BASE}${CARDCOM_ENDPOINTS.LOW_PROFILE_STATUS}?${params}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n });\r\n\r\n if (!response.ok) {\r\n return {\r\n success: false,\r\n error: `Status check failed: ${response.status}`,\r\n };\r\n }\r\n\r\n const data = (await response.json()) as CardcomLowProfileStatusResponse;\r\n\r\n if (data.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(data.ResponseCode),\r\n };\r\n }\r\n\r\n return { success: true, data };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Status check failed',\r\n };\r\n }\r\n }\r\n\r\n private handleError(error: unknown): {\r\n success: false;\r\n error: string;\r\n errorCode?: string;\r\n } {\r\n const errorMessage =\r\n error instanceof Error ? error.message : 'Unknown error occurred';\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n };\r\n }\r\n}\r\n","/**\r\n * Cardcom Type Definitions\r\n *\r\n * Type definitions for Cardcom payment gateway API v11.\r\n * Supports JSON API endpoints for Low Profile (hosted page) and direct transactions.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport type { TransactionStatus } from '@nehorai/payments/types';\r\n\r\n// ============================================================================\r\n// API Configuration\r\n// ============================================================================\r\n\r\nexport const CARDCOM_API_BASE = 'https://secure.cardcom.solutions';\r\n\r\nexport const CARDCOM_ENDPOINTS = {\r\n LOW_PROFILE_CREATE: '/api/v11/LowProfile/Create',\r\n LOW_PROFILE_STATUS: '/Interface/BillGoldGetLowProfileIndicator.aspx',\r\n DIRECT_CHARGE: '/api/v11/Transactions/Transaction',\r\n REFUND: '/api/v11/Transactions/RefundByTransactionId',\r\n} as const;\r\n\r\nexport const CARDCOM_SUPPORTED_CURRENCIES = ['ILS', 'USD', 'EUR', 'GBP'] as const;\r\n\r\nexport const CARDCOM_API_VERSION = 'v11';\r\n\r\n// ============================================================================\r\n// Cardcom Configuration\r\n// ============================================================================\r\n\r\nexport interface CardcomConfig {\r\n /** Terminal number (merchant ID) */\r\n terminalNumber: string;\r\n /** API username */\r\n apiName: string;\r\n /** API password */\r\n apiPassword: string;\r\n /** Webhook secret for signature validation */\r\n webhookSecret?: string;\r\n /** Environment (sandbox uses same endpoints but different credentials) */\r\n environment: 'sandbox' | 'production';\r\n}\r\n\r\n// ============================================================================\r\n// Operation Types\r\n// ============================================================================\r\n\r\nexport enum CardcomOperation {\r\n /** Charge immediately */\r\n BILL_ONLY = 1,\r\n /** Charge + save card token */\r\n BILL_AND_CREATE_TOKEN = 2,\r\n /** Save card without charging */\r\n CREATE_TOKEN_ONLY = 3,\r\n /** Authorize without capture (J5) */\r\n SUSPEND_DEAL_ONLY = 4,\r\n}\r\n\r\nexport enum CardcomTransactionType {\r\n REGULAR = 1,\r\n CREDIT = 2,\r\n INSTALLMENTS = 3,\r\n}\r\n\r\n// ============================================================================\r\n// Request Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n Sum: number;\r\n CoinID?: number;\r\n Operation?: CardcomOperation;\r\n Language?: string;\r\n ReturnUrl?: string;\r\n ErrorUrl?: string;\r\n ProductName?: string;\r\n CustomerName?: string;\r\n Email?: string;\r\n InvoiceLanguage?: string;\r\n SendEmail?: boolean;\r\n IndicatorUrl?: string;\r\n InternalDealNumber?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusRequest {\r\n terminalnumber: string;\r\n lowprofilecode: string;\r\n username: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n CardNumber: string;\r\n CVV: string;\r\n Year: string;\r\n Month: string;\r\n CardOwnerID: string;\r\n Sum: number;\r\n CoinID?: number;\r\n NumOfPayments?: number;\r\n Operation?: CardcomOperation;\r\n Token?: string;\r\n}\r\n\r\nexport interface CardcomRefundRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n InternalDealNumber: string;\r\n Amount: number;\r\n CoinID?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Response Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n LowProfileCode?: string;\r\n PaymentUrl?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n DealResponse?: number;\r\n OperationResponse?: number;\r\n InternalDealNumber?: string;\r\n Token?: string;\r\n CardMask?: string;\r\n CardType?: string;\r\n CardExpiration?: string;\r\n Amount?: number;\r\n Currency?: string;\r\n CardBin?: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n ApprovalNumber?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomRefundResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n Amount?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Webhook Types\r\n// ============================================================================\r\n\r\nexport interface CardcomWebhookParams {\r\n ResponseCode?: string;\r\n LowProfileCode?: string;\r\n DealResponse?: string;\r\n OperationResponse?: string;\r\n InternalDealNumber?: string;\r\n Amount?: string;\r\n Currency?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n}\r\n\r\nexport const CARDCOM_WEBHOOK_EVENTS = [\r\n 'payment.completed',\r\n 'payment.declined',\r\n 'payment.authorized',\r\n] as const;\r\n\r\nexport type CardcomWebhookEventType = (typeof CARDCOM_WEBHOOK_EVENTS)[number];\r\n\r\nexport const CARDCOM_DEAL_RESPONSE_ACTIONS: Record<number, string> = {\r\n 0: 'pending',\r\n 1: 'approved',\r\n 2: 'declined',\r\n 3: 'error',\r\n};\r\n\r\n// ============================================================================\r\n// Response Code Mapping\r\n// ============================================================================\r\n\r\nexport const CARDCOM_RESPONSE_CODE_MAP: Record<number, TransactionStatus> = {\r\n 0: 'created',\r\n 1: 'failed',\r\n 2: 'failed',\r\n 3: 'failed',\r\n 4: 'failed',\r\n 5: 'failed',\r\n 6: 'failed',\r\n 7: 'failed',\r\n 8: 'failed',\r\n 9: 'failed',\r\n 10: 'failed',\r\n};\r\n\r\nexport function mapCardcomDealResponseToStatus(\r\n dealResponse: number\r\n): TransactionStatus {\r\n switch (dealResponse) {\r\n case 0:\r\n return 'pending_authorization';\r\n case 1:\r\n return 'captured';\r\n case 2:\r\n return 'failed';\r\n case 3:\r\n return 'failed';\r\n default:\r\n return 'failed';\r\n }\r\n}\r\n\r\nexport function mapCardcomError(responseCode: number): string {\r\n const errorMessages: Record<number, string> = {\r\n 0: 'Success',\r\n 1: 'General error',\r\n 2: 'Invalid API credentials',\r\n 3: 'Invalid terminal number',\r\n 4: 'Invalid operation type',\r\n 5: 'Invalid card details',\r\n 6: 'Card declined by issuer',\r\n 7: 'Insufficient funds',\r\n 8: 'Invalid amount',\r\n 9: 'Transaction not found',\r\n 10: 'Duplicate transaction',\r\n 11: 'Terminal not active',\r\n 12: 'CVV validation failed',\r\n 13: 'Card expired',\r\n 14: 'Invalid currency',\r\n 15: 'Operation not supported',\r\n };\r\n\r\n return errorMessages[responseCode] ?? `Error code ${responseCode}`;\r\n}\r\n\r\nexport const CARDCOM_CURRENCY_CODES: Record<string, number> = {\r\n ILS: 1,\r\n USD: 2,\r\n EUR: 3,\r\n GBP: 4,\r\n};\r\n\r\nexport function getCurrencyCode(currency: string): number {\r\n return CARDCOM_CURRENCY_CODES[currency.toUpperCase()] ?? 1;\r\n}\r\n\r\nexport const CARDCOM_LANGUAGE_CODES = {\r\n en: 'en',\r\n he: 'he',\r\n} as const;\r\n","/**\r\n * Cardcom Webhook Handler\r\n *\r\n * Processes incoming Cardcom webhooks with idempotency.\r\n * Maps Cardcom callback events to transaction status updates.\r\n *\r\n * Cardcom uses GET callback parameters instead of POST webhooks.\r\n * Parameters are sent to ReturnUrl after payment completion.\r\n */\r\n\r\nimport type {\r\n PaymentProvider,\r\n TransactionStatus,\r\n WebhookProcessingResult,\r\n ReconciliationResult,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IWebhookHandler,\r\n ParsedWebhookEvent,\r\n ParseWebhookResult,\r\n} from '@nehorai/payments/providers';\r\nimport {\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n mapCardcomDealResponseToStatus,\r\n type CardcomWebhookEventType,\r\n type CardcomWebhookParams,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom Webhook Handler Implementation\r\n */\r\nexport class CardcomWebhookHandler implements IWebhookHandler {\r\n readonly provider: PaymentProvider = 'cardcom';\r\n readonly supportedEventTypes = CARDCOM_WEBHOOK_EVENTS;\r\n\r\n parseEvent(rawPayload: Record<string, unknown>): ParseWebhookResult {\r\n try {\r\n const params = rawPayload as unknown as CardcomWebhookParams;\r\n\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n const lowProfileCode = params.LowProfileCode ?? '';\r\n const internalDealNumber = params.InternalDealNumber ?? '';\r\n\r\n if (!lowProfileCode && !internalDealNumber) {\r\n return {\r\n success: false,\r\n error: 'Missing LowProfileCode or InternalDealNumber in callback',\r\n };\r\n }\r\n\r\n let eventType: CardcomWebhookEventType;\r\n if (dealResponse === 1) {\r\n eventType = 'payment.completed';\r\n } else if (dealResponse === 2) {\r\n eventType = 'payment.declined';\r\n } else if (dealResponse === 0 && responseCode === 0) {\r\n eventType = 'payment.authorized';\r\n } else {\r\n eventType = 'payment.declined';\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(dealResponse);\r\n\r\n const amountString = params.Amount ?? '0';\r\n const amountMajor = parseFloat(amountString);\r\n const amountMinor = Math.round(amountMajor * 100);\r\n\r\n const parsed: ParsedWebhookEvent = {\r\n provider: 'cardcom',\r\n // Stable id (deal identifier + event type) so redelivered callbacks\r\n // dedupe via the webhook_events (provider, provider_event_id) unique\r\n // constraint. Never include a timestamp here — that would defeat\r\n // idempotency and risk granting credits twice.\r\n eventId: `${lowProfileCode || internalDealNumber}:${eventType}`,\r\n eventType,\r\n providerTransactionId: internalDealNumber || lowProfileCode,\r\n timestamp: new Date(),\r\n rawPayload,\r\n newStatus: status,\r\n amountMinor,\r\n currency: params.Currency ?? 'ILS',\r\n };\r\n\r\n if (dealResponse === 2 || responseCode !== 0) {\r\n parsed.error = {\r\n code: String(responseCode),\r\n message: CARDCOM_DEAL_RESPONSE_ACTIONS[dealResponse] ?? 'Payment failed',\r\n };\r\n }\r\n\r\n return { success: true, event: parsed };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Parse error',\r\n };\r\n }\r\n }\r\n\r\n async processEvent(\r\n event: ParsedWebhookEvent\r\n ): Promise<WebhookProcessingResult> {\r\n const action = this.getActionForEvent(event.eventType);\r\n\r\n if (action === 'ignored') {\r\n return {\r\n success: true,\r\n action: 'ignored_event_type',\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n transactionId: event.providerTransactionId,\r\n action: 'status_updated',\r\n };\r\n }\r\n\r\n canHandle(eventType: string): boolean {\r\n return this.supportedEventTypes.includes(\r\n eventType as CardcomWebhookEventType\r\n );\r\n }\r\n\r\n async reconcile(\r\n _transactionId: string,\r\n _providerTransactionId: string\r\n ): Promise<ReconciliationResult> {\r\n return {\r\n reconciled: false,\r\n finalStatus: 'created',\r\n source: 'provider_query',\r\n statusChanged: false,\r\n };\r\n }\r\n\r\n mapEventType(providerEventType: string): string {\r\n return providerEventType;\r\n }\r\n\r\n mapStatus(providerStatus: string): TransactionStatus | null {\r\n const dealResponse = parseInt(providerStatus, 10);\r\n if (isNaN(dealResponse)) {\r\n return null;\r\n }\r\n return mapCardcomDealResponseToStatus(dealResponse);\r\n }\r\n\r\n private getActionForEvent(eventType: string): 'status_update' | 'ignored' {\r\n switch (eventType) {\r\n case 'payment.completed':\r\n case 'payment.declined':\r\n case 'payment.authorized':\r\n return 'status_update';\r\n default:\r\n return 'ignored';\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Callback Utility Functions\r\n// ============================================================================\r\n\r\nexport function validateCardcomCallback(\r\n params: Record<string, unknown>\r\n): { valid: boolean; error?: string } {\r\n const requiredFields = ['ResponseCode', 'LowProfileCode'];\r\n\r\n for (const field of requiredFields) {\r\n if (!params[field]) {\r\n return {\r\n valid: false,\r\n error: `Missing required field: ${field}`,\r\n };\r\n }\r\n }\r\n\r\n const responseCode = parseInt(String(params.ResponseCode), 10);\r\n if (isNaN(responseCode)) {\r\n return {\r\n valid: false,\r\n error: 'Invalid ResponseCode format',\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\nexport function parseCardcomCallbackUrl(url: string): CardcomWebhookParams {\r\n try {\r\n const urlObj = new URL(url);\r\n const params: CardcomWebhookParams = {};\r\n\r\n params.ResponseCode = urlObj.searchParams.get('ResponseCode') ?? undefined;\r\n params.LowProfileCode =\r\n urlObj.searchParams.get('LowProfileCode') ?? undefined;\r\n params.DealResponse = urlObj.searchParams.get('DealResponse') ?? undefined;\r\n params.OperationResponse =\r\n urlObj.searchParams.get('OperationResponse') ?? undefined;\r\n params.InternalDealNumber =\r\n urlObj.searchParams.get('InternalDealNumber') ?? undefined;\r\n params.Amount = urlObj.searchParams.get('Amount') ?? undefined;\r\n params.Currency = urlObj.searchParams.get('Currency') ?? undefined;\r\n params.CardMask = urlObj.searchParams.get('CardMask') ?? undefined;\r\n params.Token = urlObj.searchParams.get('Token') ?? undefined;\r\n\r\n return params;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function isCardcomCallbackSuccess(params: CardcomWebhookParams): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && dealResponse === 1;\r\n}\r\n\r\nexport function isCardcomCallbackAuthorized(\r\n params: CardcomWebhookParams\r\n): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && (dealResponse === 0 || dealResponse === 1);\r\n}\r\n\r\nexport function getCardcomCallbackError(\r\n params: CardcomWebhookParams\r\n): string | null {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n if (responseCode === 0 && dealResponse === 1) {\r\n return null;\r\n }\r\n\r\n if (dealResponse === 2) {\r\n return 'Payment declined by card issuer';\r\n }\r\n\r\n if (responseCode !== 0) {\r\n return `Payment failed with code ${responseCode}`;\r\n }\r\n\r\n return 'Payment processing error';\r\n}\r\n"],"mappings":"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","names":["CardcomOperation","CardcomTransactionType"]}
@@ -521,7 +521,11 @@ var CardcomWebhookHandler = class {
521
521
  const amountMinor = Math.round(amountMajor * 100);
522
522
  const parsed = {
523
523
  provider: "cardcom",
524
- eventId: `${lowProfileCode}_${internalDealNumber}_${Date.now()}`,
524
+ // Stable id (deal identifier + event type) so redelivered callbacks
525
+ // dedupe via the webhook_events (provider, provider_event_id) unique
526
+ // constraint. Never include a timestamp here — that would defeat
527
+ // idempotency and risk granting credits twice.
528
+ eventId: `${lowProfileCode || internalDealNumber}:${eventType}`,
525
529
  eventType,
526
530
  providerTransactionId: internalDealNumber || lowProfileCode,
527
531
  timestamp: /* @__PURE__ */ new Date(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/cardcom/cardcom-provider.ts","../../src/providers/cardcom/cardcom-types.ts","../../src/providers/cardcom/cardcom-webhook-handler.ts"],"sourcesContent":["/**\r\n * Cardcom Provider Implementation\r\n *\r\n * Implements IPaymentProvider for Cardcom payment gateway (Israeli market).\r\n * Uses Low Profile (hosted page) for PCI compliance and direct API for operations.\r\n * Supports Two-Phase Commit (J5) with SuspendDealOnly operation.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport * as crypto from 'crypto';\r\nimport type {\r\n PaymentProvider,\r\n CreatePaymentIntentParams,\r\n PaymentIntentResult,\r\n AuthorizePaymentParams,\r\n AuthorizationResult,\r\n CapturePaymentParams,\r\n CaptureResult,\r\n VoidPaymentParams,\r\n VoidResult,\r\n RefundParams,\r\n RefundResult,\r\n ProviderHealthStatus,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IPaymentProvider,\r\n SavePaymentMethodParams,\r\n SavePaymentMethodResult,\r\n DeletePaymentMethodResult,\r\n CreateSetupIntentParams,\r\n SetupIntentResult,\r\n CreateCustomerParams,\r\n CreateCustomerResult,\r\n} from '@nehorai/payments/providers';\r\nimport { calculateCaptureDeadline } from '@nehorai/payments/types';\r\nimport {\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CardcomOperation,\r\n getCurrencyCode,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n type CardcomLowProfileRequest,\r\n type CardcomLowProfileResponse,\r\n type CardcomLowProfileStatusResponse,\r\n type CardcomRefundRequest,\r\n type CardcomRefundResponse,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom provider constructor config\r\n */\r\nexport interface CardcomProviderConfig {\r\n terminalNumber: string;\r\n apiName: string;\r\n apiPassword: string;\r\n webhookSecret?: string;\r\n}\r\n\r\n/**\r\n * Cardcom Payment Provider\r\n *\r\n * Full implementation of IPaymentProvider for Cardcom.\r\n */\r\nexport class CardcomProvider implements IPaymentProvider {\r\n readonly name: PaymentProvider = 'cardcom';\r\n readonly supportedCurrencies = CARDCOM_SUPPORTED_CURRENCIES;\r\n readonly supportsRecurring = true;\r\n readonly supportsSplitPayments = false;\r\n\r\n private config: CardcomProviderConfig;\r\n\r\n constructor(config: CardcomProviderConfig) {\r\n if (!config.terminalNumber || !config.apiName || !config.apiPassword) {\r\n throw new Error(\r\n 'CardcomProvider requires terminalNumber, apiName, and apiPassword in config'\r\n );\r\n }\r\n this.config = config;\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Intent Operations\r\n // ==========================================================================\r\n\r\n async createPaymentIntent(\r\n params: CreatePaymentIntentParams\r\n ): Promise<PaymentIntentResult> {\r\n try {\r\n const amountMajor = params.amount.amountMinor / 100;\r\n\r\n const operation =\r\n params.captureMethod === 'manual'\r\n ? CardcomOperation.SUSPEND_DEAL_ONLY\r\n : params.metadata?.savePaymentMethod\r\n ? CardcomOperation.BILL_AND_CREATE_TOKEN\r\n : CardcomOperation.BILL_ONLY;\r\n\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: amountMajor,\r\n CoinID: getCurrencyCode(params.amount.currency),\r\n Operation: operation,\r\n Language: 'en',\r\n ReturnUrl: params.returnUrl,\r\n ErrorUrl: params.returnUrl,\r\n ProductName: params.description ?? 'Payment',\r\n InternalDealNumber: params.idempotencyKey,\r\n SendEmail: false,\r\n };\r\n\r\n if (params.metadata?.customerName) {\r\n request.CustomerName = String(params.metadata.customerName);\r\n }\r\n if (params.metadata?.customerEmail) {\r\n request.Email = String(params.metadata.customerEmail);\r\n }\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n errorCode: String(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerIntentId: response.LowProfileCode!,\r\n redirectUrl: response.PaymentUrl,\r\n status: 'created',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async authorize(params: AuthorizePaymentParams): Promise<AuthorizationResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to check payment status',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n authorizationCode: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'authorized',\r\n captureDeadline: calculateCaptureDeadline(new Date()),\r\n };\r\n }\r\n\r\n if (status.DealResponse === 2) {\r\n return {\r\n success: false,\r\n error: 'Payment declined',\r\n status: 'failed',\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not yet completed',\r\n status: 'pending_authorization',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async capture(params: CapturePaymentParams): Promise<CaptureResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to capture payment',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n providerTransactionId: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'captured',\r\n capturedAmount: {\r\n amountMinor: Math.round((status.Amount ?? 0) * 100),\r\n currency: status.Currency ?? params.amount?.currency ?? 'ILS',\r\n },\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not authorized for capture',\r\n status: mapCardcomDealResponseToStatus(status.DealResponse ?? 3),\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async void(_params: VoidPaymentParams): Promise<VoidResult> {\r\n return {\r\n success: false,\r\n error: 'Void operation not supported via API. Please use Cardcom merchant dashboard.',\r\n };\r\n }\r\n\r\n async refund(params: RefundParams): Promise<RefundResult> {\r\n try {\r\n const refundAmount = params.amount\r\n ? params.amount.amountMinor / 100\r\n : undefined;\r\n\r\n if (!refundAmount) {\r\n return {\r\n success: false,\r\n error: 'Refund amount is required',\r\n };\r\n }\r\n\r\n const request: CardcomRefundRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n InternalDealNumber: params.providerTransactionId,\r\n Amount: refundAmount,\r\n CoinID: params.amount ? getCurrencyCode(params.amount.currency) : 1,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomRefundResponse>(\r\n CARDCOM_ENDPOINTS.REFUND,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerRefundId: response.InternalDealNumber ?? params.providerTransactionId,\r\n refundedAmount: {\r\n amountMinor: Math.round((response.Amount ?? 0) * 100),\r\n currency: params.amount?.currency ?? 'ILS',\r\n },\r\n status: 'succeeded',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Method Tokenization\r\n // ==========================================================================\r\n\r\n async createSetupIntent(\r\n params: CreateSetupIntentParams\r\n ): Promise<SetupIntentResult> {\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 0,\r\n Operation: CardcomOperation.CREATE_TOKEN_ONLY,\r\n Language: 'en',\r\n InternalDealNumber: `setup_${params.userId}_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n setupIntentId: response.LowProfileCode!,\r\n clientSecret: response.PaymentUrl,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async savePaymentMethod(\r\n params: SavePaymentMethodParams\r\n ): Promise<SavePaymentMethodResult> {\r\n try {\r\n const lowProfileCode = params.setupData.lowProfileCode as string;\r\n\r\n if (!lowProfileCode) {\r\n return {\r\n success: false,\r\n error: 'Low profile code is required',\r\n };\r\n }\r\n\r\n const statusResponse = await this.getLowProfileStatus(lowProfileCode);\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to retrieve payment method',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (!status.Token) {\r\n return {\r\n success: false,\r\n error: 'No token created',\r\n };\r\n }\r\n\r\n const [expMonth, expYear] = (status.CardExpiration ?? '/').split('/');\r\n\r\n return {\r\n success: true,\r\n paymentMethodId: status.Token,\r\n cardBrand: status.CardType ?? 'unknown',\r\n cardLast4: status.CardMask?.slice(-4),\r\n cardExpMonth: expMonth?.padStart(2, '0'),\r\n cardExpYear: expYear ? `20${expYear}` : undefined,\r\n cardBin: status.CardBin,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async deletePaymentMethod(\r\n _paymentMethodId: string\r\n ): Promise<DeletePaymentMethodResult> {\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n // ==========================================================================\r\n // Customer Management\r\n // ==========================================================================\r\n\r\n async createCustomer(params: CreateCustomerParams): Promise<CreateCustomerResult> {\r\n return {\r\n success: true,\r\n customerId: params.userId,\r\n };\r\n }\r\n\r\n async getOrCreateCustomer(\r\n userId: string,\r\n email: string\r\n ): Promise<CreateCustomerResult> {\r\n return this.createCustomer({ userId, email });\r\n }\r\n\r\n // ==========================================================================\r\n // Health & Status\r\n // ==========================================================================\r\n\r\n async getHealth(): Promise<ProviderHealthStatus> {\r\n const start = Date.now();\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 1,\r\n Operation: CardcomOperation.BILL_ONLY,\r\n InternalDealNumber: `health_check_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n const healthy = response.ResponseCode === 0 || response.ResponseCode === 1;\r\n\r\n return {\r\n provider: 'cardcom',\r\n healthy,\r\n lastChecked: new Date(),\r\n avgLatencyMs: Date.now() - start,\r\n circuitBreakerOpen: false,\r\n };\r\n } catch {\r\n return {\r\n provider: 'cardcom',\r\n healthy: false,\r\n lastChecked: new Date(),\r\n circuitBreakerOpen: false,\r\n };\r\n }\r\n }\r\n\r\n validateWebhookSignature(payload: string, signature: string): boolean {\r\n if (!this.config.webhookSecret) {\r\n return false;\r\n }\r\n\r\n try {\r\n const expectedSignature = crypto\r\n .createHmac('sha256', this.config.webhookSecret)\r\n .update(payload)\r\n .digest('hex');\r\n\r\n return crypto.timingSafeEqual(\r\n Buffer.from(signature),\r\n Buffer.from(expectedSignature)\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getPaymentIntentStatus(\r\n providerIntentId: string\r\n ): Promise<{ status: string; error?: string }> {\r\n try {\r\n const result = await this.getLowProfileStatus(providerIntentId);\r\n\r\n if (!result.success || !result.data) {\r\n return {\r\n status: 'unknown',\r\n error: result.error,\r\n };\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(\r\n result.data.DealResponse ?? 0\r\n );\r\n\r\n return { status };\r\n } catch (error) {\r\n return {\r\n status: 'unknown',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Helper Methods\r\n // ==========================================================================\r\n\r\n private async makeRequest<T>(\r\n endpoint: string,\r\n data: Record<string, unknown>\r\n ): Promise<T> {\r\n const url = `${CARDCOM_API_BASE}${endpoint}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Cardcom API error: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n private async getLowProfileStatus(\r\n lowProfileCode: string\r\n ): Promise<{\r\n success: boolean;\r\n data?: CardcomLowProfileStatusResponse;\r\n error?: string;\r\n }> {\r\n try {\r\n const params = new URLSearchParams({\r\n terminalnumber: this.config.terminalNumber,\r\n lowprofilecode: lowProfileCode,\r\n username: this.config.apiName,\r\n });\r\n\r\n const url = `${CARDCOM_API_BASE}${CARDCOM_ENDPOINTS.LOW_PROFILE_STATUS}?${params}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n });\r\n\r\n if (!response.ok) {\r\n return {\r\n success: false,\r\n error: `Status check failed: ${response.status}`,\r\n };\r\n }\r\n\r\n const data = (await response.json()) as CardcomLowProfileStatusResponse;\r\n\r\n if (data.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(data.ResponseCode),\r\n };\r\n }\r\n\r\n return { success: true, data };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Status check failed',\r\n };\r\n }\r\n }\r\n\r\n private handleError(error: unknown): {\r\n success: false;\r\n error: string;\r\n errorCode?: string;\r\n } {\r\n const errorMessage =\r\n error instanceof Error ? error.message : 'Unknown error occurred';\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n };\r\n }\r\n}\r\n","/**\r\n * Cardcom Type Definitions\r\n *\r\n * Type definitions for Cardcom payment gateway API v11.\r\n * Supports JSON API endpoints for Low Profile (hosted page) and direct transactions.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport type { TransactionStatus } from '@nehorai/payments/types';\r\n\r\n// ============================================================================\r\n// API Configuration\r\n// ============================================================================\r\n\r\nexport const CARDCOM_API_BASE = 'https://secure.cardcom.solutions';\r\n\r\nexport const CARDCOM_ENDPOINTS = {\r\n LOW_PROFILE_CREATE: '/api/v11/LowProfile/Create',\r\n LOW_PROFILE_STATUS: '/Interface/BillGoldGetLowProfileIndicator.aspx',\r\n DIRECT_CHARGE: '/api/v11/Transactions/Transaction',\r\n REFUND: '/api/v11/Transactions/RefundByTransactionId',\r\n} as const;\r\n\r\nexport const CARDCOM_SUPPORTED_CURRENCIES = ['ILS', 'USD', 'EUR', 'GBP'] as const;\r\n\r\nexport const CARDCOM_API_VERSION = 'v11';\r\n\r\n// ============================================================================\r\n// Cardcom Configuration\r\n// ============================================================================\r\n\r\nexport interface CardcomConfig {\r\n /** Terminal number (merchant ID) */\r\n terminalNumber: string;\r\n /** API username */\r\n apiName: string;\r\n /** API password */\r\n apiPassword: string;\r\n /** Webhook secret for signature validation */\r\n webhookSecret?: string;\r\n /** Environment (sandbox uses same endpoints but different credentials) */\r\n environment: 'sandbox' | 'production';\r\n}\r\n\r\n// ============================================================================\r\n// Operation Types\r\n// ============================================================================\r\n\r\nexport enum CardcomOperation {\r\n /** Charge immediately */\r\n BILL_ONLY = 1,\r\n /** Charge + save card token */\r\n BILL_AND_CREATE_TOKEN = 2,\r\n /** Save card without charging */\r\n CREATE_TOKEN_ONLY = 3,\r\n /** Authorize without capture (J5) */\r\n SUSPEND_DEAL_ONLY = 4,\r\n}\r\n\r\nexport enum CardcomTransactionType {\r\n REGULAR = 1,\r\n CREDIT = 2,\r\n INSTALLMENTS = 3,\r\n}\r\n\r\n// ============================================================================\r\n// Request Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n Sum: number;\r\n CoinID?: number;\r\n Operation?: CardcomOperation;\r\n Language?: string;\r\n ReturnUrl?: string;\r\n ErrorUrl?: string;\r\n ProductName?: string;\r\n CustomerName?: string;\r\n Email?: string;\r\n InvoiceLanguage?: string;\r\n SendEmail?: boolean;\r\n IndicatorUrl?: string;\r\n InternalDealNumber?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusRequest {\r\n terminalnumber: string;\r\n lowprofilecode: string;\r\n username: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n CardNumber: string;\r\n CVV: string;\r\n Year: string;\r\n Month: string;\r\n CardOwnerID: string;\r\n Sum: number;\r\n CoinID?: number;\r\n NumOfPayments?: number;\r\n Operation?: CardcomOperation;\r\n Token?: string;\r\n}\r\n\r\nexport interface CardcomRefundRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n InternalDealNumber: string;\r\n Amount: number;\r\n CoinID?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Response Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n LowProfileCode?: string;\r\n PaymentUrl?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n DealResponse?: number;\r\n OperationResponse?: number;\r\n InternalDealNumber?: string;\r\n Token?: string;\r\n CardMask?: string;\r\n CardType?: string;\r\n CardExpiration?: string;\r\n Amount?: number;\r\n Currency?: string;\r\n CardBin?: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n ApprovalNumber?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomRefundResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n Amount?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Webhook Types\r\n// ============================================================================\r\n\r\nexport interface CardcomWebhookParams {\r\n ResponseCode?: string;\r\n LowProfileCode?: string;\r\n DealResponse?: string;\r\n OperationResponse?: string;\r\n InternalDealNumber?: string;\r\n Amount?: string;\r\n Currency?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n}\r\n\r\nexport const CARDCOM_WEBHOOK_EVENTS = [\r\n 'payment.completed',\r\n 'payment.declined',\r\n 'payment.authorized',\r\n] as const;\r\n\r\nexport type CardcomWebhookEventType = (typeof CARDCOM_WEBHOOK_EVENTS)[number];\r\n\r\nexport const CARDCOM_DEAL_RESPONSE_ACTIONS: Record<number, string> = {\r\n 0: 'pending',\r\n 1: 'approved',\r\n 2: 'declined',\r\n 3: 'error',\r\n};\r\n\r\n// ============================================================================\r\n// Response Code Mapping\r\n// ============================================================================\r\n\r\nexport const CARDCOM_RESPONSE_CODE_MAP: Record<number, TransactionStatus> = {\r\n 0: 'created',\r\n 1: 'failed',\r\n 2: 'failed',\r\n 3: 'failed',\r\n 4: 'failed',\r\n 5: 'failed',\r\n 6: 'failed',\r\n 7: 'failed',\r\n 8: 'failed',\r\n 9: 'failed',\r\n 10: 'failed',\r\n};\r\n\r\nexport function mapCardcomDealResponseToStatus(\r\n dealResponse: number\r\n): TransactionStatus {\r\n switch (dealResponse) {\r\n case 0:\r\n return 'pending_authorization';\r\n case 1:\r\n return 'captured';\r\n case 2:\r\n return 'failed';\r\n case 3:\r\n return 'failed';\r\n default:\r\n return 'failed';\r\n }\r\n}\r\n\r\nexport function mapCardcomError(responseCode: number): string {\r\n const errorMessages: Record<number, string> = {\r\n 0: 'Success',\r\n 1: 'General error',\r\n 2: 'Invalid API credentials',\r\n 3: 'Invalid terminal number',\r\n 4: 'Invalid operation type',\r\n 5: 'Invalid card details',\r\n 6: 'Card declined by issuer',\r\n 7: 'Insufficient funds',\r\n 8: 'Invalid amount',\r\n 9: 'Transaction not found',\r\n 10: 'Duplicate transaction',\r\n 11: 'Terminal not active',\r\n 12: 'CVV validation failed',\r\n 13: 'Card expired',\r\n 14: 'Invalid currency',\r\n 15: 'Operation not supported',\r\n };\r\n\r\n return errorMessages[responseCode] ?? `Error code ${responseCode}`;\r\n}\r\n\r\nexport const CARDCOM_CURRENCY_CODES: Record<string, number> = {\r\n ILS: 1,\r\n USD: 2,\r\n EUR: 3,\r\n GBP: 4,\r\n};\r\n\r\nexport function getCurrencyCode(currency: string): number {\r\n return CARDCOM_CURRENCY_CODES[currency.toUpperCase()] ?? 1;\r\n}\r\n\r\nexport const CARDCOM_LANGUAGE_CODES = {\r\n en: 'en',\r\n he: 'he',\r\n} as const;\r\n","/**\r\n * Cardcom Webhook Handler\r\n *\r\n * Processes incoming Cardcom webhooks with idempotency.\r\n * Maps Cardcom callback events to transaction status updates.\r\n *\r\n * Cardcom uses GET callback parameters instead of POST webhooks.\r\n * Parameters are sent to ReturnUrl after payment completion.\r\n */\r\n\r\nimport type {\r\n PaymentProvider,\r\n TransactionStatus,\r\n WebhookProcessingResult,\r\n ReconciliationResult,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IWebhookHandler,\r\n ParsedWebhookEvent,\r\n ParseWebhookResult,\r\n} from '@nehorai/payments/providers';\r\nimport {\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n mapCardcomDealResponseToStatus,\r\n type CardcomWebhookEventType,\r\n type CardcomWebhookParams,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom Webhook Handler Implementation\r\n */\r\nexport class CardcomWebhookHandler implements IWebhookHandler {\r\n readonly provider: PaymentProvider = 'cardcom';\r\n readonly supportedEventTypes = CARDCOM_WEBHOOK_EVENTS;\r\n\r\n parseEvent(rawPayload: Record<string, unknown>): ParseWebhookResult {\r\n try {\r\n const params = rawPayload as unknown as CardcomWebhookParams;\r\n\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n const lowProfileCode = params.LowProfileCode ?? '';\r\n const internalDealNumber = params.InternalDealNumber ?? '';\r\n\r\n if (!lowProfileCode && !internalDealNumber) {\r\n return {\r\n success: false,\r\n error: 'Missing LowProfileCode or InternalDealNumber in callback',\r\n };\r\n }\r\n\r\n let eventType: CardcomWebhookEventType;\r\n if (dealResponse === 1) {\r\n eventType = 'payment.completed';\r\n } else if (dealResponse === 2) {\r\n eventType = 'payment.declined';\r\n } else if (dealResponse === 0 && responseCode === 0) {\r\n eventType = 'payment.authorized';\r\n } else {\r\n eventType = 'payment.declined';\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(dealResponse);\r\n\r\n const amountString = params.Amount ?? '0';\r\n const amountMajor = parseFloat(amountString);\r\n const amountMinor = Math.round(amountMajor * 100);\r\n\r\n const parsed: ParsedWebhookEvent = {\r\n provider: 'cardcom',\r\n eventId: `${lowProfileCode}_${internalDealNumber}_${Date.now()}`,\r\n eventType,\r\n providerTransactionId: internalDealNumber || lowProfileCode,\r\n timestamp: new Date(),\r\n rawPayload,\r\n newStatus: status,\r\n amountMinor,\r\n currency: params.Currency ?? 'ILS',\r\n };\r\n\r\n if (dealResponse === 2 || responseCode !== 0) {\r\n parsed.error = {\r\n code: String(responseCode),\r\n message: CARDCOM_DEAL_RESPONSE_ACTIONS[dealResponse] ?? 'Payment failed',\r\n };\r\n }\r\n\r\n return { success: true, event: parsed };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Parse error',\r\n };\r\n }\r\n }\r\n\r\n async processEvent(\r\n event: ParsedWebhookEvent\r\n ): Promise<WebhookProcessingResult> {\r\n const action = this.getActionForEvent(event.eventType);\r\n\r\n if (action === 'ignored') {\r\n return {\r\n success: true,\r\n action: 'ignored_event_type',\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n transactionId: event.providerTransactionId,\r\n action: 'status_updated',\r\n };\r\n }\r\n\r\n canHandle(eventType: string): boolean {\r\n return this.supportedEventTypes.includes(\r\n eventType as CardcomWebhookEventType\r\n );\r\n }\r\n\r\n async reconcile(\r\n _transactionId: string,\r\n _providerTransactionId: string\r\n ): Promise<ReconciliationResult> {\r\n return {\r\n reconciled: false,\r\n finalStatus: 'created',\r\n source: 'provider_query',\r\n statusChanged: false,\r\n };\r\n }\r\n\r\n mapEventType(providerEventType: string): string {\r\n return providerEventType;\r\n }\r\n\r\n mapStatus(providerStatus: string): TransactionStatus | null {\r\n const dealResponse = parseInt(providerStatus, 10);\r\n if (isNaN(dealResponse)) {\r\n return null;\r\n }\r\n return mapCardcomDealResponseToStatus(dealResponse);\r\n }\r\n\r\n private getActionForEvent(eventType: string): 'status_update' | 'ignored' {\r\n switch (eventType) {\r\n case 'payment.completed':\r\n case 'payment.declined':\r\n case 'payment.authorized':\r\n return 'status_update';\r\n default:\r\n return 'ignored';\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Callback Utility Functions\r\n// ============================================================================\r\n\r\nexport function validateCardcomCallback(\r\n params: Record<string, unknown>\r\n): { valid: boolean; error?: string } {\r\n const requiredFields = ['ResponseCode', 'LowProfileCode'];\r\n\r\n for (const field of requiredFields) {\r\n if (!params[field]) {\r\n return {\r\n valid: false,\r\n error: `Missing required field: ${field}`,\r\n };\r\n }\r\n }\r\n\r\n const responseCode = parseInt(String(params.ResponseCode), 10);\r\n if (isNaN(responseCode)) {\r\n return {\r\n valid: false,\r\n error: 'Invalid ResponseCode format',\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\nexport function parseCardcomCallbackUrl(url: string): CardcomWebhookParams {\r\n try {\r\n const urlObj = new URL(url);\r\n const params: CardcomWebhookParams = {};\r\n\r\n params.ResponseCode = urlObj.searchParams.get('ResponseCode') ?? undefined;\r\n params.LowProfileCode =\r\n urlObj.searchParams.get('LowProfileCode') ?? undefined;\r\n params.DealResponse = urlObj.searchParams.get('DealResponse') ?? undefined;\r\n params.OperationResponse =\r\n urlObj.searchParams.get('OperationResponse') ?? undefined;\r\n params.InternalDealNumber =\r\n urlObj.searchParams.get('InternalDealNumber') ?? undefined;\r\n params.Amount = urlObj.searchParams.get('Amount') ?? undefined;\r\n params.Currency = urlObj.searchParams.get('Currency') ?? undefined;\r\n params.CardMask = urlObj.searchParams.get('CardMask') ?? undefined;\r\n params.Token = urlObj.searchParams.get('Token') ?? undefined;\r\n\r\n return params;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function isCardcomCallbackSuccess(params: CardcomWebhookParams): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && dealResponse === 1;\r\n}\r\n\r\nexport function isCardcomCallbackAuthorized(\r\n params: CardcomWebhookParams\r\n): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && (dealResponse === 0 || dealResponse === 1);\r\n}\r\n\r\nexport function getCardcomCallbackError(\r\n params: CardcomWebhookParams\r\n): string | null {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n if (responseCode === 0 && dealResponse === 1) {\r\n return null;\r\n }\r\n\r\n if (dealResponse === 2) {\r\n return 'Payment declined by card issuer';\r\n }\r\n\r\n if (responseCode !== 0) {\r\n return `Payment failed with code ${responseCode}`;\r\n }\r\n\r\n return 'Payment processing error';\r\n}\r\n"],"mappings":"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","names":["CardcomOperation","CardcomTransactionType"]}
1
+ {"version":3,"sources":["../../src/providers/cardcom/cardcom-provider.ts","../../src/providers/cardcom/cardcom-types.ts","../../src/providers/cardcom/cardcom-webhook-handler.ts"],"sourcesContent":["/**\r\n * Cardcom Provider Implementation\r\n *\r\n * Implements IPaymentProvider for Cardcom payment gateway (Israeli market).\r\n * Uses Low Profile (hosted page) for PCI compliance and direct API for operations.\r\n * Supports Two-Phase Commit (J5) with SuspendDealOnly operation.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport * as crypto from 'crypto';\r\nimport type {\r\n PaymentProvider,\r\n CreatePaymentIntentParams,\r\n PaymentIntentResult,\r\n AuthorizePaymentParams,\r\n AuthorizationResult,\r\n CapturePaymentParams,\r\n CaptureResult,\r\n VoidPaymentParams,\r\n VoidResult,\r\n RefundParams,\r\n RefundResult,\r\n ProviderHealthStatus,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IPaymentProvider,\r\n SavePaymentMethodParams,\r\n SavePaymentMethodResult,\r\n DeletePaymentMethodResult,\r\n CreateSetupIntentParams,\r\n SetupIntentResult,\r\n CreateCustomerParams,\r\n CreateCustomerResult,\r\n} from '@nehorai/payments/providers';\r\nimport { calculateCaptureDeadline } from '@nehorai/payments/types';\r\nimport {\r\n CARDCOM_API_BASE,\r\n CARDCOM_ENDPOINTS,\r\n CARDCOM_SUPPORTED_CURRENCIES,\r\n CardcomOperation,\r\n getCurrencyCode,\r\n mapCardcomDealResponseToStatus,\r\n mapCardcomError,\r\n type CardcomLowProfileRequest,\r\n type CardcomLowProfileResponse,\r\n type CardcomLowProfileStatusResponse,\r\n type CardcomRefundRequest,\r\n type CardcomRefundResponse,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom provider constructor config\r\n */\r\nexport interface CardcomProviderConfig {\r\n terminalNumber: string;\r\n apiName: string;\r\n apiPassword: string;\r\n webhookSecret?: string;\r\n}\r\n\r\n/**\r\n * Cardcom Payment Provider\r\n *\r\n * Full implementation of IPaymentProvider for Cardcom.\r\n */\r\nexport class CardcomProvider implements IPaymentProvider {\r\n readonly name: PaymentProvider = 'cardcom';\r\n readonly supportedCurrencies = CARDCOM_SUPPORTED_CURRENCIES;\r\n readonly supportsRecurring = true;\r\n readonly supportsSplitPayments = false;\r\n\r\n private config: CardcomProviderConfig;\r\n\r\n constructor(config: CardcomProviderConfig) {\r\n if (!config.terminalNumber || !config.apiName || !config.apiPassword) {\r\n throw new Error(\r\n 'CardcomProvider requires terminalNumber, apiName, and apiPassword in config'\r\n );\r\n }\r\n this.config = config;\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Intent Operations\r\n // ==========================================================================\r\n\r\n async createPaymentIntent(\r\n params: CreatePaymentIntentParams\r\n ): Promise<PaymentIntentResult> {\r\n try {\r\n const amountMajor = params.amount.amountMinor / 100;\r\n\r\n const operation =\r\n params.captureMethod === 'manual'\r\n ? CardcomOperation.SUSPEND_DEAL_ONLY\r\n : params.metadata?.savePaymentMethod\r\n ? CardcomOperation.BILL_AND_CREATE_TOKEN\r\n : CardcomOperation.BILL_ONLY;\r\n\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: amountMajor,\r\n CoinID: getCurrencyCode(params.amount.currency),\r\n Operation: operation,\r\n Language: 'en',\r\n ReturnUrl: params.returnUrl,\r\n ErrorUrl: params.returnUrl,\r\n ProductName: params.description ?? 'Payment',\r\n InternalDealNumber: params.idempotencyKey,\r\n SendEmail: false,\r\n };\r\n\r\n if (params.metadata?.customerName) {\r\n request.CustomerName = String(params.metadata.customerName);\r\n }\r\n if (params.metadata?.customerEmail) {\r\n request.Email = String(params.metadata.customerEmail);\r\n }\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n errorCode: String(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerIntentId: response.LowProfileCode!,\r\n redirectUrl: response.PaymentUrl,\r\n status: 'created',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async authorize(params: AuthorizePaymentParams): Promise<AuthorizationResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to check payment status',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n authorizationCode: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'authorized',\r\n captureDeadline: calculateCaptureDeadline(new Date()),\r\n };\r\n }\r\n\r\n if (status.DealResponse === 2) {\r\n return {\r\n success: false,\r\n error: 'Payment declined',\r\n status: 'failed',\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not yet completed',\r\n status: 'pending_authorization',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async capture(params: CapturePaymentParams): Promise<CaptureResult> {\r\n try {\r\n const statusResponse = await this.getLowProfileStatus(\r\n params.providerIntentId\r\n );\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to capture payment',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (status.DealResponse === 1) {\r\n return {\r\n success: true,\r\n providerTransactionId: status.InternalDealNumber ?? params.providerIntentId,\r\n status: 'captured',\r\n capturedAmount: {\r\n amountMinor: Math.round((status.Amount ?? 0) * 100),\r\n currency: status.Currency ?? params.amount?.currency ?? 'ILS',\r\n },\r\n };\r\n }\r\n\r\n return {\r\n success: false,\r\n error: 'Payment not authorized for capture',\r\n status: mapCardcomDealResponseToStatus(status.DealResponse ?? 3),\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async void(_params: VoidPaymentParams): Promise<VoidResult> {\r\n return {\r\n success: false,\r\n error: 'Void operation not supported via API. Please use Cardcom merchant dashboard.',\r\n };\r\n }\r\n\r\n async refund(params: RefundParams): Promise<RefundResult> {\r\n try {\r\n const refundAmount = params.amount\r\n ? params.amount.amountMinor / 100\r\n : undefined;\r\n\r\n if (!refundAmount) {\r\n return {\r\n success: false,\r\n error: 'Refund amount is required',\r\n };\r\n }\r\n\r\n const request: CardcomRefundRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n InternalDealNumber: params.providerTransactionId,\r\n Amount: refundAmount,\r\n CoinID: params.amount ? getCurrencyCode(params.amount.currency) : 1,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomRefundResponse>(\r\n CARDCOM_ENDPOINTS.REFUND,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n providerRefundId: response.InternalDealNumber ?? params.providerTransactionId,\r\n refundedAmount: {\r\n amountMinor: Math.round((response.Amount ?? 0) * 100),\r\n currency: params.amount?.currency ?? 'ILS',\r\n },\r\n status: 'succeeded',\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Payment Method Tokenization\r\n // ==========================================================================\r\n\r\n async createSetupIntent(\r\n params: CreateSetupIntentParams\r\n ): Promise<SetupIntentResult> {\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 0,\r\n Operation: CardcomOperation.CREATE_TOKEN_ONLY,\r\n Language: 'en',\r\n InternalDealNumber: `setup_${params.userId}_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n if (response.ResponseCode !== 0 || !response.PaymentUrl) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(response.ResponseCode),\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n setupIntentId: response.LowProfileCode!,\r\n clientSecret: response.PaymentUrl,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async savePaymentMethod(\r\n params: SavePaymentMethodParams\r\n ): Promise<SavePaymentMethodResult> {\r\n try {\r\n const lowProfileCode = params.setupData.lowProfileCode as string;\r\n\r\n if (!lowProfileCode) {\r\n return {\r\n success: false,\r\n error: 'Low profile code is required',\r\n };\r\n }\r\n\r\n const statusResponse = await this.getLowProfileStatus(lowProfileCode);\r\n\r\n if (!statusResponse.success || !statusResponse.data) {\r\n return {\r\n success: false,\r\n error: statusResponse.error ?? 'Failed to retrieve payment method',\r\n };\r\n }\r\n\r\n const status = statusResponse.data;\r\n\r\n if (!status.Token) {\r\n return {\r\n success: false,\r\n error: 'No token created',\r\n };\r\n }\r\n\r\n const [expMonth, expYear] = (status.CardExpiration ?? '/').split('/');\r\n\r\n return {\r\n success: true,\r\n paymentMethodId: status.Token,\r\n cardBrand: status.CardType ?? 'unknown',\r\n cardLast4: status.CardMask?.slice(-4),\r\n cardExpMonth: expMonth?.padStart(2, '0'),\r\n cardExpYear: expYear ? `20${expYear}` : undefined,\r\n cardBin: status.CardBin,\r\n };\r\n } catch (error) {\r\n return this.handleError(error);\r\n }\r\n }\r\n\r\n async deletePaymentMethod(\r\n _paymentMethodId: string\r\n ): Promise<DeletePaymentMethodResult> {\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n // ==========================================================================\r\n // Customer Management\r\n // ==========================================================================\r\n\r\n async createCustomer(params: CreateCustomerParams): Promise<CreateCustomerResult> {\r\n return {\r\n success: true,\r\n customerId: params.userId,\r\n };\r\n }\r\n\r\n async getOrCreateCustomer(\r\n userId: string,\r\n email: string\r\n ): Promise<CreateCustomerResult> {\r\n return this.createCustomer({ userId, email });\r\n }\r\n\r\n // ==========================================================================\r\n // Health & Status\r\n // ==========================================================================\r\n\r\n async getHealth(): Promise<ProviderHealthStatus> {\r\n const start = Date.now();\r\n try {\r\n const request: CardcomLowProfileRequest = {\r\n TerminalNumber: this.config.terminalNumber,\r\n ApiName: this.config.apiName,\r\n ApiPassword: this.config.apiPassword,\r\n Sum: 1,\r\n Operation: CardcomOperation.BILL_ONLY,\r\n InternalDealNumber: `health_check_${Date.now()}`,\r\n };\r\n\r\n const response = await this.makeRequest<CardcomLowProfileResponse>(\r\n CARDCOM_ENDPOINTS.LOW_PROFILE_CREATE,\r\n request as unknown as Record<string, unknown>\r\n );\r\n\r\n const healthy = response.ResponseCode === 0 || response.ResponseCode === 1;\r\n\r\n return {\r\n provider: 'cardcom',\r\n healthy,\r\n lastChecked: new Date(),\r\n avgLatencyMs: Date.now() - start,\r\n circuitBreakerOpen: false,\r\n };\r\n } catch {\r\n return {\r\n provider: 'cardcom',\r\n healthy: false,\r\n lastChecked: new Date(),\r\n circuitBreakerOpen: false,\r\n };\r\n }\r\n }\r\n\r\n validateWebhookSignature(payload: string, signature: string): boolean {\r\n if (!this.config.webhookSecret) {\r\n return false;\r\n }\r\n\r\n try {\r\n const expectedSignature = crypto\r\n .createHmac('sha256', this.config.webhookSecret)\r\n .update(payload)\r\n .digest('hex');\r\n\r\n return crypto.timingSafeEqual(\r\n Buffer.from(signature),\r\n Buffer.from(expectedSignature)\r\n );\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getPaymentIntentStatus(\r\n providerIntentId: string\r\n ): Promise<{ status: string; error?: string }> {\r\n try {\r\n const result = await this.getLowProfileStatus(providerIntentId);\r\n\r\n if (!result.success || !result.data) {\r\n return {\r\n status: 'unknown',\r\n error: result.error,\r\n };\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(\r\n result.data.DealResponse ?? 0\r\n );\r\n\r\n return { status };\r\n } catch (error) {\r\n return {\r\n status: 'unknown',\r\n error: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Helper Methods\r\n // ==========================================================================\r\n\r\n private async makeRequest<T>(\r\n endpoint: string,\r\n data: Record<string, unknown>\r\n ): Promise<T> {\r\n const url = `${CARDCOM_API_BASE}${endpoint}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Cardcom API error: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return response.json() as Promise<T>;\r\n }\r\n\r\n private async getLowProfileStatus(\r\n lowProfileCode: string\r\n ): Promise<{\r\n success: boolean;\r\n data?: CardcomLowProfileStatusResponse;\r\n error?: string;\r\n }> {\r\n try {\r\n const params = new URLSearchParams({\r\n terminalnumber: this.config.terminalNumber,\r\n lowprofilecode: lowProfileCode,\r\n username: this.config.apiName,\r\n });\r\n\r\n const url = `${CARDCOM_API_BASE}${CARDCOM_ENDPOINTS.LOW_PROFILE_STATUS}?${params}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n });\r\n\r\n if (!response.ok) {\r\n return {\r\n success: false,\r\n error: `Status check failed: ${response.status}`,\r\n };\r\n }\r\n\r\n const data = (await response.json()) as CardcomLowProfileStatusResponse;\r\n\r\n if (data.ResponseCode !== 0) {\r\n return {\r\n success: false,\r\n error: mapCardcomError(data.ResponseCode),\r\n };\r\n }\r\n\r\n return { success: true, data };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Status check failed',\r\n };\r\n }\r\n }\r\n\r\n private handleError(error: unknown): {\r\n success: false;\r\n error: string;\r\n errorCode?: string;\r\n } {\r\n const errorMessage =\r\n error instanceof Error ? error.message : 'Unknown error occurred';\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n };\r\n }\r\n}\r\n","/**\r\n * Cardcom Type Definitions\r\n *\r\n * Type definitions for Cardcom payment gateway API v11.\r\n * Supports JSON API endpoints for Low Profile (hosted page) and direct transactions.\r\n *\r\n * @see https://secure.cardcom.solutions/api/v11/swagger/ui/index\r\n */\r\n\r\nimport type { TransactionStatus } from '@nehorai/payments/types';\r\n\r\n// ============================================================================\r\n// API Configuration\r\n// ============================================================================\r\n\r\nexport const CARDCOM_API_BASE = 'https://secure.cardcom.solutions';\r\n\r\nexport const CARDCOM_ENDPOINTS = {\r\n LOW_PROFILE_CREATE: '/api/v11/LowProfile/Create',\r\n LOW_PROFILE_STATUS: '/Interface/BillGoldGetLowProfileIndicator.aspx',\r\n DIRECT_CHARGE: '/api/v11/Transactions/Transaction',\r\n REFUND: '/api/v11/Transactions/RefundByTransactionId',\r\n} as const;\r\n\r\nexport const CARDCOM_SUPPORTED_CURRENCIES = ['ILS', 'USD', 'EUR', 'GBP'] as const;\r\n\r\nexport const CARDCOM_API_VERSION = 'v11';\r\n\r\n// ============================================================================\r\n// Cardcom Configuration\r\n// ============================================================================\r\n\r\nexport interface CardcomConfig {\r\n /** Terminal number (merchant ID) */\r\n terminalNumber: string;\r\n /** API username */\r\n apiName: string;\r\n /** API password */\r\n apiPassword: string;\r\n /** Webhook secret for signature validation */\r\n webhookSecret?: string;\r\n /** Environment (sandbox uses same endpoints but different credentials) */\r\n environment: 'sandbox' | 'production';\r\n}\r\n\r\n// ============================================================================\r\n// Operation Types\r\n// ============================================================================\r\n\r\nexport enum CardcomOperation {\r\n /** Charge immediately */\r\n BILL_ONLY = 1,\r\n /** Charge + save card token */\r\n BILL_AND_CREATE_TOKEN = 2,\r\n /** Save card without charging */\r\n CREATE_TOKEN_ONLY = 3,\r\n /** Authorize without capture (J5) */\r\n SUSPEND_DEAL_ONLY = 4,\r\n}\r\n\r\nexport enum CardcomTransactionType {\r\n REGULAR = 1,\r\n CREDIT = 2,\r\n INSTALLMENTS = 3,\r\n}\r\n\r\n// ============================================================================\r\n// Request Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n Sum: number;\r\n CoinID?: number;\r\n Operation?: CardcomOperation;\r\n Language?: string;\r\n ReturnUrl?: string;\r\n ErrorUrl?: string;\r\n ProductName?: string;\r\n CustomerName?: string;\r\n Email?: string;\r\n InvoiceLanguage?: string;\r\n SendEmail?: boolean;\r\n IndicatorUrl?: string;\r\n InternalDealNumber?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusRequest {\r\n terminalnumber: string;\r\n lowprofilecode: string;\r\n username: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n CardNumber: string;\r\n CVV: string;\r\n Year: string;\r\n Month: string;\r\n CardOwnerID: string;\r\n Sum: number;\r\n CoinID?: number;\r\n NumOfPayments?: number;\r\n Operation?: CardcomOperation;\r\n Token?: string;\r\n}\r\n\r\nexport interface CardcomRefundRequest {\r\n TerminalNumber: string;\r\n ApiName: string;\r\n ApiPassword: string;\r\n InternalDealNumber: string;\r\n Amount: number;\r\n CoinID?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Response Types\r\n// ============================================================================\r\n\r\nexport interface CardcomLowProfileResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n LowProfileCode?: string;\r\n PaymentUrl?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomLowProfileStatusResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n DealResponse?: number;\r\n OperationResponse?: number;\r\n InternalDealNumber?: string;\r\n Token?: string;\r\n CardMask?: string;\r\n CardType?: string;\r\n CardExpiration?: string;\r\n Amount?: number;\r\n Currency?: string;\r\n CardBin?: string;\r\n}\r\n\r\nexport interface CardcomDirectChargeResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n ApprovalNumber?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n DealCode?: string;\r\n}\r\n\r\nexport interface CardcomRefundResponse {\r\n ResponseCode: number;\r\n Description?: string;\r\n InternalDealNumber?: string;\r\n Amount?: number;\r\n}\r\n\r\n// ============================================================================\r\n// Webhook Types\r\n// ============================================================================\r\n\r\nexport interface CardcomWebhookParams {\r\n ResponseCode?: string;\r\n LowProfileCode?: string;\r\n DealResponse?: string;\r\n OperationResponse?: string;\r\n InternalDealNumber?: string;\r\n Amount?: string;\r\n Currency?: string;\r\n CardMask?: string;\r\n Token?: string;\r\n}\r\n\r\nexport const CARDCOM_WEBHOOK_EVENTS = [\r\n 'payment.completed',\r\n 'payment.declined',\r\n 'payment.authorized',\r\n] as const;\r\n\r\nexport type CardcomWebhookEventType = (typeof CARDCOM_WEBHOOK_EVENTS)[number];\r\n\r\nexport const CARDCOM_DEAL_RESPONSE_ACTIONS: Record<number, string> = {\r\n 0: 'pending',\r\n 1: 'approved',\r\n 2: 'declined',\r\n 3: 'error',\r\n};\r\n\r\n// ============================================================================\r\n// Response Code Mapping\r\n// ============================================================================\r\n\r\nexport const CARDCOM_RESPONSE_CODE_MAP: Record<number, TransactionStatus> = {\r\n 0: 'created',\r\n 1: 'failed',\r\n 2: 'failed',\r\n 3: 'failed',\r\n 4: 'failed',\r\n 5: 'failed',\r\n 6: 'failed',\r\n 7: 'failed',\r\n 8: 'failed',\r\n 9: 'failed',\r\n 10: 'failed',\r\n};\r\n\r\nexport function mapCardcomDealResponseToStatus(\r\n dealResponse: number\r\n): TransactionStatus {\r\n switch (dealResponse) {\r\n case 0:\r\n return 'pending_authorization';\r\n case 1:\r\n return 'captured';\r\n case 2:\r\n return 'failed';\r\n case 3:\r\n return 'failed';\r\n default:\r\n return 'failed';\r\n }\r\n}\r\n\r\nexport function mapCardcomError(responseCode: number): string {\r\n const errorMessages: Record<number, string> = {\r\n 0: 'Success',\r\n 1: 'General error',\r\n 2: 'Invalid API credentials',\r\n 3: 'Invalid terminal number',\r\n 4: 'Invalid operation type',\r\n 5: 'Invalid card details',\r\n 6: 'Card declined by issuer',\r\n 7: 'Insufficient funds',\r\n 8: 'Invalid amount',\r\n 9: 'Transaction not found',\r\n 10: 'Duplicate transaction',\r\n 11: 'Terminal not active',\r\n 12: 'CVV validation failed',\r\n 13: 'Card expired',\r\n 14: 'Invalid currency',\r\n 15: 'Operation not supported',\r\n };\r\n\r\n return errorMessages[responseCode] ?? `Error code ${responseCode}`;\r\n}\r\n\r\nexport const CARDCOM_CURRENCY_CODES: Record<string, number> = {\r\n ILS: 1,\r\n USD: 2,\r\n EUR: 3,\r\n GBP: 4,\r\n};\r\n\r\nexport function getCurrencyCode(currency: string): number {\r\n return CARDCOM_CURRENCY_CODES[currency.toUpperCase()] ?? 1;\r\n}\r\n\r\nexport const CARDCOM_LANGUAGE_CODES = {\r\n en: 'en',\r\n he: 'he',\r\n} as const;\r\n","/**\r\n * Cardcom Webhook Handler\r\n *\r\n * Processes incoming Cardcom webhooks with idempotency.\r\n * Maps Cardcom callback events to transaction status updates.\r\n *\r\n * Cardcom uses GET callback parameters instead of POST webhooks.\r\n * Parameters are sent to ReturnUrl after payment completion.\r\n */\r\n\r\nimport type {\r\n PaymentProvider,\r\n TransactionStatus,\r\n WebhookProcessingResult,\r\n ReconciliationResult,\r\n} from '@nehorai/payments/types';\r\nimport type {\r\n IWebhookHandler,\r\n ParsedWebhookEvent,\r\n ParseWebhookResult,\r\n} from '@nehorai/payments/providers';\r\nimport {\r\n CARDCOM_WEBHOOK_EVENTS,\r\n CARDCOM_DEAL_RESPONSE_ACTIONS,\r\n mapCardcomDealResponseToStatus,\r\n type CardcomWebhookEventType,\r\n type CardcomWebhookParams,\r\n} from './cardcom-types.js';\r\n\r\n/**\r\n * Cardcom Webhook Handler Implementation\r\n */\r\nexport class CardcomWebhookHandler implements IWebhookHandler {\r\n readonly provider: PaymentProvider = 'cardcom';\r\n readonly supportedEventTypes = CARDCOM_WEBHOOK_EVENTS;\r\n\r\n parseEvent(rawPayload: Record<string, unknown>): ParseWebhookResult {\r\n try {\r\n const params = rawPayload as unknown as CardcomWebhookParams;\r\n\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n const lowProfileCode = params.LowProfileCode ?? '';\r\n const internalDealNumber = params.InternalDealNumber ?? '';\r\n\r\n if (!lowProfileCode && !internalDealNumber) {\r\n return {\r\n success: false,\r\n error: 'Missing LowProfileCode or InternalDealNumber in callback',\r\n };\r\n }\r\n\r\n let eventType: CardcomWebhookEventType;\r\n if (dealResponse === 1) {\r\n eventType = 'payment.completed';\r\n } else if (dealResponse === 2) {\r\n eventType = 'payment.declined';\r\n } else if (dealResponse === 0 && responseCode === 0) {\r\n eventType = 'payment.authorized';\r\n } else {\r\n eventType = 'payment.declined';\r\n }\r\n\r\n const status = mapCardcomDealResponseToStatus(dealResponse);\r\n\r\n const amountString = params.Amount ?? '0';\r\n const amountMajor = parseFloat(amountString);\r\n const amountMinor = Math.round(amountMajor * 100);\r\n\r\n const parsed: ParsedWebhookEvent = {\r\n provider: 'cardcom',\r\n // Stable id (deal identifier + event type) so redelivered callbacks\r\n // dedupe via the webhook_events (provider, provider_event_id) unique\r\n // constraint. Never include a timestamp here — that would defeat\r\n // idempotency and risk granting credits twice.\r\n eventId: `${lowProfileCode || internalDealNumber}:${eventType}`,\r\n eventType,\r\n providerTransactionId: internalDealNumber || lowProfileCode,\r\n timestamp: new Date(),\r\n rawPayload,\r\n newStatus: status,\r\n amountMinor,\r\n currency: params.Currency ?? 'ILS',\r\n };\r\n\r\n if (dealResponse === 2 || responseCode !== 0) {\r\n parsed.error = {\r\n code: String(responseCode),\r\n message: CARDCOM_DEAL_RESPONSE_ACTIONS[dealResponse] ?? 'Payment failed',\r\n };\r\n }\r\n\r\n return { success: true, event: parsed };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : 'Parse error',\r\n };\r\n }\r\n }\r\n\r\n async processEvent(\r\n event: ParsedWebhookEvent\r\n ): Promise<WebhookProcessingResult> {\r\n const action = this.getActionForEvent(event.eventType);\r\n\r\n if (action === 'ignored') {\r\n return {\r\n success: true,\r\n action: 'ignored_event_type',\r\n };\r\n }\r\n\r\n return {\r\n success: true,\r\n transactionId: event.providerTransactionId,\r\n action: 'status_updated',\r\n };\r\n }\r\n\r\n canHandle(eventType: string): boolean {\r\n return this.supportedEventTypes.includes(\r\n eventType as CardcomWebhookEventType\r\n );\r\n }\r\n\r\n async reconcile(\r\n _transactionId: string,\r\n _providerTransactionId: string\r\n ): Promise<ReconciliationResult> {\r\n return {\r\n reconciled: false,\r\n finalStatus: 'created',\r\n source: 'provider_query',\r\n statusChanged: false,\r\n };\r\n }\r\n\r\n mapEventType(providerEventType: string): string {\r\n return providerEventType;\r\n }\r\n\r\n mapStatus(providerStatus: string): TransactionStatus | null {\r\n const dealResponse = parseInt(providerStatus, 10);\r\n if (isNaN(dealResponse)) {\r\n return null;\r\n }\r\n return mapCardcomDealResponseToStatus(dealResponse);\r\n }\r\n\r\n private getActionForEvent(eventType: string): 'status_update' | 'ignored' {\r\n switch (eventType) {\r\n case 'payment.completed':\r\n case 'payment.declined':\r\n case 'payment.authorized':\r\n return 'status_update';\r\n default:\r\n return 'ignored';\r\n }\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Callback Utility Functions\r\n// ============================================================================\r\n\r\nexport function validateCardcomCallback(\r\n params: Record<string, unknown>\r\n): { valid: boolean; error?: string } {\r\n const requiredFields = ['ResponseCode', 'LowProfileCode'];\r\n\r\n for (const field of requiredFields) {\r\n if (!params[field]) {\r\n return {\r\n valid: false,\r\n error: `Missing required field: ${field}`,\r\n };\r\n }\r\n }\r\n\r\n const responseCode = parseInt(String(params.ResponseCode), 10);\r\n if (isNaN(responseCode)) {\r\n return {\r\n valid: false,\r\n error: 'Invalid ResponseCode format',\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\nexport function parseCardcomCallbackUrl(url: string): CardcomWebhookParams {\r\n try {\r\n const urlObj = new URL(url);\r\n const params: CardcomWebhookParams = {};\r\n\r\n params.ResponseCode = urlObj.searchParams.get('ResponseCode') ?? undefined;\r\n params.LowProfileCode =\r\n urlObj.searchParams.get('LowProfileCode') ?? undefined;\r\n params.DealResponse = urlObj.searchParams.get('DealResponse') ?? undefined;\r\n params.OperationResponse =\r\n urlObj.searchParams.get('OperationResponse') ?? undefined;\r\n params.InternalDealNumber =\r\n urlObj.searchParams.get('InternalDealNumber') ?? undefined;\r\n params.Amount = urlObj.searchParams.get('Amount') ?? undefined;\r\n params.Currency = urlObj.searchParams.get('Currency') ?? undefined;\r\n params.CardMask = urlObj.searchParams.get('CardMask') ?? undefined;\r\n params.Token = urlObj.searchParams.get('Token') ?? undefined;\r\n\r\n return params;\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nexport function isCardcomCallbackSuccess(params: CardcomWebhookParams): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && dealResponse === 1;\r\n}\r\n\r\nexport function isCardcomCallbackAuthorized(\r\n params: CardcomWebhookParams\r\n): boolean {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n return responseCode === 0 && (dealResponse === 0 || dealResponse === 1);\r\n}\r\n\r\nexport function getCardcomCallbackError(\r\n params: CardcomWebhookParams\r\n): string | null {\r\n const responseCode = parseInt(params.ResponseCode ?? '1', 10);\r\n const dealResponse = parseInt(params.DealResponse ?? '0', 10);\r\n\r\n if (responseCode === 0 && dealResponse === 1) {\r\n return null;\r\n }\r\n\r\n if (dealResponse === 2) {\r\n return 'Payment declined by card issuer';\r\n }\r\n\r\n if (responseCode !== 0) {\r\n return `Payment failed with code ${responseCode}`;\r\n }\r\n\r\n return 'Payment processing error';\r\n}\r\n"],"mappings":"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","names":["CardcomOperation","CardcomTransactionType"]}
package/dist/factory.cjs CHANGED
@@ -1327,7 +1327,11 @@ var CardcomWebhookHandler = class {
1327
1327
  const amountMinor = Math.round(amountMajor * 100);
1328
1328
  const parsed = {
1329
1329
  provider: "cardcom",
1330
- eventId: `${lowProfileCode}_${internalDealNumber}_${Date.now()}`,
1330
+ // Stable id (deal identifier + event type) so redelivered callbacks
1331
+ // dedupe via the webhook_events (provider, provider_event_id) unique
1332
+ // constraint. Never include a timestamp here — that would defeat
1333
+ // idempotency and risk granting credits twice.
1334
+ eventId: `${lowProfileCode || internalDealNumber}:${eventType}`,
1331
1335
  eventType,
1332
1336
  providerTransactionId: internalDealNumber || lowProfileCode,
1333
1337
  timestamp: /* @__PURE__ */ new Date(),